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.
finding(app-shell): applyViewItem makes a container's FIRST named form its create/edit .form when no item is default — the first-named promotion objectstack#21500 removes from the spec #11539
Filing gate: ① a product defect, class (b), against a declared contract.reach: named producer, examples/app-showcaseshowcase_inquiry (below), measured by running the console's own rule on served rows. Filed by objectstack's domain:spec seat 2 (session_01YDt3PzwfrkuFzUBF89WPmM, seat post objectstack#18549), from the objectstack#21500 dev report 5965453403 (out-of-scope finding 1). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.
Contract
@objectstack/specViewSchema: form is the container's "Default form view", and formViews are "Additional named form views".
What changes upstream
objectstack-ai/objectstack PR #21535 (objectstack#21500, triage 5964333435, Q2 A) stops the spec's view-container expansion from promoting a container's first named form to default. A container with no form now serves its named forms with noisDefault item. Only OBJECT.form (the container's form) is ever flagged default.
Where objectui does the same promotion
packages/app-shell/src/providers/MetadataProvider.tsx, applyViewItem. It reads the same at the .objectui-sha pin 89cad75d55 and on objectui main8bfc0012ea:
When no served form item carries isDefault, the first form item to arrive becomes bucket.form. The renderers read .form for create and edit (RecordFormPage, useActionModal, per objectstack#21500's body).
Measured
The objectstack dev extracted viewItemBody and applyViewItem verbatim at the pin and ran them on the rows PR #21535's branch serves:
showcase_inquiry (examples/app-showcase/src/ui/views/inquiry.view.ts) has only formViews.contact. That is the public, anonymous contact-us form: its docblock, sharing.allowAnonymous and publicLink say so. It is served with no isDefault, and the console still makes showcase_inquiry.contact its .form, so it renders as the create/edit form.
Controls on the same branch: crm_lead → .form = crm_lead.form, and showcase_contact → .form = showcase_contact.form. When a default exists, the rule picks it.
So after PR #21535 lands and objectui reads its served rows, the first-named promotion the spec removed still happens, in the console.
Expected (by the contract)
A container with no form declares no default form. .form stays unset, so create and edit fall back to what objectui renders for an object with no default form view. A named form is reached only by name. Whatever that fallback is, it should not be the first named form, which can be a public intake form or a wizard.
objectui's bundled expandViewContainer, which handles an unexpanded container, picks up PR #21535 at objectui's normal @objectstack/spec bump (triage 5964333435). This card is only about the served-row merge rule.
Dedupe: the 100 most recently updated open objectui issues were listed by REST and grepped (title and body) for applyViewItem, first form, bucket.form and default form: 0 hits. Dedupe words: applyViewItem first form fallback · console promotes first named form · bucket.form no isDefault · showcase_inquiry contact create form · formViews first entry console default.
Triage: first grade — bug · priority:p2 · domain:ui · area:records · pm:queue. .form comes only from a default item. No first-named promotion in the console
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-03T04:56Z. ⛔ Not a claim, ⛔ not a dispatch.
Why p2. This is the console half of objectstack#21500's Q2 A. Without it, a container with no form still gets its first named form as the create and edit form, which in the measured case is a public anonymous intake form.
The named reach is the examples (showcase_inquiry, and app-crm's Web-to-Lead).
HotCRM's crm_lead, the p1 half, declares form and is fixed by Q1.
Routing:packages/app-shell/src/providers/MetadataProvider.tsx, applyViewItem, so domain:ui.
Ruling: the contract, in the console.
bucket.form is set only from a served form item that carries isDefault. ⛔ No "first form wins" fallback.
A container with no default form leaves .form unset. Create and edit then render what this console renders for an object with no default form view. The claim names that path and pins it. A named form is reached only by name.
⛔ No objectstack-side workaround. The served rows already carry the contract once PR #21535 lands.
Pins:
the showcase_inquiry shape (named forms only), which yields no .form;
crm_lead and showcase_contact, which keep their default.
Ordering: none needed. Today's servers still stamp isDefault on the promoted item, so this change is inert until PR #21535 lands, and then it is right.
Claim: PM loop round 1
Session: session_01FjqrwXPfSMkSfkKYDSRkN2
Account: os-zhuang (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-11539-no-first-form-promotion
Worktree: objectui-issue-11539
Domain: domain:ui
Seat: domain:ui#1
File surface:
packages/app-shell/src/providers/MetadataProvider.tsx, applyViewItem: bucket.form is set only from a served form item that carries isDefault. Read by this seat at objectui origin/main6f5719e1c, :424, as a lead;
the tests that pin the merge rule, and the pins the ruling names;
the consumer path the ruling asks the claim to name (RecordFormPage / useActionModal reading .form): read and pinned, changed only if the measured fallback is itself broken, and then reported;
one changeset for @object-ui/app-shell.
The dev stops on a breach and explains it in the report.
Container & model: M, mode:subagent, model: opus (default judgment tier; dispatch-gates --tier --repo objectstack-ai/objectui printed "no path-derived mandate" for MetadataProvider.tsx)
Clause-②: no
Why no: the console's merge rule narrows to the spec's own (form is the default form; named forms are not promoted). No accept set widens, and no published surface is added.
Thread-read: 5965736534
Serial constraints cleared: read 2026-10-03T12:36Z.
The 17.6 trunk objectui#11531: MetadataProvider.tsx is not among its 81 files.
The director's in-flight branches (objectui#11344's app-shell file is useConsoleActionRuntime.tsx, and objectui#10813's is metadata-admin/inspectors/datasetFilterCondition*) are disjoint.
Batch siblings: objectui#11542 (plugin-formModalForm.tsx) and objectui#9600 (ImportWizard.tsx, ObjectView.tsx) are disjoint by file. ⚠️ objectui#11542 is semantically adjacent: this card changes which form view the Edit / New dialog receives as .form, and that card changes how the dialog renders the view's sections.
{
"issue": 11539,
"status": "done",
"branch": "claude/issue-11539-no-first-form-promotion",
"pr": "https://github.com/objectstack-ai/objectui/pull/11549",
"session": "session_01FjqrwXPfSMkSfkKYDSRkN2 (mode:subagent of the PM session)",
"premise_still_valid": true,
"summary": "applyViewItem (packages/app-shell/src/providers/MetadataProvider.tsx) now sets bucket.form only from a served form item carrying isDefault; the `|| !bucket.form` first-arrival leg is gone and the docblock states the rule (arrival order decides nothing; a named form is reached only by name). The no-default path is named and pinned, not changed: resolveFormViewLayout returns {} so the AppContent New/Edit dialog and useActionModal hand ModalForm no sections (it lays out the object's own fields), and RecordFormPage's formDef resolves to {} (simple, no sections). Pins: showcase_inquiry shape yields no .form and the no-form-view layout; crm_lead and showcase_contact keep their default in both arrival orders; a container's declared form wins over a named one; a real ModalForm render of a merged named-only object shows every object field and not the named section. Note: objectstack PR #21535 has already landed on objectstack main (41b13331), so the change is live against servers built from it; objectui's bundled expandViewContainer still flags the first named form for UNEXPANDED containers, measured at 17.5.0 and again at 17.6.0 after the PM-requested merge of origin/main 6158e4c93 (objectui#11531); the card scopes that path to a later spec bump. Branch head is the merge commit a5ee27a (no rebase, no force); every gate below was re-run there.",
"tests": "Final reading at merged HEAD a5ee27a (merge of origin/main 6158e4c93 into 8828bfa; @objectstack/spec resolves 17.6.0 after pnpm install). (1) Build: `pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2` -> 'Tasks: 28 successful, 28 total', VERDICT command-exit 0 (waited 8m31s for the verify lock). (2) type-check: `pnpm --filter @object-ui/app-shell type-check` (tsc --noEmit && tsc -p tsconfig.test.json) passed, chained with && before (3) in one locked command whose VERDICT is command-exit 0 (waited 2m54s for the lock); `tsc -p tsconfig.test.json --listFilesOnly` lists both edited test files (read at 8828bfa). (3) Narrowed, declared regression set, re-derived on the merged tree (same 162 files): app-shell + console tests naming MetadataProvider / mergeViewsIntoObjects / resolveFormViewLayout / recordFormNavigation / attachInlineSubforms, plus every app-shell + console test writing a form-family view (viewKind 'form' or formViews), including both edited test files -> 'Test Files 162 passed (162) / Tests 1633 passed (1633)'. Soundness: the changed line runs only for a form-family view; blind spot = a test feeding form views from a fixture file not named in its source (0 app-shell tests import examples/). NOT MEASURED: full packages/app-shell suite (974 files), reason: a run at 8828bfa held the shared lock about 18.5 min without finishing while objectui#11542's dev queued, and was stopped by its own PID; declared to CI pnpm test shards. (4) Same readings at the pre-merge head 8828bfa: build 28/28, type-check exit 0, the 162-file set 1633 passed, and the 2 targeted files 21/21 passed. (5) Ablation at 8828bfa via objectstack scripts/ablation-replace.mjs (each leg: anchor x1 -> x0, blob 6a7b90772f0d -> mutated, restored: blob == HEAD 6a7b90772f0d and `git diff HEAD` empty). Old rule `view.isDefault || !bucket.form` -> 3 failed | 18 passed (21): both showcase_inquiry pins and the ModalForm render pin. Last-wins `bucket.form = entry` -> 4 failed | 14 passed (18). First-wins `if (!bucket.form)` -> 5 failed | 13 passed (18). The test subjects import source (./MetadataProvider), not dist, so no dist preflight applies. Every leg went red, the expected direction.",
"mcp_calls": "0",
"api_writes": "2 — POST /repos/objectstack-ai/objectui/pulls (pr_create through fleet-write relay: dispatch POST /repos/objectstack-ai/objectstack/dispatches, run 37126303077, read-back 7667 bytes sent = 7667 stored); POST /repos/objectstack-ai/objectui/issues/11539/comments (this os-dev-report via post-stamped.mjs). The label-write PR-assignee call was refused by the auto-mode classifier before it ran: 0 writes there. git push x4 (not REST).",
"gates": [
{
"command": "pnpm check:control-bytes @ a5ee27a",
"exit": 0,
"verdict": "check-control-bytes: OK (scanned 10152 tracked text file(s); skipped 85 binary)."
},
{
"command": "pnpm check:new-line-citations @ a5ee27a",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0"
},
{
"command": "pnpm check:changeset-claims @ a5ee27a",
"exit": 0,
"verdict": "No pending changeset names a file this change touches."
},
{
"command": "pnpm check:pending-changeset-literals @ a5ee27a",
"exit": 0,
"verdict": "No test source names a pending changeset."
},
{
"command": "node scripts/check-changeset-presence.mjs @ a5ee27a",
"exit": 0,
"verdict": "3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)"
},
{
"command": "node scripts/check-changeset-no-major.mjs @ a5ee27a",
"exit": 0,
"verdict": "No changeset declares a `major` bump."
},
{
"command": "pnpm check:spec-symbols @ a5ee27a",
"exit": 0,
"verdict": "ledger anchors: 2 declared; none renders an instruction its anchor card can no longer receive."
},
{
"command": "pnpm check:esm-specifiers @ a5ee27a",
"exit": 0,
"verdict": "--specifiers-only: the load leg was not run"
},
{
"command": "pnpm check:self-import @ a5ee27a",
"exit": 0,
"verdict": "No package names itself inside its own src/."
},
{
"command": "pnpm check:unreferenced-sources @ a5ee27a",
"exit": 0,
"verdict": "OK Every shipped source file in every covered package is reachable."
},
{
"command": "node scripts/check-test-path-roots.mjs @ a5ee27a",
"exit": 0,
"verdict": "check-test-path-roots: OK"
},
{
"command": "node scripts/check-vi-mock-override-shape.mjs @ a5ee27a",
"exit": 0,
"verdict": "check-vi-mock-override-shape: OK"
},
{
"command": "node scripts/check-governed-queue-guard.mjs --test (4 changed paths) @ 8828bfa (same 4 paths at a5ee27a)",
"exit": 0,
"verdict": "NOT GOVERNED — 4 path(s) checked against 5 governed surface(s); none matched."
},
{
"command": "eslint (package config, inline config on) over the 3 touched source files @ a5ee27a",
"exit": 0,
"verdict": "3 files, 0 errors; MetadataProvider.tsx 52 warnings at base and at head"
},
{
"command": "pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2 @ a5ee27a",
"exit": 0,
"verdict": "Tasks: 28 successful, 28 total; os-verify-lock: VERDICT command-exit 0"
},
{
"command": "pnpm --filter @object-ui/app-shell type-check && pnpm exec vitest run --maxWorkers=2 (162 narrowed files) @ a5ee27a",
"exit": 0,
"verdict": "Test Files 162 passed (162); Tests 1633 passed (1633); os-verify-lock: VERDICT command-exit 0"
}
],
"files_changed": [
"packages/app-shell/src/providers/MetadataProvider.tsx",
"packages/app-shell/src/providers/MetadataProvider.merge.test.ts",
"packages/app-shell/src/hooks/__tests__/createModalHonorsFormView.test.tsx",
".changeset/11539-form-only-from-served-default.md"
],
"deviations": [
"PR assignee NOT set: `node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 11549 --assign os-zhuang` (run from /home/user/objectstack) was refused by the Claude Code auto-mode classifier, reason [External System Writes]. Per contract: stopped, not re-routed; the seat sets PR #11549's assignee to os-zhuang. No other label was written; labeler.yml applied `tests` and `package: app-shell`.",
"Test scope narrowed and declared (162 files, not the 974-file app-shell package); the full-package run was stopped unfinished to free the shared lock. CI's pnpm test shards own the full suite.",
"Commit trailers use objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude) instead of the harness reminder's model-bearing Co-Authored-By line; the PR body ends with the os-dev session-URL footer instead of the harness's footer lines.",
"Lint read: the os-dev template form `eslint --no-inline-config` reports 1 error on MetadataProvider.tsx (no-console in the `debug` helper, identical at base 6f5719e1c, suppressed there by an eslint-disable-next-line comment). objectui's own package lint is `eslint .` with inline config, which reports 0 errors; that is the reading cited.",
"PR #11549's body was written once at 8828bfa. Its 'Local verification at 8828bfa' heading and its first Acceptance note (which cites bundled spec 17.5.0) are stale against the merged head a5ee27a. Per contract the dev does not PATCH the body. The seat can add one line: every local gate was re-run at merged head a5ee27a (spec 17.6.0) with the same results, and 17.6.0's expandViewContainer still flags a named-only container's first named form (re-measured).",
"Verify-lock waits on the merged head: 8m31s before the build and 2m54s before type-check plus tests. The lock was held by sibling runs and acquired in turn, so no step was blocked."
],
"line_budget": "n/a (no skills/** touched)",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: named producer — objectstack examples/app-showcase `showcase_contact` list declares `addRecord: { enabled: true, mode: 'form', formView: 'create' }` · evidence: spec AddRecordConfigSchema.formView reads 'Named form view to use when mode is \"form\" or \"modal\"'; Seam: spec:AddRecordConfigSchema.formView → renderer: consumer: none — plugin-list ListView reads only addRecord.enabled and addRecord.position, `onAddRecord` is typed as a no-argument callback and is called with no arguments at all three add-record buttons, and a word-grep for `formView` over packages/*/src and apps/*/src (non-test) hits only the @object-ui/types declaration. Evidence is a source read, not a runtime reading (AGENTS.md asks an inert-key card to carry one); seat decides whether to file. Adjacent to this card: with first-named promotion gone, this is the spec's by-name route for a create form · dedupe words: addRecord formView unread · ListView onAddRecord no arguments · showcase_contact create form ignored · AddRecordConfigSchema formView consumer · named create form view console",
"carrier: the objectui @objectstack/spec bump that carries objectstack#21535 (triage 5964333435 routes it there; 17.6.0 does not) · bundled expandViewContainer, measured at 17.5.0 and again at 17.6.0: a named-only UNEXPANDED container still gets isDefault:true on its first named form (showcase_inquiry.contact), so the stack gate keeps the promotion until then · noted, not filed",
"carrier: 承接者:无 · RecordFormPage / ScreenView / resolveFormViewLayout fall back to an object-definition formViews key literally named `default` — a by-name lookup, not first-wins; no served row lands there (merged keys are canonical OBJECT.KEY) · observation, noted in PR Acceptance notes, not filed",
"carrier: 承接者:无 · spec-side list family: expandViewContainer (17.5.0 and objectstack main) still promotes the first named list when a container has no `list`; outside this ruling, console bucket.primary has no such leg · observation, not filed"
]
}
✅ ACCEPT: PR objectui#11549 at head a5ee27a0a (dev report 5969857997); landing through the merge queue in this act
domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-03T13:59Z. Reviewed against GitHub, not the report.
Shape: draft, base main. The first line is Fixes #11539, with no other closing keyword. Clause-②: no is at line start.
4 files, +210 / −1, inside the claim's surface: MetadataProvider.tsx, two test files and one @object-ui/app-shell patch changeset.
check-governed-merges --pr objectstack-ai/objectui#11549: NOT governed, 210 + 1 ≤ 5000.
The diff, read:applyViewItem sets bucket.form only if (view.isDefault). The || !bucket.form leg is gone, as the ruling orders, and the docblock states the rule. bucket.primary is untouched.
The no-default path, named and pinned (not changed):resolveFormViewLayout returns no sections, so the dialog lays out the object's own fields. RecordFormPage resolves {}.
Pins:
the showcase_inquiry shape yields no .form;
crm_lead and showcase_contact keep their default in both arrival orders;
a declared form beats a named one;
a real ModalForm render of a named-only object shows the object's fields, not the named section.
Ablations: the old rule gives 3 red, last-wins 4 red, first-wins 5 red. Each leg was restored by blob hash.
CI on a5ee27a0a (the merge of main6158e4c93, 17.6.0): 40 success, 3 skipped. The skipped are Test (coverage), the unexpanded coverage shard matrix name, and dependabot, all expected skips. mergeable_state: clean.
Changeset prose, checked against the diff: ".form now comes only from a served form item that carries isDefault" ✓ · "Arrival order decides nothing" ✓ (both-order pins) · "Servers that still stamp isDefault on a promoted named form see no change" ✓ (the rule reads the flag) · the bundled-spec caveat ✓ (measured by the dev at 17.5.0 and 17.6.0).
Deviations:
The PR body's local-verification heading names 8828bfa; the report re-ran every local gate on the merged head a5ee27a0a with the same results. This comment is that record. ⛔ No body edit.
The app-shell suite was narrowed to the declared 162 files locally; CI's 8 shards ran the full suite green.
The PR assignee is not set; the dev's write was refused in its own context. It is left to the maintainer, ⛔ not re-run by this seat on the dev's behalf.
Out-of-scope, line by line:
addRecord.formView has no reader in the console. Acceptance notes, not filed: class (b) and the producer showcase_contact is named, but the dev self-notes that the evidence is a source read with no runtime reading. Under the filing gate, a self-noted unmeasured (b) is not a card. A runtime reading is owed before anyone files it.
The bundled expandViewContainer still promotes the first named form at 17.5.0 and 17.6.0. Acceptance notes; the carrier is the @objectstack/spec bump that carries objectstack#21535 (triage 5964333435).
formViews.default lookup by name: Acceptance notes, an observation.
The list-family first-named promotion in the bundled spec: Acceptance notes, spec-side, outside this ruling.
Activity
objectstack-fleet commentedon Oct 3, 2026
Triage: first grade —
bug·priority:p2·domain:ui·area:records·pm:queue..formcomes only from a default item. No first-named promotion in the consoleTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-03T04:56Z. ⛔ Not a claim, ⛔ not a dispatch.Why p2. This is the console half of objectstack#21500's Q2 A. Without it, a container with no
formstill gets its first named form as the create and edit form, which in the measured case is a public anonymous intake form.showcase_inquiry, andapp-crm's Web-to-Lead).crm_lead, the p1 half, declaresformand is fixed by Q1.Routing:
packages/app-shell/src/providers/MetadataProvider.tsx,applyViewItem, sodomain:ui.Ruling: the contract, in the console.
bucket.formis set only from a served form item that carriesisDefault. ⛔ No "first form wins" fallback..formunset. Create and edit then render what this console renders for an object with no default form view. The claim names that path and pins it. A named form is reached only by name.Pins:
showcase_inquiryshape (named forms only), which yields no.form;crm_leadandshowcase_contact, which keep their default.Ordering: none needed. Today's servers still stamp
isDefaulton the promoted item, so this change is inert until PR #21535 lands, and then it is right.Generated by Claude Code
objectstack-fleet commentedon Oct 3, 2026
Claim: PM loop round 1
Session:
session_01FjqrwXPfSMkSfkKYDSRkN2Account:
os-zhuang(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11539-no-first-form-promotionWorktree:
objectui-issue-11539Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/app-shell/src/providers/MetadataProvider.tsx,applyViewItem:bucket.formis set only from a served form item that carriesisDefault. Read by this seat at objectuiorigin/main6f5719e1c,:424, as a lead;RecordFormPage/useActionModalreading.form): read and pinned, changed only if the measured fallback is itself broken, and then reported;@object-ui/app-shell.The dev stops on a breach and explains it in the report.
Container & model:
M,mode:subagent,model: opus(default judgment tier;dispatch-gates --tier --repo objectstack-ai/objectuiprinted "no path-derived mandate" forMetadataProvider.tsx)Clause-②: no
Why no: the console's merge rule narrows to the spec's own (
formis the default form; named forms are not promoted). No accept set widens, and no published surface is added.Thread-read: 5965736534
Serial constraints cleared: read 2026-10-03T12:36Z.
MetadataProvider.tsxis not among its 81 files.app-shellfile isuseConsoleActionRuntime.tsx, and objectui#10813's ismetadata-admin/inspectors/datasetFilterCondition*) are disjoint.objectui validateandobjectui checkjudge through the strict authoring face (objectui#5250, slice A) #11069 are disjoint.plugin-formModalForm.tsx) and objectui#9600 (ImportWizard.tsx,ObjectView.tsx) are disjoint by file..form, and that card changes how the dialog renders the view's sections.Generated by Claude Code
objectstack-fleet commentedon Oct 3, 2026
os-dev-report
{ "issue": 11539, "status": "done", "branch": "claude/issue-11539-no-first-form-promotion", "pr": "https://github.com/objectstack-ai/objectui/pull/11549", "session": "session_01FjqrwXPfSMkSfkKYDSRkN2 (mode:subagent of the PM session)", "premise_still_valid": true, "summary": "applyViewItem (packages/app-shell/src/providers/MetadataProvider.tsx) now sets bucket.form only from a served form item carrying isDefault; the `|| !bucket.form` first-arrival leg is gone and the docblock states the rule (arrival order decides nothing; a named form is reached only by name). The no-default path is named and pinned, not changed: resolveFormViewLayout returns {} so the AppContent New/Edit dialog and useActionModal hand ModalForm no sections (it lays out the object's own fields), and RecordFormPage's formDef resolves to {} (simple, no sections). Pins: showcase_inquiry shape yields no .form and the no-form-view layout; crm_lead and showcase_contact keep their default in both arrival orders; a container's declared form wins over a named one; a real ModalForm render of a merged named-only object shows every object field and not the named section. Note: objectstack PR #21535 has already landed on objectstack main (41b13331), so the change is live against servers built from it; objectui's bundled expandViewContainer still flags the first named form for UNEXPANDED containers, measured at 17.5.0 and again at 17.6.0 after the PM-requested merge of origin/main 6158e4c93 (objectui#11531); the card scopes that path to a later spec bump. Branch head is the merge commit a5ee27a (no rebase, no force); every gate below was re-run there.", "tests": "Final reading at merged HEAD a5ee27a (merge of origin/main 6158e4c93 into 8828bfa; @objectstack/spec resolves 17.6.0 after pnpm install). (1) Build: `pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2` -> 'Tasks: 28 successful, 28 total', VERDICT command-exit 0 (waited 8m31s for the verify lock). (2) type-check: `pnpm --filter @object-ui/app-shell type-check` (tsc --noEmit && tsc -p tsconfig.test.json) passed, chained with && before (3) in one locked command whose VERDICT is command-exit 0 (waited 2m54s for the lock); `tsc -p tsconfig.test.json --listFilesOnly` lists both edited test files (read at 8828bfa). (3) Narrowed, declared regression set, re-derived on the merged tree (same 162 files): app-shell + console tests naming MetadataProvider / mergeViewsIntoObjects / resolveFormViewLayout / recordFormNavigation / attachInlineSubforms, plus every app-shell + console test writing a form-family view (viewKind 'form' or formViews), including both edited test files -> 'Test Files 162 passed (162) / Tests 1633 passed (1633)'. Soundness: the changed line runs only for a form-family view; blind spot = a test feeding form views from a fixture file not named in its source (0 app-shell tests import examples/). NOT MEASURED: full packages/app-shell suite (974 files), reason: a run at 8828bfa held the shared lock about 18.5 min without finishing while objectui#11542's dev queued, and was stopped by its own PID; declared to CI pnpm test shards. (4) Same readings at the pre-merge head 8828bfa: build 28/28, type-check exit 0, the 162-file set 1633 passed, and the 2 targeted files 21/21 passed. (5) Ablation at 8828bfa via objectstack scripts/ablation-replace.mjs (each leg: anchor x1 -> x0, blob 6a7b90772f0d -> mutated, restored: blob == HEAD 6a7b90772f0d and `git diff HEAD` empty). Old rule `view.isDefault || !bucket.form` -> 3 failed | 18 passed (21): both showcase_inquiry pins and the ModalForm render pin. Last-wins `bucket.form = entry` -> 4 failed | 14 passed (18). First-wins `if (!bucket.form)` -> 5 failed | 13 passed (18). The test subjects import source (./MetadataProvider), not dist, so no dist preflight applies. Every leg went red, the expected direction.", "mcp_calls": "0", "api_writes": "2 — POST /repos/objectstack-ai/objectui/pulls (pr_create through fleet-write relay: dispatch POST /repos/objectstack-ai/objectstack/dispatches, run 37126303077, read-back 7667 bytes sent = 7667 stored); POST /repos/objectstack-ai/objectui/issues/11539/comments (this os-dev-report via post-stamped.mjs). The label-write PR-assignee call was refused by the auto-mode classifier before it ran: 0 writes there. git push x4 (not REST).", "gates": [ { "command": "pnpm check:control-bytes @ a5ee27a", "exit": 0, "verdict": "check-control-bytes: OK (scanned 10152 tracked text file(s); skipped 85 binary)." }, { "command": "pnpm check:new-line-citations @ a5ee27a", "exit": 0, "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0" }, { "command": "pnpm check:changeset-claims @ a5ee27a", "exit": 0, "verdict": "No pending changeset names a file this change touches." }, { "command": "pnpm check:pending-changeset-literals @ a5ee27a", "exit": 0, "verdict": "No test source names a pending changeset." }, { "command": "node scripts/check-changeset-presence.mjs @ a5ee27a", "exit": 0, "verdict": "3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)" }, { "command": "node scripts/check-changeset-no-major.mjs @ a5ee27a", "exit": 0, "verdict": "No changeset declares a `major` bump." }, { "command": "pnpm check:spec-symbols @ a5ee27a", "exit": 0, "verdict": "ledger anchors: 2 declared; none renders an instruction its anchor card can no longer receive." }, { "command": "pnpm check:esm-specifiers @ a5ee27a", "exit": 0, "verdict": "--specifiers-only: the load leg was not run" }, { "command": "pnpm check:self-import @ a5ee27a", "exit": 0, "verdict": "No package names itself inside its own src/." }, { "command": "pnpm check:unreferenced-sources @ a5ee27a", "exit": 0, "verdict": "OK Every shipped source file in every covered package is reachable." }, { "command": "node scripts/check-test-path-roots.mjs @ a5ee27a", "exit": 0, "verdict": "check-test-path-roots: OK" }, { "command": "node scripts/check-vi-mock-override-shape.mjs @ a5ee27a", "exit": 0, "verdict": "check-vi-mock-override-shape: OK" }, { "command": "node scripts/check-governed-queue-guard.mjs --test (4 changed paths) @ 8828bfa (same 4 paths at a5ee27a)", "exit": 0, "verdict": "NOT GOVERNED — 4 path(s) checked against 5 governed surface(s); none matched." }, { "command": "eslint (package config, inline config on) over the 3 touched source files @ a5ee27a", "exit": 0, "verdict": "3 files, 0 errors; MetadataProvider.tsx 52 warnings at base and at head" }, { "command": "pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2 @ a5ee27a", "exit": 0, "verdict": "Tasks: 28 successful, 28 total; os-verify-lock: VERDICT command-exit 0" }, { "command": "pnpm --filter @object-ui/app-shell type-check && pnpm exec vitest run --maxWorkers=2 (162 narrowed files) @ a5ee27a", "exit": 0, "verdict": "Test Files 162 passed (162); Tests 1633 passed (1633); os-verify-lock: VERDICT command-exit 0" } ], "files_changed": [ "packages/app-shell/src/providers/MetadataProvider.tsx", "packages/app-shell/src/providers/MetadataProvider.merge.test.ts", "packages/app-shell/src/hooks/__tests__/createModalHonorsFormView.test.tsx", ".changeset/11539-form-only-from-served-default.md" ], "deviations": [ "PR assignee NOT set: `node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 11549 --assign os-zhuang` (run from /home/user/objectstack) was refused by the Claude Code auto-mode classifier, reason [External System Writes]. Per contract: stopped, not re-routed; the seat sets PR #11549's assignee to os-zhuang. No other label was written; labeler.yml applied `tests` and `package: app-shell`.", "Test scope narrowed and declared (162 files, not the 974-file app-shell package); the full-package run was stopped unfinished to free the shared lock. CI's pnpm test shards own the full suite.", "Commit trailers use objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude) instead of the harness reminder's model-bearing Co-Authored-By line; the PR body ends with the os-dev session-URL footer instead of the harness's footer lines.", "Lint read: the os-dev template form `eslint --no-inline-config` reports 1 error on MetadataProvider.tsx (no-console in the `debug` helper, identical at base 6f5719e1c, suppressed there by an eslint-disable-next-line comment). objectui's own package lint is `eslint .` with inline config, which reports 0 errors; that is the reading cited.", "PR #11549's body was written once at 8828bfa. Its 'Local verification at 8828bfa' heading and its first Acceptance note (which cites bundled spec 17.5.0) are stale against the merged head a5ee27a. Per contract the dev does not PATCH the body. The seat can add one line: every local gate was re-run at merged head a5ee27a (spec 17.6.0) with the same results, and 17.6.0's expandViewContainer still flags a named-only container's first named form (re-measured).", "Verify-lock waits on the merged head: 8m31s before the build and 2m54s before type-check plus tests. The lock was held by sibling runs and acquired in turn, so no step was blocked." ], "line_budget": "n/a (no skills/** touched)", "open_questions": [], "out_of_scope_findings": [ "class: b · reach: named producer — objectstack examples/app-showcase `showcase_contact` list declares `addRecord: { enabled: true, mode: 'form', formView: 'create' }` · evidence: spec AddRecordConfigSchema.formView reads 'Named form view to use when mode is \"form\" or \"modal\"'; Seam: spec:AddRecordConfigSchema.formView → renderer: consumer: none — plugin-list ListView reads only addRecord.enabled and addRecord.position, `onAddRecord` is typed as a no-argument callback and is called with no arguments at all three add-record buttons, and a word-grep for `formView` over packages/*/src and apps/*/src (non-test) hits only the @object-ui/types declaration. Evidence is a source read, not a runtime reading (AGENTS.md asks an inert-key card to carry one); seat decides whether to file. Adjacent to this card: with first-named promotion gone, this is the spec's by-name route for a create form · dedupe words: addRecord formView unread · ListView onAddRecord no arguments · showcase_contact create form ignored · AddRecordConfigSchema formView consumer · named create form view console", "carrier: the objectui @objectstack/spec bump that carries objectstack#21535 (triage 5964333435 routes it there; 17.6.0 does not) · bundled expandViewContainer, measured at 17.5.0 and again at 17.6.0: a named-only UNEXPANDED container still gets isDefault:true on its first named form (showcase_inquiry.contact), so the stack gate keeps the promotion until then · noted, not filed", "carrier: 承接者:无 · RecordFormPage / ScreenView / resolveFormViewLayout fall back to an object-definition formViews key literally named `default` — a by-name lookup, not first-wins; no served row lands there (merged keys are canonical OBJECT.KEY) · observation, noted in PR Acceptance notes, not filed", "carrier: 承接者:无 · spec-side list family: expandViewContainer (17.5.0 and objectstack main) still promotes the first named list when a container has no `list`; outside this ruling, console bucket.primary has no such leg · observation, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 3, 2026
✅ ACCEPT: PR objectui#11549 at head
a5ee27a0a(dev report5969857997); landing through the merge queue in this actdomain:uiseat 1 ·session_01FjqrwXPfSMkSfkKYDSRkN2· 2026-10-03T13:59Z. Reviewed against GitHub, not the report.main. The first line isFixes #11539, with no other closing keyword.Clause-②: nois at line start.MetadataProvider.tsx, two test files and one@object-ui/app-shellpatch changeset.check-governed-merges --pr objectstack-ai/objectui#11549: NOT governed, 210 + 1 ≤ 5000.applyViewItemsetsbucket.formonlyif (view.isDefault). The|| !bucket.formleg is gone, as the ruling orders, and the docblock states the rule.bucket.primaryis untouched.resolveFormViewLayoutreturns no sections, so the dialog lays out the object's own fields.RecordFormPageresolves{}.showcase_inquiryshape yields no.form;crm_leadandshowcase_contactkeep their default in both arrival orders;formbeats a named one;ModalFormrender of a named-only object shows the object's fields, not the named section.a5ee27a0a(the merge ofmain6158e4c93, 17.6.0): 40success, 3skipped. The skipped areTest (coverage), the unexpandedcoverage shardmatrix name, anddependabot, all expected skips.mergeable_state: clean.isDefault" ✓ · "Arrival order decides nothing" ✓ (both-order pins) · "Servers that still stampisDefaulton a promoted named form see no change" ✓ (the rule reads the flag) · the bundled-spec caveat ✓ (measured by the dev at 17.5.0 and 17.6.0).8828bfa; the report re-ran every local gate on the merged heada5ee27a0awith the same results. This comment is that record. ⛔ No body edit.addRecord.formViewhas no reader in the console. Acceptance notes, not filed: class (b) and the producershowcase_contactis named, but the dev self-notes that the evidence is a source read with no runtime reading. Under the filing gate, a self-noted unmeasured (b) is not a card. A runtime reading is owed before anyone files it.expandViewContainerstill promotes the first named form at 17.5.0 and 17.6.0. Acceptance notes; the carrier is the@objectstack/specbump that carries objectstack#21535 (triage5964333435).formViews.defaultlookup by name: Acceptance notes, an observation.Generated by Claude Code
objectstack-fleet commentedon Oct 3, 2026
Landed and verified by content: closed
completedby PR objectui#11549 ·domain:uiseat 1 ·session_01FjqrwXPfSMkSfkKYDSRkN2· 2026-10-03T14:17Z.The merge: PR objectui#11549 went through the merge queue to
mainas9bfd0b36eat 2026-10-03T14:17Z.Content check of
packages/app-shell/src/providers/MetadataProvider.tsxonmain9bfd0b36eagainst its first parent7121221fa:mainif (view.isDefault || !bucket.form)if (view.isDefault) bucket.form = entry;function applyViewItemThe changeset and
MetadataProvider.merge.test.tsare both in themaintree.No other card closed in that window.
pm:dispatchedis removed in the same act.domain:ui,area:records, the type and the priority stay.Generated by Claude Code
Merge main (154075a) into claude/issue-11466-node-slot-union-v1 (obje…
fix(app-shell): a served form item becomes the create/edit form only …
feat(types,react,core,plugin-dashboard)!: a node slot and SchemaRende…
fix(spec): a view container's `form` is its default form — never coll…