Skip to content

docs(metadata-protocol): name each decline list's remit and add the JSDoc's missing flow-conflict bullet - #9556

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-9271-decline-list-remits
Aug 18, 2026
Merged

docs(metadata-protocol): name each decline list's remit and add the JSDoc's missing flow-conflict bullet#9556
os-sam merged 1 commit into
mainfrom
claude/issue-9271-decline-list-remits

Conversation

@os-sam

@os-sam os-sam commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #9271

Option A as ruled on 2026-08-17: the two decline lists describing
migrateStoredMetadata are an intentional scope split, now made explicit.
Two audiences, two documents, each self-describing — neither derived from nor
transcluded into the other.

Prose only. No behaviour change, no API change.

The ruling's falsifiable premise: verified, NOT falsified

The ruling carried a hard stop: verify the flow-conflict path is reachable from
a non-CLI caller, and if it turns out CLI-only, report the fork rather than
force the bullet. It is reachable, so the bullet was genuinely owed. What
settled it:

  • Two non-CLI production callers, both HTTP doors, and neither passes
    canonicalizeFlow:
    • packages/rest/src/rest-server.tsPOST /meta/_migrate-stored
    • packages/runtime/src/domains/meta.tsPOST /metadata/_migrate-stored
  • With that argument omitted, the function resolves the engine itself —
    request.canonicalizeFlow ?? this.resolveFlowCanonicalizer() — and
    resolveFlowCanonicalizer reads the automation service off the services
    registry.
  • The conflict branch is keyed on only two things: the row being a flow,
    and the canonicalization returning a non-empty conflicts array. Nothing in
    it discriminates on which caller supplied the engine.
  • Both route comments already assert that a server always holds a live
    automation engine. A live executor registry is precisely the condition
    under which the guard can refuse a real rename; the CLI's deliberately inert
    engine is the weaker case, not the only one.

Positive control for the caller sweep: the same sweep independently surfaced the
expected CLI caller (packages/cli/src/commands/migrate/meta.ts) and 25 files
in total, so the non-CLI hits are a reading rather than an artefact of a query
that matches everything or nothing.

What changed

packages/metadata-protocol/src/protocol.ts — the migrateStoredMetadata
JSDoc block only:

  1. Added the missing fifth bullet, "a flow whose rename that guard refused".
    Placed immediately after the no-reachable-engine bullet so the two
    flow-related declines sit together — and so the remit sentence's existing
    "the first bullet below" reference keeps pointing at the bullet it always
    meant.
  2. Restated the remit sentence's final clause. PR docs(metadata-protocol): add the #8957 fourth decline bullet to migrateStoredMetadata's JSDoc #9270 had already landed
    the remit sentence, ending "That does not by itself account for every
    difference between this list and cli.mdx's decline table — see [Decision] migrateStoredMetadata's JSDoc decline list and cli.mdx's decline table document different sets — intentional scope split, or two lists that drifted? #9271". Adding
    the bullet above makes that clause false: the difference is now fully
    accounted for. It now states the finished fact, and names the split as ruled
    rather than pointing at an open question. The sentence was improved in
    place, never duplicated
    — no second remit sentence was added.

content/docs/deployment/cli.mdx — one sentence naming the decline table's
remit: the operator-observable surface, plus which single member the JSDoc
carries that it does not, and why no operator door can reach it.

Per the ruling, cli.mdx deliberately does not grow a
"no reachable automation engine" row — an operator cannot reach that path, and
documenting it there would be its own small lie.

End state

JSDoc cli.mdx
flow rows with no reachable automation engine yes no, by stated remit
A flow whose rename the conflict guard refused yes (new) yes
Types with no repository write path yes yes
Rows that still fail the schema after conversion yes yes
Rows under a non-canonical metadata type spelling yes yes

Five members against four, differing by exactly one member in exactly one
direction, for a reason each document now states itself — which is the end state
the ruling predicted.

Verified mechanically rather than by eye: parsing the file with the TypeScript
compiler API reports 0 parse diagnostics, attaches a 6481-char JSDoc to
migrateStoredMetadata, and counts 5 decline bullets in it.

Changeset

None — the skip-changeset label is applied instead. This repo's
check-empty-changeset.mjs gate rejects a newly added empty-frontmatter
changeset, and AGENTS.md reserves changesets for feature or functional work. A
prose-only PR releases nothing, which is the label's textbook case as
lint.yml itself describes it.

Gates

Re-derived against the actual diff with node scripts/pm/dispatch-gates.mjs
(no path argument, so the script takes its own change set) — it returned the
same 12 families the dispatch named, no additions. All 12 run green on the
pushed tree, commit 0d3ea23, each exit status captured directly rather than
through a pipe:

check:cross-package-test-inputs · check-cross-package-test-inputs.mjs ·
check:docs-audit-scope · check:docs-redirects · check:role-word ·
check:durability-log-level · check:filter-alias-parity ·
spec check:empty-state · spec check:liveness ·
spec check:strictness-ledger · spec check:variant-docs ·
docs-audit/check-affected-docs.mjs

The affected-docs mapper flags three pages against this diff. Two are
content/docs/releases/, which is release-owned and untouched here. The third,
content/docs/concepts/metadata-lifecycle.mdx, is a negative and stays
unedited
: it carries no decline list at all (zero occurrences of "decline"),
and its single mention of the function is one accurate clause about the
no-write-path skip, a decline this PR does not alter. So there is no third list
to fold into the split — the card's two-list framing is complete.


Generated by Claude Code

… JSDoc's flow-conflict gap (#9271)

`migrateStoredMetadata` is described by two hand-written decline lists that
were not the same enumeration, and nothing enforced either count.

- `protocol.ts` JSDoc: add the missing "a flow whose rename the conflict
  guard refused" bullet. That path is internal to the function and reachable
  from every door, so its absence was a real omission rather than a scope
  choice.
- `protocol.ts` JSDoc: the remit sentence PR #9270 landed closed with "that
  does not by itself account for every difference ... see #9271". With the
  bullet above added, it now does, so the clause is restated as the finished
  fact it has become.
- `cli.mdx`: name the decline table's remit — the operator-observable
  surface — and say which single member the JSDoc carries that it does not,
  and why no operator door can reach it.

The two lists now differ by exactly one member, in one direction, for a
stated reason. Prose only; no behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qYPmkKEsfbWY1yVg83p8F
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-protocol, 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/metadata-lifecycle.mdx (via ObjectStackProtocolImplementation (symbol))

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

  • content/docs/releases/v16.mdx (via ObjectStackProtocolImplementation (symbol))
  • content/docs/releases/v17.mdx (via ObjectStackProtocolImplementation (symbol))

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

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

Which tree this was computed on

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

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

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

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 18, 2026
@os-sam os-sam added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed size/s labels Aug 18, 2026 — with Claude
@os-sam
os-sam marked this pull request as ready for review August 18, 2026 09:55
@os-sam
os-sam added this pull request to the merge queue Aug 18, 2026
Merged via the queue into main with commit 65d4fff Aug 18, 2026
32 checks passed
@os-sam
os-sam deleted the claude/issue-9271-decline-list-remits branch August 18, 2026 10:10
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 skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants