Skip to content

docs(spec): the environment artifact's checksum describe states its own coverage boundary (the metadata block only); grantedPermissions states it sits outside the digest by design (#14993) - #16008

Draft
claude[bot] wants to merge 6 commits into
mainfrom
claude/issue-14993-checksum-coverage-describe
Draft

docs(spec): the environment artifact's checksum describe states its own coverage boundary (the metadata block only); grantedPermissions states it sits outside the digest by design (#14993)#16008
claude[bot] wants to merge 6 commits into
mainfrom
claude/issue-14993-checksum-coverage-describe

Conversation

@claude

@claude claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #14993

The environment artifact envelope carries a checksum, and until now nothing on the surface said what that digest covers. The field inherited the shared Sha256DigestSchema describe — "SHA-256 digest (64 hex chars)" — which states what the value is and nothing about its scope. The digest is computed over the canonical JSON serialization of the metadata block only, so every other key on the envelope rides outside it, the install-time grantedPermissions consent set (#14865) included.

The ruling this executes

Recorded by the director seat on the card (comment 5548641412, 2026-09-05T02:09Z; maintainer verbatim 「同意」 to decision batch #41 item 3), recorded on the premise that the carrier is trusted end-to-end:

Ruled: 1. Two describe edits in packages/spec/src/system/environment-artifact.zod.ts, no contract change: the checksum field says in its own describe exactly what it covers (the metadata block) and what it does not; grantedPermissions says it is outside the digest, that integrity of the granted set rests on the carrier (environment-local, control-plane served) per ADR-0003 / cloud ADR-0007, and points at this card. Not taken: 2a (widen checksum — a breaking change on every producer and validator across the open repo and the control plane, refused by ④), 2b (held as the flip above), a rename of checksum (a breaking envelope key change for a documentation problem).

Nothing mechanical moves: no key is added or removed, no value schema changes, no digest input changes, and the accept set of EnvironmentArtifactSchema is byte-for-byte the same set it was. Option 2b — an additive sibling digest, if the maintainer states the carrier is not trusted — stays recorded on the card as the flip, and is deliberately not this PR's.

The two describes as landed

checksum gains its own field-level describe. The shared Sha256DigestSchema describe is untouched, so the other digest fields in the repo still inherit it:

SHA-256 digest of the canonical JSON serialization of the metadata block (stable key ordering), computed by the control plane when assembling the GET response. Coverage stops at that block: nothing else on the envelope — grantedPermissions included — is under this digest, so a matching checksum attests the compiled metadata and nothing more.

grantedPermissions gains one appended sentence group; its five existing clauses (the manifest-id keying, the sys_package_installation source, the enforcer consumer, absent versus {}) are unchanged:

Sits beside metadata, outside the checksum digest, which covers the metadata block only: integrity of the granted set rests on the carrier — the artifact is environment-local and control-plane served (ADR-0003 / cloud ADR-0007) — an accepted boundary of this envelope, not an oversight.

The existing ⚠ A STRING docblock note on checksum stays as it was; the describe is additive.

One declared deviation from the ruling's letter

The ruling asked the grantedPermissions sentence group to point at the card. pnpm check:doc-authoring refuses an internal issue id inside .describe() prose, and reds on exactly that string:

✗ Internal issue-id reference(s) in CUSTOMER-FACING spec text:
  packages/spec/src/system/environment-artifact.zod.ts:188  #14993  [.describe()]

Its rationale is the same premise the ruling rests on — describe prose projects into content/docs/references/** and the generated skill artifacts, where a citation-shaped id points at nothing for the reader who sees it — and its prescribed route is an adjacent // comment. So the card anchor moved to a two-line comment beside the key, and the describe keeps only the customer-resolvable references (ADR-0003 / cloud ADR-0007). The gate is green either way; this note exists so the divergence from the ruling text is read rather than discovered.

Regeneration: measured, and nothing moved

  • pnpm --filter @objectstack/spec gen:docs — 230 files generated, working tree clean afterwards. The reference pages render the module docblock and the top-level exported schema symbols; a field-level describe on a key inside the lazySchema object is not projected, so neither content/docs/references/system/environment-artifact.mdx nor the cloud mirror moves.
  • pnpm --filter @objectstack/spec check:generated — all 15 generated artifacts up to date, check:docs and check:authorable-surface among them. The json-schema.manifest and authorable-surface shards did not move.
  • Nothing under content/docs/ is hand-edited by this PR, and nothing under content/docs/releases/ is touched at all.

Verification

Run against the final commit, af3041c9 (this branch merged with origin/main at f7db8f4fd):

  • pnpm --filter @objectstack/spec test — 478 files, 12844 passed, 0 failed.
  • pnpm --filter @objectstack/spec typecheck — clean; check:test-typecheck holds at 54 files / 261 errors / 145 pinned signatures, unmoved.
  • pnpm lint (eslint . --no-inline-config, whole repo) — exit 0.
  • 72 gate commands derived by node scripts/pm/dispatch-gates.mjs --commands over this diff: 70 exit 0. The two exceptions are check:dual-build-cjs-loads and check:type-check-debt, both exit 3 / PREREQUISITE NOT MET — each needs a whole-workspace build before it measures anything, which is CI's run, not a local one. Neither is a finding.
  • Reverse verification: with the pre-change declaration restored from the merge base and the new pins left in place, 4 of the 6 new assertions go red (Tests 4 failed | 29 passed); the mutation and its restoration are both proven on disk by blob hash, and git diff HEAD is empty afterwards.

Tests

Six assertions were added, not invented: the file already pins describe text — the grantedPermissions description is asserted clause by clause, because the manifest-id-not-package_id assumption is documented nowhere else a producer reads. The coverage boundary is the same kind of fact. There is no digest mechanism to pin here (the control plane computes and verifies it; this envelope only carries the value), so the sentence is the surface, and an unpinned sentence rots silently.

The new pins assert that checksum's describe names the metadata block and states what it excludes; that the shared Sha256DigestSchema describe is unchanged and a different instance, so the key-level text did not relabel every other digest field; that the key still accepts and rejects exactly what the shared digest does; and that neither description carries an internal issue id — the negative pin check:doc-authoring asks for whenever a test twin pins customer-facing text.

Changeset

One, @objectstack/spec patch — describe text only, no behaviour change.


Generated by Claude Code

…ry on the keys it governs

`EnvironmentArtifactSchema.checksum` inherited the shared `Sha256DigestSchema`
describe ("SHA-256 digest (64 hex chars)"), which says what the value is but
nothing about what it covers. The digest is computed over the canonical JSON
serialization of the `metadata` block only, so every other envelope key —
`grantedPermissions` included — rides outside it, and nothing on the surface
said so.

Two describe edits, no contract change:

- `checksum` gets its own field-level `.describe()` (the shared
  `Sha256DigestSchema` describe is untouched, so the other digest fields still
  inherit it): what it covers first, then what it does not.
- `grantedPermissions`' describe gains one appended sentence group: it sits
  beside `metadata`, outside the digest, and integrity of the granted set rests
  on the carrier — the artifact is environment-local and control-plane served
  (ADR-0003 / cloud ADR-0007).

The accept set of `EnvironmentArtifactSchema` does not move: same keys, same
value schemas, same absent-vs-`{}` semantics.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M59rPZZFzqhfMUPFqqZTkf
`check:doc-authoring` refuses an internal issue id inside `.describe()` prose —
that text projects into `content/docs/references/**` and the generated skill
artifacts, where a citation-shaped `#NNNN` resolves to nothing for the reader
who sees it. The gate's own prescribed route is an adjacent `//` comment, so
the card anchor moves there and the describe keeps only the
customer-resolvable references (ADR-0003 / cloud ADR-0007).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M59rPZZFzqhfMUPFqqZTkf
…s it

The file already pins describe TEXT (the `grantedPermissions` key description
is asserted clause by clause, because the manifest-`id`-not-`package_id`
assumption is documented nowhere else that a producer reads). The digest
coverage boundary is the same kind of fact: no mechanism to pin — `checksum`
is computed and verified by the control plane, this envelope only carries it —
so the sentence IS the surface, and a sentence with no pin rots silently.

Six assertions: `checksum`'s own describe names the `metadata` block as what
it covers and says nothing else on the envelope is under the digest; the
shared `Sha256DigestSchema` describe is unchanged and is a different instance,
so the key-level text did not relabel every other digest field; the key still
accepts and rejects exactly what the shared digest does; and both descriptions
carry no internal issue id, the negative pin `check:doc-authoring` asks for
when a test twin pins customer-facing text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M59rPZZFzqhfMUPFqqZTkf
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation protocol:system tests tooling labels Sep 5, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 1 documentable anchor(s).

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

  • content/docs/concepts/north-star.mdx (via EnvironmentArtifactSchema (symbol, a top-level const))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17.mdx (via EnvironmentArtifactSchema (symbol, a top-level const))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • 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 — 129 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 51d59e4c9affe28922c4b4fea86cd3ac186c487fpackageMentionDocs.

Which tree this was computed on

This run read content/docs from 57e62f4b481590f688dc75026805fd17c7700b44 — the merge of head 641354355edf8f59de35812ffa43270ea114bfbf into base 51d59e4c9affe28922c4b4fea86cd3ac186c487f, 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 57e62f4b481590f688dc75026805fd17c7700b44 && git checkout 57e62f4b481590f688dc75026805fd17c7700b44
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 51d59e4c9affe28922c4b4fea86cd3ac186c487f 641354355edf8f59de35812ffa43270ea114bfbf && git checkout -B drift-repro 51d59e4c9affe28922c4b4fea86cd3ac186c487f && git merge --no-ff 641354355edf8f59de35812ffa43270ea114bfbf

node scripts/docs-audit/affected-docs.mjs --json 51d59e4c9affe28922c4b4fea86cd3ac186c487f

⚠️ 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 51d59e4c9affe28922c4b4fea86cd3ac186c487f → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@claude claude Bot changed the title docs(spec): the environment artifact's states its own coverage boundary docs(spec): the environment artifact's checksum states its own coverage boundary Sep 5, 2026
@claude claude Bot changed the title docs(spec): the environment artifact's checksum states its own coverage boundary docs(spec): the environment artifact's checksum describe states its own coverage boundary (the metadata block only); grantedPermissions states it sits outside the digest by design (#14993) Sep 5, 2026
@claude

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

CI note from the dispatching seat — the one red check on af3041c92 is not this PR's. Lint & Repo Gates fails at the step Merge-driver wiring gate (pnpm check:merge-driver), red on main itself since ~17:22Z in every lane: the check-regen-pending.mjs --self-test fixture runs pnpm -s in an unpinned directory and Corepack resolves pnpm latest = 12.3.4, whose CLI rejects -s. Anchor cards #15990 / #15992 / #15994; the one-file fix is PR #16002, in the merge queue with its own run green on that step. Every other check on this head is green. This PR needs no change for it: once #16002 lands, the branch merges main by tooling so CI re-runs, and the seat flips to ready + auto-merge (no contract-review carrier on this one — describe text only).


Generated by Claude Code

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 protocol:system size/s tests tooling

Projects

None yet

1 participant