Skip to content

test(dogfood): boot PlatformObjectsPlugin in the Setup/Account entry-view roster, so sys_exchange_rate resolves - #27873

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-27813-exchange-rate-roster
Oct 30, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-27813-exchange-rate-roster

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Refs #27813
Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:dogfood 测试 platform-app-object-entry-views.test.ts 的组装名单里加上 PlatformObjectsPlugin(只注册对象、不贡献导航),让 Setup 的「汇率」入口指向的 sys_exchange_rate 能被解析到。
  • 为什么改:sys_exchange_rate 上线后(feat(platform-objects): sys_exchange_rate — an organization's dated exchange rates, admin-written and audited, with a Setup list under Localization #27246),main 上每次 push 的 Dogfood Regression Gate (2/3) 都红在该文件的「入口指向的对象两个来源都没有声明」断言;这是该测试自己写明的修法,不是兜底。
  • 风险与回滚:只改一个私有测试包里的测试文件,不动产品代码、不发布;回滚即 revert 本 PR。
  • 先看:packages/qa/dogfood/test/platform-app-object-entry-views.test.ts 的新名单条目(apps: [])和 Reach 段新增的说明。
  • 两分钟验证:pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/platform-app-object-entry-views.test.ts,预期 52/52 通过;删掉新条目再跑,预期只红 named objects neither source declares: ['sys_exchange_rate'] 一条。
  • 需要你做的:无,席位落地。

What changes

packages/qa/dogfood/test/platform-app-object-entry-views.test.ts boots the Setup and Account composition and requires every object a merged type: 'object' entry names to be declared by the composition's registry or by the identity barrel. The Setup contribution nav_exchange_rates (in SETUP_NAV_CONTRIBUTIONS, shipped by @objectstack/setup) opens sys_exchange_rate. That object is registered by PlatformObjectsPlugin (packages/platform-objects/src/plugin.ts, the objects: [SysMigration, SysMigrationJournal, SysSecret, SysExchangeRate, SysTrustedKey] manifest in init). The test's roster did not boot that plugin, so the catalogue assertion went red on every main push since 194e66c0 (#27246).

The fix adds PlatformObjectsPlugin to the test's roster as an object-only registrant (apps: []). It lands no nav id, so it adds no row to the per-app "lands at least one navigation id" invariant. The Reach section of the file header and the remedy comment on the assertion now say that an object-only registrant goes into this roster alone. The production composition boots the same plugin (packages/cli/src/commands/serve.ts), so this makes the test's composition closer to the real one. No product code changes. No fallback, skip or exclusion is added.

check-app-nav-i18n's roster is unchanged, and this was measured. The triage remedy says to add the plugin there too. That gate's CONTRIBUTORS is a NAV roster: every entry must land a nav id, and its header records that widening it with a non-nav entry was refused. Both ways of adding the plugin go red. Each probe was a one-time disk mutation through scripts/ablation-replace.mjs, restored to HEAD afterwards:

  • apps: ['setup']: the run fails with @objectstack/platform-objects (H3 probe) landed NO setup navigation id.
  • apps: []: the self-test fails with every CONTRIBUTORS entry declares at least one app IN the population.

That gate also already judges nav_exchange_rates's labels, because the entry comes from @objectstack/setup. It is green unchanged: OK (12 contributor(s), 4 locale(s), 2 app(s) — setup: 55 merged nav id(s) ...).

Tests

Reproduction at origin/main (3865159): the test file at its base blob, built closure
FAIL  |isolated| test/platform-app-object-entry-views.test.ts > the merged Setup and Account apps are booted whole > every object an entry names is declared by the composition or by the identity barrel
AssertionError: named objects neither source declares: expected [ 'sys_exchange_rate' ] to deeply equal []
    371|     expect(UNRESOLVED, 'named objects neither source declares').toEqua…
 Test Files  1 failed (1)
      Tests  1 failed | 51 passed (52)
os-verify-lock: VERDICT command-exit 1
Fixed head (ed373af): green, and sys_exchange_rate is now judged by rule (a)
 Test Files  1 passed (1)
      Tests  52 passed (52)
os-verify-lock: VERDICT command-exit 0

 ✓ |isolated| test/platform-app-object-entry-views.test.ts > (a) no object a Setup or Account entry opens declares a caller-scoped list view first > sys_exchange_rate 3ms
pnpm --filter @objectstack/dogfood typecheck  (tsc --noEmit) -> VERDICT command-exit 0
Teeth: the new roster entry deleted on disk, run, restored
ablation-replace: ok mutation landed: anchor 1 -> 0, blob 095a91fbc110 -> 825f7e6fdc38
AssertionError: named objects neither source declares: expected [ 'sys_exchange_rate' ] to deeply equal []
    384|     expect(UNRESOLVED, 'named objects neither source declares').toEqua…
      Tests  1 failed | 51 passed (52)
ablation-replace: ok restored: blob == HEAD (095a91fbc110) and `git diff HEAD` is empty

Acceptance notes

  • The Dogfood Regression Gate shards do not run on pull_request or in the merge queue. They run on main push and on the schedule only. The first CI reading of this fix is therefore the post-merge main push. The local runs above are the evidence for this PR.
  • The header says the roster "mirrors" check-app-nav-i18n's CONTRIBUTORS, and that was already inexact before this PR. That gate also boots @objectstack/service-settings, and this test does not. The plugin contributes only nav_settings_branding, which is type: 'url', so no object entry is missing from this test's population. This is noted only, not filed (carrier: none).

Verification

All local readings were taken at head ed373afd88, the final commit, with the dogfood dependency closure built (pnpm --filter '@objectstack/dogfood^...' build, lock VERDICT command-exit 0).

  • pnpm check:app-nav-i18n exited 0: OK (12 contributor(s), 4 locale(s), 2 app(s) — setup: 55 merged nav id(s), account: 12 merged nav id(s) — every id labelled in every locale).
  • The derived gate list is node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, 51 commands. Every command was run with its exit code written to disk before any pipe. 50 exited 0. pnpm check:dual-build-cjs-loads exited 3 with PREREQUISITE NOT MET, because eight packages outside this diff have no dist/. That one is NOT MEASURED locally and is left to CI.
  • --ran reconciliation: 51 derived famil(ies) accounted for — 50 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3).
The 51 derived commands and their exit codes
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-adoption.mjs :: exit 0
node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-issue-citations.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/docs-audit/check-affected-docs.mjs :: exit 0
node scripts/docs-audit/check-drift-comment.mjs :: exit 0
pnpm --filter @objectstack/spec run check:empty-state :: exit 0
pnpm --filter @objectstack/spec run check:liveness :: exit 0
pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0
pnpm --filter @objectstack/spec run check:variant-docs :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 0
pnpm check:dual-build-cjs-loads :: exit 3
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:issue-citations :: exit 0
pnpm check:keyed-text-bounds :: exit 0
pnpm check:lean-entry-closure :: exit 0
pnpm check:logger-receiver-detach :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:objectql-double-limit :: exit 0
pnpm check:org-identifier :: exit 0
pnpm check:page-declaration-shape :: exit 0
pnpm check:platform-object-tenancy-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: exit 0
pnpm check:slot-lookup :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 0
pnpm check:system-context-census :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0

Generated by Claude Code

…view roster, so sys_exchange_rate resolves

The Setup contribution nav_exchange_rates (shipped by @objectstack/setup)
opens sys_exchange_rate, which PlatformObjectsPlugin registers. The test's
composition did not boot that plugin, so its catalogue check reported the
object as declared by neither source. Added as an object-only registrant
(apps: []): it lands no nav id, so check-app-nav-i18n's NAV roster, which
holds every entry to at least one nav id, takes no counterpart.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYmTYfaPbLQD4BJfomW
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json c4cb5ec0c3936dd2c24ae2aa9a349449d8e33bef → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:devx#2 · os-justin · session_01QSeKYmTYfaPbLQD4BJfomW

席位核对 — ACCEPT · p0 main-red stop-bleed · domain:devx#2 · head ed373afd88 · 2026-10-30T02:43Z

维护者速读

  • 改了什么:dogfood 测试 platform-app-object-entry-views.test.ts 的组装清单里加上 PlatformObjectsPlugin。这个插件只注册对象、不贡献导航(apps: []),加上后,Setup「汇率」入口指向的 sys_exchange_rate 就能被解析到。
  • 为什么改:sys_exchange_rate 上线(feat(platform-objects): sys_exchange_rate — an organization's dated exchange rates, admin-written and audited, with a Setup list under Localization #27246)后,main 上每次 push 跑的 Dogfood Regression Gate (2/3) 都红在这一条断言上:「入口指向的对象,两个来源都没有声明」。这次的改法就是测试注释里自己写明的修法,没有加兜底。
  • 风险与回滚:只改私有测试包里的一个测试文件(+15/−1),不动产品代码,也不发布。回滚 = 还原本 PR。
  • 先看:清单里新加的那一条,以及文件头 Reach 段新加的说明。
  • 两分钟验证:pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/platform-app-object-entry-views.test.ts,应为 52/52 通过。
  • 需要你做的:无。席位落地。

席位意见:合入,止血。dogfood 分片不在 PR 和合并队列上跑(#22998,有意设计的两档速度),所以证据是 dev 的本地复现:修之前红,修之后绿,把新条目删掉又变红。真正的验证是合并后第一次 main push 时 shard 2/3 转绿。

Shape: draft → main, Refs #27813. This is a generated anchor, which closes on the next green 4-hourly run, so the PR does not use Fixes. 1 file, packages/qa/dogfood/test/platform-app-object-entry-views.test.ts, +15/−1. Labels tests, size/s, skip-changeset (private package). Non-governed, so the seat lands it. Report 6513471487, claim 6512824105.

Premise measured: red 2 of #27813, shard 2/3. It fails on every completed main push from b83baed2 to 05961150. The dev reproduced it at 38651598a7: 1 of 52 failed, at L371, expected [ sys_exchange_rate ] to deeply equal [].

Seat's own read: PlatformObjectsPlugin.init registers sys_exchange_rate, at platform-objects/src/plugin.ts:205, through the manifest service. The roster entry is { source: '@objectstack/platform-objects', apps: [], load: () => ({ plugin: new PlatformObjectsPlugin() }) }. The Reach header and the remedy comment now name the object-only registrant kind. Nothing is skipped and no fallback is added.

Accepted deviation, measured: the plugin is not added to check-app-nav-i18n's roster, which triage's text and the dispatch had asked for. Both ways of adding it red that gate. apps:['setup'] reds with "landed NO setup navigation id". apps:[] reds the self-test's "every CONTRIBUTORS entry declares at least one app IN the population". The gate's header records that widening this roster with a non-nav entry was refused. check:app-nav-i18n stays green unchanged, and it already labels nav_exchange_rates. Measurement wins over a suggested route.

Gates:

  • On head ed373afd88: 51 check-runs, 33 success, 18 skipped, 0 failure; mergeable_state: clean.
  • check-expected-skips --pr 27873: OK, all 18 skips are in main's roster (exit 0).
  • check-governed-merges --pr 27873: NOT governed, 16 changed lines.
  • Dev's union: 51 derived, 50 run with exit 0. The one NOT MEASURED is check:dual-build-cjs-loads, an unrelated dist prerequisite.
  • Local: 52/52 passed, plus the teeth run (1 of 52 fails without the entry).

Out of scope: the test header says its roster mirrors check-app-nav-i18n's, which also boots @objectstack/service-settings. That plugin's only entry is a url-type one, so no object entry is missing. This goes to Acceptance notes, not a card.

Landing: non-governed. The seat readies the PR and arms auto-merge in this act. After merge, the seat verifies the merged diff and reads the first main push's Dogfood Regression Gate (2/3). The anchor stays open until the 4-hourly full run is green, which also needs #27806 (red 1, PR #27878).


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant