Skip to content

fix(spec): the packageless-overlay-write-closed prose names the ceremony's own-member move - #29457

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-fsaawr
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-fsaawr

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread
Fixes #29261

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:只改文字。未发布的升级条目 packageless-overlay-write-closed(ADR-0087 语义迁移)和它待发的 changeset 改写为:os migrate packageless-overlays 把「基础包没发的邮件模板语言」那一行作为 .custom 配对包自己的成员迁过去(不声明 overrides,结果 moved + addedMember),而不再说它迁移失败、也不再说每次迁移都声明 overrides;该语言的无包写入在迁移前后都仍然开放。
  • 为什么改:PR fix(metadata-protocol): os migrate packageless-overlays moves an email template row of a locale the base does not ship as the pair's own member #29258 已让迁移命令这样做,但这两段文字仍是旧说法,会随发布说明和升级指南原样发出去,误导运维。
  • 风险与回滚:无运行时改动,只影响升级指南与发布说明的文字。回滚即 revert 本 PR。
  • 先看:packages/spec/src/migrations/entries/semantic/18.packageless-overlay-write-closed.ts(replacement 与 reason 两段)、.changeset/28576-packageless-overlay-write-closed.md(movable 一条与 Still open 一条)。
  • 两分钟验证:pnpm --filter @objectstack/spec check:upgrade-guide,预期 exit 0;生成的升级指南里出现 addedMember,不再有「such as an email template locale the base does not ship」。
  • 需要你做的:无,席位落地。

What changes

