Repository navigation
feat(spec)!: retire PackageDependency.optional and AppManifest.dependencies, the two unread dependency spellings (ADR-0141 D8) - #26401
Conversation
…encies, the two unread dependency spellings ADR-0141 D8 items 2 and 3: both keys are tombstoned with retiredKey(), registered in RETIRED_KEYS_BY_MAJOR[18] with one D3 semantic entry (dependency-unread-spellings-retired) and a step-18 rationale fragment. No D2 conversion: neither shape is a stack collection member. Claude-Session: https://claude.ai/code/session_01BkRZmjDUobsYmkGEjwjH9U Co-authored-by: Claude <noreply@anthropic.com>
…tes for the two dependency spellings Claude-Session: https://claude.ai/code/session_01BkRZmjDUobsYmkGEjwjH9U Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkRZmjDUobsYmkGEjwjH9U Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): ⛔ 1 release-owned page(s) name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 146 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin dba7dc98556105f4992b9dd70665b08702548651 && git checkout dba7dc98556105f4992b9dd70665b08702548651
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin b33dd25b2e7144b43eae3deb54026c03c6d1689f c65c5645cbeb0a7137e73bedd962003e40bc71e3 && git checkout -B drift-repro b33dd25b2e7144b43eae3deb54026c03c6d1689f && git merge --no-ff c65c5645cbeb0a7137e73bedd962003e40bc71e3
node scripts/docs-audit/affected-docs.mjs --json b33dd25b2e7144b43eae3deb54026c03c6d1689f
|
席位核对 · ACCEPT ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, Fixes #25792 (item 6, the card's last open item), minor changeset for @objectstack/spec with a BREAKING banner. Clause-②: no (narrowing), Metadata-protocol: narrowed. Governed (1 of 19 paths: docs/adr/**): landing tier H. |
| Fix | ADR-0141 D8 items 2 and 3, decided on a measured count: 0 readers and 0 writers outside packages/spec (repo incl. ui/, examples/, apps/) and in HotCRM 9464673. Both PackageDependencySchema.optional and AppManifestSchema.dependencies retire at once (startup-stage axis, no named external user) as retiredKey() tombstones that refuse any authored value with a prescription, not a silent strip. RETIRED_KEYS_BY_MAJOR[18] rows, D3 entry dependency-unread-spellings-retired, no D2 conversion (neither is a stack collection member). A dated D8 addendum records the counts. |
| Evidence | 46 check runs succeeded and 9 were expected skips on this head, 0 failed; mergeable clean. Red first on main, an absence pin over five declared roots, and 118 derived gates exit 0. The two dogfood files red on the dev's local battery (authz-conformance census, authz-probe-blind-spot) are main's, anchored at p0 #26400; this PR touches no packages/rest or packages/qa. |
| Carried | The cloud manifest_json reader is unmeasured from here: filed as cloud-lane card #26405 (does cloud persist optional, or parse AppManifest.dependencies; residue acceptance before the bump if so). #25794 told its item 2 is stale against the addendum (6432212137). #26000's 6b and the optional half of 6a are delivered here; its triage re-scopes the rest after landing. |
| Landing | Tier H: ⛔ not armed by the seat. The PR stays draft for the maintainer's merge or an authorized APPROVED review; the seat lands it after that. |
Generated by Claude Code
Requested by Leehom · project thread
Fixes #25792
This is card item 6, the last open item (ADR-0141 D8 items 2 and 3). Items 1, 2, 4, 5 and 7 landed in #25986 and #26054, and item 3 in #26123.
Clause-②: no (narrowing)
Metadata-protocol: narrowed
维护者速读
optional(PackageDependency.optional)和应用安装清单上的裸 id 列表(AppManifest.dependencies)。两者都改为retiredKey()墓碑,写了就报错并给出改法;ADR-0141 §D8 补一条带日期的实测结论。packages/spec之外都是 0 个读者、0 个写者(本仓 packages/ui/examples/apps 与 HotCRM)。安装前检查只读manifest.dependencies,且每条都必需;留着这两个键,作者(尤其 AI)写了也不生效、也不报错。@objectstack/spec是已发布包,cloud 控制面如何解析manifest_json本仓读不到。回滚即 revert 本 PR。packages/spec/src/marketplace/package-version.zod.ts(optional墓碑与说明);②docs/adr/0141-inter-app-dependency-declared-checked-before-install.md§D8 新增的 Addendum 段;③packages/spec/src/marketplace/dependency-spellings-retirement.test.ts。pnpm --filter @objectstack/spec exec vitest run --project repo src/marketplace/dependency-spellings-retirement.test.ts,预期 14 个测试全过;在main上同一文件 12 个失败。docs/adr/**(Tier H),需要你批准后由席位落地。What changes
What an author sees change, in plain sentences:
optionalon a dependency entry of a package version snapshot (PackageManifestSchema.dependencies[], thePackageDependencyshape) is now refused, whatever the value, including the old defaultfalse. The refusal reads: "PackageDependency.optionalwas removed in @objectstack/spec 18 (ADR-0049 enforce-or-remove, ADR-0141 D8) — no install path ever honoured it: the pre-install check reads the package'smanifest.dependenciesrecord, which has no optional arm, and treats every entry as required. Delete the key. Declare a dependency inmanifest.dependencies({ 'com.acme.core': '^1.0.0' }) only when the package cannot install without it."dependencieson an app install manifest (AppManifestSchema) is now refused the same way, including the old default[]. The refusal reads: "AppManifest.dependencieswas removed in @objectstack/spec 18 (ADR-0049 enforce-or-remove, ADR-0141 D8) — nothing read it: it listed bare ids with no version range, and no install path consulted it. Delete the key. Declare each dependency with its range in the package'smanifest.dependencies({ 'com.acme.core': '^1.0.0' }), which the pre-install check enforces."tscat the authoring site.PackageDependencyParsedlosesoptional, andAppManifestParsedlosesdependencies.manifest.dependenciesis unchanged and stays the one way to declare a dependency.The retirement kit, per the
spec-property-retirementplaybook:retiredKey()onPackageDependencySchema.optional(packages/spec/src/marketplace/package-version.zod.ts) andAppManifestSchema.dependencies(packages/spec/src/system/app-install.zod.ts), with comments naming ADR-0141 D8 and the measurement.RETIRED_KEYS_BY_MAJOR[18]gainsmarketplace/PackageDependency:optionalandsystem/AppManifest:dependencies(one file each undermigrations/entries/retired-keys/). One D3 semantic entry for the family,dependency-unread-spellings-retired, and itsSTEP18_RATIONALEfragment inregistry.ts.template. No D2 conversion: neither shape is a stack collection member, so a conversion would have no seam that runs (thekernel/Manifest:capabilitiesprecedent, recorded in its retired-key entry).acceptRetiredDefaultResidueis not adopted, although both keys carried a default: no producer in this repository or HotCRM parses either schema to emit one, so there is no emitted population (reasoning written on both retired-key entries).authorable-surface/{marketplace,system}.json(each row gains[RETIRED]),authorable-defaults/{marketplace,system}.json(the two default rows leave), and the two reference pages undercontent/docs/references/, throughcheck:generated --fix.authorable-surface.base.json,api-surface/andjson-schema.manifest/do not move (a key-level tombstone keeps the def and the export).system/app-install.test.ts,contracts/app-lifecycle-service.test.ts,kernel/package-dependency-dual-source.test.ts). Each now writes the live shape, and the dual-source pin notes thatoptionalstays in the shape as a tombstone.@objectstack/specminor, BREAKING banner, FROM → TO table, ADR-0087 markerregistered dependency-unread-spellings-retired.Tests
packages/spec/src/marketplace/dependency-spellings-retirement.test.ts, 14 tests, in therepoproject (vitest.repo-tests.json), because its absence pin walks outside the package. It pins the refusal (code,path, prescription text) for every value of each key, the snapshot path['dependencies', 1, 'optional'], the controls (no key ⇒ parse passes and grows no key), thetscchannel (@ts-expect-erroron each key, compiled bytsconfig.test.json), the registry rows and the D3 entry, that no conversion names either surface, and a tree-scoped absence pin over the five declared roots with a shape matcher (optionalbesideversionRange;dependenciesbesideminKernelVersionorhasSeedData) and its own anti-vacuity cases.main6390fe52cegave 12 failed | 2 passed. The two that passed are the matcher's anti-vacuity case and the no-conversion case. The absence pin's red named exactly five authoring sites, all insidepackages/spec: the two schemas and the three tests fixed here.src/marketplace/andscripts/step18-rationale-merge.test.ts: 10 files, 124 tests passed. The new file under--project repo: 14 passed.pnpm --filter @objectstack/spec test: Test Files 727 passed, Tests 21998 passed | 1 todo (os-verify-lock VERDICT command-exit 0).pnpm --filter @objectstack/spec typecheck: exit 0 (the test layer compiles undertsconfig.test.json;test-typecheck-debt.jsonunchanged).mainis the run without them.Acceptance notes
origin/main6390fe52ce.optionalon a dependency entry: 0 readers and 0 writers outsidepackages/spec(packages/,ui/,examples/,apps/).AppManifestSchema/AppManifest: no import outsidepackages/specat all, so 0 readers ofdependencies. The only non-spec mentions were prose (ADR-0141, ADR-0027's table, a comment inpackages/core/src/artifact-packages.ts). HotCRM at9464673: 0 of either; its three module manifests (src/service,src/marketing,src/revenue) declare{ 'app.objectstack.hotcrm': '^6.0.0' }in the record, the live control.IAppLifecycleService(packages/spec/src/contracts/app-lifecycle-service.ts), the one contract that takes anAppManifest, has no implementer in this repository.publish.tsuploads the compiled artifact as it is (ADR-0141 D8 item 1), so no stored or produced snapshot changes. The addendum states the consequence for D8 item 1's future conversion (its own card): the projection writespackageIdandversionRangeonly, neveroptional. The seat should read this against that card before landing.sys_package_version.manifest_json(objectstack-ai/cloud, not readable from this session), and any other out-of-repo consumer of the published@objectstack/spec.optional) and AppManifestSchema.dependencies, now that ADR-0141 D2 judges manifest.dependencies alone #26000. That card (open,pm:retriage) proposed retiring the whole ofPackageDependencySchemaplusAppManifestSchema.dependencies. This PR retires only the two keys ADR-0141 D8 owed to this card. The rest ofPackageDependencySchemastays, as D8's projection requires.AppManifestSchemaas a whole (andIAppLifecycleService) has no reader outsidepackages/speceither. That is outside item 6 and is noted here, not changed.packages/spec/authorable-surface/system.json(a generated, driver-merged shard). A driver-freemerge-treein a throwaway bare clone answers exit 0 with a tree id for both pairs, so both merge clean.Verification
Derived gates (118 families, all exit 0)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 118 families on this diff (18 paths, +683/−18 at derivation; re-derived onc65c5645cb, same 118).packages/spec/distandpackages/lint/distunder them (each said "Nothing was measured" or named a stale dist). All 11 re-ran against the settled build and exited 0.check:cross-package-test-inputsexited 1 because the new absence pin escapes the package but was not invitest.repo-tests.json. Fixed inc65c5645cb; re-run exit 0.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran RECORD(a record carrying each exit code): exit 0, "118 derived, 118 run, 0 NOT-MEASURED, 0 UNRUN", "a DERIVED zero — all 118 recorded an exit code and none of them is 3".pnpm exec eslint --no-inline-configover the 9 touched.tsfiles: exit 0.node scripts/check-nul-bytes.mjs: exit 0.pnpm --filter @objectstack/spec check:generated: 14 of 14 up to date after--fixregeneratedcheck:docsonly.Dogfood battery (the `(narrowing)` arm)
On head
c65c5645cb, closure built first (pnpm --filter '@objectstack/dogfood^...' build, VERDICT command-exit 0), thenpnpm --filter @objectstack/dogfood testunder the lock: VERDICT command-exit 1, held the lock 1147s. Test Files 2 failed | 297 passed | 3 skipped (302); Tests 10 failed | 2521 passed | 18 skipped (2549).Both failing files are main's expected reds, anchored at #26400 (the shape #26399 uses):
test/authz-conformance.test.ts, 6 tests in "[finding]authz-conformance.matrix.ts:27states the route ledger holds "94 rows / 19 families" in the present tense — measured 91 today, and the cause is #14503, not the gate move it sits next to #17111 — the matrix docblock's ledger figures are pinned to the ledgers": "packages/rest/src/rest-route-ledger.ts: docblock says 80 rows, the table holds 81".test/authz-probe-blind-spot.test.ts, 4 tests onpackages/rest/src/rest-route-ledger.tsandpackages/rest/src/rest-server.ts: control "this.routeManager.register(" moved in rest-server.ts, expected 62, got 63.This PR touches nothing under
packages/rest/orpackages/qa/(git diff --stat 6390fe52c HEAD -- packages/rest packages/qais empty). The last change to both rest files in the base is6a2866af71(#26361, the approval lock read route, merged 2026-10-26T23:58Z), andorigin/mainb33dd25b2ecarries no later change to either file or either test.Generated by Claude Code