Repository navigation
Description
domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7
What is wrong
PR #31322 (#31206) guards the nullable amount in the automation skill's approval flow and in the HookSchema.condition example. The publish-time null-guard rule (packages/lint/src/validate-null-guards.ts) refuses an unguarded comparison on a nullable field in a gated position, and the formula skill teaches the guard (record.amount != null && …, skills/objectstack-formula/SKILL.md ≈L112-L122; flow start conditions ≈L404). The PR's dev grep and its contract review (6715980957) found these sites outside that card's claim. Read on main:
| Site | Surface | Gated? |
|---|---|---|
content/docs/getting-started/common-patterns.mdx L371-L372, edges e2/e3 (record.amount < 100 / >= 100) |
record_change flow on expense_report; amount is { type: 'currency' } with no required/default (L312) and the start condition does not guard it |
Yes, refused as written |
content/docs/automation/approvals.mdx L145, start condition (record.amount >= 50000 && …) |
record_change flow start condition on opportunity |
Yes, if amount is nullable |
content/docs/automation/hook-bodies.mdx L74 (record.status == "open" && record.amount > 1000) |
hook condition |
Yes, if amount is nullable |
content/docs/data-modeling/formulas.mdx L119, L356 (requiredWhen: P\record.amount > 10000``) |
field requiredWhen (fail-open: silently enforces nothing) |
Yes, if amount is nullable |
content/docs/data-modeling/formulas.mdx L394 (record.amount <= 0) |
validation rule | Yes, if amount is nullable |
content/docs/data-modeling/validation.mdx L329 (record.amount <= 0) |
validation rule fragment | Yes, if amount is nullable |
content/docs/automation/flows.mdx L2473 (record.amount > 500, start-node condition in the syntax table) |
flow start condition | Yes on a record_change flow, if nullable |
packages/spec/src/data/validation.zod.ts L180, generated into content/docs/references/data/validation.mdx L170/L291/L505/L571 (record.amount < 0) |
validation condition |
Yes, if nullable (spec example; regenerate, never hand-edit) |
ui/packages/app-shell/src/views/metadata-admin/SchemaForm.erasedArmMark-9830.test.tsx L110 |
hand-copies the old HookSchema.condition describe string |
Not gated; the test reads its own constant and passes, but lags the served text once #31322 lands |
Not a site: content/docs/data-modeling/validation.mdx L51 (amount is required: true at L31). Release notes and CHANGELOGs are left alone.
Evidence
PR #31322 body § Other sites found; contract review 6715980957 ③.
Suggested shape
Where an example declares its object, guard as the formula skill teaches, or declare the field required: true if that is the honest fix. Where it does not, guard anyway. A flow's start-condition guard covers its edges and decision branches (validate-expressions.ts L2967-L2976), so guard the start condition rather than each edge. The spec example rides with a spec-lane note and a regenerated reference page. The UI test fixture is the UI lane's.
Activity
objectstack-fleet commentedon Nov 8, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p2 ·
domain:devx· 2026-11-08T02:53Z⛔ Not a claim.
record.amountunguarded in a gated position. The publish-time null-guard rule (validate-null-guards.ts) refuses that shape, and onrequiredWhenit fails open. These are the sites PR docs(skills, spec): guard the nullable amount in the approval-flow and hook-condition examples #31322 (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) found outside its own claim.domain:devx(content/docs).packages/spec/src/data/validation.zod.tsexample is regenerated, never hand-edited, and rides the same PR as a spec doc-example change.uitest constant follows the served text once docs(skills, spec): guard the nullable amount in the approval-flow and hook-condition examples #31322 lands.findingremoved,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
domain:devx#3 · os-project-manager · session_01FEkQ5njkh3xbcDN6EtSfw7
Claim: PM loop round 1
Session:
session_01FEkQ5njkh3xbcDN6EtSfw7Account:
os-project-managerBranch:
claude/project-thread-2zrqid(a project card thread,session_01FEkQ5kcxM8mwtPqSQpzbVT; the thread can push only its harness branch, a measured platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-31334Domain:
domain:devxSeat:
domain:devx#3File surface: the seven
content/docs/**pages in the card's table,packages/spec/src/data/validation.zod.ts(example string) plus the regeneratedcontent/docs/references/data/validation.mdx, and one changeset if the gate asks. ⛔ Theui/SchemaForm test constant (UI lane, after #31322), release notes and CHANGELOGs are out.Container & model:
M,mode:thread,model: default — read dispatch-gates --tier on the real diff,effort: mediumClause-②: no — an example/description string on a published schema, with no accept-set change. The thread reports yes if its diff or the recognisers read otherwise.
Metadata-protocol: none
Responsibility: n/a — docs and spec example text, no user door
Thread-read: 6716403823
Premise: holds on main
dc7f5c4b4. PR #31322 is still open, and the card's sites comparerecord.amountunguarded.Ruling-ref: p2 by triage 6716403823; dispatched under the maintainer's 「并发5」 (2026-11-07T23:53Z).
Order:
pm-orders/devx/order-31334.md(project files), handed to the card thread in its opening message.objectstack-fleet commentedon Nov 8, 2026
domain:devx#3 · os-project-manager · session_01FEkQ5kcxM8mwtPqSQpzbVT
os-dev-report
{
"issue": 31334,
"status": "done",
"branch": "claude/project-thread-2zrqid",
"pr": "#31358",
"session": "session_01FEkQ5kcxM8mwtPqSQpzbVT",
"premise_still_valid": true,
"summary": "Every site in the card, re-found on main dc7f5c4, now guards the nullable amount. Six docs sites and the ValidationRule.condition describe string take
record.amount != null && ...(flows at the start condition, per the ruling); common-patterns declares the expense report amountrequired: true, because its flow branches on amount and a guarded start condition would let an amount-less submission skip approval silently. content/docs/references/data/validation.mdx was regenerated with gen:schema + gen:docs (4 rows). Bounded in-place fix, declared in the PR body: the two validation.zod.ts doc-comment examples (cross_field L257, conditional then L532) had the same defect, the rule refuses both, and they are guarded too (same file, same class, same gates, no other claim on the file). One spec patch changeset. PR #31322 still open and touches none of these files, so no merge was needed.","tests": "Real-rule probe: each changed expression fed in its declared context to validateStackExpressions from the built @objectstack/lint dist (amount declared { type: currency }, nullable). Before: REFUSED at all 9 site shapes (common-patterns e2+e3 = 2, approvals start 1, hook 1, requiredWhen 1, script rule 1, flows start 1, validation.zod.ts L180 1, L257 2, L532 1); after: accepted, 0 null-guard and 0 other errors on every row (table and raw output in the PR body). packages/spec vitest src/data/validation.test.ts + validation-boundary-description.test.ts: 2 files, 90/90 passed (lock VERDICT command-exit 0). eslint packages/spec/src/data/validation.zod.ts --no-inline-config: exit 0. No tested behaviour changed (docs and description text), so no ablation.",
"gates": "Head c4bbb0a, merge base dc7f5c4. dispatch-gates --commands --repo objectstack-ai/objectstack: 99 derived; 98 exit 0; pnpm check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, needs every package dist) = NOT MEASURED, CI reads it. dispatch-gates --ran: 99 derived, 98 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. Round 1 was stopped at line 38 because spec dist was stale after the describe edit (check:api-surface / browser-reachable-entries / dual-source-exports exit 3, plugin-teardown --self-test exit 3 on the shallow clone); after rebuilding spec + the client-react closure and fetching 621a487, round 2 ran all 99. Local-only: check:skill-frame-freshness exit 0; check:dev-prereqs exit 1 on local state only (65/107 packages have no dist in this worktree; self-test passes). check-commit-card-trailers --range origin/main..HEAD 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": "5 — all reads: issue_read get #31334, issue_read get_comments #31334 (x2), pull_request_read get #31322, pull_request_read get #31358. No MCP writes.",
"api_writes": "2 — relay fleet-write pr_create (repository_dispatch, run 42445586323, PR #31358, draft, no labels, no assignees; read-back identical bytes); this os-dev-report comment via post-stamped. git push is not a REST write.",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none · noted, not filed — packages/spec/src/automation/flow.zod.ts L1070-L1071 FlowSchema @example spells the same unguarded record.amount < 500 / >= 500 edges; as written its start node has no config.objectName, so the rule has no object and does not refuse it (probe 0 findings; 2 once bound to an object with a nullable amount). Not refused at any public door today, so no class (a)/(b)/(c) reach; recorded in the PR Acceptance notes.",
"Deviation noted for the seat: the claim scope says validation.zod.ts (example string); the PR also guards that file's two doc-comment examples under os-dev.md's bounded in-place exemption (all four conditions hold). Same file, so the declared file surface is unchanged. Labels: the order named none, and the relay refuses an empty list, so pr_create carried no labels key. The changeset is spec patch (the description text ships in dist and json-schema)."
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
domain:devx#3 · os-project-manager · session_01FEkQ5njkh3xbcDN6EtSfw7
Landed 2026-11-08T05:04Z · PR #31358 merged through the merge queue at 2026-11-08T05:04Z, as
82e6da1132d173def0f05d6104fc6fe1afaf14ce.merged: true, merge commit82e6da1132, head reviewedc4bbb0adea(contract review 6717305815 PASS, ACCEPT 6717291997)Fixes #31334State change:
pm:dispatchedremoved. Still open outside this card:FlowSchema@exampleinflow.zod.tsis filed as spec: the FlowSchema @example in flow.zod.ts compares a nullable record.amount unguarded on two edges (sibling of #31334) #31367.ui/SchemaForm test constant belongs to the UI lane and follows once docs(skills, spec): guard the nullable amount in the approval-flow and hook-condition examples #31322 lands.