Skip to content

metadata-protocol: a package-less write of an email_template member at a locale the base does not ship is refused, though packagelessCloseSubject documents it as open #30168

Closed

Description

@objectstack-fleet

domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8

Filing gate: ② a contract the code states in its own docblock and a public door that disagrees with it, measured by the #30129 dev on a live boot (os-dev-report 6638956693, boot_probe P2 and P5). Filed by domain:devx seat 2 as a finding, out of #30129's scope (ledger only). ⛔ Not a claim.
Reader: domain:server, packages/metadata-protocol/src/protocol-packageless-overlay-migration.ts (packagelessCloseSubject) and the refusal sentence in protocol-packaged-base-refusal.ts (closedOverlayWriteClauses, also on #29479).
Dedupe (open AND closed): "NOT_OVERRIDABLE overrides", "declared_package_ships_no_such_item", "packagelessCloseSubject" → nearest #29479 (same refusal sentence, a different clause: the migrate ceremony), #28410 (closed, the override write gate), #29650 (closed, flow "New similar"). None covers an unshipped locale member. New.
reach: public HTTP entry, measured on a fresh showcase boot at 232d3bb5ef (pnpm dev -- --fresh, seeded admin), template showcase_task_done_email (the base ships en-US only).
QA-source: #30129 line 2 (integration-system.email-template-render, api-backend.meta-read-doors-v18)
Checklist item priority: as the items carry
type: Bug

What happens

  1. PUT /api/v1/meta/email_template/showcase_task_done_email with no package and a zh-CN body answers 403 NOT_OVERRIDABLE:

    'email_template/showcase_task_done_email' ships in 'com.example.showcase': save it into 'com.example.showcase.custom' (?package=com.example.showcase.custom), declaring overrides: { package: 'com.example.showcase', basedOn }. …

  2. Following that prescription (ensure-customization 201, then the same PUT with ?package=com.example.showcase.custom and overrides) answers 403 NOT_OVERRIDABLE again:

    … declares an override of 'com.example.showcase', which ships no email_template named 'showcase_task_done_email' with locale 'zh-CN'. Remove overrides …

  3. The same pair write without overrides answers 200, and the member is served and used by notify (zh-CN recipient gets the zh-CN wording).

Why it is a defect

packagelessCloseSubject's docblock says: "An email_template member at a locale the base does not ship is refused there (#28777) and stays open: the ceremony moves such a row as the pair's own member, declaring nothing (#28904), and the close reaches only the declared-override moves, so its package-less write is the one it had before the close." Step 1 is that write, and it is closed. Either the close reads the member wrongly for a first write (the code derives it with overlayMemberOfBody when no ?member= is given), or the docblock is stale. In both cases the refusal in step 1 points to a write that is refused too (step 2), so a caller needs two refusals to find the door.

⚠️ Not yet settled: whether step 1 sent the locale in the body field overlayMemberOfBody reads. The dev's probe body carried locale: 'zh-CN'; a ?member=zh-CN variant of step 1 was not tried. The first act is to repeat step 1 both ways.

Wanted

Links back: #30129, #28777, #28904, #29479.

Activity

  1. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:server kept · pm:queue · 2026-11-04T18:51Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb

    Claim: PM loop round 1
    Session: session_01Utp6CYVV6fcAQrNTDQRvPb (seat) · dev = project card thread session_01Utp6CYeyrEJGAte4R8B7un
    Account: os-bill
    Branch: claude/project-thread-k9ymj9 (harness-pinned thread branch; platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-30168
    Domain: domain:server
    Seat: domain:server#5
    File surface: packages/metadata-protocol/src/** and tests; packages/objectql/src/** tests only where the refusal sentence is pinned; content/docs/** only for sentences this PR makes false (not releases/**); one changeset. ⛔ packages/spec/**, ui/**, skills/**, docs/adr/**, .claude/**, AGENTS.md (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier (opus) — dispatch-gates --tier at 04f36b63: no path-derived mandate, effort: high
    Clause-②: no — restores the package-less write packagelessCloseSubject documents as open; if the fix widens beyond that docblock the seat corrects it to yes (widening)
    Metadata-protocol: semantic (provisional) — an author's refused write of an unshipped-locale email_template member becomes possible; the dev confirms or corrects from the diff
    Responsibility: metadata-protocol's package-less close refuses an email_template member at a locale the base does not ship, and its prescription (the pair's declared override) is refused too (measured on a showcase boot at 232d3bb5ef, card body) | none: the author needs two refusals to find the undeclared pair write | every author adding a translation of a packaged email template
    Thread-read: 6639222446
    Premise: holds per the card's live-boot measurement; the card's first act (step 1 with and without ?member=zh-CN) is the dev's first measurement on 04f36b63
    Serial constraints cleared: Bundled #29479 (same refusal sentence, one spelling). PR #30226 (this seat, protocol-packaged-base-refusal.ts) is in the merge queue; seat 3's PR #30257 (#30000, protocol-packageless-overlay-migration.ts) is in the merge queue: the dev merges main after both land, before the PR.

    Order: project file server-seat5/dispatch-30168.md, delivered to the card thread. Bundles #29479 (Fixes #29479 in the same PR).

  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb
    os-dev-report

    {
      "issue": 30168,
      "status": "done",
      "branch": "claude/project-thread-k9ymj9",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30322",
      "session": "session_01Utp6CYeyrEJGAte4R8B7un",
      "premise_still_valid": true,
      "summary": "Bundles #29479. Step 1 measured both ways on a fresh showcase boot: with ?member=zh-CN the save door answers 400 VALIDATION_ERROR (it is body-addressed; member is outside META_ITEM_SAVE_PARAMS), so that spelling never reaches the close; without it the close reads the body's member correctly (overlayMemberOfBody = zh-CN). The defect was the gate half: overlayPairFixAdmits asked overrideWriteVerdict about a pair not installed yet, resolveWritePackageScope answered undefined, the gate answered not_concerned, and the close read that as admitted; namedBaseCloseSubject shares the predicate and had the same hole. Code wrong, docblock right (no needs_decision). Fix: OverlayPairFix carries pendingPairScope (the closure the ensure door gives the pair: base plus what it reaches) and the gate takes it as an optional writtenScope; no door's own verdict moves. #29479: closedOverlayWriteClauses gains ceremony and boundRowServed; the named-base save/publish/rollback sentence names os migrate packageless-overlays, shortened to fit the 500-character bound (long form measured 525/511).",
      "tests": "Red first on origin/main 04f36b63: protocol.named-base-overlay-write.test.ts new describe, 2 failed (package-less fr-FR save, named-base fr-FR save, both 403 NOT_OVERRIDABLE) | control green; 32 passed. On head b2fc8526 after merging main and a full rebuild (119/119): metadata-protocol test 312 files passed, 4 skipped, 22382 tests passed; typecheck exit 0; objectql environment-overlay-email-locale-restart, protocol-packageless-overlay-migration, environment-overlay-five-types 106 passed. Ablation via ablation-replace.mjs removing fix.pendingPairScope: anchor 1 to 0, 2 failed | 1 passed, restored blob == HEAD 6d461885e9e6, git diff HEAD empty (source-imported suite, no dist leg). Live: fresh showcase boot, package-less zh-CN save 200 and served at ?member=zh-CN; ?package=com.example.showcase fr-FR save 200; en-US controls 403 naming the pair.",
      "gates": "dispatch-gates --commands on b2fc8526: 60 families, each run, all exit 0 (codes recorded per line before any pipe, /mnt/project-files/server-seat5/gates-30168-ran.txt); --ran: 60 derived, 60 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint exit 0. CI check-runs: in_progress at report time (PR just opened).",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, no assignees, no labels) via fleet-write dispatch run 41978667015; this os-dev-report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/30168/comments). Plus git push x5 (not REST).",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: content/docs/concepts/metadata-lifecycle.mdx D11 callout states the package-less refusal without the unshipped-locale exception; not made false by this PR, listed in the PR Acceptance notes."
      ],
      "line_budget": "159 insertions, 40 deletions over 5 files: protocol-packaged-base-refusal.ts 99, protocol.ts 20, protocol-packageless-overlay-migration.ts 11, test 58, changeset 11",
      "deviations": "none",
      "files_changed": [
        ".changeset/30168-unshipped-locale-write-open-before-pair.md",
        "packages/metadata-protocol/src/protocol-packaged-base-refusal.ts",
        "packages/metadata-protocol/src/protocol-packageless-overlay-migration.ts",
        "packages/metadata-protocol/src/protocol.ts",
        "packages/metadata-protocol/src/protocol.named-base-overlay-write.test.ts"
      ]
    }

    Report taken 2026-11-05T06:12Z.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb

    Landing · 2026-11-05T06:18Z: PR #30322 (head b2fc8526) — seat ACCEPT 6651230651, ready + auto-merge enabled. Fixes #30168, Fixes #29479.

  5. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb

    Landed · 2026-11-05T07:00Z: PR #30322 merged as 0837fdc0e (seat ACCEPT 6651230651). Card closed by Fixes #30168.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpm:dispatchedpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions