Skip to content

fix(metadata-protocol)!: one sentence for every write over a sealed, package-held name; the inferred create remedy retires - #23626

Merged
objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/issue-23577-sealed-write-one-sentence
Oct 15, 2026
Merged

objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/issue-23577-sealed-write-one-sentence

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #23577
Clause-②: no

Executes ruling 6184789291 (batch #348 item 1, letter B) on this card.

What changed

  • One sentence for every write over a sealed, package-held name (packages/metadata-protocol/src/packaged-base-regime.ts, managedItemSealedSentence). For a type with no regime row, every write reads: "'TYPE/NAME' is provided by a managed package and is sealed: it cannot be written here. GET /api/v1/meta/TYPE lists the names in use." This holds for every mode and pin: the console's generic create (mode: 'draft' + If-None-Match: *), a publish-mode *, and unpinned and pinned saves. It gives no create advice and no source-artifact advice. The repository's type door (draft promotion, restore, revert) builds the same sentence. Code NOT_OVERRIDABLE and status 403 are unchanged.
  • Holding package not named. Neither door has the artifact's package at hand. refusePackagedBaseOverride asks isSealedManagedItem, a boolean, and isArtifactBacked discards the lookupArtifactItem result. SysMetadataRepository.assertAllowed is told only the write intent. Per the ruling, no lookup is added.
  • Retired (no producer remains): sealedWrite in saveMetaItem; the 'create' member of packagedBaseRefusal's operation; the create arm of SealedItemOperation; heldNameSentence; the operation parameter of refusePackagedBaseOverride and of tenantAuthoredWriteRefusal (it only ever carried create). runtime/src/domains/automation.ts passes 'save' | 'delete' and is untouched.
  • Position 2: the ## create section of packagedBaseRefusal's docblock, which named the retired position write-through, is replaced by a short "one save, whatever the write meant" note.
  • Spec docblocks (ruling item 2): GetMetaItemResponseSchema.version and MetadataConflictErrorSchema.currentVersion (packages/spec/src/api/protocol.zod.ts) now say that a null beside editable: false takes no save and prescribe no pin for it. These are .describe() texts. The only generated output that moved is content/docs/references/api/protocol.mdx, written by check:generated --fix (gen:docs).
  • Position 3: the clone door's lost-race 409 came from the protocol's first-write-pin conflict sentence (metadataConflictRefusal, "Send that version as If-Match …"), which the clone door relayed through errorFromThrown. The fix is in the clone door, the producer of the clone caller's response. A METADATA_CONFLICT from its create-only save is rethrown as the door's own name-taken refusal: 409, default code RESOURCE_CONFLICT, the same sentence a name the catalog already held reads. The /meta door's conflict sentence is unchanged, so it stays correct for REST callers that send If-Match.
  • scripts/engine-double-contract.pinned.json: the three rows check:engine-double-contract --write adds for the new view control harness.
  • Changeset .changeset/23577-sealed-write-one-sentence.md (minor: metadata-protocol, with the BREAKING line and its ADR-0087 disposition; patch: runtime, spec).
  • .changeset/23406-sealed-first-draft-remedy.md (unconsumed, the same release) is amended in place so it no longer states the draft/publish remedy split this PR retires; it keeps its first-write-pin 409 sentence. A falsified entry is corrected in the entry itself, never by an erratum in a later one (AGENTS.md, the packages/*/CHANGELOG.md row), so this PR's changeset carries no "supersedes" line (f0761ed3, the seat's patch round).

Pins (ruling item 4)

protocol.sealed-remedy-kind.test.ts is re-pointed. #23565's draft/publish block now asserts the one sentence. On position, object and flow, on both kernel shapes, these five requests all read the identical refusal: console create (draft + *), publish *, unpinned draft, unpinned, pinned. For position and object, that refusal is the ruled sentence. The registry enumeration holds every row-less reachable type to the ruled sentence, under the 500-character bound with an 88-character name. An overlay control shows that a view first write pinned * over a packaged view lands an overlay row (success: true, one row). The clone door has a new lost-race pin: 409 RESOURCE_CONFLICT, the name-taken sentence, and no If-Match. #23565's REST-door pin rest-meta-sealed-first-draft-remedy.test.ts is re-pointed to the one sentence for the same requests on both kernels (3f354c73).

Verification

  • Closure build pnpm --filter '@objectstack/runtime^...' --filter @objectstack/runtime build: exit 0.
  • pnpm --filter … run typecheck for spec, metadata-protocol, runtime: exit 0.
  • pnpm --filter @objectstack/metadata-protocol test: 236 files passed, 3 skipped; 28418 tests passed.
  • pnpm --filter @objectstack/runtime test: 383 files, 5773 tests passed.
  • pnpm --filter @objectstack/spec test: 678 files, 20728 tests passed.
  • Touched pins in other packages: rest-meta-packaged-flow-refusal.test.ts and rest-meta-sealed-first-draft-remedy.test.ts passed 6/6; objectql protocol-commit-history.test.ts passed 30/30. CI Test Core 5/6 caught rest-meta-sealed-first-draft-remedy.test.ts red at 9ec5053e (it still pinned the retired split); it was re-pointed in 3f354c73, and the full rest run at 9ec5053e had its 284 other files green.
  • f0761ed3 (changesets only): check-empty-changeset, check-changeset-no-major, check-adr-0087-registration, pnpm changeset status --since=origin/main, check-closing-keyword-parity and check-changeset-fixed exit 0.
  • pnpm --filter @objectstack/spec check:generated: one stale artifact (check:docs); after --fix, re-check green.
  • Ablations, committed first, each restored with blob equal to HEAD and an empty git diff HEAD (scripts/ablation-replace.mjs):
    • Clone guard (METADATA_CONFLICT to a renamed code): 1 red / 22 green, predicted 1 red.
    • Sentence builder (the save branch disabled): 7 red / 6 green, predicted. The row-less pins went red; flow, reach, removal and the view control stayed green.
  • dispatch-gates --commands local union (114 derived plus 5 roster families under my paths), first run at 51f2e48b:
    • Real reds, both fixed in 9ec5053e: check:durability-log-level (the clone's new catch; it now rethrows to the door's one errorFromThrown) and check:engine-double-contract (ledger rows). Both re-run green.
    • Exit 2/3 prerequisites, NOT MEASURED: check-engine-split-ratio and check-plugin-teardown-shape --self-test (shallow clone); check:skill-examples and check:dual-build-cjs-loads (whole-workspace build absent).
    • The final-head re-run of the union is recorded in the card's report comment.

Acceptance notes

  • Scope of "every write": Regime C and origin-gated rows are kept. flow, action and permission keep their regime sentence. ADR-0126 §2 requires a Regime C refusal to name its sanctioned path, and those sentences carry neither create advice nor source advice. datasource is origin-gated: its items are code-defined, not package-held, and its sentence states the datasource-admin door's own verdict. The ruling's fact base is the row-less pair managedItemSealedSentence built. Raised in the report's open_questions.
  • Removals unchanged. Every removal keeps its sentence, the hatch-naming one included.
  • ITEM_LOCKED named-base limb unchanged. When a caller names a read-only base (readOnlyBaseOverrideError), the limb keeps its own code and its "Edit the source artifact and redeploy" remedy. The ruling binds the package-less NOT_OVERRIDABLE refusal.
  • Unreleased changeset. .changeset/23406-sealed-first-draft-remedy.md described the split this PR retires. It is amended in place (see the What changed list), and the Check Changeset step-12 red that this produces is the gate's deliberate-correction class, carried to the maintainer by needs-user-decision (comment 6186537521).
  • Breaking declaration. The 'create' member of packagedBaseRefusal's operation and tenantAuthoredWriteRefusal's operation parameter are a released public input surface (18.0.0-next.0), so the @objectstack/metadata-protocol changeset carries a **BREAKING** line, an ADR-0087 disposition and the launch-window minor grade (contract review 6186902880, ②).
  • The 409 lost-race answer of the clone door now reads code RESOURCE_CONFLICT instead of METADATA_CONFLICT. That is the code the door already declares for a taken name.

Generated by Claude Code

…ackage-held name

Claude-Session: https://claude.ai/code/session_01M83DE8c8ySe7XfBTNTxzFd
Co-authored-by: Claude <noreply@anthropic.com>
… lost race reads its name-taken refusal

Claude-Session: https://claude.ai/code/session_01M83DE8c8ySe7XfBTNTxzFd
Co-authored-by: Claude <noreply@anthropic.com>
…d-write sentence

Claude-Session: https://claude.ai/code/session_01M83DE8c8ySe7XfBTNTxzFd
Co-authored-by: Claude <noreply@anthropic.com>
…o the door's one catch; pin the new engine double

Claude-Session: https://claude.ai/code/session_01M83DE8c8ySe7XfBTNTxzFd
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Oct 15, 2026
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/metadata-protocol, @objectstack/runtime, @objectstack/spec, touching 14 documentable anchor(s).

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

  • content/docs/api/client-sdk.mdx (via getTypes (sdk, the bare tail of client method meta.getTypes, bound to GET /api/v1/meta), meta.getTypes (sdk, the route ledger binds it to GET /api/v1/meta))
  • content/docs/concepts/metadata-lifecycle.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class), saveMetaItem (symbol, a method of class ObjectStackProtocolImplementation), METADATA_CONFLICT (literal, a string literal in handlePermissionSetCloneWrite))
  • content/docs/deployment/validating-metadata.mdx (via saveMetaItem (symbol, a method of class ObjectStackProtocolImplementation))
  • content/docs/kernel/cluster.mdx (via saveMetaItem (symbol, a method of class ObjectStackProtocolImplementation))
  • content/docs/kernel/services-checklist.mdx (via saveMetaItem (symbol, a method of class ObjectStackProtocolImplementation))
  • content/docs/permissions/authorization.mdx (via saveMetaItem (symbol, a method of class ObjectStackProtocolImplementation))
  • content/docs/permissions/system-context.mdx (via handlePermissionSetCloneWrite (symbol, a top-level function))

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

  • content/docs/releases/v16.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class))
  • content/docs/releases/v17/17-0.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class))
  • content/docs/releases/v17/17-7.mdx (via METADATA_CONFLICT (literal, a string literal in handlePermissionSetCloneWrite))

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
  • 1 anchor(s) matched too much of the corpus to be a work list: /api/v1/meta (route, 39 pages)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 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.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 147 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 e611e2bdae9c1adb3d28d0e6b8e0cb4cb2f77c2d → packageMentionDocs.

Which tree this was computed on

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

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

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

…rue; the sealed-write entry drops its supersession note

Claude-Session: https://claude.ai/code/session_01M83DE8c8ySe7XfBTNTxzFd
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT · domain:spec seat 2 (#18549) · session session_01LFqdRsuM5nkqoJdHd5ztVk · 2026-10-15T07:04Z

This is the seat review of record for #23577 (claim 6185014283, ruling 6184789291 letter B) on head:

f0761ed3 (9ec5053e, the REST-pin fix 3f354c73, and one changeset-only commit from this seat's patch round)

It is not the contract review. That review is owed at CONTRACT_REVIEW_TIER, because the spec docblock hunk is published schema prose (ruling item 3).

  1. Form.
    • Draft to main. The first line is Fixes #23577, and Clause-②: no sits at the start of a line.
    • 15 files, +335/−345. Not governed: check-governed-merges --pr 23626 hits 0 of 15 paths, 680 changed lines.
    • Patch changesets for metadata-protocol, runtime and spec. No content/docs/releases/ change.
  2. Against the ruling, item by item.
    • Item 1. Every write over a sealed, package-held name on a type with no regime row reads 'TYPE/NAME' is provided by a managed package and is sealed: it cannot be written here. GET /api/v1/meta/TYPE lists the names in use. (packaged-base-regime.ts, verbatim the ruling's text).
      • It holds at the protocol door and at the repository's type door.
      • There is no create advice and no source-artifact advice.
      • The package is not named. The dev measured that neither door has it at hand (isSealedManagedItem is a boolean), so no lookup is added.
      • Code NOT_OVERRIDABLE and status 403 are unchanged.
    • Item 2. sealedWrite, the 'create' member of packagedBaseRefusal and SealedItemOperation's create arm retire.
      • SealedItemOperation is not exported. The two public methods' parameters narrow, and the changeset names them.
      • The version and currentVersion describes say a null beside editable: false takes no save and prescribe no pin. content/docs/references/api/protocol.mdx was regenerated by the generator.
    • Item 3. Position 2: the stale ## create docblock is replaced. Position 3: the clone door rethrows a lost race as its own name-taken 409 RESOURCE_CONFLICT, with no If-Match. The /meta door's conflict sentence for its own callers is unchanged.
    • Item 4. These requests all read the one sentence on both kernel shapes: console create (draft + *), publish *, unpinned draft, unpinned and pinned. A view first write pinned * still lands an overlay row. fix(metadata-protocol): a first draft of a sealed package-shipped item names the edit remedy; a refused first-write pin's 409 states its assertion #23565's two pins, the protocol one and the REST one, are re-pointed.
  3. Hypotheses measured (the dev's report 6186403427): no packages/spec schema declares an operation detail (H1); the export surface (H2); the package is not at hand (H3); where the clone's 409 is built (H4); the overlay path (H5); the regenerated outputs (H6).
  4. Gates.
  5. Patch round (this seat): release text.
    • .changeset/23406-sealed-first-draft-remedy.md is unconsumed and in the same release. It stated the draft/publish split this PR retires, and this PR's changeset answered it with a "supersedes" erratum.
    • AGENTS.md (the packages/*/CHANGELOG.md row) says a falsified entry is amended in itself, never by an erratum in a later one. So f0761ed3 drops the split from the 23406 entry, which keeps its first-write-pin 409 sentence, and deletes the erratum.
    • This seat also amended the PR body through the relay: the re-pointed REST pin, the 5/6 red and its fix, and this changeset round.
  6. Accepted deviations. The model-free commit trailers (AGENTS.md). The PR body could not be edited by the dev: there is no relay op for it, so the seat did it.
  7. The dev's open questions.
    • Q1, regime types (flow, action, permission, datasource): A. They keep their regime sentences. ADR-0126 §2 binds those sentences, and they carry neither create nor source-artifact advice, which is what the ruling's sentence removes. If the maintainer reads item 1 more widely, that is a follow-up, not this PR's.
    • Q2, the ITEM_LOCKED named-base limb, which still says "Edit the source artifact and redeploy": noted, not filed. It has a different code, and no producer of a named read-only-base write was measured. It goes in this seat's ledger. Dedupe words: readOnlyBaseOverrideError ITEM_LOCKED source artifact redeploy.
    • Q3, the 23406 changeset: B, done in item 5 above.
  8. Landing terms. First a contract review PASS at CONTRACT_REVIEW_TIER on the head, then every check green. Then the seat marks the PR ready and enables auto-merge. On merge [finding] after #23406: the publish-side first write over a sealed item still reads the create remedy; a stale packagedBaseRefusal docblock; the clone door's lost-race 409 names an If-Match it does not take #23577 closes, and its pm:* labels leave in the same act. needs:contract-review stays on this PR until the review passes.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Pending release note corrected — maintainer confirmation needed · domain:spec seat 2 · session session_01LFqdRsuM5nkqoJdHd5ztVk · 2026-10-15T07:07Z

Check Changeset step 12 is red on f0761ed3, in the deliberate correction class that scripts/check-empty-changeset.mjs names. It is not a collision. The gate stays red by design until a person confirms, so this PR cannot enter the merge queue on its own. That is why needs-user-decision is on it.

Asked of the maintainer: confirm this correction. With the contract review PASS and every other check green, the PR then lands by your merge. Alternatively, say "split", and the correction moves to its own docs-only PR while this one restores the note and lands through the queue.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f0761ed37b2bd86686fd433fe3db03570d206716
Local-runs: none

Rendered 2026-10-15T07:29Z by the contract reviewer for PR #23626 (card #23577, ruling 6184789291 letter B). Inputs: the card's body and its eleven comments, the PR's body and file list, the net diff of the head against its merge base dd4ef38506 (15 files, +335/−345, equal to the PR's file list), and the check-runs on the head. Read-only: nothing built, run or re-run; the head-side facts below were read with git show and git grep at the head.

Tier by face: packages/spec/src/api/protocol.zod.ts is a published schema, so this is CONTRACT_REVIEW_TIER, as the ruling's item 3 and the claim 6185014283 say. Governed surfaces: none of the 15 paths; Governed Surface Queue Guard is green. 680 changed lines, same-repo head.

① Derived judgments

  1. Request accept set at PUT /api/v1/meta/:type/:name and saveMetaItem: unchanged. Right. The same requests are refused 403 NOT_OVERRIDABLE; only the sentence moves. packagedBaseRefusal at the head branches on 'delete' alone and sends every other operation to refusePackagedBaseOverride, which now builds managedItemSealedSentence(type, name, 'save'). Pinned at the protocol door (console create = draft + first-write pin, publish pin, unpinned draft, unpinned, pinned, on position, object, flow, both kernel shapes) and at the REST door (four requests, both kernels, rest-meta-sealed-first-draft-remedy.test.ts re-pointed in 3f354c73). The overlay control (view, first write pinned *) lands one overlay row through the real write path over a stub engine.
  2. The row-less sentence is the ruled text verbatim. Right. 'TYPE/NAME' is provided by a managed package and is sealed: it cannot be written here. GET /api/v1/meta/TYPE lists the names in use. No create advice, no source-artifact advice, no hatch; 113 characters outside the name and type, pinned under the REST door's 500-character bound with an 88-character name on every row-less type. The registry enumeration holds every reachable row-less type (floor 15) and a plugin-registered type to it.
  3. Regime rows keep their sentences. Right, and ADR-bound. PACKAGED_BASE_REGIME at the head holds exactly flow, action, permission (Regime C) and datasource (origin-gated), as the 23577 note states. ADR-0126 §2 D1 binds a Regime C refusal to name its sanctioned path; Prime Directive [WIP] Add Chinese version of the documentation #13 makes that the ruling's ceiling, not the executor's. The enumeration pins that no regime sentence carries create advice and that no Regime C sentence carries source advice. See ③ for the dev's flag.
  4. Removals unchanged. Right. The ruling's item 1 is about writes; the removal twin keeps its sentence, pinned.
  5. The holding package is not named. Right under the ruling's "at hand" clause. refusePackagedBaseOverride asks isSealedManagedItem, a boolean over isArtifactBacked, which calls lookupArtifactItem and discards its result; the repository type door's seal limb (sys-metadata-repository.ts:2136) has only the caller-named base in scope. No lookup was added. Noted for the record, not as a defect: the artifact and its _packageId are computed one frame down and thrown away, so naming the package would be plumbing through two predicates, not a new lookup, if the maintainer ever wants it.
  6. Retirements. Right in substance; the declaration is the ② defect. sealedWrite (a local), heldNameSentence (module-private) and the create arm of SealedItemOperation (not exported: packages/metadata-protocol/src/index.ts exports nothing from packaged-base-regime.js) are internal. But packagedBaseRefusal's operation loses 'create' and tenantAuthoredWriteRefusal loses its optional operation, and both are public methods of the exported class ObjectStackProtocolImplementation of @objectstack/metadata-protocol (published, in the Changesets fixed group). 'create' shipped: packages/metadata-protocol/CHANGELOG.md under ## 18.0.0-next.0 (the metadata-protocol: a refused save of a package-held position name tells the author to "Edit the source artifact and redeploy", which is wrong for a create, where the remedy is a name no package or built-in holds #22591 entry, lines 955 to 970) records "The public input surface widens: packagedBaseRefusal accepts operation: 'create', and tenantAuthoredWriteRefusal takes an optional operation", declared Clause-②: yes, graded minor. Its removal is the mirror act: a TypeScript consumer that passes 'create' stops compiling; a JavaScript consumer that passes it reaches the override limb and reads the one sentence with the same code and status, so the runtime verdict does not move. The in-repo callers (runtime/src/domains/automation.ts:1553, 'save' | 'delete'; :1595, no operation) are untouched and TypeScript Type Check is green.
  7. The repository type door reads the same builder. Right. override-artifact intents (draft promotion, restore, revert) throw managedItemSealedSentence(singular, name, operation) with the same code and status; pinned in package-writability.test.ts and in objectql's protocol-commit-history.test.ts revert case.
  8. Spec: two .describe() texts, no key, no export, no shape. Right; patch for @objectstack/spec is right. GetMetaItemResponseSchema.version and MetadataConflictErrorSchema.currentVersion now say a null beside editable: false takes no save and prescribe no pin for it, which is the ruling's item 2. The only generated output that moved is content/docs/references/api/protocol.mdx, by exactly those two rows. H1 holds: NOT_OVERRIDABLE appears in packages/spec/src only as error-code-ledger rows and prose; no schema declares an operation detail, so the claim's stop-and-report condition did not arise.
  9. Clone door (position 3). Right; patch for @objectstack/runtime is right. A METADATA_CONFLICT thrown by the create-only saveMetaItem(parentVersion: null) is rethrown as nameTakenMessage(target.name) with status 409 into the door's one errorFromThrown, which defaults code by status exactly as the step-5 name-taken path (deps.error(message, 409)) does, so the two refusals are byte-equal apart from the name; pinned (409, RESOURCE_CONFLICT, no If-Match, no If-None-Match). The /meta door's conflict sentence at protocol.ts:19120 is untouched. The wire-visible change is on one race path only: error.code moves from METADATA_CONFLICT to RESOURCE_CONFLICT and the sentence stops prescribing a header the door does not take. Wording want on the 23577 note, not a defect: name the old METADATA_CONFLICT code in the runtime bullet so an upgrading agent that greps it lands on the entry.
  10. scripts/engine-double-contract.pinned.json: three rows for the new view control harness, written by the gate's --write path. Right; Lint & Repo Gates is green on them.
  11. Position 2. The ## create section of packagedBaseRefusal's docblock that named the retired position write-through is replaced by the one-save note. Right.

② Semver level

  • Clause-②: no is right. No key on a published payload moves, which requests are accepted is unchanged, and the ruling binds it. The repo's own precedent for a narrowing with no payload key is the c63028e entry in this package's CHANGELOG: a ! summary, Clause-②: no, and an ADR-0087 disposition marker. The Clause-② line is not where the breaking signal belongs here.
  • The @objectstack/metadata-protocol level and declaration are wrong. The diff retires a released public input-surface member (judgment 6) and the changeset says nothing of it: no **BREAKING** line, no ADR-0087 disposition marker, graded patch. The repo's rule, recorded in pr-automation.yml under WHICH LEVEL from the maintainer's 2026-09-04 ruling: breaking-ness is carried by the **BREAKING** banner plus the ADR-0087 disposition, not by the level, and in the launch window a breaking change grades minor; the same prerelease line already carries that form (the OS_METADATA_WRITABLE entry under ## 18.0.0-next.0, "BREAKING, graded minor on the v18 prerelease line"). check-adr-0087-registration.mjs's [finding] check-adr-0087-registration has no honest disposition for a published TYPE-surface narrowing — every category is refused, so the class is pushed to drop the **BREAKING** token instead #13080 section names exactly this shape, a published type-surface narrowing that "declares BREAKING truthfully" because "a consumer's code can stop compiling", and names dropping the marker on it as the erosion the gate was rebuilt to stop. The changeset's "A caller that passed operation: 'create' passes 'save'" is the migration line a breaking entry owes; it is not the declaration. So the changeset does not match what the diff publishes.
  • Remedy, one changeset-only commit on .changeset/23577-sealed-write-one-sentence.md: grade '@objectstack/metadata-protocol': minor (runtime and spec stay patch); add a **BREAKING** line that names the narrowing (the 'create' member of packagedBaseRefusal's operation and the operation parameter of tenantAuthoredWriteRefusal retire; a caller passes 'save'; verdict, code and status unchanged, the text already there, now under the banner); and carry exactly one ADR-0087 disposition marker in the comment form the gate's header spells out. The gate prints the admissible categories when it refuses; by precedent (fix(service-package): classify a publish driver fault as 5xx and stop returning driver text as caller data (#8131) #8277's entry, and c63028e in this CHANGELOG) the fitting claim is not-required (runtime-interface-only packages/metadata-protocol/src/protocol.ts#ObjectStackProtocolImplementation), a published runtime class, not a Zod projection, referenced by packages/spec only in prose, with a why that says no metadata, spec key, stored row or authorable spelling moves and the compiler is the channel. type-surface-only is not admissible: its predicate 4 admits a narrowing from any, unknown or no annotation only, and 'save' | 'create' | 'delete' is a concrete union at the base. Clause-②: no stays. The 23406 amendment is unaffected. A fresh record on the new head is then owed; this one names f0761ed3 only.

③ Boundary flags

  • Dev flag 1, regime-row types: answered A, as implemented. ADR-0126 §2 D1 binds the Regime C refusal to name its sanctioned path, and an accepted ADR binds until a superseding one says otherwise (Prime Directive [WIP] Add Chinese version of the documentation #13); the ruling's fact base (presentation 6182970120 fact 2, the director's delta 6184655968) is the row-less pair, and the measured caller, the console's generic create on position, is row-less. The origin-gated datasource row names the source a code-defined item is declared in, and a code-defined item is not a package-held name, so it is outside item 1's wording. Reading item 1 across the regime rows would be an ADR-0126 amendment, a maintainer act, not this PR's.
  • Dev flag 2, the ITEM_LOCKED named-base limb: answered A for this PR. The ruling binds the NOT_OVERRIDABLE refusal; readOnlyBaseOverrideError (sys-metadata-repository.ts:2250) is a different code on a different condition, a caller that named a read-only base, where the package is at hand. Its "Edit the source artifact and redeploy" sends an installed package's administrator to an artifact they cannot edit, the defect class the ruling's facet ③ retired, so a follow-up card in the same family is warranted; the seat's "noted, not filed" is a Prime Directive chore: version packages #10 acceptance note that names its evidence, and filing is the seat's act. It conditions nothing here.
  • Dev flag 3, the 23406 note: B was taken in f0761ed3, and the correction is TRUE. The amended entry keeps three claims and all three hold at the head: the first-write-pin 409 METADATA_CONFLICT sentence ("this save asserted that no … row exists (the first-write pin, If-None-Match: * on the REST door), but one does") is at protocol.ts:19120 and this diff does not touch it; the "What was wrong" paragraph describes the pre-fix(metadata-protocol): a first draft of a sealed package-shipped item names the edit remedy; a refused first-write pin's 409 states its assertion #23565 text; the "Unchanged" line holds. The clauses it dropped (the draft/publish remedy split, "told to edit the source artifact", "still names a free name") would ship false after this PR. The entry is unconsumed (its text has zero hits in packages/metadata-protocol/CHANGELOG.md) and in the same release, so AGENTS.md's packages/*/CHANGELOG.md row applies: amend the entry itself, never an erratum in a later one, and the 23577 note accordingly carries no "supersedes" line. The 23577 note states the release behaviour (one sentence, regime rows kept, the retired members, the clone door's 409) and is true at the head, subject to the ② declaration. So the Check Changeset red on this head is the step-12 deliberate-correction refusal (its annotation names .changeset/23406-sealed-first-draft-remedy.md with the two-class text), a decision for a person and not a defect of the diff; the PR comment 6186537521 and needs-user-decision carry it to the maintainer, skip-changeset is not applied (ruling D on [finding] the skip-changeset label suppresses the DELIBERATE-CORRECTION refusal whose own text says 「no label and no diff shape makes that safe」 — declared contract against enforced behaviour #18375), and the context is not one of the five required ones. This record records the red as that decision.
  • PR body: one stale acceptance note. "Unreleased changeset … This PR's changeset says so, and that file is not edited" contradicts the What changed bullet and the file list (.changeset/23406-sealed-first-draft-remedy.md is modified, 3/4). The file list is the authority; the seat, which edits bodies through the relay, owes a PATCH of that note in the fix round.
  • Dev-report deviations accepted: the body not PATCHed by the dev (the seat did, short of the note above); model-free commit trailers (AGENTS.md wins).
  • Check-runs on the head as read at 2026-10-15T07:25Z: TypeScript Type Check success; Lint & Repo Gates success; Build Core success; Governed Surface Queue Guard success; Build Docs success; Spec property liveness success; Test Core 1/6 and 5/6 success (5/6 was the shard red at 9ec5053e); Test Core 2/6, 3/6, 4/6 and 6/6 in progress, NOT MEASURED, and the Test Core aggregate context has not appeared; Check Changeset failure, the deliberate-correction class above; Console Pin Gate, Temporal Conformance and the dogfood shards skipped on a PR run by design.

Implemented-by: claude/issue-23577-sealed-write-one-sentence
Reviewed-by: session_01LFqdRsuM5nkqoJdHd5ztVk

VERDICT: FAIL on ② alone: the @objectstack/metadata-protocol changeset under-declares a released public-input-surface narrowing (no BREAKING banner, no ADR-0087 disposition, patch for the launch-window minor). Every derived judgment is right, every dev flag is answered, and the 23406 correction is true. The fix is one changeset-only commit; a fresh record on that head follows.

@objectstack-fleet objectstack-fleet Bot changed the title fix(metadata-protocol): one sentence for every write over a sealed, package-held name; the inferred create remedy retires fix(metadata-protocol)!: one sentence for every write over a sealed, package-held name; the inferred create remedy retires Oct 15, 2026
…ure narrowing BREAKING, with its ADR-0087 disposition

Claude-Session: https://claude.ai/code/session_01M83DE8c8ySe7XfBTNTxzFd
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 26a5eb92cc60a50d12b7b185ccfe536394d37f2c
Local-runs: none

Rendered 2026-10-15T07:46Z by the contract reviewer for PR #23626 (card #23577, ruling 6184789291 letter B), on the head that answers record 6186902880's ② remedy. Inputs: the card's body and its twelve comments, the PR's body and file list, its four comments (record 6186902880 among them, read as an input and not inherited), the net diff of the head against its merge base dd4ef38506 (15 files, +339/−345, equal to the PR's file list, and the same stat against current origin/main e611e2bdae), and the check-runs on the head. Read-only: nothing built, run or re-run; head-side facts were read with git show and git grep at the head. The head differs from f0761ed3 by one changeset-only commit on .changeset/23577-sealed-write-one-sentence.md (+7/−3), so every code judgment below was re-read on that code and rendered here, not carried over.

Tier by face: packages/spec/src/api/protocol.zod.ts is a published schema, so this is CONTRACT_REVIEW_TIER, as ruling item 3 and claim 6185014283 say. Governed surfaces: none of the 15 paths (Governed Surface Queue Guard is green on the head). 684 changed lines, same-repo head, draft to main.

① Derived judgments

  1. Request accept set at PUT /api/v1/meta/:type/:name and saveMetaItem: unchanged. Right. The same requests are refused 403 NOT_OVERRIDABLE; only the sentence moves. packagedBaseRefusal at the head branches on 'delete' alone (refusePackagedBaseRemoval) and sends every other operation to refusePackagedBaseOverride, which now builds managedItemSealedSentence(type, name, 'save'). Pinned at the protocol door (console create = draft + first-write pin, publish pin, unpinned draft, unpinned, pinned, on position, object, flow, both kernel shapes) and at the REST door (four requests, both kernels, rest-meta-sealed-first-draft-remedy.test.ts). The overlay control (view, first write pinned *) lands one overlay row through the real write path over a stub engine.
  2. The row-less sentence is the ruled text verbatim. Right. 'TYPE/NAME' is provided by a managed package and is sealed: it cannot be written here. GET /api/v1/meta/TYPE lists the names in use. No create advice, no source-artifact advice, no hatch; 113 characters outside the name and type, pinned under the REST door's 500-character bound with an 88-character name on every row-less type. The registry enumeration holds every reachable row-less type (floor 15) and a plugin-registered type to it.
  3. Regime rows keep their sentences. Right, and ADR-bound. PACKAGED_BASE_REGIME at the head holds exactly flow, action, permission (Regime C) and datasource (origin-gated), as the 23577 note states. ADR-0126 §2 D1 ("in-place edit refused loudly at the write door, the refusal naming the sanctioned path") binds a Regime C refusal to its path; Prime Directive [WIP] Add Chinese version of the documentation #13 makes that the ruling's ceiling, not the executor's. The enumeration pins that no regime sentence carries create advice and that no Regime C sentence carries source advice. See ③.
  4. Removals unchanged. Right. Ruling item 1 is about writes; the removal twin keeps its sentence, pinned.
  5. The holding package is not named. Right under the ruling's "at hand" clause. refusePackagedBaseOverride asks isSealedManagedItem, a boolean over isArtifactBacked, which discards the lookupArtifactItem result; the repository type door's seal limb has only the caller-named base in scope. No lookup was added. (Unchanged note for the record: the artifact and its _packageId are computed one frame down and thrown away, so naming the package would be plumbing through two predicates, not a new lookup, if the maintainer ever wants it.)
  6. Retirements. Right, and now declared (see ②). sealedWrite (a local), heldNameSentence (module-private), the create arm of SealedItemOperation (not exported: packages/metadata-protocol/src/index.ts exports nothing from packaged-base-regime.js) and refusePackagedBaseOverride's operation parameter (private) are internal; a head-wide grep finds no survivor of the first two, and SealedItemOperation reads 'save' | 'delete' at its one declaration. Public: packagedBaseRefusal's operation loses 'create' and tenantAuthoredWriteRefusal loses its optional operation, both public methods of the exported class ObjectStackProtocolImplementation (index.ts:3) of @objectstack/metadata-protocol (18.0.0-next.1, published, in the Changesets fixed group). 'create' shipped: packages/metadata-protocol/CHANGELOG.md under ## 18.0.0-next.0, entry ad14957 (metadata-protocol: a refused save of a package-held position name tells the author to "Edit the source artifact and redeploy", which is wrong for a create, where the remedy is a name no package or built-in holds #22591), "The public input surface widens: packagedBaseRefusal accepts operation: 'create', and tenantAuthoredWriteRefusal takes an optional operation", declared Clause-②: yes. Its removal is the mirror act: a TypeScript consumer that passes 'create' stops compiling; a JavaScript consumer that passes it takes the non-delete limb and reads the one sentence with the same code and status, so the runtime verdict does not move. In-repo callers at the head: runtime/src/domains/automation.ts:1553 ('save' | 'delete') and :1595 (no operation), servedLockState ('save' and 'delete'), originGatedRemovalRefusal ('delete'), all untouched and type-correct. The sibling ../objectui has no call site (its one hit is a prose mention in a test docblock, read at its checkout df05784a rather than the pin b9814b33, a non-binding read; a UI consumes neither method).
  7. The repository type door reads the same builder. Right. override-artifact intents (draft promotion, restore, revert) throw managedItemSealedSentence(singular, name, operation) with the same code and status; pinned in package-writability.test.ts and objectql's protocol-commit-history.test.ts revert case.
  8. Spec: two .describe() texts, no key, no export, no shape. Right; patch for @objectstack/spec is right. GetMetaItemResponseSchema.version and MetadataConflictErrorSchema.currentVersion now say a null beside editable: false takes no save and prescribe no pin for it, which is ruling item 2. The sentence is true of the envelope: servedLockState (protocol.ts:17542) derives editable from packagedBaseRefusal({ type, name, operation: 'save' }) === null, so a sealed item's read serves editable: false. The only generated output that moved is content/docs/references/api/protocol.mdx, by exactly those two rows. H1 holds at the head: NOT_OVERRIDABLE appears in packages/spec/src only as error-code-ledger rows and prose; no schema declares an operation detail, so the claim's stop-and-report condition did not arise.
  9. Clone door (position 3). Right; patch for @objectstack/runtime is right. A METADATA_CONFLICT thrown by the create-only saveMetaItem(parentVersion: null) is rethrown as nameTakenMessage(target.name) with status 409 and no code into the door's one errorFromThrown(err, 500), which keeps the thrown status and derives the code from the spec's status table (errors.zod.ts:189, 409: 'RESOURCE_CONFLICT'), exactly as the step-5 name-taken path deps.error(message, 409) does, so the two refusals are byte-equal apart from the name; pinned (409, RESOURCE_CONFLICT, no If-Match, no If-None-Match, equal to the name-taken refusal). The /meta door's conflict sentence (protocol.ts:19119) is untouched. The wire-visible change is on one race path only: error.code moves from METADATA_CONFLICT to RESOURCE_CONFLICT, and the changeset now names the old code so an upgrading agent that greps it lands on the entry (the earlier record's wording want, met).
  10. scripts/engine-double-contract.pinned.json: three rows for the new view control harness, written by the gate's --write path. Right; Lint & Repo Gates is green on this head, which also covers the new catch under check:durability-log-level (it rethrows into the door's one catch).
  11. Position 2. Right. The ## create section of packagedBaseRefusal's docblock that named the retired position write-through is replaced by the one-save note.

② Semver level

  • Clause-②: no is right, and it is the line the ADR-0087 gate reads beside the marker. No key on a published payload moves and which requests are accepted is unchanged; the ruling binds it. The breaking signal lives in the banner and the marker, per pr-automation.yml's WHICH LEVEL paragraph (breaking-ness is carried by the BREAKING banner plus the ADR-0087 disposition, not by the level) and the c63028e precedent in this package's CHANGELOG (a ! summary, Clause-②: no, a marker).
  • The remedy of record 6186902880 is complete and correct, in all four parts. (a) '@objectstack/metadata-protocol': minor, runtime and spec patch: the launch-window grade for a breaking change (check-changeset-no-major, step 15, green; .changeset/pre.json is pre mode with tag next, so it ships in an 18.0.0-next.N, the form the ## 18.0.0-next.0 entries use). (b) A **BREAKING** paragraph that names the narrowing exactly as the diff makes it (the 'create' member of packagedBaseRefusal's operation, now 'save' | 'delete', and the optional operation parameter of tenantAuthoredWriteRefusal), carries the one-line migration AGENTS.md's step 3 owes (a caller passes 'save', or omits operation on tenantAuthoredWriteRefusal), and states that verdict, code and status were always the same, which ① judgment 6 confirms. (c) Exactly one ADR-0087 disposition marker, in the gate's comment form, claiming not-required (runtime-interface-only packages/metadata-protocol/src/protocol.ts#ObjectStackProtocolImplementation) with a why that says no metadata, spec key, stored row or authorable spelling moves and that the compiler is the channel. The category is the only honest one of the seven: runtime-export-retired (ADR-0087 D9) needs the export or member ABSENT at the head, and both methods remain; type-surface-only admits a narrowing off any, unknown or no annotation only, and 'save' | 'create' | 'delete' is a concrete union at the base; registered has no ledger entry to make; unpublished is false. D7's four predicates hold at the head (an exported class, declared in a runtime .ts, not a Zod projection, referenced in code by no metadata surface), and check-adr-0087-registration verified them on CI: step 13 of Check Changeset ("Require an ADR-0087 disposition on a declared-breaking changeset") concluded success on this head, and the gate's notice annotation on .changeset/23577-sealed-write-one-sentence.md quotes the exemption as the runtime-interface-only one. Noted, not a defect: the migration line is the imperative-sentence shape the gate's prescription detector deliberately leaves out of reach (its header records fix(service-package): classify a publish driver fault as 5xx and stop returning driver text as caller data (#8131) #8277's "read X where you read Y" as that residue), so the exemption rests on the four predicates verified positively, and on this record naming the detector miss, rather than on the detector's silence, which is the discipline the gate's [finding] ADR-0087's no-migration-prescription detector missed a FROM -> TO line again — an exemption the categories inherit can be held by silence, and #8299 closed the category gap, not this one #18745 section prescribes. (d) The runtime bullet names the old code (RESOURCE_CONFLICT, where it used to answer code METADATA_CONFLICT).
  • The changeset matches what the diff publishes. The 23577 note's release behaviour (one sentence, regime rows kept, the retired members, the spec describes, the clone door's 409) is true at the head; the 23406 amendment is unchanged since f0761ed3 and is judged under ③.

③ Boundary flags

  • Dev flag 1, regime-row types: answered A, as implemented. ADR-0126 §2 D1 binds the Regime C refusal to name its sanctioned path, and an accepted ADR binds until a superseding one says otherwise (Prime Directive [WIP] Add Chinese version of the documentation #13); the ruling's fact base (presentation 6182970120 fact 2, the director's delta 6184655968) is the row-less pair, and the measured caller, the console's generic create on position, is row-less. The origin-gated datasource row names the source a code-defined item is declared in, and a code-defined item is not a package-held name, so it is outside item 1's wording. Reading item 1 across the regime rows would be an ADR-0126 amendment, a maintainer act, not this PR's.
  • Dev flag 2, the ITEM_LOCKED named-base limb: answered A for this PR. The ruling binds the NOT_OVERRIDABLE refusal; readOnlyBaseOverrideError is a different code on a different condition, a caller that named a read-only base, where the package is at hand. Its source-artifact remedy is the defect class the ruling's facet ③ retired, so a follow-up card in the same family stays warranted; the seat's "noted, not filed" is a Prime Directive chore: version packages #10 acceptance note naming its evidence, held in the seat's ledger with dedupe words, and filing is the seat's act. It conditions nothing here.
  • Dev flag 3, the 23406 note: B was taken in f0761ed3, and the correction is still TRUE at this head. The amended entry keeps three claims and all three hold: the first-write-pin 409 METADATA_CONFLICT sentence is at protocol.ts:19119 and this diff does not touch it; the "What was wrong" paragraph describes the pre-fix(metadata-protocol): a first draft of a sealed package-shipped item names the edit remedy; a refused first-write pin's 409 states its assertion #23565 text; the "Unchanged" line holds. The clauses it dropped (the draft/publish remedy split) would ship false after this PR. The entry is unconsumed and in the same release, so AGENTS.md's packages/*/CHANGELOG.md row applies: amend the entry itself, never an erratum in a later one, and the 23577 note accordingly carries no "supersedes" line. So the Check Changeset red on this head is the step-12 deliberate-correction refusal (step 12, "Reject an empty-frontmatter changeset added by this PR", failure; its annotation names .changeset/23406-sealed-first-draft-remedy.md with the two-class text), a decision for a person and not a defect of the diff: PR comment 6186537521 and needs-user-decision carry it to the maintainer, skip-changeset is correctly not applied (the workflow's route 0 forbids it for this class), and the context is not one of the five required ones. This record records the red as that decision. Judged separately: step 13 (the ADR-0087 registration) passes on this head, as ② says, and steps 14 and 15 (the allow-major read and the launch-window major guard) pass.
  • PR body: one residual wording inconsistency, for the seat. The earlier record's stale note is gone (the body now says the 23406 note "is amended in place"). What remains: the What changed bullet still reads "Changeset .changeset/23577-sealed-write-one-sentence.md (patch: metadata-protocol, runtime, spec)", while the Acceptance note's "Breaking declaration" bullet and the file say minor for metadata-protocol. The file is the authority; the seat, which edits bodies through the relay, owes a one-word PATCH. Not a diff defect.
  • Dev-report deviations accepted: the body not PATCHed by the dev (the seat did); model-free commit trailers (AGENTS.md wins).
  • Check-runs on the head as read at 2026-10-15T07:45:04Z: Lint & Repo Gates success (all eight Lint lanes success); Build Core success; Build Docs success; Governed Surface Queue Guard success; Spec property liveness success; Dogfood Regression Gate success (its shards and Dogfood Verify CLI skipped on a PR run by design); Check Changeset failure, the step-12 deliberate-correction class above, with step 13 success; Type Check · debt ledger, · source gates and · consumer gates success; Type Check · workspace and the TypeScript Type Check aggregate in progress, NOT MEASURED; Test Core 1/6 to 6/6 in progress, NOT MEASURED, and the Test Core aggregate has not appeared; Console Pin Gate and Temporal Conformance skipped on a PR run by design. On f0761ed3, whose code is byte-identical to this head outside the one changeset, TypeScript Type Check and Test Core (shards 1/6 to 5/6 success; 6/6 cancelled by the next push) concluded success, so what is still running here re-measures code those runs already passed; it stays NOT MEASURED in this record, and the seat's landing terms (comment 6186492810, item 8) wait on every check regardless of it.

Implemented-by: claude/issue-23577-sealed-write-one-sentence
Reviewed-by: session_01LFqdRsuM5nkqoJdHd5ztVk

VERDICT: PASS. Every derived judgment is right; the changeset now declares the released public-input-surface narrowing in the form the repo's rule and gate require (minor, the BREAKING banner with its migration line, one CI-verified runtime-interface-only disposition, Clause-②: no); every dev flag is answered; and the 23406 correction is true, its step-12 red being the maintainer's decision under needs-user-decision and not a defect. Landing stays on the seat's terms: this record, then every check green, then ready and the queue.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Maintainer confirmation recorded · batch #349, the PR line · director seat (summon #42, session_01AKVFxqmRLqktJspVXwPE9A) · 2026-10-15T11:04Z

The maintainer answered 「确认修正 (推荐)」 to this PR's line in batch #349 (presented in this seat's session): the in-place correction of .changeset/23406-sealed-first-draft-remedy.md (comment 6186537521) is confirmed. Not taken: 「split」.

Read in this act: head 26a5eb92, draft, contract review PASS at CONTRACT_REVIEW_TIER (6187173423), seat ACCEPT (6186492810), every required check success on the head; Check Changeset red in the step-12 deliberate-correction class, which is not a required context.

Landing: this confirmation is the person the gate waits for. needs-user-decision leaves this PR in this act. The owning seat (domain:spec seat 2, seat post #18549) lands it on its own terms (6186492810 item 8): ready, then auto-merge through the queue; the step-12 red stays by design on the PR run and is outside the queue's required set. If the queue refuses on that check, the maintainer's direct merge is the fallback, with this comment as the record.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 15, 2026 12:59
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit 4feb2d0 Oct 15, 2026
51 of 55 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23577-sealed-write-one-sentence branch October 15, 2026 13:26
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/l tests tooling

Projects

None yet

2 participants