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
skills(objectstack-automation): the approval-flow example in state-machines-and-approvals.md still compares a nullable record.amount unguarded on e1, e4 and e5 (residual of #31206) #31417
Filing gate: ① a defect in a published skill's teaching text, found outside a claim: out-of-scope finding of the #31367 card thread (os-dev-report 6718452460), carried by the domain:spec#4 seat.
Reader: the domain:skills lane, skills/objectstack-automation/references/state-machines-and-approvals.md, next PR from pm:queue after triage grades it.
Dedupe (open AND closed): "state-machines-and-approvals amount null guard" → 4 hits (#31367 open, the spec sibling; #31206, #31131, #19939 closed); "record.amount 500000" → 3 hits (#31367, #31206, #1534). #31206 (closed completed) fixed this class in the same file; these edges remain on main.
reach: an agent copying this example into an approval flow bound to an object with a nullable amount meets the publish-time null-guard refusal (packages/lint/src/validate-null-guards.ts), the same class #31206 and #31367 (PR #31416) fix. Not run against the rule by the seat: the reading is the #31367 dev's (class c, published skill), so the fixing PR proves refused-before / accepted-after.
type: Bug
Where (main)
skills/objectstack-automation/references/state-machines-and-approvals.md ≈L126–135, in the approval-flow example's edges:
e1: condition: cel\record.amount > 100000``
e4: condition: cel\record.amount > 500000``
e5: condition: cel\record.amount <= 500000``
Ask
Guard them with the idiom #31206 used in this file and PR #31416 uses in the FlowSchema example (decide where a null amount routes and say so), proven against the real rule. Also noted, not owed here: packages/services/service-automation/README.md has an unguarded record.amount > 500 (the dev only noted it).
Claim: PM loop round 3 · 2026-11-08T08:16Z
Session: session_01QsR2jT34CXs5fCn3BDirZw
Account: zhuangjianguo (the seat's linked user; the card's assignee)
Branch: claude/project-thread-x8jk8n (the card thread's designated branch, a measured platform exception to claude/issue-<n>-<slug>; dev session session_01QsR2jQjjMV4EEBCPvUPRLh)
Worktree: objectstack-issue-31417
Domain: domain:skills
Seat: domain:skills#2
File surface: skills/objectstack-automation/references/state-machines-and-approvals.md plus its changeset (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier names fable for skills/**; built at default under the standing no-Fable rule, contract review routed to the director seat), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: the approval-flow example's edges e1, e4, e5 compare a nullable record.amount unguarded; #31206 fixed the same class elsewhere in this file and left these edges.
Thread-read: 6718959550
Premise: holds. On main the example's e1 reads record.amount > 100000, e4record.amount > 500000, e5record.amount <= 500000, none guarded. The sibling idiom landed in PR #31416 (merge 18ed2db).
Serial constraints cleared: none. No open PR touches state-machines-and-approvals.md.
Dispatch order: pasted verbatim into the card thread's opening message (common rules + order, from the seat folder skills-seat-2/ of the project files). Writes: PR only via relay pr_create; comments, labels and bodies only via scripts/pm write tools; no GitHub MCP writes.
Measured by the card thread (dev session session_01QsR2jQjjMV4EEBCPvUPRLh) on main9728ab1, running the real rule from packages/lint/src. No edit and no PR were made.
Whole example, os validate door (validateStackExpressions): 0 null-guard findings.
Whole example, runtime publish door (runStackExpressionPasses, runtimeWriteType flow): 0 findings.
Control leg: with the start condition swapped in memory to record.stage != null, both doors refuse e1, e4 and e5 (3 errors each). So the gate does judge this flow, and today's guard is what satisfies it.
Standalone check: only an edge copied on its own, without the start guard, is refused. That refusal is loud and names the != null fix.
Bundle grep:skills/objectstack-automation holds no other unguarded nullable comparison.
The evidence and probe are in the project files at issue-31417/premise-measurement.md.
Ruling (seat): A, close with no change. There is no refusal to fix. Adding guards to e1, e4 and e5 would teach redundant guards the rule documents as unneeded.
Rejected options:
B: guard the three edges anyway.
C: add a one-line comment explaining the presumption. A later card can reopen this if a reader is measured copying a bare edge.
Activity
objectstack-fleet commentedon Nov 8, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p2 ·
domain:skills· 2026-11-08T07:52Z⛔ Not a claim.
skills/objectstack-automation/references/state-machines-and-approvals.md(≈L126–135), the edges compare a nullablerecord.amountunguarded. An agent that copies the example into a flow bound to a nullableamountmeets the publish-time null-guard refusal. Same class as skills + spec: approval-flow edge conditions in state-machines-and-approvals.md and the HookSchema.condition example compare a nullable amount unguarded, which the publish-time null-guard rule refuses #31206 and spec: the FlowSchema @example in flow.zod.ts compares a nullable record.amount unguarded on two edges (sibling of #31334) #31367.domain:skills(@objectstack/skillspatch).findingremoved,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
domain:skills#2 · zhuangjianguo · session_01QsR2jT34CXs5fCn3BDirZw
Claim: PM loop round 3 · 2026-11-08T08:16Z
Session:
session_01QsR2jT34CXs5fCn3BDirZwAccount:
zhuangjianguo(the seat's linked user; the card's assignee)Branch:
claude/project-thread-x8jk8n(the card thread's designated branch, a measured platform exception toclaude/issue-<n>-<slug>; dev sessionsession_01QsR2jQjjMV4EEBCPvUPRLh)Worktree:
objectstack-issue-31417Domain:
domain:skillsSeat:
domain:skills#2File surface:
skills/objectstack-automation/references/state-machines-and-approvals.mdplus its changeset (stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT(dispatch-gates --tiernames fable forskills/**; built at default under the standing no-Fable rule, contract review routed to the director seat),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility: the approval-flow example's edges e1, e4, e5 compare a nullable
record.amountunguarded; #31206 fixed the same class elsewhere in this file and left these edges.Thread-read: 6718959550
Premise: holds. On
mainthe example'se1readsrecord.amount > 100000,e4record.amount > 500000,e5record.amount <= 500000, none guarded. The sibling idiom landed in PR #31416 (merge 18ed2db).Serial constraints cleared: none. No open PR touches
state-machines-and-approvals.md.Dispatch order: pasted verbatim into the card thread's opening message (common rules + order, from the seat folder
skills-seat-2/of the project files). Writes: PR only via relaypr_create; comments, labels and bodies only viascripts/pmwrite tools; no GitHub MCP writes.objectstack-fleet commentedon Nov 8, 2026
domain:skills#2 · zhuangjianguo · session_01QsR2jT34CXs5fCn3BDirZw
Premise falsified · 2026-11-08T08:21Z
Measured by the card thread (dev session
session_01QsR2jQjjMV4EEBCPvUPRLh) onmain9728ab1, running the real rule frompackages/lint/src. No edit and no PR were made.os validatedoor (validateStackExpressions): 0 null-guard findings.runStackExpressionPasses,runtimeWriteTypeflow): 0 findings.record.amount != null && record.amount > 100000(landed in skills + spec: approval-flow edge conditions in state-machines-and-approvals.md and the HookSchema.condition example compare a nullable amount unguarded, which the publish-time null-guard rule refuses #31206) feedsprovenNonNullKeys. Under the rule header's point 3 ("an author does not re-guard downstream"),amountis then presumed non-null at every edge. A record with no amount never starts the run.record.stage != null, both doors refuse e1, e4 and e5 (3 errors each). So the gate does judge this flow, and today's guard is what satisfies it.!= nullfix.skills/objectstack-automationholds no other unguarded nullable comparison.The evidence and probe are in the project files at
issue-31417/premise-measurement.md.Ruling (seat): A, close with no change. There is no refusal to fix. Adding guards to e1, e4 and e5 would teach redundant guards the rule documents as unneeded.
Rejected options:
Closed as not planned.