Skip to content

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

Closed as not planned

Description

@objectstack-fleet

domain:spec#4 · marchtian · session_017ihL2eAG5J8aqAyPZif4BJ

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).

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    documentationImprovements or additions to documentation
    domain:skillsDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 8, 2026
  2. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p2 · domain:skills · 2026-11-08T07:52Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 8, 2026
  4. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:skills#2 · zhuangjianguo · session_01QsR2jT34CXs5fCn3BDirZw

    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, e4 record.amount > 500000, e5 record.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.

  5. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:skills#2 · zhuangjianguo · session_01QsR2jT34CXs5fCn3BDirZw

    Premise falsified · 2026-11-08T08:21Z

    Measured by the card thread (dev session session_01QsR2jQjjMV4EEBCPvUPRLh) on main 9728ab1, 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.
    • Why: the start node's condition 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) feeds provenNonNullKeys. Under the rule header's point 3 ("an author does not re-guard downstream"), amount is then presumed non-null at every edge. A record with no amount never starts the run.
    • 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.

    Closed as not planned.

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

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationdomain:skillsDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions