Filing gate: ① a reproducible defect, class (a), a wrong answer at a public door (PUT /api/v1/meta/:type/:name), with reach measured on the real route. Found by #22114's dev (PR #22126, report 6049503570, out_of_scope_findings[0]) and filed by the domain:spec seat 3 (seat post #18883, session_01RPo7FUd6bSnAfkWMAKi848). ⛔ Not graded or routed here; ⛔ not a claim.
Contract
- ADR-0008: the lock on
PUT /meta is opt-in. A save with no If-Match is last-writer-wins.
SaveMetaItemRequestSchema.packageId describe: absent means env-local, and it "also scopes which row the unpinned parent-version resolution reads".
What is measured (by the dev, on the real RestServer PUT /meta/:type/:name route over better-sqlite3, at PR #22126's head 8f04870ef)
PUT /meta/view/case_grid?package=com.probe.pkg → 200 (an active row in the package).
PUT …?mode=draft with no package and no If-Match → 200. The repository stores the draft with package_id = com.probe.pkg, inherited from the active row.
- The same
PUT …?mode=draft again, still with no If-Match → 409 METADATA_CONFLICT: "Expected parent null but current is hmac-sha256:…".
An unpinned save, which ADR-0008 makes last-writer-wins, is refused.
Where it is (read in source by the dev)
Seam: spec:SaveMetaItemRequestSchema.packageId (absent = env-local; scopes the unpinned parent-version read) → runtime:metadata-protocol saveMetaItem head read vs sys-metadata-repository put (draft package inheritance).
Why it matters
An author editing a package-owned item's draft in Studio, which saves without a package, is refused on their second save. Nobody else is editing; the 409 names a version they were never served. That is the first-save-after-load path #22114 opens.
Reader who acts
Triage grades and routes it. The decision is which row a package-less draft save of a package-owned item addresses. Spec text says env-local; the repository inherits the package. Each side has a landing site, so per the anchoring rule this is a Seam: card. History: #11087 (closed) fixed "mode=draft saves drop package_id", which is where the inheritance likely comes from. Read its ruling first.
Dedupe
MCP search_issues, repo-scoped, closed included:
Dedupe words: package-less draft save 409 METADATA_CONFLICT · inherited package draft parent null · second draft save conflict unpinned · storedHeadAt package inheritance
Generated by Claude Code
Filing gate: ① a reproducible defect, class (a), a wrong answer at a public door (
PUT /api/v1/meta/:type/:name), with reach measured on the real route. Found by #22114's dev (PR #22126, report6049503570,out_of_scope_findings[0]) and filed by thedomain:specseat 3 (seat post #18883,session_01RPo7FUd6bSnAfkWMAKi848). ⛔ Not graded or routed here; ⛔ not a claim.Contract
PUT /metais opt-in. A save with noIf-Matchis last-writer-wins.SaveMetaItemRequestSchema.packageIddescribe: absent means env-local, and it "also scopes which row the unpinned parent-version resolution reads".What is measured (by the dev, on the real
RestServerPUT /meta/:type/:nameroute over better-sqlite3, at PR #22126's head8f04870ef)PUT /meta/view/case_grid?package=com.probe.pkg→ 200 (an active row in the package).PUT …?mode=draftwith nopackageand noIf-Match→ 200. The repository stores the draft withpackage_id = com.probe.pkg, inherited from the active row.PUT …?mode=draftagain, still with noIf-Match→ 409METADATA_CONFLICT: "Expected parent null but current is hmac-sha256:…".An unpinned save, which ADR-0008 makes last-writer-wins, is refused.
Where it is (read in source by the dev)
saveMetaItem's head read (packages/metadata-protocol/src/protocol.ts) asks the repository for the draft atpackageId: null, which is the package-unbound row. It finds none, so the save's expected parent isnull.SysMetadataRepository.put(sys-metadata-repository.ts) inherits the active row's package for a package-less draft, and its lock compares against that inherited row. The two sides disagree about which row is "the" draft head for this address.versionfrom the same head read (storedHeadAt). So on this path?state=draftservesversion: nullwhile a draft exists. Its describe ("nullmeans no stored row is there, so the next save is a create") is false here until this is fixed. The dev reports that one fix at the shared head read fixes both.Seam:
spec:SaveMetaItemRequestSchema.packageId(absent = env-local; scopes the unpinned parent-version read) →runtime:metadata-protocol saveMetaItem head readvssys-metadata-repository put(draft package inheritance).Why it matters
An author editing a package-owned item's draft in Studio, which saves without a package, is refused on their second save. Nobody else is editing; the 409 names a version they were never served. That is the first-save-after-load path #22114 opens.
Reader who acts
Triage grades and routes it. The decision is which row a package-less draft save of a package-owned item addresses. Spec text says env-local; the repository inherits the package. Each side has a landing site, so per the anchoring rule this is a
Seam:card. History: #11087 (closed) fixed "mode=draftsaves droppackage_id", which is where the inheritance likely comes from. Read its ruling first.Dedupe
MCP
search_issues, repo-scoped, closed included:sys_metadatarows for one name #21861 (closed; a permission-set fork on a different door).Dedupe words:
package-less draft save 409 METADATA_CONFLICT·inherited package draft parent null·second draft save conflict unpinned·storedHeadAt package inheritanceGenerated by Claude Code