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
spec: minLength still has the pre-#11566 defect pair — validated as no more than a number, authorable on every field type #11949
Found while implementing #11566 (maxLength tightening). Filed unassigned — scope discipline kept it out of that PR, and the correct shape is a judgment call, not mechanical extrapolation.
What
packages/spec/src/data/field.zod.ts still declares:
minLength: z.number().optional().describe('Min character length'),
on the base field schema — the exact defect pair #11566 was ruled on for maxLength:
Authorable on every type.boolean, lookup, autonumber, … accept it; the write-time validator (packages/objectql/src/validation/record-validator.ts) enforces it only on the same ten bounded-string types as maxLength (now exported as BOUNDED_STRING_FIELD_TYPES).
The #11566 ruling (comment on that card, 2026-08-24) is the natural template: shape z.number().int().min(0 or 1) + applicability BOUNDED_STRING_FIELD_TYPES + both form rows aligned. The one open question is the lower bound (0 = explicit no-op allowed, 1 = a no-op declaration is refused).
Triage: → needs-user-decision + domain:spec, Bug — the defect pair is #11566's twin (no shape validation + authorable everywhere), but the filer is right that it is not a mechanical rider: minLength: 0 has a defined meaning ("no minimum"), so the lower bound is a genuine contract fork #11566's ruling does not cover. Everything else inherits the #11566 template (shape + BOUNDED_STRING_FIELD_TYPES applicability + both form rows converged).
① 项目长远合理性:与 maxLength 同模板收敛(shape + 适用类型 + 两张表单行)是缩小特例;唯一分叉在下界 —— 允许 minLength: 0 就是允许一个永真的空声明留在契约面上。
② 实际业务拉动:今天作者可以在 boolean/lookup 上声明 minLength、可以写 -5/2.5,运行时静默不兑现 —— 撞上的是「声明了却不生效」,与 maxLength 同一类客户困惑。
③ 防 AI 犯错:minLength: 0 是 AI 批量生成元数据时最容易顺手写出的无效声明;响亮拒绝(min(1))让它在编写期就炸,放行(min(0))则永远静默 —— 声明即强制的立场倾向拒绝。
④ 创业阶段不扩散:两案成本几乎相同,差别只在拒绝集边界;选 min(1) 不新增任何维护义务,选 min(0) 则要给「合法但永真」的值写一行解释。
推荐:B = z.number().int().min(1)(0 视为无声明,响亮拒绝,与 maxLength 同姿态);A = .min(0)(显式允许无操作声明)。回一个字母即可。
置信缺口:未 sweep 存量语料/生成器今天是否有 minLength: 0 的实际产出 —— 若有,B 需先带清扫面;裁前建议让 dev 先跑一遍语料 grep 作为前提验证。
Maintainer ruling — B: z.number().int().min(1); zero is refused, the #11566 template applies in full
Source: maintainer, 2026-08-25, live PM chat (decision-inbox batch 8 review, session session_01KWRU3s15AJz7PGW7a7wdCh), verbatim: 「同意」 — accepting the batch's presented recommendation for this card: B.
The lower bound is 1: minLength: 0 is refused loudly — "no minimum" is expressed by omitting the key, not by declaring a vacuous truth. Same posture as maxLength; a permanently-true declaration is exactly the noise an AI metadata author mass-produces, and the refusal surfaces it at authoring time.
Pre-step from the stated confidence gap: grep the corpus and generators for any existing minLength: 0 (and negative/fractional) output before landing. In-repo occurrences ride the PR as cleanup; if a shipped, customer-facing generator emits minLength: 0, ⛔ stop and fork back here rather than breaking it silently.
Interaction note from #11875 (signature/qrcode joined the bounded-string family, maintainer ruling 2026-08-25): the write-time validator's string branch now reads the spec's BOUNDED_STRING_FIELD_TYPES directly instead of a hand-copied type list (record-validator.ts), and the set itself gained signature / qrcode. Two consequences for this card:
the applicability half of a minLength tightening no longer needs a validator-side list edit — converging minLength on the same set is now one superRefine in field.zod.ts, and enforcement follows automatically (the branch already applies min_length to every set member, the two new types included);
whatever set this card's ruling lands on, it is twelve members today, not the ten quoted in the card body.
The two authoring-form minLength rows (3 types in field.form.ts, 9 in object.form.ts) remain unaligned and are untouched by #11875 — deliberately, since the ruled scope there covered maxLength only.
Claim: PM loop round R6 (wave 2)
Session: session_01NDGG54XF5gbTLdQzCtnaVV
Branch: claude/issue-11949-minlength-defect-pair
Worktree: objectstack-issue-11949
Domain: domain:spec
File surface: packages/spec/src/data/field.zod.ts (minLength region) + field.form.ts / object.form.ts (minLength rows only) + two migrations semantic shards (this card's minLength entry + #11950's deferred maxLength entry) + regenerated migrations registry + tests + changeset (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: claude-fable-5 — dispatch-gates 2026-08-25 @8619f95: "no path-derived mandate … The tier stays the PM's per-card judgment call (floor sonnet · default opus · ceiling fable)"; clause-② content leg (accept/reject changes — previously-parsing declarations now refuse, per the recorded ruling) ⇒ fable mandatory
Clause-②: yes
Serial constraints cleared: FAMILY DISPATCH — #11950 folded under this chain head (five gates: ① twin Length-constraint defect family, same #11566/#8321 template ✓ ② same package/region — field.zod.ts + migrations ✓ ③ both adjudicated: this card ruled B 2026-08-25 「同意」, #11950's registration mandated by the #11566 closure ✓ ④ independently checkable: one Fixes line and one commit per member, per-member criteria ✓ ⑤ exclusions — NOT in this family: #11875 (landed), any form row beyond minLength/maxLength, numeric min/max keys, #11805 defaultSort, #12055 ratchet sweep). Migrations writers: sole in this batch; prior writer PR #12114 MERGED 09:58Z; PR #12120 (draft, objection window) carries a different semantic shard — re-merge main if it lands first. H17: field.zod.ts is on-hold #8345's Restart-touch — notification posted on that card per its precedent, no rider taken. Sibling pin note: #11875 landed (validator now reads BOUNDED_STRING_FIELD_TYPES directly, set = 12 members) — carried into the dispatch as a constraint, not a pin.
{
"issue": 11949,
"status": "done",
"branch": "claude/issue-11949-minlength-defect-pair",
"pr": "https://github.com/objectstack-ai/objectstack/pull/12191",
"premise_still_valid": true,
"family": {
"chain_head": 11949,
"members": [
{
"issue": 11949,
"commit": "f081ac6",
"fixes_line": "Fixes #11949",
"premise_still_valid": true,
"files_changed": [
"packages/spec/src/data/field.zod.ts",
"packages/spec/src/data/field.form.ts",
"packages/spec/src/data/object.form.ts",
"packages/spec/src/data/field.test.ts",
"packages/lint/src/validate-predicate-path-refs.test.ts",
"packages/spec/src/migrations/entries/semantic/18.field-min-length-malformed-or-misplaced-refused.ts",
"packages/spec/src/migrations/registry.ts",
"content/docs/references/data/field.mdx",
".changeset/minlength-bounded-string-only.md"
]
},
{
"issue": 11950,
"commit": "d15c716",
"fixes_line": "Fixes #11950",
"premise_still_valid": true,
"files_changed": [
"packages/spec/src/migrations/entries/semantic/18.field-max-length-malformed-or-misplaced-refused.ts",
"packages/spec/src/migrations/registry.ts",
".changeset/maxlength-adr0087-ledger-entry.md"
]
}
],
"chain_commits_beyond_members": [
"0aa141a merge origin/main (post-#11875 twelve-member set), semantic resolution stacking both intents",
"1f68923 regen (registry + field.mdx) discharging the os-regen deferral",
"5f50d3e merge origin/main (no overlap with this diff)"
]
},
"summary": "Member 1 (#11949): minLength tightened per ruling B — z.number().int().min(1) (0 refused; 'no minimum' = omit the key), applicability refused outside BOUNDED_STRING_FIELD_TYPES via a superRefine twin of maxLength's reading the exported set, both form rows aligned to the set, D3 semantic entry + changeset (adr-0087: registered). Ruled pre-step: corpus/generator grep for minLength 0/negative/fractional — zero hits repo-wide, stop condition did not fire, no cleanup rides. Member 2 (#11950): the deferred #11566 maxLength ADR-0087 entry registered as major-18 D3 semantic shard per the #8321 template, semantics authoritative to PR #11989's actual diff; no D2 conversion, accept surface untouched (Clause-② no re-affirmed). #12119 (#11875) landed mid-flight: merged and converged minLength on the twelve-member set exactly as that PR moved maxLength.",
"tests": "spec full suite at merged tree 1f68923 (spec surface byte-identical at final head 5f50d3e): 'Test Files 426 passed (426) / Tests 11362→11364 passed' (pre-merge run 426/11362 also green); spec typecheck green (same lock run, command-exit 0); field.test.ts targeted run 199 passed pre-merge incl. the 15 new tests (0/-5/12.5 refusals asserting path+code+message; wrong-type refusals; byte-identical round-trip minLength:2→2 across the set; minLength:1 pin; absence pin) and +1 (color) post-merge; objectql record-validator.test.ts 92 passed; lint validate-predicate-path-refs.test.ts 54 passed with census equality re-derived 44→41; migrations.test.ts 105 passed at the member-2 tree. All heavy runs via scripts/pm/os-verify-lock.sh; verdicts read from the wrapper's VERDICT lines, not piped $?.",
"gates": "Union at final head 5f50d3e (re-run after the last merge; dispatch-gates.mjs derivation stderr stamps 'objectstack-ai/objectstack at commit 1f68923', re-run identical at 5f50d3e): 28/28 green — changeset-gate-self-tests, cross-package-test-inputs, doc-anchors, doc-authoring, doc-formula-expressions, doc-security-posture, docs-audit-scope, docs-redirects, empty-state, liveness, merge-driver, objectui-changeset, published-files, published-readme-links, query-options-erasure, quick-reference-counts, react-page-adapter-contract, role-word, slot-lookup, spec-parsed-alias, strictness-ledger, test-source-alias, type-source-resolution, variant-docs, adr-0087-registration ('registered' ids resolve, new in diff), changeset-no-major, nul-bytes, ci-filter-parity ('OK: all 96 declared cross-package glob(s)…' — runnable spelling is node scripts/check-ci-filter-parity.mjs; the pnpm script name in my batch script was a nonexistent spelling and that one FAIL line is the wrong-name probe, not a red gate). check:generated at 5f50d3e: '✓ All 14 generated artifacts are up to date.' Newly derived beyond the PM list (docs riders of field.mdx): doc-anchors, doc-authoring, doc-security-posture, docs-audit-scope, docs-redirects, objectui-changeset, published-readme-links, quick-reference-counts, react-page-adapter-contract, role-word, changeset-no-major — all run and green.",
"line_budget": "no skills/** diff (skills/objectstack-data/rules/field-types.md verified consistent with the ruling — documents minLength only on text/textarea/password, all in-set), so no line budget owed",
"deviations": [
"Interaction-note premise (#11949 comment 5408644743) was not yet true at branch base 577fabf: #11875 NOT landed, set was 10 members, record-validator still hand-coded its list. Implemented set-driven; #12119 then landed mid-flight and the merge converged minLength on the twelve exactly as that PR moved maxLength (forms, describe, set-derived superRefine message, tests +color/twelve).",
"packages/lint/src/validate-predicate-path-refs.test.ts edited beyond the dispatch's literal file surface — the RHS census consumes the shipped forms corpus (consumption-radius rule; exact #11989 precedent), re-derived 44→41.",
"#11950 card wording 'nothing ever enforced the malformed value' measured false for malformed values on bounded-string types (validator's raw comparison consumed them; maxLength:0 = empty-only, negative = unwritable); both ledger entries state the measured split — misplaced = inert mechanical delete, malformed-on-bounded = judgment/re-declare. PR body flags the correction.",
"content/docs/references/data/field.mdx regenerated (check:docs artifact of the describe change) — generated rider, not a hand edit.",
"REST channel unavailable in this container (api.github.com → proxy 403 'GitHub access is not enabled for this session', measured with and without auth header) — issue reads/writes and PR creation went through the GitHub MCP tools (issue_read/add_issue_comment/issue_write/create_pull_request only; no MCP list/search calls). The #12174 dedup sweep was therefore local-grep only, flagged in that card.",
"Report comment first line uses the literal 'os-dev-report' spelling per the dispatch (the HTML-marker form is measured-eaten by the sanitizer, and this container has no comment-edit channel to repair it post-hoc)."
],
"open_questions": [],
"out_of_scope_findings": [
"filed as #12174: ui FormFieldBaseSchema (view.zod.ts) minLength/maxLength + min/max/precision/scale still bare z.number().optional() — the pre-#11566 shape one surface over; readers unmeasured, so template-vs-enforce-or-remove needs triage"
]
}
Checklist conclusion (verified against GitHub + local branch diff): draft ✓ · base main ✓ · TWO Fixes lines, one commit per member ✓ · 11 files +362/−12 exactly matching the per-member manifests ✓ · branch spot-read: minLength: z.number().int().min(1).optional() with the twelve-type set named in the describe — ruling B to the letter ✓ · applicability superRefine reads the exported set (post-#11875/#12119 convergence handled mid-flight with the timeline documented) ✓ · both form rows aligned to the set ✓ · refusal envelopes assert path+code+message for 0/−5/12.5 plus ten wrong-type representatives; byte-identical round-trips and absence pins present ✓ · ruled pre-step ran and the stop condition did NOT fire (zero malformed hits repo-wide; placement triage documented per occurrence, including the export-format fixture correctly left outside the consumption radius) ✓ · both D3 shards + regenerated registry; adr-0087: registered gate-verdicted ✓ · H17: zero currency surface ✓ · no governed path ✓.
Deviations reviewed and accepted: the lint census file beyond the literal surface (consumption-radius rule, exact #11989 precedent, declared); the interaction-note premise being false at base and converged mid-flight (correct handling, not drift); and — the substantive one — the #11950 card wording "nothing ever enforced the malformed value" measured HALF false: malformed values on bounded-string types WERE consumed by the raw comparison (maxLength: 0 = empty-only; negative = unwritable). The ledger entries state the measured split (misplaced = inert mechanical delete; malformed-on-bounded = judgment/re-declare), which is exactly why their deletion is not sold as behaviour-preserving. Dev correcting the card in the artifact of record is the intended shape. Out-of-scope finding #12174 verified filed with an honest dedup-gap note.
Contract review (clause-② content leg on the chain head; member #11950 re-affirmed no — registration only, commit 2 moves no accept/reject): fuse reading get_session.external_metadata.last_served_model = claude-fable-5 = CONTRACT_REVIEW_TIER (this seat, self-dispatched-card path). Verdict: PASS — the narrowing lands the ruled shape exactly, the migration prescriptions carry the measured semantics, and the twelve-member landing truth vs the ten-member historical truth are kept distinct per entry. Clearing needs:contract-review both carriers in this write batch.
Next: ready + merge queue once EVERY check is green (CI started 12:22 — flip rides the next check-in).
Activity
claude commentedon Aug 25, 2026
Triage: →
needs-user-decision+domain:spec, Bug — the defect pair is #11566's twin (no shape validation + authorable everywhere), but the filer is right that it is not a mechanical rider:minLength: 0has a defined meaning ("no minimum"), so the lower bound is a genuine contract fork #11566's ruling does not cover. Everything else inherits the #11566 template (shape +BOUNDED_STRING_FIELD_TYPESapplicability + both form rows converged).① 项目长远合理性:与 maxLength 同模板收敛(shape + 适用类型 + 两张表单行)是缩小特例;唯一分叉在下界 —— 允许
minLength: 0就是允许一个永真的空声明留在契约面上。② 实际业务拉动:今天作者可以在 boolean/lookup 上声明
minLength、可以写-5/2.5,运行时静默不兑现 —— 撞上的是「声明了却不生效」,与 maxLength 同一类客户困惑。③ 防 AI 犯错:
minLength: 0是 AI 批量生成元数据时最容易顺手写出的无效声明;响亮拒绝(min(1))让它在编写期就炸,放行(min(0))则永远静默 —— 声明即强制的立场倾向拒绝。④ 创业阶段不扩散:两案成本几乎相同,差别只在拒绝集边界;选 min(1) 不新增任何维护义务,选 min(0) 则要给「合法但永真」的值写一行解释。
推荐:B =
z.number().int().min(1)(0 视为无声明,响亮拒绝,与 maxLength 同姿态);A =.min(0)(显式允许无操作声明)。回一个字母即可。置信缺口:未 sweep 存量语料/生成器今天是否有
minLength: 0的实际产出 —— 若有,B 需先带清扫面;裁前建议让 dev 先跑一遍语料 grep 作为前提验证。Generated by Claude Code
os-support-ai commentedon Aug 25, 2026
Maintainer ruling — B:
z.number().int().min(1); zero is refused, the #11566 template applies in fullSource: maintainer, 2026-08-25, live PM chat (decision-inbox batch 8 review, session
session_01KWRU3s15AJz7PGW7a7wdCh), verbatim: 「同意」 — accepting the batch's presented recommendation for this card: B.minLengthconverges on the spec:maxLengthis authorable on every field type and validated as no more than a number —maxLength: 0andmaxLength: 12.5parse cleanly #11566 template exactly: shapez.number().int().min(1), applicability restricted toBOUNDED_STRING_FIELD_TYPES, both authoring forms' rows aligned (field.form.ts,object.form.ts).minLength: 0is refused loudly — "no minimum" is expressed by omitting the key, not by declaring a vacuous truth. Same posture asmaxLength; a permanently-true declaration is exactly the noise an AI metadata author mass-produces, and the refusal surfaces it at authoring time.minLength: 0(and negative/fractional) output before landing. In-repo occurrences ride the PR as cleanup; if a shipped, customer-facing generator emitsminLength: 0, ⛔ stop and fork back here rather than breaking it silently.Discipline: Clause-② yes (accept/reject behaviour changes — previously-parsing declarations now refuse);
CONTRACT_REVIEW_TIER; spec seat.State:
needs-user-decision→pm:queuein the same write;domain:specstands.Generated by Claude Code
os-warren commentedon Aug 25, 2026
Interaction note from #11875 (signature/qrcode joined the bounded-string family, maintainer ruling 2026-08-25): the write-time validator's string branch now reads the spec's
BOUNDED_STRING_FIELD_TYPESdirectly instead of a hand-copied type list (record-validator.ts), and the set itself gainedsignature/qrcode. Two consequences for this card:minLengthon the same set is now one superRefine infield.zod.ts, and enforcement follows automatically (the branch already appliesmin_lengthto every set member, the two new types included);The two authoring-form
minLengthrows (3 types infield.form.ts, 9 inobject.form.ts) remain unaligned and are untouched by #11875 — deliberately, since the ruled scope there coveredmaxLengthonly.Generated by Claude Code
os-litant commentedon Aug 25, 2026
Claim: PM loop round R6 (wave 2)
Session:
session_01NDGG54XF5gbTLdQzCtnaVVBranch:
claude/issue-11949-minlength-defect-pairWorktree:
objectstack-issue-11949Domain:
domain:specFile surface:
packages/spec/src/data/field.zod.ts(minLength region) +field.form.ts/object.form.ts(minLength rows only) + two migrations semantic shards (this card's minLength entry + #11950's deferred maxLength entry) + regenerated migrations registry + tests + changeset (stop on breach; explain in the report)Container & model: M,
mode:subagent,model: claude-fable-5— dispatch-gates 2026-08-25 @8619f95: "no path-derived mandate … The tier stays the PM's per-card judgment call (floor sonnet · default opus · ceiling fable)"; clause-② content leg (accept/reject changes — previously-parsing declarations now refuse, per the recorded ruling) ⇒ fable mandatoryClause-②: yes
Serial constraints cleared: FAMILY DISPATCH — #11950 folded under this chain head (five gates: ① twin Length-constraint defect family, same #11566/#8321 template ✓ ② same package/region — field.zod.ts + migrations ✓ ③ both adjudicated: this card ruled B 2026-08-25 「同意」, #11950's registration mandated by the #11566 closure ✓ ④ independently checkable: one
Fixesline and one commit per member, per-member criteria ✓ ⑤ exclusions — NOT in this family: #11875 (landed), any form row beyond minLength/maxLength, numeric min/max keys, #11805 defaultSort, #12055 ratchet sweep). Migrations writers: sole in this batch; prior writer PR #12114 MERGED 09:58Z; PR #12120 (draft, objection window) carries a different semantic shard — re-merge main if it lands first. H17:field.zod.tsis on-hold #8345's Restart-touch — notification posted on that card per its precedent, no rider taken. Sibling pin note: #11875 landed (validator now reads BOUNDED_STRING_FIELD_TYPES directly, set = 12 members) — carried into the dispatch as a constraint, not a pin.Generated by Claude Code
fix(spec): minLength is a positive integer, authorable only on bounde…
os-litant commentedon Aug 25, 2026
os-dev-report
{ "issue": 11949, "status": "done", "branch": "claude/issue-11949-minlength-defect-pair", "pr": "https://github.com/objectstack-ai/objectstack/pull/12191", "premise_still_valid": true, "family": { "chain_head": 11949, "members": [ { "issue": 11949, "commit": "f081ac6", "fixes_line": "Fixes #11949", "premise_still_valid": true, "files_changed": [ "packages/spec/src/data/field.zod.ts", "packages/spec/src/data/field.form.ts", "packages/spec/src/data/object.form.ts", "packages/spec/src/data/field.test.ts", "packages/lint/src/validate-predicate-path-refs.test.ts", "packages/spec/src/migrations/entries/semantic/18.field-min-length-malformed-or-misplaced-refused.ts", "packages/spec/src/migrations/registry.ts", "content/docs/references/data/field.mdx", ".changeset/minlength-bounded-string-only.md" ] }, { "issue": 11950, "commit": "d15c716", "fixes_line": "Fixes #11950", "premise_still_valid": true, "files_changed": [ "packages/spec/src/migrations/entries/semantic/18.field-max-length-malformed-or-misplaced-refused.ts", "packages/spec/src/migrations/registry.ts", ".changeset/maxlength-adr0087-ledger-entry.md" ] } ], "chain_commits_beyond_members": [ "0aa141a merge origin/main (post-#11875 twelve-member set), semantic resolution stacking both intents", "1f68923 regen (registry + field.mdx) discharging the os-regen deferral", "5f50d3e merge origin/main (no overlap with this diff)" ] }, "summary": "Member 1 (#11949): minLength tightened per ruling B — z.number().int().min(1) (0 refused; 'no minimum' = omit the key), applicability refused outside BOUNDED_STRING_FIELD_TYPES via a superRefine twin of maxLength's reading the exported set, both form rows aligned to the set, D3 semantic entry + changeset (adr-0087: registered). Ruled pre-step: corpus/generator grep for minLength 0/negative/fractional — zero hits repo-wide, stop condition did not fire, no cleanup rides. Member 2 (#11950): the deferred #11566 maxLength ADR-0087 entry registered as major-18 D3 semantic shard per the #8321 template, semantics authoritative to PR #11989's actual diff; no D2 conversion, accept surface untouched (Clause-② no re-affirmed). #12119 (#11875) landed mid-flight: merged and converged minLength on the twelve-member set exactly as that PR moved maxLength.", "tests": "spec full suite at merged tree 1f68923 (spec surface byte-identical at final head 5f50d3e): 'Test Files 426 passed (426) / Tests 11362→11364 passed' (pre-merge run 426/11362 also green); spec typecheck green (same lock run, command-exit 0); field.test.ts targeted run 199 passed pre-merge incl. the 15 new tests (0/-5/12.5 refusals asserting path+code+message; wrong-type refusals; byte-identical round-trip minLength:2→2 across the set; minLength:1 pin; absence pin) and +1 (color) post-merge; objectql record-validator.test.ts 92 passed; lint validate-predicate-path-refs.test.ts 54 passed with census equality re-derived 44→41; migrations.test.ts 105 passed at the member-2 tree. All heavy runs via scripts/pm/os-verify-lock.sh; verdicts read from the wrapper's VERDICT lines, not piped $?.", "gates": "Union at final head 5f50d3e (re-run after the last merge; dispatch-gates.mjs derivation stderr stamps 'objectstack-ai/objectstack at commit 1f68923', re-run identical at 5f50d3e): 28/28 green — changeset-gate-self-tests, cross-package-test-inputs, doc-anchors, doc-authoring, doc-formula-expressions, doc-security-posture, docs-audit-scope, docs-redirects, empty-state, liveness, merge-driver, objectui-changeset, published-files, published-readme-links, query-options-erasure, quick-reference-counts, react-page-adapter-contract, role-word, slot-lookup, spec-parsed-alias, strictness-ledger, test-source-alias, type-source-resolution, variant-docs, adr-0087-registration ('registered' ids resolve, new in diff), changeset-no-major, nul-bytes, ci-filter-parity ('OK: all 96 declared cross-package glob(s)…' — runnable spelling is node scripts/check-ci-filter-parity.mjs; the pnpm script name in my batch script was a nonexistent spelling and that one FAIL line is the wrong-name probe, not a red gate). check:generated at 5f50d3e: '✓ All 14 generated artifacts are up to date.' Newly derived beyond the PM list (docs riders of field.mdx): doc-anchors, doc-authoring, doc-security-posture, docs-audit-scope, docs-redirects, objectui-changeset, published-readme-links, quick-reference-counts, react-page-adapter-contract, role-word, changeset-no-major — all run and green.", "line_budget": "no skills/** diff (skills/objectstack-data/rules/field-types.md verified consistent with the ruling — documents minLength only on text/textarea/password, all in-set), so no line budget owed", "deviations": [ "Interaction-note premise (#11949 comment 5408644743) was not yet true at branch base 577fabf: #11875 NOT landed, set was 10 members, record-validator still hand-coded its list. Implemented set-driven; #12119 then landed mid-flight and the merge converged minLength on the twelve exactly as that PR moved maxLength (forms, describe, set-derived superRefine message, tests +color/twelve).", "packages/lint/src/validate-predicate-path-refs.test.ts edited beyond the dispatch's literal file surface — the RHS census consumes the shipped forms corpus (consumption-radius rule; exact #11989 precedent), re-derived 44→41.", "#11950 card wording 'nothing ever enforced the malformed value' measured false for malformed values on bounded-string types (validator's raw comparison consumed them; maxLength:0 = empty-only, negative = unwritable); both ledger entries state the measured split — misplaced = inert mechanical delete, malformed-on-bounded = judgment/re-declare. PR body flags the correction.", "content/docs/references/data/field.mdx regenerated (check:docs artifact of the describe change) — generated rider, not a hand edit.", "REST channel unavailable in this container (api.github.com → proxy 403 'GitHub access is not enabled for this session', measured with and without auth header) — issue reads/writes and PR creation went through the GitHub MCP tools (issue_read/add_issue_comment/issue_write/create_pull_request only; no MCP list/search calls). The #12174 dedup sweep was therefore local-grep only, flagged in that card.", "Report comment first line uses the literal 'os-dev-report' spelling per the dispatch (the HTML-marker form is measured-eaten by the sanitizer, and this container has no comment-edit channel to repair it post-hoc)." ], "open_questions": [], "out_of_scope_findings": [ "filed as #12174: ui FormFieldBaseSchema (view.zod.ts) minLength/maxLength + min/max/precision/scale still bare z.number().optional() — the pre-#11566 shape one surface over; readers unmeasured, so template-vs-enforce-or-remove needs triage" ] }Generated by Claude Code
os-litant commentedon Aug 25, 2026
ACCEPT (family: #11949 + #11950) — PR #12191 (R6 W2, reviewer of record: spec seat, session
session_01NDGG54XF5gbTLdQzCtnaVV).Checklist conclusion (verified against GitHub + local branch diff): draft ✓ · base
main✓ · TWOFixeslines, one commit per member ✓ · 11 files +362/−12 exactly matching the per-member manifests ✓ · branch spot-read:minLength: z.number().int().min(1).optional()with the twelve-type set named in the describe — ruling B to the letter ✓ · applicability superRefine reads the exported set (post-#11875/#12119 convergence handled mid-flight with the timeline documented) ✓ · both form rows aligned to the set ✓ · refusal envelopes assert path+code+message for 0/−5/12.5 plus ten wrong-type representatives; byte-identical round-trips and absence pins present ✓ · ruled pre-step ran and the stop condition did NOT fire (zero malformed hits repo-wide; placement triage documented per occurrence, including the export-format fixture correctly left outside the consumption radius) ✓ · both D3 shards + regenerated registry;adr-0087: registeredgate-verdicted ✓ · H17: zero currency surface ✓ · no governed path ✓.Deviations reviewed and accepted: the lint census file beyond the literal surface (consumption-radius rule, exact #11989 precedent, declared); the interaction-note premise being false at base and converged mid-flight (correct handling, not drift); and — the substantive one — the #11950 card wording "nothing ever enforced the malformed value" measured HALF false: malformed values on bounded-string types WERE consumed by the raw comparison (
maxLength: 0= empty-only; negative = unwritable). The ledger entries state the measured split (misplaced = inert mechanical delete; malformed-on-bounded = judgment/re-declare), which is exactly why their deletion is not sold as behaviour-preserving. Dev correcting the card in the artifact of record is the intended shape. Out-of-scope finding #12174 verified filed with an honest dedup-gap note.Contract review (clause-② content leg on the chain head; member #11950 re-affirmed no — registration only, commit 2 moves no accept/reject): fuse reading
get_session.external_metadata.last_served_model = claude-fable-5=CONTRACT_REVIEW_TIER(this seat, self-dispatched-card path). Verdict: PASS — the narrowing lands the ruled shape exactly, the migration prescriptions carry the measured semantics, and the twelve-member landing truth vs the ten-member historical truth are kept distinct per entry. Clearingneeds:contract-reviewboth carriers in this write batch.Next: ready + merge queue once EVERY check is green (CI started 12:22 — flip rides the next check-in).
Generated by Claude Code
fix(spec): minLength is a positive integer, authorable only on bounde…
fix(spec): os migrate meta guidance for the ui-* and plugin-* migrati…
test(spec): the second data/ file group's test titles state each cite…