Repository navigation
Description
repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2
Filing gate: executing a recorded ruling. On objectstack-ai/cloud#3619 (PR objectstack-ai/cloud#3633) the maintainer chose B for the boolean-default breach that contract review 6661416702 found. Their selection, verbatim: 「改选 B,#3633 等 spec」. The ruling record is on objectstack-ai/cloud#3619. This card is the spec half. objectstack-ai/cloud#3619 is pm:blocked on it.
Owner. The repo:cloud lane (repo:cloud#3, #30278) follows it to close. It widens a published schema (Clause-②: yes (widening)), so it is spec-lane work, and triage routes it. It takes the same route as #30430 (PR #30484, widget aggregate and view startDateField).
维护者速读
AI 搭建应用时,「是否完成 / 已付款」这类布尔字段本该默认「否」,cloud 的搭建指引也这么教(cloud#972 事故之后)。但蓝图的字段定义里没有 defaultValue,AI 写了也会被悄悄丢掉,新建记录时这个字段是空,不是「否」,按「否」筛选会漏掉这些记录。cloud#3633 要把「写了不认识的键」改成直接拒收,届时 AI 照指引写反而搭建失败。按裁决,给蓝图字段加一个可选的 defaultValue。
Measured
packages/spec/src/ai/solution-blueprint.zod.ts:109-126at objectstackorigin/maindeclares these keys onBlueprintFieldSchema:name,label,type,required,reference,options,summaryOperationsandexpression. It has nodefaultValue. The strict designer mirrorStrictField(:407) has the same keys.- Cloud's solution-design corpus (
packages/service-ai-studio/src/skills/solution-design-skill.ts,process-modelingrule, the 「CHECKBOX / 是否X FLAGS ARE NEVER REQUIRED」 bullet) tells every in-app build and every MCP client: "Write every 是否完成 / 已付款 / is_active-style flag as{ type:'boolean', defaultValue:false }". This follows the live failure cloud#972, where a required boolean refused the unchecked switch. - At cloud's pin
1a3ea0c0,SolutionBlueprintSchema.safeParsestripsdefaultValuewithsuccess: true, measured by the cloud#3619 dev. Cloud's applier setsdefaultValue: falseonly on a boolean sentrequired: true(relaxRequiredBooleans), so a flag written as the guidance says gets no default at all.
The ruled design
- Add an optional
defaultValueon the blueprint field, in the lenientBlueprintFieldSchemaand in the strict mirrorStrictField. The strict mirror needs a shape the designer's structured output can carry. The spec lane picks it, for example a scalar union or nullable, and states its choice. - The value is checked against the field's
type: a boolean takes a boolean, a number a number, a select one of its own option values, and so on. The spec lane decides which types admit a default at all. It refuses the rest by name rather than stripping them, and states that list in the describe. - The describe says the value becomes the built field's default. It also says the boolean-flag rule: a 是否X flag is never
requiredand defaults tofalse.
Acceptance
- Schema tests: a boolean with
defaultValue: falseparses; a type-mismatched value is refused; an absent value still parses (the key is optional); the strict mirror accepts what the lenient schema accepts for each admitted type. - A liveness ledger row for the new key, with its consumer named: the objectstack-ai/cloud#3619 cloud half, where cloud's applier carries it into the built field and the undeclared-key refusal admits it on the pin move. The row stays
planneduntil that lands. Clause-②: yes (widening), with the spec-lane contract review on record.
Dedupe (issues, open and closed, 2026-11-05): repo:objectstack-ai/objectstack blueprint field defaultValue is:issue returned 5 hits, all seat posts or unrelated (#6017, #21464, #6015, #12708, #20749). BlueprintFieldSchema default is:issue returned 3 hits, all closed and on other keys (#24198 option kind, #20827 select options, #24197 formula reference). None is on this slot.
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p1 ·
domain:spec· 2026-11-05T18:53Z⛔ Not a claim.
Clause-②: yes), so it is p1 under the standing rule that a protocol addition is p1 and takes the same route as spec: the blueprint dashboard widget has no aggregation slot, so an AI-built 「平均面试评分」 metric sums (908 instead of an average); add an optional aggregate (objectstack-ai/cloud#3607 row 2 ruling A) #30430 (PR feat(spec): blueprint dashboard widgets say how they aggregate, and calendar views which date field they schedule on #30484).repo:cloud#3follows it.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
Claim: PM loop round 5 (p1)
Session:
session_01L6bhgTqqeHSwZYJmApbDCaAccount:
os-salesBranch: the card thread's own
claude/project-thread-*branch (the measured platform exception toclaude/issue-30584-…), restated in a later claim once the thread opensWorktree:
objectstack-issue-30584Domain:
domain:specSeat:
domain:spec#3File surface:
packages/spec/src/ai/solution-blueprint.zod.ts:BlueprintFieldSchemaand its strict designer mirrorStrictField(:407) gain an optionaldefaultValue, type-checked against the field'stype.BlueprintFieldis a governed liveness type; the dev measures whether it is, and reports the carrier if it is not.content/docs/references/**, strictness-ledger rows), merged withbash scripts/pm/os-regen-merge.sh.@objectstack/specminor changeset.packages/runtimeor the build applier, and no existing key's shape or default moves.Container & model:
M,mode:thread,model: TIER_DEFAULT,effort: xhigh(p1)Clause-②: yes (widening) (expected; the dev measures)
Metadata-protocol: added (expected; the dev measures)
Responsibility: n/a. This executes a recorded ruling (objectstack-ai/cloud#3619, letter B: 「改选 B,#3633 等 spec」), not a defect.
Thread-read: 6666474709
Premise: holds at
origin/main14c67d44.BlueprintFieldSchema(:109-126) declaresname,label,type,required,reference,options,summaryOperationsandexpression, with nodefaultValue, so a blueprint that writes one has it stripped on parse.Design calls left to the dev by the ruling, each stated in the PR and judged by the contract review:
requiredand defaults tofalse).Serial constraints cleared: of the 33 open PRs (file lists read 20:08Z), none touches
solution-blueprint.zod.ts.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
Claim: PM loop round 5 (p1), restated with the branch
Session:
session_01L6bhgTqqeHSwZYJmApbDCaAccount:
os-salesBranch:
claude/project-thread-7e1clu. This is the card thread's own branch, a measured platform exception toclaude/issue-30584-…. Card thread session:session_01L6bhgUCEUicLCQ4tkXayK2.Worktree:
objectstack-issue-30584Domain:
domain:specSeat:
domain:spec#3File surface: unchanged from claim 6668086354.
Container & model:
M,mode:thread,model: TIER_DEFAULT,effort: xhighClause-②: yes (widening). This is expected, as claim 6668086354 says; the dev measures it.
Metadata-protocol: added. This is expected, as claim 6668086354 says; the dev measures it.
Responsibility: unchanged from claim 6668086354.
Thread-read: 6668086354
Premise: holds, as read on claim 6668086354.
Serial constraints cleared: unchanged from claim 6668086354.
Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgUCEUicLCQ4tkXayK2
os-dev-report
{ "issue": 30584, "status": "done", "branch": "claude/project-thread-7e1clu", "pr": "https://github.com/objectstack-ai/objectstack/pull/30655", "session": "session_01L6bhgUCEUicLCQ4tkXayK2", "premise_still_valid": true, "summary": "BlueprintFieldSchema and the strict mirror StrictField gain defaultValue, one scalar union boolean|number|string (lenient optional, strict nullable and required). The lenient field checks it against type with a superRefine that runs even after the union issue (when returns true) over a table keyed by every FieldType member: 21 types admitted and judged by FieldSchema's own literal contract checkLiteralDefaultValue (select/radio narrowed to the field's own option values, runtime tokens refused), the other 28 refused by name at the key, never stripped. Both describes state the admitted list and the boolean-flag rule. Premise measured at base 14c67d44: a boolean field's defaultValue false parsed success:true with the key stripped, on both schemas.", "tests": "spec full suite under os-verify-lock at 13a078c8: Test Files 817 passed (817), Tests 25750 passed | 1 todo (25751), VERDICT command-exit 0 (first run at 5d57ab6a: 1 red, scripts/dropped-refinements.test.ts expected 1023 read 1020, fixed by 13a078c8). src/ai/solution-blueprint.test.ts: 96 passed (96), 11 new cases plus defaultValue null on 7 strict fixtures. spec typecheck exit 0, check:test-typecheck OK 52 files / 240 errors / 131 signatures unchanged. packages/lint formula-one-hop test 13 passed (13). eslint on both changed source files exit 0. Ablation 1 via scripts/ablation-replace.mjs (superRefine detached, blob 16639542 to cdf6df65): Tests 5 failed | 91 passed (96). Ablation 2 (lenient key renamed, blob to f7c41b8f): Tests 9 failed | 87 passed (96). Both restored, blob == HEAD 16639542, git diff HEAD empty. Repro at base 14c67d44: boolean field defaultValue false parsed success true with the key stripped, both schemas.", "gates": "dispatch-gates --commands at 13a078c8: 102 derived families, each run with exit code written before any pipe; --ran reconciliation: 102 derived, 102 run, 0 NOT-MEASURED, 0 UNRUN, exit 0; all 102 exit 0. Six first exited 3 (built output missing: lint doc-formula-expressions, doc-security-posture, spec check:skill-examples, docs-transcript-drift, dual-build-cjs-loads, lean-entry-closure); after a full build (turbo build filter not docs, 118 successful of 118, exit 0, tree clean) all six reran exit 0. spec check:generated exit 0; check:liveness exit 0; check-adr-0087-registration --base origin/main exit 0 on the committed head. CI: running on PR head 13a078c8 at report time, not yet concluded; base main moved to b8929f48 since, git merge-tree clean and none of the 6 files touched.", "line_budget": "6 files, +421 / -9 (430 changed lines), under the 3000-line class (c) bound", "files_changed": [ "packages/spec/src/ai/solution-blueprint.zod.ts", "packages/spec/src/ai/solution-blueprint.test.ts", "packages/spec/dropped-refinements.baseline.json", "packages/spec/authorable-surface/ai.json", "content/docs/references/ai/solution-blueprint.mdx", ".changeset/30584-blueprint-field-default-value.md" ], "deviations": [ "Liveness: no ledger row. check:liveness at base 14c67d44 governs 43 types and no blueprint shape (a blueprint is never persisted and is not a metadata type), so the card's Acceptance row has no ledger to live in. Carrier for planned-until-cloud-lands: cloud#3619 / cloud#3633. The built field's defaultValue is governed by liveness/field.json props.defaultValue (live).", "dropped-refinements.baseline.json gains 3 hand-edited sites (ai/BlueprintField root, ai/BlueprintObject fields.element, ai/SolutionBlueprint objects.element.fields.element) and its droppedRefinementSites total 1020 to 1023: the ruled type check has no JSON Schema form (option membership reads a sibling key). Inside the claim's regenerated-artifacts surface in spirit, but the ledger is hand-edited by design, so named here.", "The brief's example admitted list names a checkbox type; FieldType has none. checkboxes is the multi-option type and is refused with the other list types.", "Harness branch claude/project-thread-7e1clu instead of claude/issue-30584-*; named by claim 6668151062." ], "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "4 — all reads: mcp__github__issue_read get #30584, mcp__github__issue_read get_comments #30584, mcp__github__pull_request_read get #30605, mcp__github__pull_request_read get #30655 (read-back). 0 MCP writes. Plus one session subscription to PR activity on #30655 (harness tool, not a GitHub write).", "api_writes": "2 — via the fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches carrying pr_create (#30655, read-back identical, 15217 bytes, no assignees, no labels, draft), and this os-dev-report issue comment on #30584 via post-stamped.mjs. git push x3 (not REST).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted, not filed — dropped-refinements.baseline.json measured header already stale at base: refinementSitesThatDidProject 369 vs the build's 714, zod 4.4.3 vs resolved 4.6.7; no test reads either field" ] }objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgUCEUicLCQ4tkXayK2
os-dev-report
{ "issue": 30584, "status": "done", "round": 1, "branch": "claude/project-thread-7e1clu", "pr": "https://github.com/objectstack-ai/objectstack/pull/30655", "head": "32b39007", "session": "session_01L6bhgUCEUicLCQ4tkXayK2", "premise_still_valid": true, "summary": "Round 1 of PR 30655, from contract review 6670092320 (PASS, one should-fix, adopted by the seat). refuseUnfitDefaultValue now runs the isRuntimeDefaultToken check before the type rule for every type: user plus current_user and date plus NOW() are refused as runtime tokens, a blueprint default being a literal, and on a type that takes no default the refusal says that type takes no defaultValue in a blueprint and ends Remove defaultValue from this field, never reading the type reason, which was false of a token. An admitted type keeps its message. Still refused, no token admitted. origin/main merged in with a merge commit (66a8822b), no conflict. Round 0: BlueprintFieldSchema and the strict mirror StrictField gain defaultValue, one scalar union boolean|number|string (lenient optional, strict nullable and required). The lenient field checks it against type with a superRefine that runs even after the union issue (when returns true) over a table keyed by every FieldType member: 21 types admitted and judged by FieldSchema's own literal contract checkLiteralDefaultValue (select/radio narrowed to the field's own option values, runtime tokens refused), the other 28 refused by name at the key, never stripped. Both describes state the admitted list and the boolean-flag rule. Premise measured at base 14c67d44: a boolean field's defaultValue false parsed success:true with the key stripped, on both schemas.", "tests": "Round 1 at 32b39007: src/ai/solution-blueprint.test.ts 97 passed (97), one new pin (user and lookup with current_user, date with NOW(), datetime with now(): one issue, token reason, ends Remove defaultValue from this field, never the type reason). spec full suite under the lock: Test Files 817 passed (817), Tests 25786 passed | 1 todo (25787), VERDICT command-exit 0. spec typecheck exit 0, check:test-typecheck OK 52 files / 240 errors / 131 signatures unchanged (first run without a raised heap died out of memory in tsc -p tsconfig.test.json, rerun with max-old-space-size 6144 green). eslint on both changed files exit 0; check-nul-bytes OK. Ablation 3 via scripts/ablation-replace.mjs (round-0 type-before-token block placed back ahead of the token check, anchor 1 to 0, blob b490c570 to 234c4bbe): Tests 1 failed | 96 passed (97), the new pin red; restored, blob == HEAD b490c570, git diff HEAD empty. Round 0 at 13a078c8: spec full suite under os-verify-lock at 13a078c8: Test Files 817 passed (817), Tests 25750 passed | 1 todo (25751), VERDICT command-exit 0 (first run at 5d57ab6a: 1 red, scripts/dropped-refinements.test.ts expected 1023 read 1020, fixed by 13a078c8). src/ai/solution-blueprint.test.ts: 96 passed (96), 11 new cases plus defaultValue null on 7 strict fixtures. spec typecheck exit 0, check:test-typecheck OK 52 files / 240 errors / 131 signatures unchanged. packages/lint formula-one-hop test 13 passed (13). eslint on both changed source files exit 0. Ablation 1 via scripts/ablation-replace.mjs (superRefine detached, blob 16639542 to cdf6df65): Tests 5 failed | 91 passed (96). Ablation 2 (lenient key renamed, blob to f7c41b8f): Tests 9 failed | 87 passed (96). Both restored, blob == HEAD 16639542, git diff HEAD empty. Repro at base 14c67d44: boolean field defaultValue false parsed success true with the key stripped, both schemas.", "gates": "Round 1 at 32b39007, after a post-merge full build (118 successful of 118, exit 0, tree clean): dispatch-gates --commands gives 102 derived families, the same list as round 0; each run with its exit code written before any pipe; --ran reconciliation: 102 derived, 102 run, 0 NOT-MEASURED, 0 UNRUN, exit 0; all 102 exit 0 on the first run. spec check:generated exit 0 (first run red only on the same out-of-memory). check-adr-0087-registration --base origin/main exit 0. CI on 32b39007: running at report time. CI on round-0 head 13a078c8: 65 check-runs, 57 success, 8 skipped, 0 failed. Round 0: dispatch-gates --commands at 13a078c8: 102 derived families, each run with exit code written before any pipe; --ran reconciliation: 102 derived, 102 run, 0 NOT-MEASURED, 0 UNRUN, exit 0; all 102 exit 0. Six first exited 3 (built output missing: lint doc-formula-expressions, doc-security-posture, spec check:skill-examples, docs-transcript-drift, dual-build-cjs-loads, lean-entry-closure); after a full build (turbo build filter not docs, 118 successful of 118, exit 0, tree clean) all six reran exit 0. spec check:generated exit 0; check:liveness exit 0; check-adr-0087-registration --base origin/main exit 0 on the committed head.", "line_budget": "6 files, +441 / -9 (450 changed lines) against merge base 66a8822b, under the 3000-line class (c) bound", "files_changed": [ "packages/spec/src/ai/solution-blueprint.zod.ts", "packages/spec/src/ai/solution-blueprint.test.ts", "packages/spec/dropped-refinements.baseline.json", "packages/spec/authorable-surface/ai.json", "content/docs/references/ai/solution-blueprint.mdx", ".changeset/30584-blueprint-field-default-value.md" ], "deviations": [ "Liveness: no ledger row. check:liveness at base 14c67d44 governs 43 types and no blueprint shape (a blueprint is never persisted and is not a metadata type), so the card's Acceptance row has no ledger to live in. Carrier for planned-until-cloud-lands: cloud#3619 / cloud#3633. The built field's defaultValue is governed by liveness/field.json props.defaultValue (live).", "dropped-refinements.baseline.json gains 3 hand-edited sites (ai/BlueprintField root, ai/BlueprintObject fields.element, ai/SolutionBlueprint objects.element.fields.element) and its droppedRefinementSites total 1020 to 1023: the ruled type check has no JSON Schema form (option membership reads a sibling key). Inside the claim's regenerated-artifacts surface in spirit, but the ledger is hand-edited by design, so named here.", "The brief's example admitted list names a checkbox type; FieldType has none. checkboxes is the multi-option type and is refused with the other list types.", "Harness branch claude/project-thread-7e1clu instead of claude/issue-30584-*; named by claim 6668151062.", "Round 1: the r1 PR body is a file for the seat (first line the seat signature, as ordered), not a PATCH from this session." ], "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "7 — all reads: mcp__github__issue_read get 30584, mcp__github__issue_read get_comments 30584, mcp__github__pull_request_read get 30605, mcp__github__pull_request_read get 30655, mcp__github__pull_request_read get_check_runs 30655 (twice), mcp__github__pull_request_read get_comments 30655. 0 MCP writes. Plus one session subscription to PR activity on 30655 (harness tool, not a GitHub write).", "api_writes": "3 — via the fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches carrying pr_create (30655), the round-0 os-dev-report comment 6669582413 on 30584, and this round-1 os-dev-report comment on 30584 via post-stamped.mjs. git push x4 (not REST). PR body r1 written to /mnt/project-files/briefs/30584-body-r1.md for the seat to send; not patched here.", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted, not filed — dropped-refinements.baseline.json measured header already stale at base: refinementSitesThatDidProject 369 vs the build's 714, zod 4.4.3 vs resolved 4.6.7; no test reads either field" ] }objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
ACCEPT → PR #30655 comment 6671021504 · head
32b39007ee649da8520bdcc92e212a81871da576. Contract review PASS twice (6670092320 on13a078c8, one should-fix landed in round 1; delta 6670989717). Handed to the merge queue withpr_ready+automerge_enableat 2026-11-05T22:20Z. Carried: cloud#3633 (the cloud applier that carries the value into the built field).Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
Landed: PR #30655 merged at
4bf9a2d7.defaultValue(boolean | number | string): optional onBlueprintFieldSchema, nullable on the strict mirror.BLUEPRINT_DEFAULT_VALUE_RULESadmits it on 21 field types and judges the value withFieldSchema's own literal contract. A select / radio default must be one of its own option values.NOW(),current_user) on any type, are refused by name at the field'sdefaultValueand are no longer silently stripped.is_activeflag is aboolean, neverrequired,defaultValue: false.origin/mainafter the mergegit merge-base --is-ancestor 4bf9a2d7 origin/main(tip4bf9a2d7e)git grepforBLUEPRINT_DEFAULT_VALUE_RULESinsolution-blueprint.zod.ts, and forai/BlueprintField:defaultValueinauthorable-surface/ai.jsonThe merge queue landed it at 2026-11-05T22:43:56Z. Its
Fixesline closed the card as completed. This seat removespm:dispatchedin the same stroke. Carried: cloud#3633, the cloud applier that carries the value into the built object field; the server half of ruling B lives there.Generated by Claude Code