Skip to content

docs(cli,core): attribute unpack-time integrity re-verification to the future runtime loader, not the cloud control plane - #16826

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-16533-unpack-reverification-owner
Sep 8, 2026
Merged

docs(cli,core): attribute unpack-time integrity re-verification to the future runtime loader, not the cloud control plane#16826
os-project-manager merged 2 commits into
mainfrom
claude/issue-16533-unpack-reverification-owner

Conversation

@claude

@claude claude Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #16533

Clause-②: no

Five source comments in packages/cli and packages/core still attributed unpack-time manifest.integrity re-verification to the cloud control plane. That attribution was ruled wrong (decision batch #58, option C) and was already corrected in packages/spec/src/kernel/manifest.zod.ts, which names the future runtime loader (ADR-0025 §3.5 steps 4–7). Until this PR the repo stated both things at once. This propagates the ruling to the remaining five sites and does nothing else.

The five sites

file site line at merge-base
packages/cli/src/utils/osplugin.ts module docblock 20
packages/cli/src/utils/osplugin.ts sriDigest TSDoc 47
packages/cli/src/commands/plugin/publish.ts integrity-preflight inline comment (wraps two lines) 116-117
packages/core/src/security/index.ts verifyIntegrity export comment 40
packages/core/src/security/plugin-artifact-integrity.ts module docblock of the verifier itself 12

Every site was located by the 11331 / re-verification anchor, never by line number — the card's line numbers had already drifted on the base (:18→:20, :116→:117, :38→:40, :11→:12), exactly as the claim predicted.

The last site is the sharpest: it had explained the module's byte-for-byte portability by the wrong owner. It now explains it by the leg itself — the module stays portable to whatever runs unpack-time re-verification.

What is deliberately NOT changed

The other half of every one of these comments — 「computed at build, self-checked at the os plugin publish preflight」 — is true, was kept by #16333, and is kept verbatim here. This card swaps the owner only; it does not delete the integrity-chain description. Proof: every deleted line in the diff is an attribution clause, and the os plugin publish preflight sentence still appears at all five sites.

The two CHANGELOG.md files quote the pre-correction sentence and are untouched — they are generated release records and are held by open PR #15334. They appear in the re-check grep below; that is expected.

The line-wrap trap — and a note on this PR's own output

grep 'control plane' on publish.ts returned 0 hits at the merge-base while the site was plainly there: the phrase wrapped across lines 116/117 (cloud control / plane's). "None left" and "already fixed" look identical to a line-matching query.

The first commit here reproduced that hazard in the fix itself — future runtime loader wrapped at two of the five sites, so a grep for the corrected phrase answered "3". The second commit re-wraps those two comments so the phrase sits on one line at all five. The re-check is now double-anchored and neither anchor can be split.

Verification

All runs at the final commit 43cc17869e.

Acceptance re-checkgit grep -n '11331' -- packages/cli packages/core, 7 lines (5 corrected source sites + 2 untouched CHANGELOG records):

packages/cli/CHANGELOG.md:3150:- 9688f58: `os plugin publish` now verifies the artifact's own de  … [TRUNCATED HERE FOR THE PR BODY — file NOT edited]
packages/cli/src/commands/plugin/publish.ts:118:    // control plane (#11331) — this preflight does not discharge it.
packages/cli/src/utils/osplugin.ts:21: * control plane (#11331). This module owns the two contracts the
packages/cli/src/utils/osplugin.ts:49: * cloud control plane, #11331).
packages/core/CHANGELOG.md:1118:- 9688f58: `os plugin publish` now verifies the artifact's own d  … [TRUNCATED HERE FOR THE PR BODY — file NOT edited]
packages/core/src/security/index.ts:41:// control plane (#11331).
packages/core/src/security/plugin-artifact-integrity.ts:13: * #11331, NOT discharged by this module). The framework caller is the

Wrap-immune cross-anchor — git grep -n 'future runtime loader' -- packages/cli/src packages/core/src returns 5, one per source site, each on a single line.

Both packages' test + typecheck (the card names this as exactly why it was not folded into #16333):

pnpm --filter @objectstack/core test        Test Files 49 passed (49)    Tests 1197 passed (1197)
pnpm --filter @objectstack/core typecheck   exit 0 — tsc --noEmit, tsconfig.examples.json, check:test-typecheck OK
pnpm --filter @objectstack/cli  test        Test Files 221 passed (221)  Tests 2855 passed | 6 expected fail (2861)
pnpm --filter @objectstack/cli  typecheck   exit 0 — tsc --noEmit, check:test-typecheck OK

@objectstack/cli's test is the full vitest run, i.e. both the unit and integration tiers (185 + 36 files), not the unit tier alone.

Gates — the family set was derived from the actual change set with scripts/pm/dispatch-gates.mjs, not hand-listed:

Run reconciliation — 53 derived, 53 run, 0 NOT-MEASURED, 0 UNRUN.
✓ dispatch-gates --ran: 53 derived famil(ies) accounted for — 53 run, 0 NOT-MEASURED.

pnpm lint (repo-wide eslint . --no-inline-config): exit 0, no findings — a full scan, so no narrowing is claimed.

Two gates first answered exit 3check:dual-build-cjs-loads (PREREQUISITE NOT MET … this is NOT a pass: nothing was measured) and check:i18n-coverage (COULD NOT MEASURE). Both document exit 3 as distinct from a finding's 1. Both read built output, a full pnpm build was run to satisfy the prerequisite, and both then returned exit 0. They are reported as measured green, not as recovered reds.

Changeset

.changeset/unpack-reverification-owner-runtime-loader.md, patch for both packages. Measured on the built output rather than assumed:

  • @objectstack/cli — the sriDigest TSDoc does ride into the shipped dist/utils/osplugin.d.ts, so an editor hover stops naming the control plane. Published content moves.
  • @objectstack/core — its two sites do not reach the published bundle. A module docblock and a line comment above an export {} are both dropped from dist/index.d.ts (measured: zero hits, against 2253 surviving TSDoc lines as the positive control). It is declared anyway because the pre-correction sentence is quoted in packages/core/CHANGELOG.md, which may not be hand-edited — a changeset naming the package is the only way the correction reaches that published record.

This slightly qualifies the card's rationale, which expected the plugin-artifact-integrity.ts docblock to reach consumers through @objectstack/core's .d.ts the way the spec one did. On the built output it does not. The correction is still right and still worth making; only the blast radius is smaller than the card assumed.

Docs drift — the advisory, and the hand-read that stands in for its blind spot

The Docs Drift Check on this PR lists 1 page, but states itself that 3 of my 4 changed files yielded no anchor (osplugin.ts, security/index.ts, plugin-artifact-integrity.ts), so the pages documenting those are not covered by that run. ⛔ The "1 page" is therefore not a near-clean bill of health — three quarters of the diff got no automated coverage, and the hand-read below is what stands in for it.

Tree validity first. The bot computed on the merge commit ceda6de329ee (head 43cc17869e into base d4401f75bbe2), not on my head, and a worktree cut from an older main can legitimately hold a different content/docs. Checked rather than assumed: git diff --stat 30b0990787 ceda6de329ee -- content/docs is emptycontent/docs is byte-identical between my base and the bot's tree, so the reading below is valid on the tree the bot actually judged. The sweep was additionally re-run against ceda6de329ee directly and reproduces identically.

1. The listed page — content/docs/protocol/kernel/plugin-spec.mdx, NOT falsified. It was listed via the os plugin publish command anchor off publish.ts. It makes exactly two integrity-adjacent claims, and neither states this change's rule:

  • Line 591, "install validates the manifest and signature, records the package" — this is the metadata install path (registry.installPackage()), which the page itself distinguishes from the .osplugin tarball a few lines later; it concerns the signature leg, not the per-file digest map, and it attributes ownership to nobody.
  • Line 757, "Per-file content digests (sha256-BASE64 integrity map)" — a descriptive list of what the archive contains. No verification claim, no owner.

2. Hand-read for the RULE, not the symbols. This is the bot's declared permanent blind spot: a page stating a rule by its inputs shares no identifier with the emitter. The rule this change carries is unpack-time re-verification is owned by the future runtime loader (ADR-0025 §3.5 steps 4–7), not the cloud control plane, so content/ was searched for the rule's own vocabulary in short, wrap-immune tokens — never the full sentence, which is the trap that nearly cost a site in the source tree:

token hits in content/ verdict
unpack 0 decisive — no page discusses unpack-time anything
re-verification / re-verify 4 all unrelated (AI dev loop; liveness-ledger security sweep in release notes)
manifest.integrity 0
verifyIntegrity 0
integrity many referential integrity, generated .describe() tables, or archive-content descriptions
control plane 18 files intersected with integrity/digest/sha256/verif vocabulary → 8 files, all read

The 8-file intersection carries no instance of the defect: #sha256= artifact-pinned boot (publish-and-preview, self-hosting, cli) and the canonical-metadata checksum (north-star, environment-artifact) are different mechanisms; the rest are unrelated. Release notes were read but are never editable here.

Result: no sixth site. Repo-wide, the three other places that state this rule already carry the corrected attribution — packages/spec/liveness/manifest.json ("owned by the future runtime loader … NOT by the cloud control plane"), docs/qa/platform-checklist/areas/cli.json ("nothing re-verifies it at unpack — #11331 is open on exactly that", no owner claimed), and the pending .changeset/manifest-integrity-unpack-tsdoc-truth.md, which states the old wording only as the history it is correcting. ADR-0025, the authority all of them cite, contains zero occurrences of "control plane".

Nothing was changed in content/ by this PR, and nothing needed to be.

验收备注

  1. Re-check by anchor, not by the full phrase. git grep -n '11331' -- packages/cli packages/core7 lines: the 5 source sites, all now reading "future runtime loader (ADR-0025 §3.5 steps 4–7)" with the #11331 pointer kept, plus the 2 CHANGELOG lines left alone. Output pasted above. Cross-checked with the wrap-immune future runtime loader anchor → 5 source lines. Zero hits remain for control plane's obligation or owes the unpack-time under packages/cli/src and packages/core/src.
  2. The build/preflight half is unchanged. 「computed at build, self-checked at the os plugin publish preflight」 is kept verbatim at every site; every removed line in the diff is an attribution clause. The diff is comment prose only — no accept set, export, signature or runtime behaviour moves.
  3. Both packages' test + typecheck run and pasted — see Verification above. @objectstack/core 1197 tests, @objectstack/cli 2855 tests across both tiers; both typechecks exit 0.
  4. content/docs/releases/ untouched. The complete changed-file list is the 4 source files plus one .changeset/*.md — no releases page, no CHANGELOG.md, nothing outside the surface declared in the claim comment.

Out-of-scope findings

noted, not filed: the @objectstack/core docblock does not reach the package's published .d.ts (detailed under Changeset above). Recorded rather than filed: it is an observation about this card's own rationale, not a reproducible defect, a contract breach, or a metadata trap. Carrier: whoever next revisits the ADR-0025 integrity chain — no PR is queued that would touch it.

Nothing else was found. No new fork appeared, so this did not go to the decision box: the owner was already ruled.


Generated by Claude Code

…egrity re-verification owner

Five source comments still said unpack-time `manifest.integrity`
re-verification was the cloud control plane's obligation. That
attribution was corrected in `packages/spec/src/kernel/manifest.zod.ts`,
so the repo stated both things at once. Swap the owner clause at all
five sites to the future runtime loader (ADR-0025 §3.5 steps 4-7),
keeping the `#11331` pointer and the true build/preflight half.

Comment prose only: no accept set, export, signature or runtime
behaviour moves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QE8qk46e5CHJxyQEUjbf8
…site

Two of the five rewritten comments wrapped `future runtime loader`
across a line break, which re-creates the exact hazard this change is
about: a line-matching grep for the phrase answers "3 sites", and
"none left" is indistinguishable from "already fixed".

Pure re-wrap of lines this branch already rewrote; no wording changes.
The re-check is now double-anchored — `11331` finds 7 lines (5 source
+ 2 generated CHANGELOG records) and `future runtime loader` finds all
5 source sites on their own lines.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QE8qk46e5CHJxyQEUjbf8
@github-actions github-actions Bot added the size/s label Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/core, touching 2 documentable anchor(s). ⚠️ 3 changed file(s) yielded no anchor (packages/cli/src/utils/osplugin.ts, packages/core/src/security/index.ts, packages/core/src/security/plugin-artifact-integrity.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/kernel/plugin-spec.mdx (via os plugin publish (command, read off packages/cli/src/commands/plugin/publish.ts))
What this run could not see
  • 3 changed file(s) yielded no anchor (packages/cli/src/utils/osplugin.ts, packages/core/src/security/index.ts, packages/core/src/security/plugin-artifact-integrity.ts) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 40 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 d4401f75bbe2e9e1b6f52f9bad83e377c5c33277packageMentionDocs.

Which tree this was computed on

This run read content/docs from ceda6de329ee4e9771eb01ef9ce8c04e5ef035e4 — the merge of head 43cc17869e7defa0d5949f878853812669dc2506 into base d4401f75bbe2e9e1b6f52f9bad83e377c5c33277, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ceda6de329ee4e9771eb01ef9ce8c04e5ef035e4 && git checkout ceda6de329ee4e9771eb01ef9ce8c04e5ef035e4
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d4401f75bbe2e9e1b6f52f9bad83e377c5c33277 43cc17869e7defa0d5949f878853812669dc2506 && git checkout -B drift-repro d4401f75bbe2e9e1b6f52f9bad83e377c5c33277 && git merge --no-ff 43cc17869e7defa0d5949f878853812669dc2506

node scripts/docs-audit/affected-docs.mjs --json d4401f75bbe2e9e1b6f52f9bad83e377c5c33277

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs d4401f75bbe2e9e1b6f52f9bad83e377c5c33277 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Sep 8, 2026

Copy link
Copy Markdown
Collaborator
VERDICT: ACCEPT
Implemented-by: `claude/issue-16533-unpack-reverification-owner`
Reviewed-by: `session_015QE8qk46e5CHJxyQEUjbf8`

Accepted by the domain:cli execution PM seat (#6024, R71). Re-measured at source — ⛔ a delivery report is not a reading.

Gate ① — CI

39 raw check runs → 33 after latest-per-name collapse: 30 success, 3 skipped, 0 red, 0 pending; mergeable_state=clean. Legacy statuses read separately (the check-suite signal does not cover them): combined success (1 context, Vercel).

Gate ② — clause ②

--pair 16826 exit 0, and both declaration documents read independently (⛔ the gate's 「both carriers agree」 is about the label carriers — #16770): PR body → no, card claim 5581309438no.

Acceptance — the card's four, verified in the diff

Item 1 — the re-check shape. git grep -n '11331' -- packages/cli packages/core returns exactly 7 lines: 5 corrected source sites + 2 CHANGELOG records untouched — the predicted shape.

⚠️ A correction to this seat's own first reading, recorded because it is the card's own failure mode. Four of those 7 lines still show control plane (#11331), and I first read that as the sites being unchanged. Wrong. The phrase survives in negation — "owned by the future runtime loader (ADR-0025 §3.5 steps 4–7), not by the cloud control plane" — with the negating clause on the line above the anchor. ⇒ I committed this card's own error in the opposite direction: a line-oriented read said "unchanged" about a statement that had been corrected.

The anchor is right for FINDING sites; it is ⛔ not sufficient for JUDGING them. The rubric says "confirm the clauses now read…", and a clause is not a line. Only reading the whole comment settles it. Keeping the phrase in negation is also the better call than deleting it: a reader who remembers the old attribution gets it explicitly corrected rather than silently dropped.

Item 2 — the true half kept. 「computed at build, self-checked at the os plugin publish preflight」 survives at every site. ⚠️ Stated precisely: my grep pattern matched 3 files; publish.ts keeps it as "this preflight does not discharge it", which I confirmed by reading the diff, not by that grep.

Item 3 — both packages run. Reported: @objectstack/core 49 files / 1197 tests, @objectstack/cli 221 files / 2855 passed + 6 expected-fail (the full vitest run, both tiers), typecheck exit 0 on both, all under the verify lock. CI's own green on the same head is the independent confirmation.

Item 4 — content/docs/releases/ untouched. Verified from the file list: the diff is 5 files and nothing under content/ is in it at all. ⛔ Both CHANGELOGs untouched — doubly forbidden (generated records, and held by PR #15334).

Controlled zero on the claim that matters: the old possessive attribution (control plane's obligation / owes the unpack-time) has zero hits under packages/cli/src + packages/core/src, while the identical pattern still matches in packages/cli/CHANGELOG.md. The zero is a reading, not a broken grep.

Serial — re-measured at accept time with FULL pagination

22 open PRs, all four target files → 0 other holders. Control fired: packages/metadata-protocol/src/protocol.ts 3 holders, scripts/engine-double-contract.pinned.json 3.

⚠️ Recorded because this seat got it wrong earlier in the round: capping the per-PR file listing at 3 pages made me report "0 holders" for both CHANGELOGs when PR #15334 (changeset-release/main) holds them — its file list is long enough to push them past page 3. ⛔ "Didn't look far enough" and "nothing there" are indistinguishable. This scan paginates fully.

⭐ Two things the delivery did that are worth naming

  • It caught itself recreating this card's own hazard, inside the fix. Its first commit split future runtime loader across a line break at 2 of 5 sites, so a grep for the corrected phrase answered 3 instead of 5. It found that itself and pushed a second commit re-wrapping them. Verified on the final head: future runtime loader is greppable on one line at 5/5 sites. ⇒ the corrected phrase cannot be missed the way the old one was — the fix is now wrap-immune in both directions.
  • It declined the ablation and said why, rather than manufacturing one: "this card adds no guard and no assertion whose ability to fail needs proving; the change is comment prose with no runtime or type effect." ⭐ Refusing to produce ceremonial evidence is the right call, and saying so plainly is better than a hollow artifact.

Docs drift — answered, and the caveat was measured rather than assumed

The bot listed 1 page but declared 3 of the 4 changed files anchor-less and therefore uncovered"not a clean bill of health for those files." So the hand-read was the only coverage they got.

⭐ The delivery tested the bot's tree caveat instead of repeating it: git diff --stat 30b0990787 ceda6de329ee -- content/docs is EMPTY, so content/docs is byte-identical between its base and the bot's merge tree — the "different tree" warning provably does not apply here. Then it swept the rule's vocabulary in short wrap-immune tokens (⛔ never the full sentence): unpack = 0 hits in all of content/ — decisive, since the rule is about unpack-time. No sixth site. It also established that the three other places stating this rule already carry the corrected attribution, and that ADR-0025 — the authority they all cite — contains zero occurrences of "control plane".

⚠️ A correction to this seat's claim comment

My claim 5581309438 asserted that plugin-artifact-integrity.ts's docblock "reaches consumers through @objectstack/core's .d.ts; that is why the card matters". ⛔ I repeated the card's rationale without measuring it. The delivery measured it: that docblock does not reach dist/index.d.ts (a module docblock and a comment above export {} are both dropped — zero hits against 2253 surviving TSDoc lines as the positive control), while @objectstack/cli's sriDigest TSDoc does ride into dist/utils/osplugin.d.ts.

⇒ The correction is still right; only its blast radius is narrower than the card and I both claimed. Clause-② no is untouched — a comment that never reaches the .d.ts is further from a published-surface change, not closer.

⚠️ I checked the comment attachment shapes at source and they corroborate the mechanism (unattached module docblock and a // above a re-export, versus a TSDoc directly on export function sriDigest). ⛔ But I read the shape, not the emitted artifact — the .d.ts reading is the delivery's, with its own control, and I did not independently re-derive it.

Landing: marked ready and routed to the merge queue. ⛔ Not merged outside the queue; ⛔ no governed surface in this diff.


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review September 8, 2026 09:03
@os-project-manager
os-project-manager added this pull request to the merge queue Sep 8, 2026
Merged via the queue into main with commit f89812e Sep 8, 2026
41 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-16533-unpack-reverification-owner branch September 8, 2026 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Five source comments in packages/cli and packages/core still call unpack-time manifest.integrity re-verification the cloud control plane's obligation

2 participants