Repository navigation
apps/console FormPage.buildSections renders an EMPTY section for a spec-legal sections[].group — the third form-section consumer, untouched by objectui#7051 #8641
Description
Found while implementing objectui#7051 (the form.sections[].group reference form on @object-ui/plugin-form). Filed rather than fixed there: it is a different package, a different renderer, and a different code path, so it is out of that card's scope.
What was measured
@objectstack/spec 17.3.0 declares group on FormSectionSchema — a section may point at one of the object's declared fieldGroups instead of enumerating fields (objectstack#13855, ADR-0085 §5). Measured against the installed package on origin/main:
FormSectionSchema.safeParse({ group: 'contact_info' })
-> ACCEPT { collapsible: false, collapsed: false, columns: 1, group: 'contact_info' }
apps/console/src/components/FormPage.tsx has its own section builder, independent of @object-ui/plugin-form:
export function buildSections(form: FormViewSpec, objectSchema: ObjectSchemaPayload | null): RenderableSection[] {
const sections = form.sections ?? form.groups ?? [];
...
for (const entry of sec.fields ?? []) { ... } // a { group } section has no `fields`
...
return { label: sec.label, ..., fields }; // a { group } section has no `label` either
}So a spec-legal { group: 'contact_info' } section reaches this builder and produces a section with no label and no fields — it renders nothing, reports nothing, and the members the group declares are simply absent from the console's form page. This is the same silent-drop class objectui#7051 fixed on the plugin-form chain, on the third consumer.
sec.fields ?? [] cannot produce rows for a section that carries no fields), not by a DOM measurement of the console page. Whoever takes this should reproduce it first — that is cheap here and the reproduction is the acceptance evidence.
Why it is not the same fix
FormPage is not a plugin-form container: it does not go through ObjectForm's dispatcher (where objectui#7051 resolves the reference, once, above the routing fork), and the resolver packages/plugin-form/src/sectionGroups.ts is package-internal — it is not exported from @object-ui/plugin-form's public surface. So the options are a deliberate choice, not a mechanical copy:
- A. Export the resolver from
@object-ui/plugin-formand call it frombuildSections— one assembler, one behaviour, at the cost of a new published export (andcheck-readme-exportsfollows an export). - B. Have
buildSectionscallderiveFieldGroupLayout(ADR-0085 §5) itself. Still the single upstream assembler, no new published surface, but a second adapter onto a section shape. - C. Leave it, and record the divergence deliberately —
FormPageis a reference-app renderer, not the published one.
⛔ Whatever is chosen, no assembly rule (declared order, empty-group drop, ungrouped trailing bucket, collapse/visibleWhen passthrough) may be re-implemented on the objectui side — that is objectui#7051's and objectstack#13855's standing constraint.
Non-regression axis for whoever takes it
⭐ Not "the form renders" and not "the section is non-empty" — both pass on a builder that drops every group-referenced section, which is today's behaviour. The discriminating assertion is that a group-referenced section renders the members that group declares, asserted against concrete field identifiers, with a second section referencing a different group so a constant-resolution caricature cannot satisfy both.
Refs
- objectui#7051 — the
plugin-formhalf (this finding's parent measurement) - objectui#8497 / PR fix(plugin-detail): implement
sections[].group, bound a section's blast radius, and resolve enumerated field labels through the declaredlabel#8584 — therecord:detailshalf - objectstack#13855 — the spec form and its ruled design
- Measured and filed by a Claude Code session while implementing objectui#7051 (https://claude.ai/code).
Generated by Claude Code
Activity
os-justin commentedon Sep 9, 2026
Claim: session
session_01YBWFb5YgMU5dw8p2VKj16S· branchclaude/issue-8641-console-formpage-section-groupPM dispatch (
domain:uiseat). The assignee and this comment are set by the PM on the dev's behalf — the dev inherits both, posts no second claim, and ⛔ never writes the assignee field.⭐ The blocker is gone — objectui#7051 landed while this card waited
PR #8644 merged (
a29ae2d66onmain). Sopackages/plugin-form/src/sectionGroups.ts— the resolver this card's options A and B both point at — exists onmainnow, and the reference implementation you must not diverge from is readable rather than hypothetical.ObjectForm's routing fork, so all six layouts inherit it, and it routes throughderiveFieldGroupLayout(ADR-0085 §5) via the package's existing single adapter — "no assembly rule is re-implemented on this side." That sentence is the constraint you inherit.⭐ Step one is REPRODUCTION — the card says so about itself
⇒ render
FormPagewith a spec-legal{ group: 'contact_info' }section and report what it draws. ⛔ Do not repair a defect nobody has observed. Two other cards tonight (objectui#8665, objectui#8703) were half or wholly falsified because a source reading was mistaken for a behavioural one; this card names that risk about itself, which is exactly why it must be checked.FormSectionSchema.safeParse({ group: 'contact_info' })was measured ACCEPT on installed spec 17.3.0. Confirm it, and confirmbuildSectionsstill has the shape quoted.The choice is yours between A and B — ⛔ C is not
@object-ui/plugin-formand call it frombuildSections. One assembler, one behaviour, at the cost of a new published export (andcheck:readme-exportsfollows an export).buildSectionscallderiveFieldGroupLayoutitself. Still the single upstream assembler, no new published surface, at the cost of "a second adapter onto a section shape."⛔ C — "leave it and record the divergence" — is NOT yours to take. It is a product ruling about whether the reference app may silently drop spec-legal content, and the reference app is what teaches people how to use the product. If your measurement makes C look right, stop and report rather than choosing it.
⛔ And the hard constraint, from objectui#7051 and objectstack#13855: no assembly rule may be re-implemented on the objectui side — not declared order, not empty-group drop, not the ungrouped trailing bucket, not collapse /
visibleWhenpassthrough. If your arm requires re-spelling any of them, it is the wrong arm.⭐ The non-regression axis is stated on the card — use it verbatim
⭐ That second-group requirement is not decoration: PR #8644's dev found their own layout rows staying green under a constant-resolution caricature because they referenced the first declared group, which is exactly what that caricature returns. "A leg a caricature satisfies by accident tests nothing." ⇒ reference the second group.
Evidence bar
{ group }section — show what it actually produces (a section with no label and no fields, if the card is right).trapon EXIT/INT/TERM with absolute paths, proving the mutation on disk in both directions (anchor counts ANDgit hash-objectvs the HEAD blob) plus a line-total gate; restore by state (git diff HEADempty;git checkout HEAD -- ABSOLUTE_PATH, never the bare form). A void leg is VOID, not green; a leg that lands but does not discriminate is NEGATIVE, not void — report it as negative.git checkout HEAD -- PATHdestroys uncommitted work in that path without a word. Commit your own edits before any leg touches their file — that cost a redo on PR test(plugin-map,plugin-timeline): pin what these two contractEnvelope-6839 waits were standing on #8713 tonight.objectui traps (measured, carry them)
pnpm --filter PKG exec vitest run FILE;cd packages/X && pnpm exec vitestsilently re-roots ontoapps/console. ⛔--no-inline-configis an objectstack convention and manufactures errors here CI does not have.apps/consoleis NOT private —@object-ui/consolepublishes. Decide the changeset on the gate's own verdict line;skip-changesetis a phantom label.TS2307for every workspace import — a PRECONDITION, recorded NOT MEASURED.apps/console's dev server resolves package subpaths theexportsmap forbids — green in the browser,TS2307inBuild Console(objectui#8710, measured on PR feat(app-shell,i18n): announce inbox arrivals with a toast and a desktop notification (#7011) #8668 tonight). ⭐ This bites your arm A directly: if you import the resolver by a subpath specifier, check it against@object-ui/plugin-form'sexportsmap, not against whether the dev server resolves it..at(-1)is TS2550 in packages inheriting the rootlib: ["ES2020"](objectui#8691); jest-dom matchers are untyped in some test programs (objectui#8714).search_issuesreturns false zeros here — measured returningtotal_count: 0for a token carried in a matching card's own title — and REST search has answered 403 including its control. Declare your channel; ⛔ if neither works, report rather than filing blind.Collisions
git ls-remote --heads origin 'gh-readonly-queue/*'— apr-<N>-<sha>branch means that PR is queued and building. ⛔ Nothing queued touchesapps/console/src/components/FormPage.tsx; keep it that way and stop and report if your arm reaches into a queued PR's files.Generated by Claude Code
fix(console,plugin-form): render a form section that references a fie…
os-justin commentedon Sep 9, 2026
os-dev-report
{ "issue": 8641, "status": "done", "branch": "claude/issue-8641-console-formpage-section-group", "pr": "https://github.com/objectstack-ai/objectui/pull/8727", "premise_still_valid": true, "summary": "REPRODUCED FIRST, in the DOM, before repairing: on origin/main at a29ae2d66 a spec-legal `{ group }` form section reached apps/console FormPage.buildSections and produced `{ columns:2, fields:[] }` with no label — rendered as an EMPTY BORDERED CARD (class `rounded-md border bg-card p-4`), heading-less, zero inputs, no diagnostic, IDENTICALLY on the internal /forms/:name and public /f/:slug routes. The card's wording 'renders nothing' is one word off: the section element IS emitted, so a submitter sees a visible blank box, not an invisible omission. Premise re-derived against the INSTALLED @objectstack/spec 17.3.0: FormSectionSchema.safeParse({group:'contact_info'}) ACCEPTs, and REJECTs `label` beside `group`; `buildSections` still had the quoted `sec.fields ?? []` / `label: sec.label` shape. Chose ARM A: `resolveSectionGroupReferences` is now published from @object-ui/plugin-form and called by buildSections. B is not merely worse, it is disqualified by the standing constraint: deriveFieldGroupLayout emits `collapse` as the enum 'none'|'collapsible'|'collapsed' while RenderableSection carries the boolean pair {collapsible, collapsed}, so arm B could not land a section without RE-SPELLING the collapse mapping and the visibleWhen passthrough — two of the four rules #7051/objectstack#13855 forbid re-implementing, plus the match-by-key, the `label ?? key` fallback and the unresolvable-reference diagnostic. Arm A's cost is one new published name plus its options type, the same surface decision this barrel already made for this same file in #6059 (omitServerResolvedDefaults, published because FormPage is 'the SECOND form renderer'); this is the third consumer of the same class. Withheld set (hasSectionGroupReference, resetSectionGroupReports, GROUP_OWNED_SECTION_KEYS, SECTION_LAYOUT_KEYS) is pinned, not left to the eye. The subpath trap was checked rather than assumed: plugin-form's exports map declares '.' only, so the import is from the package root and `@object-ui/console:build` (tsc && vite build && tsc -p tsconfig.plugin.json) is green — no TS2307. Also plumbed: ObjectSchemaPayload gains `fieldGroups`, ObjectFieldDef gains `group`, and loadInternalForm copies fieldGroups (that rebuild is key by key, so an uncopied key is gone before the builder sees it; the public route forwards the payload whole, which is why both routes are pinned separately). formType is forwarded so `group` on a wizard section gets the spec door's own refusal. No behaviour change for any form that does not author `group`.", "tests": "All from the repo root with paths (objectui#3378/#3288), on final commit 666717c69. SUITES: new pins `vitest run apps/console/src/components/FormPage.sectionGroup.test.tsx packages/plugin-form/src/__tests__/sectionGroupResolverPublished-8641.test.ts` -> 2 files, 12 passed, exit 0. `vitest run --project @object-ui/console` -> 94 files / 1112 passed, exit 0. `vitest run packages/plugin-form/` -> 85 files / 859 passed, 1 skipped, exit 0. `vitest run packages/plugin-view/ packages/plugin-designer/ examples/` -> 86 files / 2609 passed, exit 0. `vitest run packages/app-shell/` -> 660 files / 6361 passed, 1 skipped, exit 0. Affected set taken from `TURBO_SCM_BASE=a29ae2d66 turbo ls --affected` (9 packages), not guessed. BUILD/TYPE/LINT: `turbo run build --filter='!@object-ui/site'` 43/43 successful exit 0; `turbo run type-check --filter=@object-ui/console --filter=@object-ui/plugin-form` 37/37 successful exit 0; `turbo run lint` on both 0 errors (211 pre-existing warnings, none from new code, no `any` added). Both typecheck programs VERIFIED to contain the new tests via `tsc --listFiles` (console program: FormPage.sectionGroup.test.tsx present, 94 test files; plugin-form tsconfig.test.json: the surface pin present) — an excluding typecheck would have been NOT MEASURED. GATES (exit code captured before any pipe; verdict lines quoted from the gate itself): check-readme-exports OK but ONLY on the built tree — the first run printed '36 unbuilt' and 'the population COLLAPSED', recorded NOT MEASURED, re-run after build printed '0 unbuilt' and OK; check-changeset-presence OK ('declares 1 changeset(s)'); check-changeset-fixed / -no-major / -overwrite OK; check-control-bytes OK plus a manual `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over the UNTRACKED new files (the gate scans tracked files only) — no hits; check-spec-symbol-derivation OK; check-governed-queue-guard --test -> 'NOT GOVERNED'. ABLATION — read sites only, from a COMMITTED tree, each leg with `trap ... EXIT INT TERM` and absolute paths, mutation proven on disk in BOTH directions (deleted-anchor count down AND injected-anchor count up) plus `git hash-object` differing from the HEAD blob plus a line-total delta, restored BY STATE (`git checkout HEAD -- ABSOLUTE_PATH`, never the bare form; `git diff HEAD --quiet` = 0), classified per-test from vitest's JSON reporter with harness-death strings counted separately. LEG 1 (pre-fix, the reproduction above) is quoted verbatim in the PR body and in the test file header. LEG 3 constant-resolution caricature — sectionGroups.ts `byKey.get(group)` -> `derived?.[0]`, anchors 1->0 / 0->1, hash 1888346e -> c807bafa, lines delta 0: 7 RED, 0 harness deaths; fingerprint \"expected 'Contact Info' to be 'Billing Details'\" and \"expected ['email','phone'] to deeply equal ['invoice_no','po_number']\" — i.e. the SECOND-declared-group section is the one that reddens and the contact_info assertions stay GREEN, which is exactly why the discriminating leg references `billing` and not the first group. LEG 4 drop-every-group-section (today's behaviour restored) — FormPage.tsx resolver call removed, anchors 1->0 / 0->1, hash c31f2ca2 -> 0fca9673, lines delta -12: 8 RED, 0 harness deaths, including BOTH diagnostic pins (\"expected '' to contain 'no_such_group_8641'\", \"expected '' to contain 'wizard'\") — the 'reports nothing' half. LEG 5 un-publish the resolver from the barrel (hash 7e4e3040 -> e953a2f5): the positive surface pin reddens. LEG 6 barrel widened to `export * from './sectionGroups'` (hash 7e4e3040 -> 76ebce2c): the withheld-set pin reddens. Post-ablation the tree is byte-clean and the 12 pins are green again. NOT OBSERVED RED, reported rather than counted: (1) 'PREMISE: spec ACCEPTS a bare { group }' is a premise probe against the installed package — its red condition is a spec regression, unproducible by ablating this diff; (2) 'CONTROL: a form with no group reference is built exactly as before' is the control that MUST stay green in every leg, without which every toEqual above would be equally satisfied by a renderer that draws nothing. No ablation touched a pin; no leg was void.", "mcp_calls": "0 — channel declared: repo-scoped REST throughout (probe `GET /repos/objectstack-ai/objectui` -> HTTP 200), plus git. Dedup for the finding below used the REST list endpoint paged to exhaustion (5 pages, 494 rows) reconciled against the repo's own open_issues_count (494, exact) and grepped locally; the control word 'FormPage' hit #8641, so the zero on 'FormSectionSpec'/'SchemaForm' is a real read and not a false zero. No /search/* call, no MCP GitHub call.", "open_questions": [], "out_of_scope_findings": [ "filed as #8725: app-shell `FormSectionSpec` re-declares `fields` as REQUIRED so the spec-legal `{ group }` section does not compile for a TypeScript author (this PR's fixture casts around it), and metadata-admin `SchemaForm` is a FOURTH form-section renderer whose three `s.fields` reads (lines 786, 1030, 1147) are unguarded and above the JSX — the same above-the-loop shape that blanked SimpleObjectForm before #8644. No assignee, no labels. Reachability was NOT measured and the issue says so; not fixed here because widening that type is a behaviour ruling on a different renderer." ] }Generated by Claude Code
os-justin commentedon Sep 9, 2026
Contract review — accepted. PR #8727 is out of draft and armed. No open questions to rule on.
⭐ Reproduced first, in the DOM — and the card's wording is one word off in the worse direction
⇒ "renders nothing" undersold it. An invisible omission is a defect nobody reports; a visible empty bordered card on a public form page is one a submitter sees and cannot act on. And it is on both routes, which is why both are pinned separately — the internal one rebuilds the payload key by key (so an uncopied key is gone before the builder sees it), the public one forwards it whole.
The premise was re-derived against the installed spec:
FormSectionSchema.safeParse({ group: 'contact_info' })ACCEPTs, and REJECTslabelbesidegroup— a detail nobody had, and it is why the built section has no heading.⭐⭐⭐ Arm B is not "worse" — it is DISQUALIFIED, and only a measurement shows it
I presented A and B as an engineering trade. It is not one:
⇒ the hard constraint I stated ("no assembly rule may be re-implemented on the objectui side") closes the choice by itself, and the only way to see that is to compare the two shapes. ⭐ A dev who took my framing at face value would have picked B on "no new published surface" and discovered the violation halfway through — or worse, shipped the re-spelling.
And A's cost is precedented rather than novel: this same barrel made this same decision for this same file in objectui#6059 (
omitServerResolvedDefaults, published becauseFormPageis "the SECOND form renderer"). ⇒ this is the third consumer of the same class, which is an argument about the class, not about this card.⭐ The subpath trap I warned about was checked, not assumed
That is objectui#8710 exactly, and it fires precisely on arm A. ⭐ Checked against the
exportsmap, not against whether the dev server resolved it — which is the distinction that cost PR #8668 a redBuild Consoletonight.The publishing discipline: one name published, the rest pinned private
hasSectionGroupReference,resetSectionGroupReports,GROUP_OWNED_SECTION_KEYS,SECTION_LAYOUT_KEYSare withheld and asserted withheld — and LEG 6 (barrel widened toexport * from './sectionGroups') reddens that pin. ⇒ the published surface is "one new name plus its options type" as a measurement, not as an intention. On a card whose whole cost is a widened public API, that is the assertion that matters.⭐ The second-group requirement earned its place, with a fingerprint
That is PR #8644's lesson ("a leg a caricature satisfies by accident tests nothing") reproduced independently, with the failure text as evidence rather than the claim. LEG 4 (today's behaviour restored) reddens 8, including both diagnostic pins — the "reports nothing" half, which a fix could easily have left unaddressed.
⭐ Two things reported rather than counted, and both are right
check-readme-exportsfirst printed36 unbuiltand "the population COLLAPSED" ⇒ recorded NOT MEASURED, re-run after the build printed0 unbuiltand OK. The gate's own collapse guard caught a precondition failure that would otherwise have read as a pass.toEqualabove would be equally satisfied by a renderer that draws nothing." ⇒ naming the pin that cannot fail, and saying what would make it fail, is the correct handling of the one exception to an assertion never observed to fail has not been tested.The control-byte scan was additionally run by hand over the untracked new files, because the gate scans tracked files only. Small, and exactly the kind of gap that publishes a clean verdict about nothing.
⭐ And the enumeration was incomplete again — objectui#8725
⇒ objectui#7051's ruling named two consumers, its own dogfood found a third (objectui#8057), this card was the third form-section renderer — and there is a fourth. That is the second enumeration tonight to come back incomplete, and the second time the answer to "is there another?" was yes. Reachability correctly NOT measured and said so, and correctly not fixed here: widening that type is a behaviour ruling on a different renderer.
0 MCP calls, and the dedup deserves a note: with
/search/*dead, it was done by paging the REST list endpoint to exhaustion — 5 pages, 494 rows — reconciled against the repo's ownopen_issues_count(494, exact), with a control word that hit. ⭐ That is a real dedup on a broken instrument, and it is reproducible; three seats tonight reported the search endpoint 403-ing on its own control.Generated by Claude Code
docs(plugin-form): give the section-group snippet its input, and stop…
os-justin commentedon Sep 9, 2026
os-dev-report
{ "issue": 8641, "status": "done", "branch": "claude/issue-8641-console-formpage-section-group", "pr": "https://github.com/objectstack-ai/objectui/pull/8727", "premise_still_valid": true, "summary": "Repair-only, one file: packages/plugin-form/README.md, +11/-5, no new changeset (the PR already carries one, and nothing published moved). Both red checks reproduced BEFORE the edit and both are green after. (1) Doc Snippet Type Check: `authoredSections` is now declared as `ObjectFormSection[]`, imported `import type` from `@object-ui/types`. That is not a plausible-looking type, it is the parameter type read off the BUILT surface the gate compiles against: packages/plugin-form/dist/sectionGroups.d.ts spells `resolveSectionGroupReferences(sections: ObjectFormSection[] | undefined, opts: ResolveSectionGroupsOptions)`. It is also honest for the documented scenario rather than merely accepted by the compiler: the built `@object-ui/types` declares `group?: string` on `ObjectFormSection` and leaves `fields` optional (PR #8644 widened it), so a host's own builder genuinely can hold `{ group: 'x' }` sections at that type — which is exactly what the surrounding prose is about. `@object-ui/types` is a declared `dependencies` entry of `@object-ui/plugin-form`, so it is inside the gate's third-party bound (`dependencies` only, never peers) and five other blocks in this same README already import from it. No `any`, and no `Parameters[0]` escape either: the latter would have been tautologically green while naming no type at all. The two `declare const` lines now sit BELOW the imports, which is the order a reader would write. (2) doc-version-claims: took the DELETION arm. `\"@objectstack/spec` 17.3.0\"` is gone from line 382; the sentence keeps its meaning from objectstack#13855 and ADR-0085 §5, and the version floor now points at the `@objectstack/spec` entry in this package's own package.json. No KNOWN_CLAIMS row was added.", "declared_type_and_why": "`declare const authoredSections: ObjectFormSection[];` with `import type { ObjectFormSection } from '@object-ui/types';`. Chosen because it is the function's OWN parameter type as shipped (dist/sectionGroups.d.ts, quoted above), not a restatement of it; because that type declares `group` and optional `fields`, so it is the shape the prose describes rather than a shape that merely compiles; and because it is load-bearing in BOTH directions, which was measured (leg B below): widening it to `unknown[]` reddens the gate with TS2345. Rejected: `any[]` (erases the check the gate exists to make), `unknown[]` (does not even compile — it is leg B), the `Parameters` of `typeof resolveSectionGroupReferences` at index 0 (cannot be wrong, therefore proves nothing and teaches the reader no name).", "version_literal_arm_and_measurement": "DELETION. Measurement behind it, in this order: (a) the installed @objectstack/spec in this worktree is 17.3.0, so the literal was TRUE at this commit — which is precisely the condition under which it goes silently false later, not a reason to keep it; (b) packages/plugin-form/package.json declares `\"@objectstack/spec\": \"^17.0.0\"` in `dependencies`, so any 17.x minor satisfies the manifest and would leave the prose stale with nothing in the repo able to notice — the gate's own words for that state are 'nothing in this repository can tell whether it is still true'; (c) a KNOWN_CLAIMS row of kind `restatement` was not available: that kind is for prose restating a manifest range, and `17.3.0` is not `^17.0.0` — it would have had to be `unanchored`, i.e. an inventoried unmeasurable claim, which is the debt objectui#3645 is the cautionary tale for; (d) the two OTHER mentions of `@objectstack/spec` in this same README (lines 286 and 451) already carry no version and read fine, so the deletion is this document's existing house style, not a new one. Replacement text: 'objectstack#13855, ADR-0085 §5 — the spec range that carries it is the `@objectstack/spec` entry in this package's own `package.json`'. Verified the new wording does not merely dodge the recogniser by accident: CLAIM_RES matches FIRST_PARTY + up to 6 separator chars + a VERSION token, and what now follows the package name is the word 'entry'.", "tests": "PRECONDITION FIRST. Fresh worktree /home/user/objectui-pr8727 at 666717c69, `pnpm install` exit 0, then the gate's OWN build filter (`node scripts/check-doc-snippet-types.mjs --build-filter`, 34 `--filter=...` words) through `pnpm exec turbo run build $FILTER_ARGS --concurrency=2` -- exit 0, 'Tasks: 35 successful, 35 total / Cached: 35 cached'. That was a FULL TURBO cache hit whose replayed logs name a different worktree path, so 'built' was NOT inferred from the turbo line: packages/types/dist/index.d.ts and packages/plugin-form/dist/index.d.ts were listed on disk by hand, and the gate's own resolution control then confirmed it.\n\nCONTROLS, every run, quoted from the gate: 'resolution Module name '@object-ui/types' was successfully resolved to '/home/user/objectui-pr8727/packages/types/dist/index.d.ts'' | 'sentinel importing 'ThisNameIsDefinitelyNotExported' produced 1 diagnostic(s) (TS2305)' | 'positive importing 'BaseSchema' produced 0 diagnostic(s)' | 'undeclared importing '@floating-ui/react-dom' ... produced 1 diagnostic(s) (TS2307)' | 'root-declared importing 'vitest' ... produced 1 diagnostic(s) (TS2307)'. These match the healthy CI run named in the dispatch, so no verdict below is recorded NOT MEASURED.\n\nBEFORE (unedited tree, controls healthy as above): `node scripts/check-doc-snippet-types.mjs` exit 1 -- '[semantic] packages/plugin-form/README.md:397:48 TS2304: Cannot find name 'authoredSections'.' and 'Semantic phase: 636 of 636 block(s) judged, 1 failed.' Both dispatch failures reproduced exactly.\n\nBEFORE, failure 2: `pnpm exec vitest run scripts/__tests__/doc-version-claims.test.ts --reporter=json --outputFile=...` from the REPO ROOT with the path (never `pnpm --filter PKG exec vitest`, never `cd packages/X`, never `--no-inline-config`) -- exit 1, JSON reporter: 29 tests, 28 passed, 1 failed; the one failure is 'doc version claims - the ratchet records every version literal on the scanned surfaces', message 'These doc surfaces state a version and nothing in this repository can tell whether it is still true: - packages/plugin-form/README.md:382 \"@objectstack/spec` 17.3.0\"' ... 'expected [ Array(1) ] to deeply equal []'. One-element array confirmed.\n\nAFTER (commit bd686c2f1): snippet gate exit 0 -- 'Semantic phase: 636 of 636 block(s) judged, 0 failed.' + 'Every covered documentation snippet compiles against the built types.', same five control lines. doc-version-claims exit 0 -- JSON reporter: 7 suites, 29 tests, 29 passed, 0 failed, 0 pending; a separate grep for harness-death strings (unhandled / Failed to load / suite failed / Cannot find module) over the run log counted 0, so the green is 29 real outcomes and not a suite that died quietly.\n\nLOAD-BEARING PROOF (the 'delete it again' leg), run from the COMMITTED tree, script with `trap restore EXIT INT TERM`, absolute paths from `git rev-parse --show-toplevel`, restore always `git checkout HEAD -- ABSOLUTE_PATH` and never the bare form. HEAD blob 8d0e7dc091e6c21f2192de1c6ab5a3729f809e5b, asserted non-empty before either leg.\n LEG A, delete the declaration line: on-disk proof deleted-anchor 1 to 0, lines 1042 to 1041, hash 8d0e7dc0 to 7c999b20 (differs from the HEAD blob). Gate exit 1 -- '[semantic] packages/plugin-form/README.md:402:48 TS2304: Cannot find name 'authoredSections'.', 636 judged, 1 failed. TS2304 comes back. Restored BY STATE: `git diff HEAD --quiet` exit 0, hash back to 8d0e7dc0.\n LEG B, widen the declared TYPE to `unknown[]` and change nothing else: deleted-anchor 1 to 0, injected-anchor 0 to 1, lines 1042 to 1042 (equal-length replacement, which is why the anchor counts and the hash carry the proof and `git diff --stat` alone would not). Hash 8d0e7dc0 to 1e663a3a. Gate exit 1 -- '[semantic] packages/plugin-form/README.md:403:48 TS2345: Argument of type 'unknown[]' is not assignable to parameter of type 'ObjectFormSection[]'. Type 'unknown' is not assignable to type 'ObjectFormSection'.' Restored by state, `git diff HEAD --quiet` exit 0, hash back to 8d0e7dc0. Leg B is the one the card did not ask for and it is the one that matters: leg A alone would be satisfied by `declare const authoredSections: any[]`. B shows the declaration could NOT have been anything.\n Post-ablation the worktree is byte-clean (`git status --porcelain` 0 paths) and both checks re-run green on that exact tree.\n Note on line numbers: the failure moves 397 to 402/403 across the legs because the fix adds lines above the call. Same block, same call site.\n\nNEIGHBOURING GATES the dispatch did not name, run because this diff is a README (exit code captured before any pipe): check-readme-exports exit 0 -- 'OK (43 tracked README(s) ... 762 import binding(s), 538 of them self-imports judged (538 real, 0 wrong-path, 0 fabricated) ... 1 unbuilt, 3 declare no types)' -- the healthy shape, not the collapsed '36 unbuilt' precondition this PR's first run hit earlier tonight. check-doc-component-types exit 0. check-doc-fence-languages exit 0. check-doc-expression-carriage exit 0 (report-only census). check-doc-example-shared-reader exit 0. Control bytes: `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' packages/plugin-form/README.md` -- no hits (grep exit 1).\n\nNOT RUN, and why: no package test suite, no build of the app, no lint pass. This diff is prose and one fenced block in one README; it changes no source file, no export and no published behaviour. CI runs the farm.", "pushed_sha": "bd686c2f12c150809e30b8ffd10fa315efdded94", "mcp_calls": "3 -- two repo-scoped MCP reads (issue_read get_comments on #8641 to verify the newest Claim: names this branch, issue_read get on #8725 to check the finding below was already filed rather than filing a duplicate) plus this comment. Everything else was git and local scripts.", "open_questions": [], "out_of_scope_findings": [], "things_the_card_did_not_say": [ "The dispatch's remedy list for the version literal names 'the package's own peerDependencies'. For this package that field is React only -- `@objectstack/spec` is a `dependencies` entry (`^17.0.0`). The replacement prose therefore points at package.json rather than at peerDependencies, which is the same remedy spelled to the manifest that actually carries it.", "`type ResolveSectionGroupsOptions` in that block is imported and never referenced. Pre-existing, reviewed, and deliberately left alone rather than widened into the repair -- and it is not inert: an import of a type the package does not export is TS2305 here (that is exactly the gate's sentinel control), so the name's existence IS checked on every commit. Its SHAPE is not. Annotating the options literal with it would close that, and is a one-line follow-up somebody may want; it was out of this repair's scope.", "The turbo build reported 'FULL TURBO, 35 cached' and replayed logs whose paths name a worktree that is not this one. A cache hit does restore outputs, but 'the tree is built' was verified by listing the two dist `.d.ts` files and by the gate's resolution control, not read off the turbo summary. Worth carrying: on this repo a fresh worktree can go from `pnpm install` to a fully built closure in under a second, and that is the shape most likely to be mistaken for a build that did not happen.", "`ObjectFormSection` in `@object-ui/types` already declares `group?: string` with `fields` optional, so the type gap objectui#8725 reports for app-shell's `FormSectionSpec` does NOT exist on the type this snippet uses. That is why an honest declaration was available at all here. #8725 stays open and untouched.", "PR draft state and auto-merge were not touched, per the dispatch. No second Claim: comment, no assignee write." ] }Generated by Claude Code
fix(console,plugin-form): render a form section that references a fie…