You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
publishPackageDrafts judges a package's drafts without its own extension drafts, so a formula or hop into a field a sibling extension draft adds is refused and the whole batch rolls back #33152
Filing gate: ③ a follow-up a contract review surfaced (S3 of the delta record 6864935727 on PR #33119, #33072). It holds the same on main for object drafts, so it is not #33119's to fix.
Business reason: a Studio author who publishes a package whose drafts depend on each other gets a false INVALID_METADATA refusal, and the all-or-nothing batch rolls back everything. os build accepts the same package, so the author has no fix except publishing items one by one in the right order. #10377 fixed this class for same-batch dataset drafts; extension drafts still miss it.
Reader who acts: the owner of packages/metadata-protocolprotocol-publish-batch.ts (the batch's pending set).
Measured (reviewer probe, real doors, PR #33119 heads 8c1950cb and ac6dd79d)
Drafts { extend: 'crm_region', fields: { tier__c } } and { extend: 'crm_account', fields: { score__c: formula 'record.region.tier__c' } }, then publishPackageDrafts → INVALID_METADATA, unknown field tier__c on crm_region; both roll back. The build reports 0 findings. Publishing the region extension first through the per-item door, then the other, is accepted.
On main: an object draft whose formula hops into a field a sibling extension draft adds is refused the same way.
Related, same class, per-item door: an object's own formula cannot read a field its package's published extension adds (unknown field at the object door; the build accepts), and the object save's destructive-change guard reads such a field as removed unless forced.
Expected
The batch's validation universe carries the batch's extension drafts the way it carries object and dataset drafts (#10377), so a package os build accepts publishes in one batch. The object door's universe folds the package's own published extensions of the object it judges.
Dedupe
repo:objectstack-ai/objectstack is:issue is:open publishPackageDrafts checked at filing (#33005 is a seed-load timing issue, not this). Related: #10377 (closed, datasets), #33072, #32875.
Row: a Studio author publishing a package whose drafts depend on each other gets a false INVALID_METADATA, and the whole batch rolls back, while os build accepts the same package. That is a false refusal on a core authoring act (p2). Publishing item by item in the right order is not a named workaround (rule 6), so there is no discount.
Claim: area-lease pilot #33059, area A5 thread · 2026-11-14T15:02Z · p2, dispatched to an os-dev subagent of this thread (parallel run approved 14:55Z); kept in A5 by the seat although the path is E1's (E1 has no open PR on the file)
Session: session_016WV4cykhsWAtSL6Sr4VWFG
Account: os-elon-musk
Branch: claude/area-A5-33152
Worktree: objectstack-issue-33152
Domain: domain:server
Seat: domain:server#5 (area A5)
File surface: packages/metadata-protocol/src/protocol-publish-batch.ts (the batch's pending set) and the object door's validation universe it shares, their tests, changesets. Stop on breach.
Clause-②: no (expected widening of what a batch accepts; the final value is declared from the diff)
Metadata-protocol: none (expected; the final value is declared from the diff)
Premise: re-measured on origin/main before any edit; premise_still_valid: false is a valid result
{
"issue": 33152,
"status": "done",
"branch": "claude/area-A5-33152",
"pr": "https://github.com/objectstack-ai/objectstack/pull/33300",
"session": "session_016WV4cykhsWAtSL6Sr4VWFG",
"premise_still_valid": true,
"summary": "Premise re-measured on origin/main d4fbb4dbb (after PR #33119): with the three metadata-protocol source files at BASE, a batch with the extension draft {extend: crm_region, fields: {tier__c}} beside an extension (or object) draft whose formula hops record.region.tier__c was refused (object_extension/crm_site failed author-time validation ... [expression-invalid]; object/crm_custom_deal failed; the transaction rolled back). Fix: collectBatchPendingDeclarations (protocol-publish-batch.ts) now collects the batch's object_extension drafts into a new pending key objectExtensions (routing row object_extension: 'objectExtensions'; RuntimePendingDeclarations = RuntimeStackContext plus that optional key, module-internal), and evaluateRuntimeAuthoringGate folds each draft's fields onto its target in the object universe (foldPendingObjectExtensions, the registry's field merge), after mergePendingDeclarations and also on the #32666 subject universe; an object_extension write's own draft is left out because the rules fold the written entry themselves (#33072). draftPublishVerdict shares the collector, so the draft read's publish verdict agrees. Scope is the batch half only: the card's per-item object-door case judges the written body, a different function, and is reported below as a follow-up. Changeset: @objectstack/metadata-protocol patch, Clause-②: no (quoting the published 0c24898 changelog sentence) and Metadata-protocol: none. Worked in the harness-provided isolated worktree on branch claude/area-A5-33152 rather than a separate ../objectstack-issue-33152 tree, and left that worktree in place because the harness locks it.",
"tests": "All at head 6d0278e0d unless noted. pnpm --filter @objectstack/metadata-protocol test: Test Files 339 passed | 9 skipped (348), Tests 22847 passed | 43 skipped, lock VERDICT command-exit 0. metadata-protocol typecheck EXIT=0. pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/domains/meta-object-extension-item.test.ts: Tests 32 passed (32), including the 3 new [#33152] cases (2 LIT published-in-one-batch, 1 CONTROL refused with INVALID_METADATA naming tier__c and both rows still drafts). runtime typecheck EXIT=0 (check:test-typecheck OK, debt ledger held). New pure pins in protocol-publish-drafts-closure.test.ts (26 passed in that file). Reverse verification (doubles as the premise reading): the 3 source files restored to BASE d4fbb4dbb with git restore, then src marker count 0, metadata-protocol rebuilt, and ablation-dist-preflight --absent: marker absent from all 24 built files. Then -t 33152: 2 failed | 1 passed (both LITs red, CONTROL green). Restore leg: git checkout HEAD --, each path's git hash-object equal to its HEAD blob, git diff HEAD empty, rebuild (VERDICT command-exit 0; the first restore rebuild got queue-timeout 99 and was re-run), preflight present exit=0 (hit dist/index.cjs and dist/index.js). First-draft note: the first version of the runtime pins asserted not.toBeInstanceOf(Error), but the batch door returns a refusal instead of throwing, so that was vacuous. The first run showed it (the CONTROL was admitted), and the pins were rewritten to assert outcome, failed[] and row states before any reading above.",
"gates": "Local, at 6d0278e0d: node scripts/pm/dispatch-gates.mjs --commands derived 69 commands. 67 exited 0 on the first pass. pnpm check:dual-build-cjs-loads exited 3 (dist missing) at first and exited 0 after the full build: '123 published require entry point(s) across 72 package(s) load'. node scripts/check-plugin-teardown-shape.mjs --self-test exited 3: PREREQUISITE, the shallow clone cannot reach its pinned fixture. NOT MEASURED locally; CI runs it. dispatch-gates --ran: '69 derived famil(ies) accounted for — 69 run, 0 NOT-MEASURED'. node scripts/check-nul-bytes.mjs exit 0. Exit codes were captured before any pipe; each command's output was redirected to its own log. CI: PR #33300 head 6d0278e0d check-runs total_count 0 when read just after the PR opened, so every CI family is in_progress (not yet reported). No local re-run of CI families.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 relay strokes (each one POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/33300/assignees [os-elon-musk]; (2) os-dev-report comment = POST /repos/objectstack-ai/objectstack/issues/33152/comments via post-stamped.mjs. git push is not counted.",
"open_questions": [
{
"question": "Metadata-protocol declaration for a batch door that now accepts packages it falsely refused: none or added?",
"options": [
"A none — the authorable set (spec, os build) does not change; the runtime door stops contradicting it, which is how the claim pre-declared it",
"B added — the runtime batch door's accept set grows, which is read as a new accepted value (minor on metadata-protocol)"
],
"recommendation": "A, because the refusal contradicted both os build and the published 0c24898 contract sentence; nothing new became writable. The contract review rules if B is preferred, and the change is one changeset line plus a minor bump."
}
],
"security_findings": "none",
"out_of_scope_findings": [
"class: a · reach: named producer (card #33152 'Related' bullet, reviewer probe on real doors: per-item object door PUT /api/v1/meta/object) · an object's own formula cannot read a field its package's published extension adds (unknown field at the object door; the build accepts), and the object save's destructive-change guard reads such a field as removed unless forced. Not the batch universe: the object door judges the WRITTEN body, which replaces the served object in the snapshot. Follow-up card for the seat, since this PR says Fixes #33152 · dedupe words: object door published extension field formula unknown field, destructive-change guard extension field removed, written object body served fold",
"class: a · reach: protocol publishPackageDrafts on the real store rig (the method behind the package publish route), not measured over HTTP and not against os build · a batch published an object_extension whose formula hops through a lookup the SAME extension adds into a field that exists nowhere: { extend: crm_account, fields: { region__c: lookup crm_region, tier_label__c: formula \"record.region__c.tier__c + '!'\" } } with crm_region lacking tier__c answered success: true (the first, discarded draft of this PR's CONTROL; with or without this fix the fold adds no tier__c). A hop through a base lookup is refused, as this PR's CONTROL pins · dedupe words: extension formula hop extension-added lookup unknown field accepted, expression-invalid object_extension lookup hop",
"carrier: domain:server#5 seat (outside this claim's file surface) · two @objectstack/lint comments that state the defect this PR fixes: packages/lint/src/validate-expressions.ts (runtimeWriteType docblock) and packages/lint/src/authoring-rules.ts (expression rule surfaces comment). Also the last bullet of the unreleased .changeset/33072-object-extension-door-formula.md. Noted in the PR's Acceptance notes, not filed",
"carrier: none · lenient direction, not measured: a batch draft that drops a field from the package's already-published extension of a target is folded over the served target, which still carries the published extension, so a sibling's reference to the dropped field still resolves (as it did before this PR; the single-item extension door narrows this since #33072). Noted in the PR's Acceptance notes, not filed"
]
}
Activity
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: first touch →
domain:server· p2 ·pm:queue· 2026-11-13T21:47Z⛔ Not a claim.
INVALID_METADATA, and the whole batch rolls back, whileos buildaccepts the same package. That is a false refusal on a core authoring act (p2). Publishing item by item in the right order is not a named workaround (rule 6), so there is no discount.packages/metadata-protocolprotocol-publish-batch.ts(the batch's pending set), which is server's, not lint's. Same class as publishPackageDrafts validation closure omits same-batch dataset drafts: a package shipping dashboard+dataset together can never publish (widget-dataset-unknown) #10377 (same-batch dataset drafts).docs(metadata-protocol): state the batch-publish limit and the folds'…
objectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cykhsWAtSL6Sr4VWFG
Claim: area-lease pilot #33059, area A5 thread · 2026-11-14T15:02Z · p2, dispatched to an os-dev subagent of this thread (parallel run approved 14:55Z); kept in A5 by the seat although the path is E1's (E1 has no open PR on the file)
Session:
session_016WV4cykhsWAtSL6Sr4VWFGAccount:
os-elon-muskBranch:
claude/area-A5-33152Worktree:
objectstack-issue-33152Domain:
domain:serverSeat:
domain:server#5(area A5)File surface:
packages/metadata-protocol/src/protocol-publish-batch.ts(the batch's pending set) and the object door's validation universe it shares, their tests, changesets. Stop on breach.Clause-②: no (expected widening of what a batch accepts; the final value is declared from the diff)
Metadata-protocol: none (expected; the final value is declared from the diff)
Premise: re-measured on
origin/mainbefore any edit;premise_still_valid: falseis a valid resultobjectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cykhsWAtSL6Sr4VWFG
os-dev-report
{ "issue": 33152, "status": "done", "branch": "claude/area-A5-33152", "pr": "https://github.com/objectstack-ai/objectstack/pull/33300", "session": "session_016WV4cykhsWAtSL6Sr4VWFG", "premise_still_valid": true, "summary": "Premise re-measured on origin/main d4fbb4dbb (after PR #33119): with the three metadata-protocol source files at BASE, a batch with the extension draft {extend: crm_region, fields: {tier__c}} beside an extension (or object) draft whose formula hops record.region.tier__c was refused (object_extension/crm_site failed author-time validation ... [expression-invalid]; object/crm_custom_deal failed; the transaction rolled back). Fix: collectBatchPendingDeclarations (protocol-publish-batch.ts) now collects the batch's object_extension drafts into a new pending key objectExtensions (routing row object_extension: 'objectExtensions'; RuntimePendingDeclarations = RuntimeStackContext plus that optional key, module-internal), and evaluateRuntimeAuthoringGate folds each draft's fields onto its target in the object universe (foldPendingObjectExtensions, the registry's field merge), after mergePendingDeclarations and also on the #32666 subject universe; an object_extension write's own draft is left out because the rules fold the written entry themselves (#33072). draftPublishVerdict shares the collector, so the draft read's publish verdict agrees. Scope is the batch half only: the card's per-item object-door case judges the written body, a different function, and is reported below as a follow-up. Changeset: @objectstack/metadata-protocol patch, Clause-②: no (quoting the published 0c24898 changelog sentence) and Metadata-protocol: none. Worked in the harness-provided isolated worktree on branch claude/area-A5-33152 rather than a separate ../objectstack-issue-33152 tree, and left that worktree in place because the harness locks it.", "tests": "All at head 6d0278e0d unless noted. pnpm --filter @objectstack/metadata-protocol test: Test Files 339 passed | 9 skipped (348), Tests 22847 passed | 43 skipped, lock VERDICT command-exit 0. metadata-protocol typecheck EXIT=0. pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/domains/meta-object-extension-item.test.ts: Tests 32 passed (32), including the 3 new [#33152] cases (2 LIT published-in-one-batch, 1 CONTROL refused with INVALID_METADATA naming tier__c and both rows still drafts). runtime typecheck EXIT=0 (check:test-typecheck OK, debt ledger held). New pure pins in protocol-publish-drafts-closure.test.ts (26 passed in that file). Reverse verification (doubles as the premise reading): the 3 source files restored to BASE d4fbb4dbb with git restore, then src marker count 0, metadata-protocol rebuilt, and ablation-dist-preflight --absent: marker absent from all 24 built files. Then -t 33152: 2 failed | 1 passed (both LITs red, CONTROL green). Restore leg: git checkout HEAD --, each path's git hash-object equal to its HEAD blob, git diff HEAD empty, rebuild (VERDICT command-exit 0; the first restore rebuild got queue-timeout 99 and was re-run), preflight present exit=0 (hit dist/index.cjs and dist/index.js). First-draft note: the first version of the runtime pins asserted not.toBeInstanceOf(Error), but the batch door returns a refusal instead of throwing, so that was vacuous. The first run showed it (the CONTROL was admitted), and the pins were rewritten to assert outcome, failed[] and row states before any reading above.", "gates": "Local, at 6d0278e0d: node scripts/pm/dispatch-gates.mjs --commands derived 69 commands. 67 exited 0 on the first pass. pnpm check:dual-build-cjs-loads exited 3 (dist missing) at first and exited 0 after the full build: '123 published require entry point(s) across 72 package(s) load'. node scripts/check-plugin-teardown-shape.mjs --self-test exited 3: PREREQUISITE, the shallow clone cannot reach its pinned fixture. NOT MEASURED locally; CI runs it. dispatch-gates --ran: '69 derived famil(ies) accounted for — 69 run, 0 NOT-MEASURED'. node scripts/check-nul-bytes.mjs exit 0. Exit codes were captured before any pipe; each command's output was redirected to its own log. CI: PR #33300 head 6d0278e0d check-runs total_count 0 when read just after the PR opened, so every CI family is in_progress (not yet reported). No local re-run of CI families.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 relay strokes (each one POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/33300/assignees [os-elon-musk]; (2) os-dev-report comment = POST /repos/objectstack-ai/objectstack/issues/33152/comments via post-stamped.mjs. git push is not counted.", "open_questions": [ { "question": "Metadata-protocol declaration for a batch door that now accepts packages it falsely refused: none or added?", "options": [ "A none — the authorable set (spec, os build) does not change; the runtime door stops contradicting it, which is how the claim pre-declared it", "B added — the runtime batch door's accept set grows, which is read as a new accepted value (minor on metadata-protocol)" ], "recommendation": "A, because the refusal contradicted both os build and the published 0c24898 contract sentence; nothing new became writable. The contract review rules if B is preferred, and the change is one changeset line plus a minor bump." } ], "security_findings": "none", "out_of_scope_findings": [ "class: a · reach: named producer (card #33152 'Related' bullet, reviewer probe on real doors: per-item object door PUT /api/v1/meta/object) · an object's own formula cannot read a field its package's published extension adds (unknown field at the object door; the build accepts), and the object save's destructive-change guard reads such a field as removed unless forced. Not the batch universe: the object door judges the WRITTEN body, which replaces the served object in the snapshot. Follow-up card for the seat, since this PR says Fixes #33152 · dedupe words: object door published extension field formula unknown field, destructive-change guard extension field removed, written object body served fold", "class: a · reach: protocol publishPackageDrafts on the real store rig (the method behind the package publish route), not measured over HTTP and not against os build · a batch published an object_extension whose formula hops through a lookup the SAME extension adds into a field that exists nowhere: { extend: crm_account, fields: { region__c: lookup crm_region, tier_label__c: formula \"record.region__c.tier__c + '!'\" } } with crm_region lacking tier__c answered success: true (the first, discarded draft of this PR's CONTROL; with or without this fix the fold adds no tier__c). A hop through a base lookup is refused, as this PR's CONTROL pins · dedupe words: extension formula hop extension-added lookup unknown field accepted, expression-invalid object_extension lookup hop", "carrier: domain:server#5 seat (outside this claim's file surface) · two @objectstack/lint comments that state the defect this PR fixes: packages/lint/src/validate-expressions.ts (runtimeWriteType docblock) and packages/lint/src/authoring-rules.ts (expression rule surfaces comment). Also the last bullet of the unreleased .changeset/33072-object-extension-door-formula.md. Noted in the PR's Acceptance notes, not filed", "carrier: none · lenient direction, not measured: a batch draft that drops a field from the package's already-published extension of a target is folded over the served target, which still carries the published extension, so a sibling's reference to the dropped field still resolves (as it did before this PR; the single-item extension door narrows this since #33072). Noted in the PR's Acceptance notes, not filed" ] }