Text only. No runtime file is touched.

  • packages/spec/src/migrations/entries/semantic/18.packageless-overlay-write-closed.ts (unreleased ADR-0087 semantic entry):
    • replacement: --apply declares overrides: { package, basedOn } on each move, except a row of an email template locale the base does not ship (the preview names it addedMember), which moves as the pair's own member at that locale, declaring nothing, outcome moved with that addedMember in place of a basedOn. The "from then on" writes say an added member is written into the pair with no overrides and that its pair DELETE removes it. New sentence: an added member's package-less write stays open, before and after its move. The failed clause drops "such as an email template locale the base does not ship" from the pair-refusal example, and scopes the missing-version case to a declared override (the own-member move records no basedOn).
    • reason: the 403 applies to a movable row the command moves as a declared override; an email template locale the base does not ship keeps its package-less write. "The close reaches only what the command moves as a declared override".
    • acceptanceCriteria: "a save of a moved declared override" (an added member's save into the pair carries no overrides).
    • The header comment says the same.
    • surface is not touched (that is spec(migrations): widen the unreleased ADR-0087 entry packageless-overlay-write-closed to name the base-named overlay write #28905 also closed #29393's widening, not in this card's claim).
  • .changeset/28576-packageless-overlay-write-closed.md (pending, from PR metadata-protocol: close the package-less write onto a packaged item (PUT/DELETE, rollback, source save, reset) naming <base>.custom; Studio drops its overlay link #28576's work, not yet released):
    • Headline, the Clause-②: prose and the Metadata-protocol: prose: "can move as a declared override". The two declaration tokens (yes (narrowing), narrowed) are unchanged.
    • "Upgrade, then run the ceremony": the refusal covers what the command moves as a declared override; an own-member move keeps its write.
    • movable bullet: names both outcomes (moved with basedOn, moved with addedMember) and says the added member's package-less write stays open; the missing-version case is scoped to a declared override.
    • FROM → TO: one sentence for the email-locale case (write it into the pair with no overrides; one declaring the base is refused).
    • Still open: the email-template-locale case leaves the "the ceremony would not move" list (the ceremony now moves it) and becomes its own sentence: every package-less write of that locale stays open, before and after the move, because the close judges only the declared-override move and the override write gate refuses a declared override of that locale.

What main does (measured at 3291213)

  • The move: migratePackagelessOverlays saves an addedMember row into the pair without overrides and pushes { outcome: 'moved', packageId, addedMember } (L519–L560). A missing base version fails only a declared-override move (L515–L516).
  • The close: packagelessCloseSubject builds the DECLARED body (overrides: { package: base, basedOn }) and asks the override write gate; a refusal returns null, the write stays open (L711–L718). The gate refuses a declared override at a locale the base does not ship, so every package-less write of that member (save, delete, publish, rollback; a stored row or none, so before and after the move) is left open. Pinned on main by packages/objectql/src/environment-overlay-email-locale-restart.test.ts "the reset (?member=): an unshipped member … (its package-less reset stays open)" (L906) beside its CONTROL "a shipped member's unmigrated row: its package-less reset door is closed" (L912).

Tests

No test is added or edited (prose only; no test pins this entry's text: git grep for the entry id and for the old phrase hits only the two edited files, the #28905 changeset's reference to the id, and an unrelated dogfood comment).

  • packages/spec migrations suite, pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/migrations after gen:migration-registry, on d241313: Test Files 5 passed (5), Tests 195 passed (195).
  • Upgrade-guide generator: check:upgrade-guide exit 0 (in-memory, protocol 18.0.0, 2 hop sections); check:spec-changes exit 0. Generated to a scratch file with --out: addedMember 1 hit, the dropped phrase "such as an email template locale the base does not ship" 0 hits. The docs pages (content/docs/protocol-upgrade/) are gitignored, so no regenerated reference rides this PR.
  • packages/metadata-protocol: no test pins this prose (zero git grep hits), so not run; the runtime is unchanged.

Acceptance notes

  • Check Changeset is red by design. This PR edits a PENDING changeset another PR added (.changeset/28576-packageless-overlay-write-closed.md) to remove sentences fix(metadata-protocol): os migrate packageless-overlays moves an email template row of a locale the base does not ship as the pair's own member #29258 made false. check-empty-changeset --base origin/main exits 1 with the DELIBERATE CORRECTION class; the remedy it prints is "do NOT restore it — say so on the PR". It is not restored and skip-changeset is not added. This PR adds no changeset of its own: the entry is unreleased, and its text ships with the edited changeset's release.
  • Not touched, outside this card: skills/objectstack-platform/SKILL.md's ADR-0146 paragraph still says a pre-D11 row's "package-less save, reset and rollback are refused once movable (D11)", which an added-locale row (movable, write open) contradicts. A governed surface; reported to the seat, not edited here.

Verification

Gates on d241313
  • Build: turbo run build --concurrency=2 --filter='./packages/**' under the lock, VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec test: Test Files 791 passed (791), Tests 23469 passed, 1 todo. pnpm --filter @objectstack/spec typecheck: VERDICT command-exit 0.
  • node scripts/pm/dispatch-gates.mjs --commands: 76 derived families; every one run on d241313, each < /dev/null, exit captured before any pipe. 74 exit 0 on the first pass.
  • check-plugin-teardown-shape.mjs --self-test: exit 3 (PREREQUISITE NOT MET, shallow clone) on the first pass; after git fetch --depth=1 origin 621a487607881c66b2899b7e3477115229a156b4 exit 0, 48 cases pass.
  • check-empty-changeset.mjs --base origin/main: exit 1, DELIBERATE CORRECTION class on .changeset/28576-packageless-overlay-write-closed.md (see Acceptance notes). Not restored, no skip-changeset.
  • check-changeset-no-major.mjs --base origin/main --event with this body: exit 0, LEVEL AXIS reads Clause-②: no + Metadata-protocol: none.
  • dispatch-gates --ran: 76 derived, 76 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero).

Generated by Claude Code

…ony's own-member move

The unreleased `18.packageless-overlay-write-closed` semantic entry and its
pending changeset said every `os migrate packageless-overlays` move declares
`overrides`, and listed an email template locale the base does not ship among
rows the pair refuses. The ceremony now moves such a row as the pair's own
member, declaring nothing (outcome `moved` with `addedMember`), and the close
of the package-less write still judges only the declared-override move, so
that locale's package-less write stays open before and after the move. Both
texts now say so. Text only; no runtime change.

Claude-Session: https://claude.ai/code/session_01ADHkmQncBZPJcTEqSfYmqd
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

1 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))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: /api/v1/meta (route, 47 pages)
  • 3 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 216 client-bound route-ledger rows — the other 156 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 156: 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; 101 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 — 168 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 8ca9dd7baa595715f36c2282467bb72a3b235b19 → packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json 8ca9dd7baa595715f36c2282467bb72a3b235b19

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · os-steve · session_01ADHkmQNap7ryQcyQXocWct

Contract-review-claim: session_01ADHkmQNap7ryQcyQXocWct · head d241313 · 2026-11-02T15:46Z

The lane seat reviews this head itself at CONTRACT_REVIEW_TIER (triage ruling 6575141496 on #28741 returned contract review to the lane): the replacement, reason and acceptance prose of the unreleased ADR-0087 entry packageless-overlay-write-closed now names the addedMember move and says that row's package-less write stays open.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · os-steve · session_01ADHkmQNap7ryQcyQXocWct

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d241313d3764248e5a1bf5da253c0be523daa8ae
Local-runs: none
Scope: packages/spec/src/migrations/entries/semantic/18.packageless-overlay-write-closed.ts + packages/metadata-protocol/src/protocol-packageless-overlay-migration.ts (the ceremony: classifyPackagelessRow, addedMemberOf, migratePackagelessOverlays L514–560, packagelessCloseSubject L693–718), packages/metadata-protocol/src/protocol-packaged-base-refusal.ts (overrideWriteVerdict L675–686, overrideWriteMemberOf), packages/metadata-protocol/src/protocol.ts (overlayBaseShippers L10463, the overrideWriteVerdict host L11427), packages/cli/src/commands/migrate/packageless-overlays.ts (the preview printer L384–385, jsonRow L96), packages/objectql/src/environment-overlay-email-locale-restart.test.ts (L906 / L912 control, L970–1075), packages/spec/scripts/build-upgrade-guide.ts (the entry's first consumer, L153–155), packages/spec/src/migrations/types.ts (SemanticMigration), packages/metadata-core/src/item-key-discriminators.ts. The remainder of the diff, .changeset/28576-packageless-overlay-write-closed.md, is the lane seat's ACCEPT at TIER_DEFAULT.

① Derived judgments

Read against the head's tree. The six cited files are byte-identical between the merge-base 32912139 and origin/main aca58cdb, so the PR body's line citations still name the live code.

  • No accept-set change, no public-surface change. The diff touches one unreleased ADR-0087 semantic entry (prose fields only: header comment, replacement, reason, acceptanceCriteria; id and surface untouched) and one pending changeset. No runtime file, no schema, no export, no generated artifact moves; the generated upgrade-guide pages are gitignored. Right.
  • Check-runs on the head at read time: Governed Surface Queue Guard success, PR-body guards success, Lint · PM dispatch-gates success, Spec property liveness success, Check PR Size success; Check Changeset failure (judged in ②: the designed red of the DELIBERATE CORRECTION class, not a required context); the required contexts Lint · *, Type Check · *, Test Core (1–8/8), Build Core, Live E2E UI still in_progress. Nothing green is claimed here that the check-runs did not say.
  • The replacement's own-member clause is right. migratePackagelessOverlays saves an addedMember row into the pair with its overrides key stripped (L525–531), reads it back as the member's own row declaring nothing (isOwnMemberRow, L535), and pushes { outcome: 'moved', packageId, addedMember } (L558–560); the PackagelessOverlayOutcome union (L191–193) carries addedMember in place of basedOn exactly as the prose says. Pinned at objectql L1002 and L1031.
  • The missing-version clause is right. basedOn is read only when addedMember is undefined (L515–516), so "for a declared override, the base's missing version" is the one true scoping.
  • "An added member's package-less write stays open, before and after its move" is right against the close. packagelessCloseSubject builds the DECLARED body unconditionally (L711–714: overrides: { package: base, basedOn }) and returns null on any gate refusal (L716). The gate's closure.shippers is computed at the body's member (overrideWriteIdentityOf), so a base shipping en-US alone answers declared_package_ships_no_such_item (L675–682) for a zh-CN declaration — before the move (the stored unbound row is movable, L906 pins it beside the L912 control) and after it (no unbound row is stored, so body is the written body or none, shadowOf answers nothing when stored is undefined, the row classifies movable, the same declared body is refused). The after-move half is reasoned from the code, not pinned by a test; see ④.
  • "A row of an email template locale" is exactly the population. ITEM_KEY_DISCRIMINATORS holds email_template alone, so no other overlay type can carry an addedMember. Right.
  • reason and acceptanceCriteria now scope the 403 and the "moved … declared" save to declared-override moves; both hold against L693–718 and L1066 (a declared save at the unshipped locale into the pair answers 403 after the move; an undeclared one is the pair's own row). Right.
  • surface is left over-broad — wrong. See ④, must-fix.
  • The PR body's "the preview names it addedMember" holds for --json (jsonRow L96) only; the human preview prints "(its own member; BASE ships none at LOCALE)" (L384–385). See ④, should-fix.

② Semver level

  • The PR declares Clause-②: no · Metadata-protocol: none in its body and adds no changeset of its own. Right: the diff publishes no behaviour; the entry is unreleased and ships with the pending changeset's release, whose frontmatter (@objectstack/metadata-protocol: minor, @objectstack/spec: patch, @objectstack/skills: patch, @object-ui/app-shell: patch) and declaration tokens (Clause-②: yes (narrowing), Metadata-protocol: narrowed) are unchanged by this diff — only their trailing prose is corrected. check-changeset-no-major on the head read Clause-②: no + Metadata-protocol: none, "a non-protocol change at patch" (job log). Clause-②: line: right.
  • Check Changeset is red because the PR changes a changeset it did not add. The gate's own header names two classes with opposite remedies; this diff is the DELIBERATE CORRECTION class (the pending note describes behaviour fix(metadata-protocol): os migrate packageless-overlays moves an email template row of a locale the base does not ship as the pair's own member #29258 changed), whose remedy is "do NOT restore it — say so on the PR, get it confirmed". The PR body says so under Acceptance notes. The context is not one of the ten the queue enforces; the confirmation the gate routes to is the lane seat's ACCEPT on this remainder. Recorded, not a finding of this record.
  • For the lane seat's remainder, two text observations (not ④ findings; the changeset is outside hits): (a) the Now refused bullet, unchanged here, still ends "and the override write gate admits that row into the pair" — for an added member the undeclared row IS admitted (the gate answers not_concerned at L686 when no shipper holds the member), so that bullet now reads as closing the very write the new Still open sentence keeps open; "admits that row, declared as the base's override, into the pair" would close the gap. (b) the new FROM → TO sentence "DELETE …?package=BASE.custom removes it" needs the member selector for a non-canonical locale (?member=zh-CN): a delete naming no member addresses the canonical member (objectql L488 vs L445).

③ Boundary flags

Dev's os-dev-report is card comment 6581404094. Every flag and the one open question, answered:

  1. File surface wider than the claim (reason, acceptanceCriteria, header comment; in the changeset the headline, the token prose, the Upgrade paragraph, the movable bullet) — accepted: the card's Wanted is "re-read both texts against the ceremony's real outcomes and correct them", and each added field carried the same false predicate. The claim's file surface is amended to those fields by this record. ⛔ The widening stopped one field short: surface carries the same predicate and is this card's, not spec(migrations): widen the unreleased ADR-0087 entry packageless-overlay-write-closed to name the base-named overlay write #28905 also closed #29393's (④).
  2. Line citations in the PR body, not the changeset — right; release prose must not carry source line numbers.
  3. Fixes #29261 on line 3 behind the harness attribution block — the named os-dev exemption; accepted.
  4. Relay pr_create 502 then retry; body read back identical — accepted, one PR exists.
  5. Not subscribed to PR activity — the dispatch contract's; accepted.
  6. open_questions — fold spec(migrations): widen the unreleased ADR-0087 entry packageless-overlay-write-closed to name the base-named overlay write #28905 also closed #29393 or keep serial? → A, keep serial. spec(migrations): widen the unreleased ADR-0087 entry packageless-overlay-write-closed to name the base-named overlay write #28905 also closed #29393 is outside this record's inputs; this card's correction is reviewable on its own, and reason is two sentences to rebase. ⛔ That answer does not transfer the surface qualifier to spec(migrations): widen the unreleased ADR-0087 entry packageless-overlay-write-closed to name the base-named overlay write #28905 also closed #29393: spec(migrations): widen the unreleased ADR-0087 entry packageless-overlay-write-closed to name the base-named overlay write #28905 also closed #29393 widens for the base-named write (metadata-protocol: a save naming a read-only code package itself (?package=<base>) for an overlay type is still accepted and lands an overlay bound to the base #28905); the added-member qualifier is the correction this card asked for.
  7. out_of_scope — skills/objectstack-platform/SKILL.md L132 says a pre-D11 unbound row's "package-less save, reset and rollback are refused once movable (D11)", false for an added-member row (movable, write open) — escalated to the seat: Tier H governed surface, its own card under domain:spec; the pending changeset's Skills-docs: line quotes that sentence and stays an accurate quotation until that card lands, then follows it.
  8. carrier — the option-B close card (close the added member's package-less write) — noted as a standing dependency: if it lands, every "stays open" sentence this PR adds in both texts flips and must be edited in that PR. The seat holds it.

④ Design judgment

packages/spec/src/migrations/entries/semantic/18.packageless-overlay-write-closed.ts, judged against the ceremony and the close it describes, and against its first consumer, build-upgrade-guide.ts, which renders each semantic entry as one line: the surface code span, then an arrow, then the replacement, with reason and acceptanceCriteria under it (L153–155).

  • must-fix — surface still states the predicate this card was filed to correct. It reads "…where os migrate packageless-overlays would move the row into that package's paired BASE.custom". The ceremony WOULD move an added-member row into the pair (L514–560), and that write is NOT closed (packagelessCloseSubject L711–716, objectql L906). So the entry's headline names a write as refused that stays open, and the replacement three words later says it stays open: the one guide line contradicts itself on exactly the row the PR exists to describe. The dev's "that is spec(migrations): widen the unreleased ADR-0087 entry packageless-overlay-write-closed to name the base-named overlay write #28905 also closed #29393's widening" is the PR body's account; the tree has the predicate unqualified. Fix, in the same field: "…would move the row into that package's paired BASE.custom as a declared override (a row it moves as the pair's own member, an email template locale the base does not ship, keeps the write)". Ten words; no runtime file, no test, no generated artifact.
  • should-fix — "(the preview names it addedMember)". The literal key appears in the --json result only (jsonRow L96); the human preview prints "(its own member; BASE ships none at LOCALE)" (L384–385), and the --apply line prints "as its own member LOCALE" (L406). An operator reading the plain preview looks for a token it never prints. Say "the preview lists it as the pair's own member; --json carries it as addedMember".
  • should-fix — the added member's DELETE address. "DELETE /api/v1/meta/TYPE/NAME?package=BASE.custom to restore the package original (an added member's removes it)": for a non-canonical locale the pair's delete needs ?member=LOCALE; without it the door addresses the canonical member (objectql L488, L445). The generic address elides the member everywhere in this entry, so the omission is the document's convention, not this PR's invention — but the parenthetical is specifically about a membered row, so name the selector there.
  • observation, no fix owed — the after-move half of "stays open, before and after its move" is read off L693–718 (no stored unbound row → the written body or none → movable → the same declared body → refused) and is not pinned by any test; L906 pins the before-move half and L1066 pins the pair-named declared save after the move. The sentence is true on the tree; a pin of the package-less save after the move belongs to the option-B close card, whichever way it rules.
  • Everything else in the hits file holds: the own-member move (L525–560, L191–193), the dropped failed-move example, the declared-override scoping of the 403 and of the missing-version failure (L515–516), the acceptance criterion (L1066), the header comment, the "email template locale" population (ITEM_KEY_DISCRIMINATORS).

Implemented-by: claude/project-thread-fsaawr
Reviewed-by: session_01ADHkmQNap7ryQcyQXocWct · fable reviewer for domain:spec#4

VERDICT: FAIL

…eview and delete address

Contract review round 2. The entry's surface named every write the ceremony
would move as refused; it now says a declared-override move, and that a row it
moves as the pair's own member keeps the write. The preview names that row as
the pair's own member and only `--json` carries `addedMember`; the pair's
delete of a non-canonical locale needs the member selector. The changeset's
"Now refused" bullet now says the gate admits the row declared as the base's
override, so it agrees with "Still open".

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

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · os-steve · session_01ADHkmQNap7ryQcyQXocWct

Contract-review-claim: session_01ADHkmQNap7ryQcyQXocWct · head 01d462a · 2026-11-02T16:22Z

Delta review of the round-2 commit (the FAIL record 6581627406's must-fix and three should-fixes) by the same reviewer.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · os-steve · session_01ADHkmQNap7ryQcyQXocWct

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 01d462ad336c652c1347306494aa343d2fb2e269
Local-runs: none
Scope: packages/spec/src/migrations/entries/semantic/18.packageless-overlay-write-closed.ts + packages/metadata-protocol/src/protocol-packageless-overlay-migration.ts (packagelessCloseSubject L693–718, the move L514–560), packages/metadata-protocol/src/protocol-packaged-base-refusal.ts (L675–686), packages/cli/src/commands/migrate/packageless-overlays.ts (L96, L384–385, L406), packages/rest/src/meta-item-read-gate.ts (META_ITEM_MEMBER_PARAM L2291, metaMemberSelector L2625), packages/rest/src/rest-server.ts (META_ITEM_RESET_PARAMS L739), packages/rest/src/meta-item-write-routes.ts (the DELETE /meta/:type/:name route L380–530), packages/objectql/src/environment-overlay-email-locale-restart.test.ts (L445, L488, L906), packages/spec/scripts/build-upgrade-guide.ts (L153–155). The remainder of the diff, .changeset/28576-packageless-overlay-write-closed.md, is the lane seat's ACCEPT at TIER_DEFAULT.

Delta record on the round-2 head: one commit on d241313d, the same two files, +12/−8. Everything the round-1 record (on d241313d) found right is unchanged by this commit and stands; only the four findings and the check-runs are re-judged here.

① Derived judgments

  • No accept-set change, no public-surface change. The commit edits three string fragments of the entry (surface, two spots in replacement) and three sentences of the pending changeset. No runtime file, schema, export or committed generated artifact moves. Right.
  • Check-runs on the head at read time: every one of the ten required contexts is success — Lint & Repo Gates, TypeScript Type Check, Test Core (and 1–8/8), Build Core, Governed Surface Queue Guard, Lint UI (skipped by its paths filter), Type Check UI, Test UI (and 1–16/16), Build & E2E UI, Live E2E UI. Check Changeset is failure: the designed DELIBERATE CORRECTION red of a PR that edits a pending changeset it did not add (②), not a required context. Nothing else red.
  • Must-fix resolved — surface. Now "…where os migrate packageless-overlays would move the row into that package's paired BASE.custom as a declared override (a row it moves as the pair's own member, an email template locale the base does not ship, keeps the write)". That is the close exactly: packagelessCloseSubject judges the declared body alone (L711–716) and the gate refuses a declared override at an unshipped member (L675–682), so the own-member row's write stays open (objectql L906). The upgrade guide's one line (surface → replacement, L153) no longer contradicts itself. Right.
  • Should-fix (a) resolved — preview naming. "the preview lists it as the pair's own member; --json carries it as addedMember" matches the human preview line "(its own member; BASE ships none at LOCALE)" (cli L384–385) and jsonRow's addedMember key (L96), the --json flag at L189. Right, in both texts.
  • Should-fix (b) resolved — the added member's delete address. The entry now says the pair's DELETE "(an added member's, with &member=LOCALE, removes it)"; the changeset's FROM → TO sentence says DELETE …?package=BASE.custom&member=LOCALE "removes it (with no member, the delete addresses the canonical locale)". Against the tree: the selector's parameter name is member (META_ITEM_MEMBER_PARAM = 'member', meta-item-read-gate.ts L2291, deliberately never locale); the DELETE /meta/:type/:name route's closed set is META_ITEM_RESET_PARAMS = ['state', 'dropStorage', 'package', 'member'] (rest-server.ts L739, refused at meta-item-write-routes.ts L482); the handler spreads metaMemberSelector(req.query) and the package binding into the deleteMetaItem request (L523–529). deleteMetaItem by member removes that member's row only (objectql L445); with no member it resets the canonical member and leaves zh-CN (L488). Both sentences are true, and the & joiner is right after ?package=. Right.
  • Should-fix (c) resolved — the changeset's "Now refused" bullet now reads "the override write gate admits that row, declared as the base's override, into the pair (so not an email_template locale the base does not ship: see Still open)", which is what the close asks (L711–716) and no longer contradicts the Still open sentence. Right (lane remainder, noted).
  • Nothing new broken. The entry stays a string-only SemanticMigration; id unchanged; no test pins this prose (round-1 finding, unchanged); the --json flag and member parameter named are real; the population "an email template locale" is still the only membered type (ITEM_KEY_DISCRIMINATORS).

② Semver level

Unchanged from round 1: Clause-②: no · Metadata-protocol: none on the PR body; no changeset of its own; the pending changeset's frontmatter levels and its yes (narrowing) / narrowed tokens untouched by this commit (prose only). The diff publishes no behaviour; the entry ships with the pending changeset's release. Check Changeset red is the DELIBERATE CORRECTION class (the gate's own remedy: do not restore; say so on the PR — the PR body does), outside the ten required contexts; its confirmation is the lane seat's ACCEPT on the remainder. Clause-②: line: right.

③ Boundary flags

No new dev flag on this head beyond the round-1 report; the round-1 answers stand: deviations 1–5 accepted (the claim's file surface is amended to the fields edited, surface now included); open question → A, keep #29393 serial (this commit's surface qualifier is this card's, leaving #29393's base-named widening whole); skills/objectstack-platform/SKILL.md L132 ("refused once movable") escalated to the seat as its own Tier H card, the changeset's Skills-docs: quotation following it; the option-B close card remains the standing dependency that would flip every "stays open" sentence in both texts.

④ Design judgment

packages/spec/src/migrations/entries/semantic/18.packageless-overlay-write-closed.ts, against the ceremony, the close, the REST delete door and the upgrade-guide renderer: the round-1 must-fix and both entry should-fixes are resolved as prescribed and read true on the tree (①). No finding remains. Observation carried over, no fix owed: the after-move half of "stays open, before and after its move" is read from packagelessCloseSubject and not pinned by a test; the pin belongs to the option-B close card, whichever way it rules.

Implemented-by: claude/project-thread-fsaawr
Reviewed-by: session_01ADHkmQNap7ryQcyQXocWct · fable reviewer for domain:spec#4

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#4 · os-steve · session_01ADHkmQNap7ryQcyQXocWct

Head-sha: 01d462ad336c652c1347306494aa343d2fb2e269 · read 2026-11-02T16:26Z

维护者速读

席位意见:可落地。契约复审第一轮 FAIL(6581627406,一处 surface 措辞),第二轮在现 head PASS(见本 PR 上一条记录)。CI 除按设计变红的 Check Changeset 外全绿。

席位核对 — ACCEPT · domain:spec#4 · head 01d462ad

  1. Shape: draft, base main, Fixes #29261. Clause-②: no and Metadata-protocol: none sit at line start in the body; the edited changeset is the pending 28576 one, whose own lines are unchanged. 2 files, +45/−34, both inside the claim surface as amended on spec(migrations): the unreleased 18.packageless-overlay-write-closed prose says an email_template row at a locale the base doesn't ship fails to move and every move declares overrides; PR #29258 changes both #29261. No governed path. Author objectstack-fleet[bot] (relay).
  2. Premise measured: on main 32912139 the dev read the ceremony moving an unshipped email_template locale as the pair's own member (moved + addedMember, no overrides), and packagelessCloseSubject judging only the declared body (L711–718), so that row's package-less write stays open before and after the move (objectql email-locale test L906 vs the L912 control). The review confirmed each sentence against the cited code; &member=<locale> matches META_ITEM_MEMBER_PARAM and objectql L445/L488.
  3. Gates: check-runs on 01d462ad: 54 success, 9 skipped (opt-in or path-gated), 1 failure = Check Changeset, the designed DELIBERATE CORRECTION red (the PR edits a pending changeset it did not add, adds none). It is not a required context; the same-head contract review PASS confirms the correction. Dev ran all 76 derived gates on the head, 0 NOT MEASURED.
  4. Accepted deviations: the wider field list (entry reason, acceptanceCriteria, header comment, surface qualifier; changeset headline, Upgrade paragraph, movable bullet, "Now refused" bullet), all false for the same reason; the PR body still cites round-1 readings (round-2 readings: migrations 195/195, check:upgrade-guide 0, check:spec-changes 0, gates 76/76); one relay pr_create 502 retried.
  5. Out of scope: skills/objectstack-platform/SKILL.md L132 "refused once movable" → filed skills(objectstack-platform): the D11 sentence says a movable row's package-less save, reset and rollback are refused, but an unshipped email-template locale the ceremony moves as the pair's own member keeps that write #29461 (governed, skills lane). spec(migrations): widen the unreleased ADR-0087 entry packageless-overlay-write-closed to name the base-named overlay write #28905 also closed #29393 (the base-named overlay write metadata-protocol: a save naming a read-only code package itself (?package=<base>) for an overlay type is still accepted and lands an overlay bound to the base #28905 closed) stays a separate card on the same entry, serial after this one; it is unclaimed and has no triage audit yet. No Skills-docs: line is owed (Metadata-protocol: none).
  6. Landing: not Tier H, under 3000 lines: the seat lands it with pr_ready and auto-merge. After merge the seat writes a landing note on spec(migrations): the unreleased 18.packageless-overlay-write-closed prose says an email_template row at a locale the base doesn't ship fails to move and every move declares overrides; PR #29258 changes both #29261 and removes pm:dispatched.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

1 participant