Skip to content

Commit e655361

Browse files
test(dogfood): boot PlatformObjectsPlugin in the Setup/Account entry-view roster, so sys_exchange_rate resolves (#27873)
Refs #27813 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:dogfood 测试 `platform-app-object-entry-views.test.ts` 的组装名单里加上 `PlatformObjectsPlugin`(只注册对象、不贡献导航),让 Setup 的「汇率」入口指向的 `sys_exchange_rate` 能被解析到。 - 为什么改:`sys_exchange_rate` 上线后(#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 <details><summary>Reproduction at origin/main (3865159): the test file at its base blob, built closure</summary> ``` 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 ``` </details> <details><summary>Fixed head (ed373af): green, and sys_exchange_rate is now judged by rule (a)</summary> ``` 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 ``` </details> <details><summary>Teeth: the new roster entry deleted on disk, run, restored</summary> ``` ablation-replace: ok mutation landed: anchor 1 -> 0, blob 095a91f -> 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 (095a91f) and `git diff HEAD` is empty ``` </details> ## 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)`. <details><summary>The 51 derived commands and their exit codes</summary> ``` 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 ``` </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01QSeKYmTYfaPbLQD4BJfomW)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6e53003 commit e655361

1 file changed

Lines changed: 15 additions & 1 deletion

File tree

‎packages/qa/dogfood/test/platform-app-object-entry-views.test.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@
6666
* - The roster below mirrors check-app-nav-i18n's `CONTRIBUTORS`. A
6767
* contributor added there and not here is one this file does not see, so
6868
* the two move together.
69+
* - The one kind of entry that has no counterpart there is an OBJECT-ONLY
70+
* registrant (`apps: []`): a plugin that registers an object an entry
71+
* names and lands no nav id itself. `PlatformObjectsPlugin` is one — it
72+
* registers `sys_exchange_rate`, which the Setup contribution
73+
* `nav_exchange_rates` (shipped by `@objectstack/setup`) opens. That
74+
* gate's roster is a NAV roster that holds every entry to at least one
75+
* nav id and judges labels, not objects, so such a plugin is added here
76+
* only.
6977
* - plugin-auth's `nav_sso_providers` is contributed only when an external
7078
* IdP is wired, so no composition this file boots merges it.
7179
* - An object that declares ONLY caller-scoped list views cannot meet (a)
@@ -76,6 +84,7 @@
7684
import { describe, it, expect } from 'vitest';
7785
import { ObjectQL } from '@objectstack/objectql';
7886
import * as IdentityObjects from '@objectstack/platform-objects/identity';
87+
import { PlatformObjectsPlugin } from '@objectstack/platform-objects/plugin';
7988
import { createSetupAppPlugin } from '@objectstack/setup';
8089
import { createAccountAppPlugin } from '@objectstack/account';
8190
import { SecurityPlugin } from '@objectstack/plugin-security';
@@ -147,6 +156,10 @@ const CONTRIBUTORS: readonly Contributor[] = [
147156
manifests: [CLOUD_CONNECTION_UI_BUNDLE, MARKETPLACE_BROWSE_UI_BUNDLE, MARKETPLACE_INSTALLED_UI_BUNDLE] as Manifest[],
148157
}),
149158
},
159+
// Object-only: registers `sys_exchange_rate` (Setup → `nav_exchange_rates`)
160+
// and lands no nav id, so it lands in no app and has no entry in
161+
// check-app-nav-i18n's NAV roster (see "Reach" above).
162+
{ source: '@objectstack/platform-objects', apps: [], load: () => ({ plugin: new PlatformObjectsPlugin() }) },
150163
];
151164

152165
type NavItem = { id?: string; type?: string; objectName?: string; viewName?: string; children?: NavItem[] };
@@ -367,7 +380,8 @@ describe('the merged Setup and Account apps are booted whole', () => {
367380

368381
it('every object an entry names is declared by the composition or by the identity barrel', () => {
369382
// Remedy for a red here: add the plugin that registers the object to the
370-
// roster above (and to check-app-nav-i18n's), never a fallback.
383+
// roster above (and to check-app-nav-i18n's when it also lands a nav id;
384+
// an object-only registrant goes here alone, `apps: []`), never a fallback.
371385
expect(UNRESOLVED, 'named objects neither source declares').toEqual([]);
372386
});
373387

0 commit comments

Comments
 (0)