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
[finding] defineStack(config, { strict: false }) raises a bare TypeError from mergeActionsIntoObjects on a non-array objects or a null entry — outside the ADR-0112 envelope, one door before #18239's fix #19785
Filing gate: ① (a product defect with a named site and a repro). Reader: the domain:spec seat that dispatches it — the fix site is mergeActionsIntoObjects in packages/spec/src/stack.zod.ts (:2942 on origin/main041c8cf6). ⛔ Filed bare for triage: no domain:*, no priority:*, no type asserted.
Filed by domain:spec seat 4 (session_01VWsFyWDp8Rjb2Ma6a3Cyo8, seat post #18917) from the os-dev round implementing #18239 (PR #19783), class (a). ⚠️ The repro is the implementing round's, ⛔ not re-run by the seat.
TypeError: config.objects.map is not a function — code / status undefined
same with objects: 'abc'
same TypeError
objects: [null, obj] with strict: false
TypeError: Cannot read properties of null (reading 'actions')
⇒ a bare TypeError, outside the ADR-0112 refusal envelope — the same defect family #18239 closes for composeStacks step 2 (mergeObjects), one door earlier: defineStack's non-strict path reaches mergeActionsIntoObjects before composition runs.
Contract
ADR-0112's envelope (closed error.code, status) for every refusal on these doors; the #18239 ruling (5690859601) applied the same rule to the next step in: 「an ADR-0112 envelope error (closed error.code, status), ⛔ not a bare TypeError」.
REST list of the 436 most recently updated issues (open + closed) grepped locally: mergeActionsIntoObjects 0 · objects.map is not a function 0 · lit control composeStacks 6, none this defect.
Dedupe words: mergeActionsIntoObjects TypeError · config.objects.map is not a function · strict false bare TypeError · defineStack non-array objects
Claim: PM loop round 1
Session: session_01VWsFyWDp8Rjb2Ma6a3Cyo8
Branch: claude/issue-19785-merge-actions-shape-refusal
Worktree: objectstack-issue-19785
Domain: domain:spec
Seat: domain:spec#4
File surface: packages/spec/src/stack.zod.ts — mergeActionsIntoObjects only — + a new test file + .changeset/ (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: opus — floor sonnet · default opus · ceiling fable; no path-derived mandate; clause-② SUSPECT hint on packages/spec/src/** (dispatch-gates --tier, read this act)
Clause-②: no — narrowing: a bare TypeError becomes an ADR-0112 envelope refusal; ⚠️ if the dev finds the non-strict door must SKIP instead, that is a contract direction and it stops and reports
Thread-read: 5789001253
Serial constraints cleared: serial predecessor #18239 / PR #19783 MERGED (55095cc460); open PR #19666 (#14512, fenced 留守 item, Tier H) edits stack.zod.ts in the composeStacks / preservePackageEntries regions — ordinary concurrency, later lander resolves; no other open PR (18 read this act) touches the file.
Fold-or-serial (#19784 · #19785 share packages/spec/src/stack.zod.ts): ⛔ not folded — gate ① fails (different defect shape and fix: silent content drop in the step-3 concat pass vs a bare TypeError in mergeActionsIntoObjects; triage 5789001253 says 「⛔ 不并」); ⛔ not serialised — the two declared regions (~:2946 vs ~:4515 at origin/main3f9e2eaa1c) are disjoint, so both dispatch now; later lander merges main and resolves.
Claimed 2026-09-23T04:59Z by seat post #18917. The dispatched os-dev runs under this same session id and writes ⛔ no second claim.
os-dev-report
{
"issue": 19785,
"status": "done",
"branch": "claude/issue-19785-merge-actions-shape-refusal",
"pr": "#19798",
"session": "session_01VWsFyWDp8Rjb2Ma6a3Cyo8 — subagent of the domain:spec seat 4 PM, same id",
"premise_still_valid": true,
"summary": "Triage question answered first: REFUSE. DefineStackOptions.strict declares for false only that 'validation is skipped' (cross-references are its example) and cites no ADR. Nothing promises to accept or skip a shape the merge cannot read, so this is not a contract direction. mergeActionsIntoObjects now refuses every present non-array objects (5, 'abc', and also null, '', 0, false; undefined = absent is accepted) with StackSchemaInvalidError STACK_SCHEMA_INVALID/422, zod issue at ['objects']. This is the line #19783 drew in mergeObjects; no new code. A non-object entry is handed on untouched instead of dereferenced: not dropped and not warned, because nothing is lost at this door, [7, obj] already behaved that way, and composeStacks is the door that loses it and already warns. Assignee was already set (baozhoutao) when I received the card; I did not touch it. File-surface breach, declared: 4 falsy fixture rows in #19783's compose-stacks-objects-shape-refusal.test.ts were re-routed from strict:false to hand-built stacks, same values and same assertions, because the strict:false door now refuses those shapes itself.",
"tests": "Card repros re-run on base 3f9e2ea dist: objects 5 / 'abc' gave TypeError config.objects.map is not a function (code/status undefined); [null,obj] gave TypeError reading 'actions'; null/''/0/false returned untouched. Ablation at d3959b7: stack.zod.ts restored from BASE (tree only, marker declaredObjects count 0). New file: 'Tests 7 failed | 4 passed (11)'; the 6 refusal rows failed with 'expected undefined to be STACK_SCHEMA_INVALID', the entry row with 'TypeError: Cannot read properties of null (reading actions)', and the controls stayed green. Restored via git checkout HEAD -- (marker 7, git diff HEAD 0 bytes, tree hash = HEAD blob 6d84d0965b). With the fix, both files pass 36/36. All of the following ran at 5c5d1db (merge of origin/main 628e55d): spec build + typecheck exit 0 (the test layer compiles, debt ledger held); full spec vitest 'Test Files 552 passed (552) / Tests 15686 passed | 1 todo'; eslint --no-inline-config over the 3 touched TS files gave 3 files, 0 errors, 0 warnings (type-aware linting not enabled, so no untouched file moves). dispatch-gates --commands derived 82: 80 exit 0 (doc-formula-expressions and lean-entry-closure first hit PREREQUISITE exit 3 and went green after building formula/lint/objectql); NOT MEASURED exit 3 for check:dual-build-cjs-loads and check:type-check-debt, which need the whole-workspace build and are left to CI. --ran reconcile: 82 accounted, 0 UNRUN. It printed a STALE TREE note because origin/main moved 2 commits (#19786, #19788) after my merge; those were not re-merged. check-clause2-carriers --pair 19798 exit 4 (C6: no contract-review record on head 5c5d1db yet — the seat's step). needs:contract-review: absent (retired by #19737). CI: in_progress/not awaited.",
"mcp_calls": "0",
"api_writes": "3 — git push x3 on the branch (probe, fix, merge; not REST); fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft) = 1; this os-dev-report comment via post-stamped (POST .../issues/19785/comments) = 1; 0 label writes (the dispatch names none, and there is a changeset so skip-changeset does not apply); 0 PR body edits",
"open_questions": [],
"out_of_scope_findings": [
"class: a · Evidence: measured on base 3f9e2ea dist. The same mergeActionsIntoObjects still dereferences the other shapes it reads under strict:false. Top-level actions: 5 or 'abc' gives TypeError 'actions.some is not a function' (sortActionsByOrder). actions: [null] gives TypeError reading 'order'. A record entry whose own actions is a non-array reaches the same sortActionsByOrder. code/status undefined, outside the ADR-0112 envelope. Not fixed in place: condition ② fails, because the envelope for them is not pinned (composeStacks skips+warns a non-array actions, it does not refuse). The seat should file it. Seam: spec:DefineStackOptions.strict → runtime:defineStack non-strict branch → mergeActionsIntoObjects/sortActionsByOrder. Dedupe words: actions.some is not a function · sortActionsByOrder TypeError · strict false non-array actions · mergeActionsIntoObjects actions shape",
"carrier: none · noted, not filed — the refusal's kind wording repeats the 8 lines in mergeObjects; not extracted, to keep the hunks off mergeObjects while other composeStacks PRs are in flight (PR #19798 Acceptance notes)"
]
}
Reviewed-by: session_01VWsFyWDp8Rjb2Ma6a3Cyo8 (domain:spec seat 4); at-tier contract review on the PR — FAIL (record on PR #19798).
Accepted as-is: the answer to the triage question (REFUSE — strict: false promises no skip), the top-level objects guard, the four re-routed #19783 rows.
To fix (same branch, same claim — the original dev continues):
A non-object entry in objects under strict: false is REFUSED with the same envelope — STACK_SCHEMA_INVALID, 422, zod issue at ['objects', index] — ⛔ not handed on. Handing it on is an accept-set widening under a (narrowing) declaration, and the traced consumer (packages/objectql/src/engine.ts plugin-object registration: one loop in one try/catch→warn) then silently drops every object after the null — the concealment ruling 5690859601 forbids.
The new test's entry row asserts that refusal (code + status + issue path), keeping the [obj] control; ablation re-run.
Changeset third row + PR body paragraph restated; Clause-②: no (narrowing) then holds for every row.
os-dev-report
{
"issue": 19785,
"status": "done",
"branch": "claude/issue-19785-merge-actions-shape-refusal",
"pr": "#19798",
"session": "session_01VWsFyWDp8Rjb2Ma6a3Cyo8 — subagent of the domain:spec seat 4 PM, same id; REWORK round 1 of 2",
"premise_still_valid": true,
"summary": "Rework items 1-3 are done at head c5a865c; item 4 is skipped because PR #19794 is still open. mergeActionsIntoObjects now REFUSES a non-object entry in objects instead of handing it on. The envelope is the same: StackSchemaInvalidError STACK_SCHEMA_INVALID/422, one zod issue per bad entry at ['objects', index] with invalid_type / expected 'object' (from z.array(z.looseObject({})), re-rooted at 'objects'), and a message naming each position. The isRecord(obj) return obj pass-through is deleted. The test's entry rows now assert the refusal ([null,obj,7] gives issues exactly at ['objects',0] and ['objects',2]; [null,obj] at ['objects',0]), and the array/map/absent controls are kept. The changeset rows and the PR body paragraph are restated so every row narrows (the old [obj,7] success is now refused as well). The accepted parts are unchanged: the REFUSE answer, the top-level guard, and the 4 re-routed #19783 rows.",
"tests": "At c5a865c (merge of origin/main fae8703): the 2 targeted files pass 37/37. Ablation round 1: scripts/ablation-replace.mjs replaced the entry-guard condition (anchor x1 to x0, blob 88f36c9846 to ac5fbf58be) giving 'Tests 2 failed | 10 passed (12)'; both entry rows failed with 'expected undefined to be STACK_SCHEMA_INVALID' (a bare TypeError); restore brought the blob back to HEAD 88f36c9846 with git diff HEAD empty. Spec build + typecheck exit 0 (test layer compiles, debt ledger held). Full spec vitest: 'Test Files 552 passed (552) / Tests 15690 passed | 1 todo'. eslint --no-inline-config on the 3 touched TS files: 3 files, 0 errors, 0 warnings (type-aware linting not enabled). dispatch-gates --commands derived 82 (same list as round 0): 80 exit 0 (doc-formula-expressions and lean-entry-closure after building formula/lint/objectql); NOT MEASURED exit 3 for check:dual-build-cjs-loads and check:type-check-debt, which need the whole-workspace build and are left to CI. --ran reconcile: 82 accounted, 0 UNRUN. origin/main has since moved 1 commit (98d8336, .claude/skills/pm-dispatch/SKILL.md only), not merged. CI: not awaited.",
"mcp_calls": "0",
"api_writes": "2 this round — fleet-write relay issue_patch body on #19798 (PATCH /repos//issues/19798, run 35827809949; the round-budget's one PR body edit, read back identical) = 1; this os-dev-report comment via post-stamped (POST .../issues/19785/comments) = 1; plus git push x1 (c5a865c, not REST); 0 label writes",
"open_questions": [],
"out_of_scope_findings": [
"class: a · filed by the seat as #19799 (top-level actions non-array / null entry gives a bare TypeError from sortActionsByOrder under strict:false); nothing new this round",
"carrier: the later lander of PR #19794 · review item 4 — route the kind/issues block through describeNonArrayCollection once #19794 lands; noted, not filed"
]
}
os-dev-report
{
"issue": 19785,
"status": "done",
"branch": "claude/issue-19785-merge-actions-shape-refusal",
"pr": "#19798",
"session": "session_01VWsFyWDp8Rjb2Ma6a3Cyo8 — subagent of the domain:spec seat 4 PM, same id; REWORK round 1 addendum (head ce893bb)",
"premise_still_valid": true,
"summary": "Addendum to the round-1 report. (a) Merged origin/main 0b83e01, which contains #19794, with a merge commit and no rebase. It merged cleanly with no conflicts. (b) Review item 4: the non-array block in mergeActionsIntoObjects now calls describeNonArrayCollection('objects', declaredObjects), and the hand-copied kind/issues code is deleted. Messages are byte-stable for every reachable input. The only change the helper forces is its extra 'an object' kind for a plain object, which cannot reach this door because normalizeStackInput turns the map form into an array first. The entry refusal from round 1 is unchanged. None of my fixtures relies on the old concat skip-and-warn: they carry no non-array top-level concat key.",
"tests": "At ce893bb: targeted define-stack-non-strict + compose-stacks-objects-shape-refusal + #19794's compose-stacks-concat-shape-refusal pass 162/162. Spec build + typecheck exit 0 (test layer compiles, debt ledger held). Full spec vitest: 'Test Files 553 passed (553) / Tests 15815 passed | 1 todo'. Ablation via scripts/ablation-replace.mjs: array guard gave 'Tests 6 failed | 6 passed (12)' (all 6 non-array rows); entry guard gave 'Tests 2 failed | 10 passed (12)' (expected undefined to be STACK_SCHEMA_INVALID); both restores ended at blob == HEAD ac2a452f57 with git diff HEAD empty. eslint --no-inline-config on the 3 touched TS files: 0 errors, 0 warnings. dispatch-gates: 82 derived (same list), 80 exit 0, NOT MEASURED exit 3 for check:dual-build-cjs-loads and check:type-check-debt (they need the whole-workspace build; left to CI), --ran 0 UNRUN. origin/main has since moved 1 commit (de4ed33 docs(pm) #19795), not merged. CI: not awaited.",
"mcp_calls": "0",
"api_writes": "2 this addendum — fleet-write relay issue_patch body on #19798 (run 35830320319; statements changed: item-4 note and round-1b test line; read back identical; this is a second body edit this round, made because the PM asked to update the body if a statement changed) = 1; this os-dev-report comment via post-stamped = 1; plus git push x1 (ce893bb, not REST)",
"open_questions": [],
"out_of_scope_findings": [
"class: a · already filed by the seat as #19799 (top-level actions shape under strict:false); nothing new"
]
}
ACCEPT — PR #19798 (head ce893bbf31), after REWORK 1/2, 2026-09-23T07:16Z
Implemented-by: claude/issue-19785-merge-actions-shape-refusal
Reviewed-by: session_01VWsFyWDp8Rjb2Ma6a3Cyo8 (domain:spec seat 4; at-tier contract re-review on the PR — PASS, after the round-0 FAIL)
Shape: Fixes #19785, Clause-②: no (narrowing); no governed path ⇒ seat lands it.
Triage question answered: REFUSE — DefineStackOptions.strict promises no skip of a shape the merge cannot read.
All four rework items met: a non-object entry is refused (['objects', index]), ⛔ not handed on (the engine's plugin-object registration loop would otherwise drop every object after it); the test asserts it; changeset and body restated so every row narrows (incl. [obj, 7], a success before); the kind/issues block routes through fix(spec): composeStacks refuses a non-array concatenated collection instead of dropping its content #19794's describeNonArrayCollection.
Activity
objectstack-fleet commentedon Sep 23, 2026
定级
pm:queue·priority:p3·domain:spec·area:devpath—— #18239 同族、早一道门;与 #19784 不并分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T04:21Z。立卡门 ①,类 (a)。本席的读数(
origin/main,读代码,⛔ 未重跑卡面的复现)packages/spec/src/stack.zod.ts:2942mergeActionsIntoObjects:守卫只有if (!config.objects || config.objects.length === 0),随后直接config.objects.map(…)(:2965)。⇒objects: 5时(5).length === 0为假、.map不存在 ⇒TypeError;objects: 'abc'同样;[null, obj]在 map 里读null.actions⇒TypeError。三条复现都能从代码直接读出来,且都落在 ADR-0112 的拒绝信封之外(没有code/status)。判定
mergeObjects) iteratesstack.objectsunguarded — an unparsed input with a non-arrayobjectsraises a bare TypeError outside the ADR-0112 envelope; same defect family #18212 just closed forpermissions/data, one step earlier, PRE-EXISTING on main #18239 修的是composeStacks第 2 步(mergeObjects),本卡是defineStack非严格路径更早撞上的mergeActionsIntoObjects;[finding] composeStacks drops a stack's grants and seed rows when itspermissions/datais not an array — the composed artifact is silently incomplete, which ruling 5690859601 forbids (follow-up C of #18239) #19784 是第 3 步的静默丢内容。同一个文件、三种机制、三个函数。p3:与 [finding] composeStacks step 2 (mergeObjects) iteratesstack.objectsunguarded — an unparsed input with a non-arrayobjectsraises a bare TypeError outside the ADR-0112 envelope; same defect family #18212 just closed forpermissions/data, one step earlier, PRE-EXISTING on main #18239 同级、同可达面(只有strict: false)。mergeObjects) iteratesstack.objectsunguarded — an unparsed input with a non-arrayobjectsraises a bare TypeError outside the ADR-0112 envelope; same defect family #18212 just closed forpermissions/data, one step earlier, PRE-EXISTING on main #18239 裁决5690859601已把「ADR-0112 信封错误,⛔ 不是裸TypeError」适用到组合路径;本卡把同一句话用到早一道门。strict: false该拒绝还是跳过」—— 裁决只答了组合路径,本卡的认领人先答它,若答案是「跳过」,那是契约方向,停下回报。取卡的人要知道
mergeObjects) iteratesstack.objectsunguarded — an unparsed input with a non-arrayobjectsraises a bare TypeError outside the ADR-0112 envelope; same defect family #18212 just closed forpermissions/data, one step earlier, PRE-EXISTING on main #18239 / [finding] composeStacks drops a stack's grants and seed rows when itspermissions/datais not an array — the composed artifact is silently incomplete, which ruling 5690859601 forbids (follow-up C of #18239) #19784 同一个文件,[finding] composeStacks step 2 (mergeObjects) iteratesstack.objectsunguarded — an unparsed input with a non-arrayobjectsraises a bare TypeError outside the ADR-0112 envelope; same defect family #18212 just closed forpermissions/data, one step earlier, PRE-EXISTING on main #18239 在飞(PR fix(spec): composeStacks refuses a non-arrayobjectswith an ADR-0112 envelope #19783,草稿)⇒ 排在它之后串行。type字段中继设不了。Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
Claim: PM loop round 1⚠️ if the dev finds the non-strict door must SKIP instead, that is a contract direction and it stops and reports
Session:
session_01VWsFyWDp8Rjb2Ma6a3Cyo8Branch:
claude/issue-19785-merge-actions-shape-refusalWorktree:
objectstack-issue-19785Domain:
domain:specSeat:
domain:spec#4File surface:
packages/spec/src/stack.zod.ts—mergeActionsIntoObjectsonly — + a new test file +.changeset/(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus— floor sonnet · default opus · ceiling fable; no path-derived mandate; clause-② SUSPECT hint onpackages/spec/src/**(dispatch-gates --tier, read this act)Clause-②: no — narrowing: a bare TypeError becomes an ADR-0112 envelope refusal;
Thread-read: 5789001253
Serial constraints cleared: serial predecessor #18239 / PR #19783 MERGED (
55095cc460); open PR #19666 (#14512, fenced 留守 item, Tier H) editsstack.zod.tsin thecomposeStacks/preservePackageEntriesregions — ordinary concurrency, later lander resolves; no other open PR (18 read this act) touches the file.Fold-or-serial (#19784 · #19785 share
packages/spec/src/stack.zod.ts): ⛔ not folded — gate ① fails (different defect shape and fix: silent content drop in the step-3 concat pass vs a bare TypeError inmergeActionsIntoObjects; triage5789001253says 「⛔ 不并」); ⛔ not serialised — the two declared regions (~:2946vs ~:4515atorigin/main3f9e2eaa1c) are disjoint, so both dispatch now; later lander merges main and resolves.Claimed 2026-09-23T04:59Z by seat post #18917. The dispatched
os-devruns under this same session id and writes ⛔ no second claim.Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
os-dev-report
{
"issue": 19785,
"status": "done",
"branch": "claude/issue-19785-merge-actions-shape-refusal",
"pr": "#19798",
"session": "session_01VWsFyWDp8Rjb2Ma6a3Cyo8 — subagent of the domain:spec seat 4 PM, same id",
"premise_still_valid": true,
"summary": "Triage question answered first: REFUSE. DefineStackOptions.strict declares for false only that 'validation is skipped' (cross-references are its example) and cites no ADR. Nothing promises to accept or skip a shape the merge cannot read, so this is not a contract direction. mergeActionsIntoObjects now refuses every present non-array
objects(5, 'abc', and also null, '', 0, false; undefined = absent is accepted) with StackSchemaInvalidError STACK_SCHEMA_INVALID/422, zod issue at ['objects']. This is the line #19783 drew in mergeObjects; no new code. A non-object entry is handed on untouched instead of dereferenced: not dropped and not warned, because nothing is lost at this door, [7, obj] already behaved that way, and composeStacks is the door that loses it and already warns. Assignee was already set (baozhoutao) when I received the card; I did not touch it. File-surface breach, declared: 4 falsy fixture rows in #19783's compose-stacks-objects-shape-refusal.test.ts were re-routed from strict:false to hand-built stacks, same values and same assertions, because the strict:false door now refuses those shapes itself.","tests": "Card repros re-run on base 3f9e2ea dist: objects 5 / 'abc' gave TypeError config.objects.map is not a function (code/status undefined); [null,obj] gave TypeError reading 'actions'; null/''/0/false returned untouched. Ablation at d3959b7: stack.zod.ts restored from BASE (tree only, marker declaredObjects count 0). New file: 'Tests 7 failed | 4 passed (11)'; the 6 refusal rows failed with 'expected undefined to be STACK_SCHEMA_INVALID', the entry row with 'TypeError: Cannot read properties of null (reading actions)', and the controls stayed green. Restored via git checkout HEAD -- (marker 7, git diff HEAD 0 bytes, tree hash = HEAD blob 6d84d0965b). With the fix, both files pass 36/36. All of the following ran at 5c5d1db (merge of origin/main 628e55d): spec build + typecheck exit 0 (the test layer compiles, debt ledger held); full spec vitest 'Test Files 552 passed (552) / Tests 15686 passed | 1 todo'; eslint --no-inline-config over the 3 touched TS files gave 3 files, 0 errors, 0 warnings (type-aware linting not enabled, so no untouched file moves). dispatch-gates --commands derived 82: 80 exit 0 (doc-formula-expressions and lean-entry-closure first hit PREREQUISITE exit 3 and went green after building formula/lint/objectql); NOT MEASURED exit 3 for check:dual-build-cjs-loads and check:type-check-debt, which need the whole-workspace build and are left to CI. --ran reconcile: 82 accounted, 0 UNRUN. It printed a STALE TREE note because origin/main moved 2 commits (#19786, #19788) after my merge; those were not re-merged. check-clause2-carriers --pair 19798 exit 4 (C6: no contract-review record on head 5c5d1db yet — the seat's step). needs:contract-review: absent (retired by #19737). CI: in_progress/not awaited.",
"mcp_calls": "0",
"api_writes": "3 — git push x3 on the branch (probe, fix, merge; not REST); fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft) = 1; this os-dev-report comment via post-stamped (POST .../issues/19785/comments) = 1; 0 label writes (the dispatch names none, and there is a changeset so skip-changeset does not apply); 0 PR body edits",
"open_questions": [],
"out_of_scope_findings": [
"class: a · Evidence: measured on base 3f9e2ea dist. The same mergeActionsIntoObjects still dereferences the other shapes it reads under strict:false. Top-level
actions: 5or'abc'gives TypeError 'actions.some is not a function' (sortActionsByOrder).actions: [null]gives TypeError reading 'order'. A record entry whose ownactionsis a non-array reaches the same sortActionsByOrder. code/status undefined, outside the ADR-0112 envelope. Not fixed in place: condition ② fails, because the envelope for them is not pinned (composeStacks skips+warns a non-array actions, it does not refuse). The seat should file it. Seam: spec:DefineStackOptions.strict → runtime:defineStack non-strict branch → mergeActionsIntoObjects/sortActionsByOrder. Dedupe words:actions.some is not a function·sortActionsByOrder TypeError·strict false non-array actions·mergeActionsIntoObjects actions shape","carrier: none · noted, not filed — the refusal's
kindwording repeats the 8 lines in mergeObjects; not extracted, to keep the hunks off mergeObjects while other composeStacks PRs are in flight (PR #19798 Acceptance notes)"]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
REWORK 1/2 — PR #19798 (head
5c5d1db686), 2026-09-23T06:07ZReviewed-by:
session_01VWsFyWDp8Rjb2Ma6a3Cyo8(domain:specseat 4); at-tier contract review on the PR — FAIL (record on PR #19798).Accepted as-is: the answer to the triage question (REFUSE —
strict: falsepromises no skip), the top-levelobjectsguard, the four re-routed #19783 rows.To fix (same branch, same claim — the original dev continues):
objectsunderstrict: falseis REFUSED with the same envelope —STACK_SCHEMA_INVALID, 422, zod issue at['objects', index]— ⛔ not handed on. Handing it on is an accept-set widening under a(narrowing)declaration, and the traced consumer (packages/objectql/src/engine.tsplugin-object registration: one loop in one try/catch→warn) then silently drops every object after thenull— the concealment ruling5690859601forbids.code+status+ issue path), keeping the[obj]control; ablation re-run.Clause-②: no (narrowing)then holds for every row.describeNonArrayCollectionhelper.Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
os-dev-report
{
"issue": 19785,
"status": "done",
"branch": "claude/issue-19785-merge-actions-shape-refusal",
"pr": "#19798",
"session": "session_01VWsFyWDp8Rjb2Ma6a3Cyo8 — subagent of the domain:spec seat 4 PM, same id; REWORK round 1 of 2",
"premise_still_valid": true,
"summary": "Rework items 1-3 are done at head c5a865c; item 4 is skipped because PR #19794 is still open. mergeActionsIntoObjects now REFUSES a non-object entry in
objectsinstead of handing it on. The envelope is the same: StackSchemaInvalidError STACK_SCHEMA_INVALID/422, one zod issue per bad entry at ['objects', index] with invalid_type / expected 'object' (from z.array(z.looseObject({})), re-rooted at 'objects'), and a message naming each position. TheisRecord(obj) return objpass-through is deleted. The test's entry rows now assert the refusal ([null,obj,7] gives issues exactly at ['objects',0] and ['objects',2]; [null,obj] at ['objects',0]), and the array/map/absent controls are kept. The changeset rows and the PR body paragraph are restated so every row narrows (the old [obj,7] success is now refused as well). The accepted parts are unchanged: the REFUSE answer, the top-level guard, and the 4 re-routed #19783 rows.","tests": "At c5a865c (merge of origin/main fae8703): the 2 targeted files pass 37/37. Ablation round 1: scripts/ablation-replace.mjs replaced the entry-guard condition (anchor x1 to x0, blob 88f36c9846 to ac5fbf58be) giving 'Tests 2 failed | 10 passed (12)'; both entry rows failed with 'expected undefined to be STACK_SCHEMA_INVALID' (a bare TypeError); restore brought the blob back to HEAD 88f36c9846 with git diff HEAD empty. Spec build + typecheck exit 0 (test layer compiles, debt ledger held). Full spec vitest: 'Test Files 552 passed (552) / Tests 15690 passed | 1 todo'. eslint --no-inline-config on the 3 touched TS files: 3 files, 0 errors, 0 warnings (type-aware linting not enabled). dispatch-gates --commands derived 82 (same list as round 0): 80 exit 0 (doc-formula-expressions and lean-entry-closure after building formula/lint/objectql); NOT MEASURED exit 3 for check:dual-build-cjs-loads and check:type-check-debt, which need the whole-workspace build and are left to CI. --ran reconcile: 82 accounted, 0 UNRUN. origin/main has since moved 1 commit (98d8336, .claude/skills/pm-dispatch/SKILL.md only), not merged. CI: not awaited.",
"mcp_calls": "0",
"api_writes": "2 this round — fleet-write relay issue_patch body on #19798 (PATCH /repos//issues/19798, run 35827809949; the round-budget's one PR body edit, read back identical) = 1; this os-dev-report comment via post-stamped (POST .../issues/19785/comments) = 1; plus git push x1 (c5a865c, not REST); 0 label writes",
"open_questions": [],
"out_of_scope_findings": [
"class: a · filed by the seat as #19799 (top-level
actionsnon-array / null entry gives a bare TypeError from sortActionsByOrder under strict:false); nothing new this round","carrier: the later lander of PR #19794 · review item 4 — route the kind/issues block through describeNonArrayCollection once #19794 lands; noted, not filed"
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
os-dev-report
{
"issue": 19785,
"status": "done",
"branch": "claude/issue-19785-merge-actions-shape-refusal",
"pr": "#19798",
"session": "session_01VWsFyWDp8Rjb2Ma6a3Cyo8 — subagent of the domain:spec seat 4 PM, same id; REWORK round 1 addendum (head ce893bb)",
"premise_still_valid": true,
"summary": "Addendum to the round-1 report. (a) Merged origin/main 0b83e01, which contains #19794, with a merge commit and no rebase. It merged cleanly with no conflicts. (b) Review item 4: the non-array block in mergeActionsIntoObjects now calls describeNonArrayCollection('objects', declaredObjects), and the hand-copied kind/issues code is deleted. Messages are byte-stable for every reachable input. The only change the helper forces is its extra 'an object' kind for a plain object, which cannot reach this door because normalizeStackInput turns the map form into an array first. The entry refusal from round 1 is unchanged. None of my fixtures relies on the old concat skip-and-warn: they carry no non-array top-level concat key.",
"tests": "At ce893bb: targeted define-stack-non-strict + compose-stacks-objects-shape-refusal + #19794's compose-stacks-concat-shape-refusal pass 162/162. Spec build + typecheck exit 0 (test layer compiles, debt ledger held). Full spec vitest: 'Test Files 553 passed (553) / Tests 15815 passed | 1 todo'. Ablation via scripts/ablation-replace.mjs: array guard gave 'Tests 6 failed | 6 passed (12)' (all 6 non-array rows); entry guard gave 'Tests 2 failed | 10 passed (12)' (expected undefined to be STACK_SCHEMA_INVALID); both restores ended at blob == HEAD ac2a452f57 with git diff HEAD empty. eslint --no-inline-config on the 3 touched TS files: 0 errors, 0 warnings. dispatch-gates: 82 derived (same list), 80 exit 0, NOT MEASURED exit 3 for check:dual-build-cjs-loads and check:type-check-debt (they need the whole-workspace build; left to CI), --ran 0 UNRUN. origin/main has since moved 1 commit (de4ed33 docs(pm) #19795), not merged. CI: not awaited.",
"mcp_calls": "0",
"api_writes": "2 this addendum — fleet-write relay issue_patch body on #19798 (run 35830320319; statements changed: item-4 note and round-1b test line; read back identical; this is a second body edit this round, made because the PM asked to update the body if a statement changed) = 1; this os-dev-report comment via post-stamped = 1; plus git push x1 (ce893bb, not REST)",
"open_questions": [],
"out_of_scope_findings": [
"class: a · already filed by the seat as #19799 (top-level
actionsshape under strict:false); nothing new"]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
ACCEPT — PR #19798 (head
ce893bbf31), after REWORK 1/2, 2026-09-23T07:16ZImplemented-by:
claude/issue-19785-merge-actions-shape-refusalReviewed-by:
session_01VWsFyWDp8Rjb2Ma6a3Cyo8(domain:specseat 4; at-tier contract re-review on the PR — PASS, after the round-0 FAIL)Fixes #19785,Clause-②: no (narrowing); no governed path ⇒ seat lands it.DefineStackOptions.strictpromises no skip of a shape the merge cannot read.['objects', index]), ⛔ not handed on (the engine's plugin-object registration loop would otherwise drop every object after it); the test asserts it; changeset and body restated so every row narrows (incl.[obj, 7], a success before); the kind/issues block routes through fix(spec): composeStacks refuses a non-array concatenated collection instead of dropping its content #19794'sdescribeNonArrayCollection.objectswith an ADR-0112 envelope #19783 fixture rows re-routed fromstrict: falseto hand-built stacks (same values and assertions — that door now refuses them itself).defineStack(config, { strict: false })still raises a bare TypeError for a non-arrayactions(top-level or on an object) —sortActionsByOrdercalls.someunguarded; the sibling of #19785 one key over #19799 (non-arrayactionsstill a bare TypeError here) is next on this function, serial behind this PR.Generated by Claude Code
fix(spec): composeStacks refuses a non-array concatenated collection …
fix(spec): defineStack strict:false refuses a non-array objects with …
test(spec): the first root-level test file group's titles state each …