Skip to content

docs(spec): cite the cloud decision as cloud ADR-0025, not a bare number that resolves to the plugin-packaging ADR - #18754

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-18685-cloud-adr-citation-spelling
Sep 17, 2026
Merged

os-bill merged 1 commit into
mainfrom
claude/issue-18685-cloud-adr-citation-spelling

Conversation

@os-bill

@os-bill os-bill commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Clause-②: no

Fixes #18685

What changed

One docblock line in packages/spec/src/contracts/ai-service.ts, plus a changeset. ToolExecutionContext.userMessageText read:

* Populated by whichever layer owns the agent route (cloud, post-ADR-0025).

The parenthetical names cloud as the owning layer; the id was spelled bare. A bare id resolves against this registry, where ADR-0025 is docs/adr/0025-plugin-package-distribution.md — a real record about .osplugin artifacts, plugin trust tiers and marketplace install, which decides nothing about who owns the agent route.

AGENTS.md Prime Directive 13, verbatim: an ADR "lives in the repository whose code it governs", and cloud decisions are cited as cloud ADR-NNNN — "never as a bare number".

The line now reads (cloud, post-cloud ADR-0025): byte-for-byte the phrase the sibling member confirmedBlueprintIdentity already carries seven lines below. The two were knowingly inconsistent while the card was open; they agree again.

Premise re-verified before editing. The card asked the taker to falsify two things. (1) This repo's ADR-0025 really is unrelated to the agent route — it contains exactly one case-insensitive agent hit, at line 408, where agent is one of the plugin contribution kinds a manifest may declare. Nothing in it decides route ownership. (2) Whether cloud has an ADR-0025 at all stays NOT MEASURED — the cloud repo is outside this session's scope, and nothing here asserts what the bare number was meant to point at. What is measured is where the bare number did land: this repo's plugin-packaging record.

Acceptance controls

control reading
LITcloud ADR-0025 in ai-service.ts 1 (was 0 on the base commit; the sibling's copy is line-wrapped, so it did not read as a contiguous string)
DARK a — verbatim (cloud, post-ADR-0025) under packages/spec/src/** 0 files
DARK a' — the same string repo-wide, tracked + untracked 0 files
DARK b — legitimate ADR-0025 references to this repo's plugin-packaging ADR 326 occurrences across 100 files, before and after — identical

DARK b is the proof there was no blanket replace, and it is stronger than a file count: the ADR-0025 token total is unchanged at 326. The edit inserted the word cloud in front of exactly one of them and removed none.

The seat's two questions, answered by measurement

1. Does scripts/check-adr-anchors.mjs change its verdict on this line?

No — and it never had one. Both readings taken on the real gate:

run exit output
BEFORE (base 0e2ebce37b) 0 OK (53 anchored file(s) … 36082 citation(s) across 4628 file(s) resolve …)
AFTER 0 byte-identical to the BEFORE run

ai-service.ts is named zero times in either run. The gate's citation audit exempts a cross-repo qualifier and otherwise only asks that the number resolve; 0025 resolves here either way, so the gate is blind to this defect in both directions. That is what the card predicted, now measured rather than assumed.

One thing the measurement turned up that the prediction did not — reported, not folded in. The exemption is an exact-token test against CROSS_REPO_QUALIFIERS = {objectui, object-ui, cloud}, and the token is whatever [A-Za-z0-9_./-]+ sits immediately before the id, on the same line. Probed with five throwaway spellings, each run against the real gate:

spelling gate
cloud ADR-9911 exit 0 — exempt
post-cloud ADR-9912 exit 1 — NOT exempt
objectstack-ai/cloud ADR-9913 exit 0 — exempt
`objectstack-ai/cloud` ADR-9914 exit 1 — NOT exempt (the closing backtick strands the qualifier)
bare ADR-9915 exit 1 — correctly refused

So the spelling this PR lands, post-cloud ADR-0025, is not recognised as cross-repo; it stays green only because this repo also owns an ADR-0025. The same is true of the backticked prose form used in docs/adr/0135-* and docs/adr/0133-*. Handed back as a finding rather than acted on — changing the qualifier set or the idiom is a different defect class from this card's, so the bounded in-place-fix exemption does not open.

2. How many other bare numbers sit in cloud context?

Surface swept: the gate's own corpus, taken with the gate's own command (git grep --untracked -IonE '([A-Za-z0-9_./-]+[ \t]+)?ADR-[0-9]{4}') and parsed with the gate's own regex and qualifier set, so the surface swept equals the surface that gate reads.

tier predicate count
A every ADR citation in the repo 36082 citations / 4628 files
B of those, the ones resolved against this registry (qualifier not in CROSS_REPO_QUALIFIERS) 35839
C of B, cloud governs the same clause — within 48 chars before the id, same line, no .;)] between 40
D of B, a cross-repo qualifier stranded at the end of the previous line (correct to a human, bare to the gate) 2

A loose first pass (cloud anywhere within ±2 lines) returned 1105 and was discarded as too noisy to be a predicate — reported because the number is the honest cost of the tighter one.

The 40 tier-C hits were triaged by hand. Most are false positives in which the cited number genuinely is ours and the word cloud merely sits nearby (packages/runtime/src/cloud/ as a directory; cloud-only (ADR-0025) where ADR-0025 really is the distribution decision). Two are the same defect class as this card and are handed back in the report rather than folded in here. Details, dedupe words and the triage verdict for every ambiguous hit are in the os-dev-report comment on #18685.

Acceptance notes

Out-of-scope observations, noted and deliberately not filed:

  • packages/spec/src/api/ai-agents-envelope.test.ts:112 cites cloud#816 / ADR-0057. 0057 is one of the three allowlisted collision numbers, and neither of this repo's two 0057 records (ERP authorization core; system-data lifecycle) is about agent capabilities — so this may be a cloud number spelled bare. I could not settle which registry it means without reading the cloud repo, which is out of session scope, so it is recorded as ambiguous rather than asserted. Next toucher: whoever does the #5992 route-B slug-qualification pass over the 0057 pair, which has to read every 0057 citation anyway.
  • content/docs/releases/v16.mdx:879went cloud-only (ADR-0025). Reads as a legitimate reference to this repo's distribution ADR, and release notes are a frozen surface no PR edits. Taker: none.

Verification

All on the final commit edcbcda254.

  • pnpm lint (eslint . --no-inline-config, the whole repo, not a narrowing) — exit 0.
  • pnpm --filter @objectstack/spec typecheck && pnpm --filter @objectstack/spec testexit 0, 486 test files / 13964 tests passed.
  • Gate families derived mechanically with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (75 commands) — 74 green.
  • The one not measured: pnpm check:dual-build-cjs-loads exits 3PREREQUISITE NOT MET, it reads built output for 87 packages and asks for a full pnpm build. That is CI's run, not a finding; the gate states in its own words that "nothing was measured". check:lean-entry-closure and check:doc-formula-expressions refused the same way, were cleared with a targeted turbo run build --filter=@objectstack/objectql --filter=@objectstack/formula --filter=@objectstack/lint, and then both passed.
  • pnpm check:nul-bytes green, plus a direct control-character scan over both changed files.

Why a changeset, given the diff is prose. Measured rather than assumed: packages/spec ships dist in its files[], and after building the package the edited sentence is present in dist/contracts/index.d.ts and dist/contracts/index.d.mts — 2 published files, with the untouched neighbouring sentences of the same docblock as the positive control (also 2). Published bytes move, so skip-changeset does not apply and this lands as a patch.

Draft on purpose; landing is the seat's.


🤖 Generated with Claude Code

https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3


Generated by Claude Code

…umber

`ToolExecutionContext.userMessageText`'s docblock said the agent route is owned
by cloud "post-ADR-0025" — cloud context, bare id. A bare id resolves against
THIS registry, where ADR-0025 is Plugin Package Distribution: a real record
about `.osplugin` artifacts and marketplace install, which decides nothing about
the agent route.

An id that resolves to the wrong page is worse than one that resolves to
nothing: a dangling number stops the reader, a live one lets them believe they
read the right decision.

Prime Directive 13: an ADR "lives in the repository whose code it governs", and
a cloud decision is cited as `cloud ADR-NNNN`, never as a bare number. The line
now reads `(cloud, post-cloud ADR-0025)` — verbatim what the sibling member
`confirmedBlueprintIdentity` already says two declarations below, so the two
neighbouring lines are consistent again.

Docblock prose only: no type change, no export added or removed.

Co-Authored-By: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Sep 17, 2026
@github-actions

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/protocol/knowledge.mdx (via ToolExecutionContext (symbol, a top-level interface))

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

  • content/docs/releases/v15.mdx (via ToolExecutionContext (symbol, a top-level interface))
  • content/docs/releases/v9.mdx (via ToolExecutionContext (symbol, a top-level interface))

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
  • 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 — 136 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 09e16a5745b66ca4e5cdddb6248551d1761f0dddpackageMentionDocs.

Which tree this was computed on

This run read content/docs from 470189f8b31a757128eb3afa14e049774a6b4288 — the merge of head edcbcda2548d8a23d9147adf4dd59ffa3fb87add into base 09e16a5745b66ca4e5cdddb6248551d1761f0ddd, 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 470189f8b31a757128eb3afa14e049774a6b4288 && git checkout 470189f8b31a757128eb3afa14e049774a6b4288
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 09e16a5745b66ca4e5cdddb6248551d1761f0ddd edcbcda2548d8a23d9147adf4dd59ffa3fb87add && git checkout -B drift-repro 09e16a5745b66ca4e5cdddb6248551d1761f0ddd && git merge --no-ff edcbcda2548d8a23d9147adf4dd59ffa3fb87add

node scripts/docs-audit/affected-docs.mjs --json 09e16a5745b66ca4e5cdddb6248551d1761f0ddd

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

@os-bill os-bill added domain:spec priority:p2 Medium: important, M3 labels Sep 17, 2026 — with Claude
@os-bill
os-bill marked this pull request as ready for review September 17, 2026 19:47
@os-bill
os-bill added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 922923b Sep 17, 2026
45 checks passed
@os-bill
os-bill deleted the claude/issue-18685-cloud-adr-citation-spelling branch September 17, 2026 20:08
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 domain:spec priority:p2 Medium: important, M3 size/s tooling

Projects

None yet

2 participants