docs(spec): the api install door doc block says what the in-process primitive does with enableOnInstall - #19710
Conversation
…n-process primitive reads enableOnInstall
`MetadataProtocol.installPackage` has honoured the key since `482d584121`:
`true` enables, `false` disables, an absent key makes no lifecycle call.
The doc block on `PackageInstallRequestSchema.enableOnInstall` still said
its own implementation does not read it.
Only that half of the compound sentence was false. The second half — this
door does not forward the key down that seam — is still true on `main`:
`handlePackages` calls `installPackage({ manifest, settings })` and performs
the flip itself, so the durable environment-keyed record follows the row
this door returned. The replacement states both, and scopes the primitive's
half to the registry row, because an `InstallPackageRequest` carries no
environment to key the durable record by.
Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 136 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 820ec1080b63186addbc4c9a6a05e5714898aca3 && git checkout 820ec1080b63186addbc4c9a6a05e5714898aca3
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 106d4c8dd7fe35d6195c507304ac21a299c510ea 6697f75093a5a1167181760ccc18847eada5326c && git checkout -B drift-repro 106d4c8dd7fe35d6195c507304ac21a299c510ea && git merge --no-ff 6697f75093a5a1167181760ccc18847eada5326c
node scripts/docs-audit/affected-docs.mjs --json 106d4c8dd7fe35d6195c507304ac21a299c510ea |
…ckage-api-denial One content conflict, in the `PackageInstallRequestSchema.enableOnInstall` TSDoc block (`packages/spec/src/api/package-api.zod.ts`), resolved by hand so both sides' meaning survives: - `origin/main` re-declared the key `z.boolean().optional()` and rewrote the kernel-copy bullet to "Same type, same OPTIONALITY, same meaning". That half is taken verbatim — the branch's inherited `same default` wording and its `.default(true)` belong to the pre-merge state, not to this PR's change, and reinstating either would silently revert the three-state ruling. - This branch's correction is kept whole: the in-process primitive HONOURS the key on the REGISTRY ROW (`true` enables, `false` disables, ABSENT makes no lifecycle call), with the "on the REGISTRY ROW" scope qualifier intact — the durable half is environment-keyed and this door still does not forward the key down that seam. The paragraph above the bullet list (the two-state prose) merges from main's side unchanged; main had already replaced it there. Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: 100/100
Rendered by an isolated at-tier review subagent. ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS — on head Tier control — measured by the seat, not reported by the reviewerThe reviewer self-reported
One finding that did not change the verdict, recorded for its own lane
Generated by Claude Code |
Contract reviewServed-tier: 122/122 Rendered by an isolated at-tier review subagent. This head is the hand-resolved merge that the prior record (comment 5778173554, binding ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Tier control — measured by the seat, not reported by the reviewerThe reviewer declined to self-count and said the transcript stamps are the control. Correct. The seat measured its transcript:
|
Fixes #19339
Clause-②: no
The second and final increment on this card. PR #19691 corrected three of the four carriers the executable criterion names — the kernel
.describe()and the two reference pages generated from it — and landed as7e1b048a1d. One carrier remained, in the file that #19691's dispatch had fenced out by mistake (recorded on the card at comment 5773730316): the doc block onPackageInstallRequestSchema.enableOnInstallinpackages/spec/src/api/package-api.zod.ts.That block is the map a reader follows from the authority to the other two declarations of this key, and its entry for the kernel copy said:
It ships.
src/**/*.zod.tsis in this package'sfiles[], and the comment survives bundling intodist/api/index.jsanddist/browser/api/index.mjs— so this is published text, not an internal note.⭐ Only ONE half of that sentence was false
It is a compound claim about two different layers, and they were re-derived separately from the source rather than rewritten together. Correcting the true clause would have swapped one false sentence for another.
mainMetadataProtocol.installPackage482d584121POST /api/v1/packagesHalf one, measured.
packages/metadata-protocol/src/protocol.ts, therequestedEnabledarms:=== truecallsenablePackage,=== falsecallsdisablePackage, an absent key makes no lifecycle call at all.=== true/=== false, never a truthiness test and never a??default, so the three states are three outcomes.Half two, measured.
packages/runtime/src/domains/packages.ts, the install handler: it callsprotocolSvc.installPackage({ manifest, settings: body.settings })— the key is not in that call — then performs the enable/disable flip itself against the registry, and writes the durable record from the row it returned (setPackageDisabled(environmentId, pkgId, rowDisabled)). So the clause is still accurate, and the replacement text now says WHY rather than only THAT.The scope words are load-bearing, and they follow #19691's pattern. The primitive moves the registry row — what every in-process reader serves, for the life of the process. The durable disabled-package record is keyed by ENVIRONMENT, which an
InstallPackageRequestdoes not carry, soPOST /api/v1/packagesstill owns the half that survives a restart. Stating the primitive "honours it" without that qualifier would overstate it in the other direction.Premise, re-verified on this tree rather than relayed
482d584121is an ancestor of this branch:git merge-base --is-ancestor 482d584121 origin/mainexits 0. Control leg on the same checkout with a commit known to be in that history (596090efbe, the commit that WROTE the denial) also exits 0, so the positive reading is not a shallow-clone artefact.git rev-parse --is-shallow-repositoryreadsfalseindependently.git grepover the whole tracked tree. The exact phrase stood inpackages/spec/src/api/package-api.zod.tsfor this key. Dark control on a near-miss spelling of the same shape over the same file: 0 hits, so the probe discriminates.The criterion is fully satisfied — measured after merging
origin/mainorigin/main(with #19691 in it) is merged into this branch throughscripts/pm/os-regen-merge.sh, so the four places the criterion names can be read on ONE tree:packages/spec/src/kernel/package-registry.zod.tscontent/docs/references/api/protocol.mdxcontent/docs/references/kernel/package-registry.mdxpackages/spec/src/api/package-api.zod.tsDark control on a near-miss spelling over the same four files: 0 on each.
#19691's implementation body was re-asserted present after the merge, along with #19685's incoming entries, so nothing was swallowed in either direction. That is why this PR uses a closing keyword where #19691 usedPart of.No generated page changes — measured, not assumed
pnpm --filter @objectstack/spec check:generatedreports all 15 generated artifacts up to date, before and after the edit, with no regeneration and no--fixrun. That is the expected reading and it is the measurement: the corrected text is a TSDoc block inside the schema factory, not a.describe(), and only.describe()text reachescontent/docs/references/**. The generated row for this key oncontent/docs/references/api/package-api.mdxalready read "honoured at POST /api/v1/packages", and still does, byte-identical. ⛔ No reference page was hand-edited; none needed regenerating.The same text does reach
packages/spec/json-schema/**for the KERNEL copy only — that tree is gitignored, generated at build time from the kernel.describe()#19691 corrected, and it is clean on this branch.Changeset — measured against
files[], not pattern-matchedpatchon@objectstack/spec;skip-changesetwould be a false declaration. Answered against the package's ownfiles[]after a real build,npm pack --dry-run --json, 2031 files:src/api/package-api.zod.tsis present in the listing (files[]carriessrc/**/*.zod.ts), and the corrected comment also reachesdist/api/index.js,dist/api/index.mjs,dist/browser/api/index.jsanddist/browser/api/index.mjs, all underdist.dist/index.d.tsis in the same listing, as it must be.*.test.tspaths and 0content/paths are in that listing, so the instrument is not simply answering yes.Level: nothing is added, removed, renamed or retyped and no default moves —
check:api-surfaceandcheck:authorable-surfaceare green with no diff — so this is a correction to a published description, not a widening.Verification, at
3e94943aa7Gates — ⛔ not a recalled list. Derived from the real change set with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, each exit code captured BEFORE any pipe, then reconciled with--ran:All 76 exit 0. On the pre-merge head three of them first answered exit 3 = PREREQUISITE NOT MET (
check:doc-formula-expressions,check:dual-build-cjs-loads,check:lean-entry-closure) because the workspace was not built; that was cleared withpnpm buildand all three re-run to exit 0. ⛔ An exit 3 was never read as a pass. The whole union was then re-derived and re-run on the merged head — byte-identical family set, 76/76 at exit 0.Tests
pnpm build(turbo, excluding docs)pnpm --filter @objectstack/spec testpnpm --filter @objectstack/spec typechecktsc --noEmit, pluscheck:scripts-typecheckandcheck:test-typecheck(53 files / 257 errors / 142 pinned signatures held, shrink-only), so the test layer is MEASURED, not assumedpnpm lint(repo-wideeslint . --no-inline-config)pnpm --filter @objectstack/spec check:generatedNo new test, and this is deliberate.
check:docscan only ever prove a page equals its.describe(); nothing can compare a sentence to an implementation, which is the card's own finding. Inventing an instrument here would be a new verification surface the card did not ask for.Acceptance notes
The pending changeset carrying the same root is still standing, and is still not a dev edit.
.changeset/18605-enable-on-install-one-authority.mdstates that the kernel copy's published description "now records that this layer does not read it". #19691 made that sentence false and left the note alone on purpose —pr-automation.ymlroute 0 classes editing another card's pending note as a DELIBERATE CORRECTION requiring written confirmation on the PR. The card body ruled the same way. It is a release decision, handed to the review seat, and it is outside this card's executable criterion, which names four places and not this one.content/docs/releases/v17/17-0.mdxalso carries the phrase and is correctly untouched. Release notes record what shipped in the version they document; that surface is RELEASE-OWNED and read-only to a code PR.Sequencing with #19273. That card is the SHAPE half of this field (
.default(true)versus the ruled 「缺省 = 保持」) and is fenced out here. It rewrites the same field's published text from the other side; whichever lands second regenerates the same rows. ⛔ Not this PR's to sequence.Clause-② hint, recorded and answered.
dispatch-gatesflagspackages/spec/src/**as a clause-② SUSPECT surface, so construction is atCONTRACT_REVIEW_TIER. It is a hint, not a verdict: this diff adds no key to a published payload, changes no accept or reject behaviour, and leaves the accept set byte-for-byte — the declaration staysno, which is also the dispatching seat's reading.⛔ No label was written by this branch.
needs:contract-reviewis the seat's to place, andskip-changesetis refuted by the measurement above.Generated by Claude Code