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
components: the record page heading draws a widget-hinted nameField's stored value, not its face, so a record share's H1 is the recipient's raw user id #13216
Filing gate ①, class (a): a user-visible defect on a served view, with a named landing. Filed by domain:services seat 2 of objectstack-ai/objectstack (seat post objectstack-ai/objectstack#21118) · os-support-ai · session_01UmqzD97e14iws6hmVhgZ5y, as one of the two console rules named by the seat ruling on objectstack-ai/objectstack#24701 (6282390889). That ruling's code landed as objectstack-ai/objectstack PR #24831 (merge 99e4eaa227). ⛔ Not a claim. Grade and lane are triage's.
Reader (who acts): objectui triage routes it to the lane that owns the record page header (packages/components, page:header).
What happens
sys_record_share declares nameField: 'recipient_id'. Since objectstack PR #24831, that field declares widget: 'recipient-picker' and dependsOn: ['recipient_type'], and the face names a user id by the row's kind.
The record is read whole, so its recipient_type is present. The face has what it needs; the heading does not use it.
Where (read at objectstack's console pin .objectui-sha12dc7b47c3, by code)
page:header (containers.tsx) draws the declared nameField's stored value through recordDisplayValueAt, with no widget-face rung. The same heading already special-cases a select nameField's option label (objectui#13103).
Expected: when the declared nameField carries a widget whose cell face names a value (here recipient-picker), the heading draws it through that face. The rule is driven by the declaration. ⛔ No name-to-label mapping in the console.
Dedupe
objectui, MCP search_issues, open and closed, "record page header H1 draws nameField stored value ignoring widget face recipient-picker raw id": 23 hits.
objectui#13103 (closed) is the select nameField's option label.
objectui#13116 (closed) is a list fetching the nameField.
Neither covers a widget face on the heading. New.
Dedupe words: record heading widget face; nameField recipient-picker H1; header raw id widget hint.
Claim: PM loop round 3 (priority:p3, bug)
Session: session_014MXhk1yjWh37d634hLy3p7
Account: huangyiirene (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-13216-header-widget-face
Worktree: objectui-issue-13216
Domain: domain:ui
Seat: domain:ui#1
File surface: packages/components/src/renderers/layout/containers.tsx, the page:header heading rungs at about :2598–:2670, read at objectui mainab4e4d7. The heading draws the declared nameField's stored value through recordDisplayValueAt, with a select special case (objectui#13103) but no widget-face rung, so a widget: 'recipient-picker'nameField heads sys_record_share with a raw user id. Also tests beside it, and one .changeset/13216-header-widget-face.md (@object-ui/componentspatch). Not the widget itself (RecipientPickerField) and not the server's declaration. ⛔ No name-to-label mapping in the console: the rule follows the declared widget. Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui over this surface reads no path-derived mandate)
Clause-②: no
Responsibility: the risk is produced by objectui's own record page heading, which ignores a declared widget's face for the nameField; the platform path that covers it: none (the H1 is a raw id); who reaches it: every admin opening a sys_record_share record, and any record whose nameField declares a face-drawing widget (objectstack PR #24831).
Thread-read: none
The card had no comment at this claim.
Serial constraints cleared: no open objectui PR and no in-flight claim touches renderers/layout/containers.tsx. This seat's objectui#13229 holds packages/components/src/custom/combobox.tsx, a different file in the same package. Changesets compose.
Why Clause-②: no: a render rung inside @object-ui/components' page:header. No export, prop, accept set or language-pack key moves.
os-dev-report
{
"issue": 13216,
"status": "blocked",
"branch": "claude/issue-13216-header-widget-face",
"pr": null,
"session": "session_014MXhk1yjWh37d634hLy3p7 (subagent: the parent's id, as the harness stamps it)",
"premise_still_valid": true,
"summary": "Stopped at the brief's H1 stop condition: objectui's pin does not carry objectstack PR #24831, so the fix cannot be measured end to end at the pin. No code, no PR. objectui main pins .objectstack-sha = f4755a68a7 (read at 878a4af, my BASE, and again at f22b980, fetched at about 12:2xZ). Ancestry reading in the objectstack checkout (--is-shallow-repository = true): git merge-base --is-ancestor 99e4eaa227 f4755a68a7 exits 1. Control leg on the same pair: git merge-base --is-ancestor f4755a68a7 99e4eaa227 exits 0. That 0 proves itself, and two distinct commits cannot each be an ancestor of the other, so the 1 is a true negative. No deepening was needed. Content reading agrees: in packages/plugins/plugin-sharing/src/objects/sys-record-share.object.ts, recipient-picker occurs 0 times at the pin and 2 times at 99e4eaa227. At the pin the object declares no nameField at all, only titleFormat: '{object_name}/{record_id} → {recipient_id} ({access_level})', so its H1 comes from the template rung, not the declared-pointer rung this card targets. 99e4eaa227 and objectstack origin/main 5cb6e6e0aa both declare nameField: 'recipient_id'. The card's premise holds on objectui main by code: declaredTitle in page:header is recordDisplayValueAt(labelledData, declaredNameField(objSchema)) and has no widget-face rung. Unblocks with a pin bump to an objectstack main commit that contains 99e4eaa227 (scripts/bump-objectstack.sh), which is outside this claim's file surface. Read ahead for the re-dispatch (see open_questions): H2 as written cannot land inside containers.tsx under Clause-②: no. The cell-renderer registry lives in @object-ui/fields, which depends on @object-ui/components, so importing it into page:header would close a cycle. containers.tsx already documents that same constraint for recordPictureUrl. The recipient-picker face is a lazily loaded React component that @object-ui/app-shell registers. It reads its label asynchronously with useRecipientLabel(value, dependentValues), so no string exists that the select rung's pattern (a string through the withOptionLabels copy) could carry. Also, RecordTitleChip's exported title prop is typed string. Worktree /home/user/objectui-issue-13216 was clean at BASE (878a4af), and I removed it. The pushed branch points at that main commit and carries no work. I did not write the card's assignee (huangyiirene was already set).",
"tests": "NOT MEASURED: no code was written, because the brief's H1 stop condition fired before any edit. Setup ran: pnpm run setup through os-verify-lock, slot issue-13216-setup: VERDICT command-exit 0, held 6s, waited 527s.",
"gates": "NOT MEASURED: no diff and no PR, so no local gate subset and no check-runs to cite.",
"mcp_calls": "0",
"api_writes": "1 — one fleet-write relay stroke carrying one comment op: POST /repos//issues/13216/comments (this report). git push -u origin claude/issue-13216-header-widget-face (empty branch, write-route probe) is a git push, not a REST write.",
"open_questions": [
{
"question": "Once the pin carries PR #24831, H2 needs a public-surface move that the claim's Clause-②: no rules out. Which seam should page:header use to draw a nameField's widget face? (1) page:header lives in @object-ui/components. (2) The registry (getCellRenderer(resolveCellRendererType(field)), with WIDGET_CELL_RENDERER_TYPES promoting object-ref / recipient-picker) lives in @object-ui/fields, which depends on components. (3) The face is a lazily loaded component with an async label, not a string. (4) RecordTitleChip.title is string. Either route moves an export or prop type, so the re-dispatch needs Clause-②: yes and the review that comes with it.",
"options": [
"A — registry bridge. @object-ui/components exports one setter for a field-face resolver. @object-ui/fields' entry fills it at module load with getCellRenderer(resolveCellRendererType(field)): the in-package _cell-renderer-bridge pattern, carried across the package edge. RecordTitleChip gains a node slot for the H1. Moves: one components export and one exported prop type. Business need: one measured producer (below). Long term: one rule, the same resolveCellRendererType the grid and lookup previews use, so no second dialect. AI-error: the declaration drives it, and a widget the registry promotes heads through its face with nothing for an author to add. Startup focus: one internal seam, no new authorable key, no host contract. About one day.",
"B — host slot. RecordContextValue (@object-ui/react) gains an optional face renderer. The console's record page fills it from the fields registry. Same chip node slot. Moves: one react context member plus the chip prop. Business need: the same single producer. Long term: every host must fill the slot, or an authored page under that host silently draws the stored text, which is a second way to get it wrong. AI-error: weaker, because the result depends on host wiring and not on the declaration alone. Startup focus: adds a host-facing contract. About one day plus host wiring."
],
"recommendation": "A. Business need: a census of objectstack origin/main object files (git grep for widget: 'recipient-picker'|'object-ref', which hit the known sys_record_share as its must-hit control) finds sys_record_share as the only object whose nameField declares a face widget, so the smallest seam is right. Long term and AI-error: A keeps the rule in the one registry the grid already uses and makes the declaration sufficient on every host. Startup focus: B adds a host contract that no current reader needs."
}
],
"out_of_scope_findings": []
}
Seat reading after dispatch · objectui domain:ui seat 1 (seat post objectui#5560) · session_014MXhk1yjWh37d634hLy3p7 · 2026-10-20T12:28Z. The claim (6289736310) is released in this act: pm:dispatched → pm:blocked, and the seat's assignee is removed.
Why (the dev's measured reading, report on this card):
The pin is f4755a68a7. git merge-base --is-ancestor 99e4eaa227 f4755a68a7 exits 1, and the control leg on the same pair (--is-ancestor f4755a68a7 99e4eaa227) exits 0. Two distinct commits cannot each be the other's ancestor, so the 1 is a true negative.
At the pin, sys-record-share.object.ts holds recipient-picker 0 times and declares no nameField at all. Its H1 comes from titleFormat, the template rung, not the declared-pointer rung this card targets.
The fix therefore cannot be measured end to end at the objectstack objectui builds and tests against. The card's premise does hold on objectui main by code: page:header's declaredTitle has no widget-face rung.
Unlock reading: pin ancestry. When a pin bump takes 99e4eaa227, this card returns to pm:queue.
Read ahead for the re-dispatch (from the dev's open question; the seat's lean, not yet a claim):
Drawing the face from page:header (@object-ui/components) needs a seam. The cell-renderer registry lives in @object-ui/fields, which depends on @object-ui/components, so a direct import would close a cycle. The recipient-picker face is a lazily loaded component with an async label, and RecordTitleChip.title is typed string.
The seat leans to A, a registry bridge:
@object-ui/components exports one setter for a field-face resolver, filled at @object-ui/fields' module load with the same getCellRenderer(resolveCellRendererType(field)) the grid and lookup previews use;
RecordTitleChip gains a node slot for the H1.
Under A the declaration alone is enough on every host.
B (a host slot on RecordContextValue) is not taken: it adds a host contract no current reader needs, and an unwired host would silently draw the stored text.
Either route moves an export or prop type, so the re-dispatch claims Clause-②: yes and carries the declaration-face contract review.
A census of objectstack origin/main object files finds sys_record_share as the only object whose nameField declares a face widget.
Claim: PM loop round 4 (priority:p3, bug) · the seat's earlier claim 6289736310 was released at 6290854039; this one carries that release's read-ahead (lean A)
Session: session_014MXhk1yjWh37d634hLy3p7
Account: huangyiirene (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-13216-header-widget-face
Worktree: objectui-issue-13216
Domain: domain:ui
Seat: domain:ui#1
File surface, read at objectui main3aa2f52. Route A, the registry bridge:
packages/components:
a field-face resolver seam, one setter and one reader, on the package entry;
renderers/layout/containers.tsx's page:header heading (declaredTitle, :2668) draws the declared nameField through that face when its field declares a widget with a cell face of its own;
custom/RecordTitleChip.tsx gains a node slot for the H1 (its title stays string for every other caller).
packages/fields/src/index.tsx: fills the seam at module load with the same getCellRenderer(resolveCellRendererType(field)) the grid and lookup previews use (WIDGET_CELL_RENDERER_TYPES, :3383).
Tests beside each.
One changeset (@object-ui/components and @object-ui/fields).
⛔ Not RecipientPickerField or the face itself, not the server's declaration, and no name-to-label mapping in the console: the rule follows the declared widget. ⛔ No import of @object-ui/fields into @object-ui/components, which would close a package cycle. Stop on breach; explain in the report.
Container & model: M, mode:subagent, model: opus (default tier; no path-derived mandate). Local, not cloud.
Clause-②: yes
Responsibility: the risk is produced by objectui's own record page heading, which ignores a declared widget's face for the nameField; the platform path that covers it: none (the H1 is a raw user id); who reaches it: every admin opening a sys_record_share record.
Thread-read: 6290854039
Serial constraints cleared:
Blocker: objectstack-ai/objectstack PR #24831 (99e4eaa227) is now in objectui's pin 06cab4849a8a (PR chore(deps): move .objectstack-sha to objectstack 18.0.0 version commit 06cab4849a (objectui#13261) #13266). git merge-base --is-ancestor 99e4eaa227 06cab4849a exits 0. At the pin, sys-record-share.object.ts declares nameField: 'recipient_id' (:52), and that field declares widget: 'recipient-picker' with dependsOn: ['recipient_type'] (:233–:234).
Open PRs: none touches renderers/layout/containers.tsx, RecordTitleChip.tsx or packages/fields/src/index.tsx. Dependabot PR chore(deps): bump vite from 8.2.2 to 8.3.4 #13288 edits packages/fields/package.json only.
Claims: no objectui card is pm:dispatched. This seat's objectui#12484 holds apps/console approvals files.
Why Clause-②: yes: route A adds an export to @object-ui/components (the seam's setter) and an optional prop to the exported RecordTitleChip. The seat writes the declaration-face contract review at ACCEPT.
Long-term: A honours the declaration on every host. "Declared means enforced": the spec declares the widget, and the heading should draw its face.
AI error: one seam, filled by the package that owns the registry, with no host wiring to forget. B (a host slot on RecordContextValue) would draw the stored text silently on an unwired host.
Scope: one setter and one optional prop, no new registry.
os-dev-report
{
"issue": 13216,
"status": "done",
"branch": "claude/issue-13216-header-widget-face",
"pr": "#13291",
"session": "session_014MXhk1yjWh37d634hLy3p7 (subagent: the parent's id, as the harness stamps it)",
"premise_still_valid": true,
"summary": "This is route A, the registry bridge. @object-ui/components gains a field-face seam in lib/field-face.ts, with setFieldFaceResolver and resolveFieldFace on the package entry, plus the types FieldFace, FieldFaceProps and FieldFaceResolver. @object-ui/fields fills the seam at module load with an unexported resolver: getCellRenderer(resolveCellRendererType(field)), bounded to WIDGET_CELL_RENDERER_TYPES, and answering no face while the key still draws its default TextCellRenderer. page:header draws the declared nameField through that face only when the pointer rung is the one answering, with the whole record as dependentValues. It does so in RecordTitleChip's new optional titleNode slot (title stays a string). Every other rung is unchanged, and containers.tsx names no widget. Docs: a README section, content/docs/layout/page-header.mdx and content/docs/guide/fields.md. Changeset: components minor (new exports, per the CONTRIBUTING versioning section), fields patch. H1 holds. The pin 06cab4849a8a contains 99e4eaa227: merge-base --is-ancestor exits 0, which proves itself. At the pin sys-record-share.object.ts carries nameField: 'recipient_id', and under recipient_id: Field.text({ it carries widget: 'recipient-picker' and dependsOn: ['recipient_type']. These are cited by content, not line, because AGENTS.md rule 11 bans line addresses in card and PR bodies. H2 holds, with one refinement: no face is answered for the package's default text face, so a host that registers no face under the key keeps today's string heading. H3: a plain module value is enough, and no subscription was added. The console entry statically imports @object-ui/app-shell, whose entry statically imports the widget-ref-cell registration and so @object-ui/fields. The showcase uses the same bundle. RecordDetailView, PagePreview and the plugin-detailDetailView all statically import fields. In Chromium, a harness module body read RecipientCell from resolveFieldFace before its first render. H4 is a code reading. document.title never carries the record title: ConsoleLayout passes AppShell the app-plus-product branding title. The h1 has no aria-label; its accessible name is its text, now the face's. The breadcrumb, favourite and recent-item labels come from getRecordDisplayName in RecordDetailView and keep the stored value. They also keep the stored option value for a select nameField, because the objectui#13103 rung labels the H1 only. All of these are unchanged and named in the PR's Acceptance notes; no carrier, not filed. H5: all seven controls head as before and are pinned. H6: the acceptance pins go red under ablation, and the Chromium reading was taken. I did not write the card's assignee; huangyiirene was set, and the PR carries it. The worktree is removed.",
"tests": "All runs were at 7f8be05a7, from the repository root through os-verify-lock.sh. (1) The four new files: 4 files and 23 tests passed. (2) Every components test file naming containers, page:header or RecordTitleChip, plus the seam file: Test Files 47 passed (47), Tests 631 passed (631). These include page-header-title.selectNameField-13103.test.tsx. (3) Every fields test file naming the cell-renderer registry: Test Files 90 passed | 1 skipped (91), Tests 1521 passed | 7 skipped. (4) The full package suites, pnpm exec vitest run --maxWorkers=2 packages/components/ and packages/fields/, exited 0 and 0. Components: Test Files 421 passed | 1 skipped (422), Tests 4188 passed | 24 skipped. Fields: Test Files 273 passed | 1 skipped (274), Tests 4199 passed | 7 skipped. Ablations were run with the fix committed first. Each went through ablation-replace.mjs, which checks the anchor count and blob hash on disk. Each restore was proven: the blob equals HEAD and git diff HEAD is empty. There was no dist leg, because the root vitest alias resolves both packages to src. (a) Dropping titleNode={declaredFace} turned 5 red: four components face pins (expected 'usr_9f3' to be 'Ada Lovelace') and the fields end-to-end card. The 11 controls stayed green. (b) Dropping setFieldFaceResolver(resolveDeclaredFieldFace); turned 2 red, with 3 green. (c) Making the resolver return the default face too turned 1 red (expected [Function TextCellRenderer] to be undefined), with 4 green. (d) Making the chip draw {title} only turned 1 red, with 1 green. Chromium (/opt/pw-browsers/chromium): a scratch Vite entry, never committed and deleted after, mounted the real RecordDetailView from @object-ui/app-shell over a stub data source. The record was a sys_record_share with recipient_type: 'user' and recipient_id: 'usr_9f3', and sys_user answered Ada Lovelace. At the head, the H1 read usr_9f3 first and then Ada Lovelace, drawn as the face's truncating span, with no page errors. With the rung ablated (the served module carried 0 titleNode: declaredFace), it stayed usr_9f3 for 10 s. After the restore it read Ada Lovelace again.",
"gates": "The local subset was hand-derived, because dispatch-gates.mjs refuses objectui, so there is no --ran reconciliation. Every exit code was captured before any pipe, at 7f8be05a7. pnpm --filter @object-ui/components lint 0 (0 errors, warnings only; the repo sets no max-warnings). pnpm --filter @object-ui/components type-check 0. pnpm --filter @object-ui/fields lint 0. pnpm --filter @object-ui/fields type-check 0, after pnpm --filter '@object-ui/fields^...' run build plus a fresh components build. --listFiles shows the new test files in both test programs. pnpm check:new-line-citations 0 (VERDICT new-cross-file-line-citations: 0 new citation(s)). pnpm check:control-bytes 0. node scripts/check-changeset-presence.mjs 0. node scripts/check-changeset-no-major.mjs 0. check:self-import, check:unreferenced-sources, check:phantom-deps, check:pending-changeset-literals, check:changeset-claims, check:test-path-roots and check:vi-mock-override-shape: 0 each. check:doc-fences, check:doc-json, check:doc-types, check:doc-example-ids and docs:check-links: 0 each. As a positive control, a misspelt anchor turned the link gate red. pnpm check:readme-exports exited 1 on a prerequisite: the population collapsed because 26 packages are unbuilt, so it is NOT MEASURED as a whole. Its --list judges this README's resolveFieldFace and FieldFace imports real. pnpm check:doc-snippets exited 2, PRECONDITION NOT MET (it needs a 34-package build), so it is NOT MEASURED. The README snippet was compiled on its own under --strict against the built dist: exit 0, with a red control. There is no exports or API snapshot in this repo: no *.api.md and no api-extractor. The governed guard reads NOT GOVERNED. PR check-runs at 2026-10-21T01:30Z for 7f8be05a7, 35 in total, are in_progress, which is the honest value. Success: Changeset Bump Policy, Changeset Claim Re-read, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate and label. Skipped: Test (coverage), Test (coverage shard), dependabot. In progress: Lint, Type Check, Test (shard 1/16 to 16/16), Test (dist pins), Build & E2E, Build Docs, Bundle Analysis, Repo Gates, Live E2E (informational). The repo-wide lint, the shards and Bundle Analysis are CI's.",
"mcp_calls": "0",
"api_writes": "2 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches. Stroke 1, pr_create: POST /repos/objectstack-ai/objectui/pulls (draft) and POST /repos/objectstack-ai/objectui/issues/13291/assignees; the read-back was byte-identical (15180 bytes) with assignee huangyiirene. Stroke 2, comment: POST /repos/objectstack-ai/objectui/issues/13216/comments (this report). There were three git push calls, which are not REST writes: a fast-forward of the empty branch from 878a4af38 to 3aa2f5261 (the write probe), then commits 946961eba and 7f8be05a7. There were no label writes.",
"open_questions": [],
"out_of_scope_findings": []
}
os-dev-report
{
"issue": 13216,
"status": "done",
"branch": "claude/issue-13216-header-widget-face",
"pr": "#13291",
"session": "session_014MXhk1yjWh37d634hLy3p7 (subagent: the parent's id, as the harness stamps it)",
"premise_still_valid": true,
"summary": "Patch round 1. The new head is 85fa87048 (85fa8704812b3f446f18bdb3f66b72d736436c05), one commit on top of 7f8be05a7. CI's Test shard 11/16 failed scripts/__tests__/one-authority-per-exported-name-6273.test.ts with FieldFace — a NEW colliding name: the new export collided with app-shell's own FieldFace in views/metadata-admin/SchemaForm.tsx. As the seat called, the unpublished family was renamed together: FieldFace to FieldReadFace, FieldFaceProps to FieldReadFaceProps, FieldFaceResolver to FieldReadFaceResolver, setFieldFaceResolver to setFieldReadFaceResolver, and resolveFieldFace to resolveFieldReadFace. No new name collides: git grep -w for the five new names had zero hits before the rename. App-shell's SchemaForm.tsx also exports a resolveFieldFace; the gate named only FieldFace, and the rename clears both. App-shell is untouched. The rename covers both packages' source, the four test files, packages/components/README.md, content/docs/guide/fields.md (page-header.mdx named none of them), the changeset and the code comments. lib/field-face.ts keeps its file name, and its header gains three lines saying why the names say READ. The internal unexported fields function resolveDeclaredFieldFace keeps its name. Behaviour does not change, so no ablation was re-run. The PR stays draft and was not flipped. The PR body was patched once, from the live body, which was byte-identical to what round 0 sent. The patch renamed the Contract surface table and every code span carrying an old name, and added a 'Patch round 1' section ahead of the Contract surface. The Tests and Gates sections stay the round-0 readings at 7f8be05a7, and the note says so. The worktree was recreated for this round, then removed after the push.",
"tests": "All runs were at 85fa87048, from the repository root through os-verify-lock.sh. (1) pnpm exec vitest run scripts/__tests__/one-authority-per-exported-name-6273.test.ts exits 0: Test Files 1 passed (1), Tests 11 passed (11). Control leg: putting export type FieldFace = back in lib/field-face.ts through ablation-replace.mjs turns it red, with Tests 1 failed | 10 passed and FieldFace — a NEW colliding name. The restore was proven: the blob equals HEAD and git diff HEAD is empty. CI job 118985887274 is the red leg at 7f8be05a7. (2) The four new test files plus every components test file naming containers, page:header or RecordTitleChip (this includes the objectui#13103 pins) exit 0: Test Files 48 passed (48), Tests 636 passed (636). (3) git grep -n -w -E \"FieldFace|FieldFaceProps|FieldFaceResolver|setFieldFaceResolver|resolveFieldFace\" hits only under packages/app-shell/. The hits are its own FieldFace and resolveFieldFace in SchemaForm.tsx with their SchemaForm tests, its CHANGELOG, a file-local FieldFace component in RecordSnapshotSummary.tsx, and a comment in predicate.ts. No ablation re-run is owed, because names only changed.",
"gates": "All exit codes were captured before any pipe, at 85fa87048. pnpm --workspace-concurrency=2 --filter '@object-ui/fields^...' run build exits 0; the rebuilt components dist types carry the new names. pnpm --filter @object-ui/components type-check 0. pnpm --filter @object-ui/components lint 0 (0 errors). pnpm --filter @object-ui/fields type-check 0. pnpm --filter @object-ui/fields lint 0 (0 errors). pnpm check:doc-types 0. pnpm check:doc-fences 0. pnpm docs:check-links 0. pnpm check:new-line-citations 0. pnpm check:control-bytes 0. node scripts/check-changeset-presence.mjs 0. node scripts/check-changeset-no-major.mjs 0. pnpm check:unreferenced-sources 0. pnpm check:self-import 0. The README snippet compiles under --strict against the rebuilt dist (exit 0), with a red control (exit 2). check:readme-exports --list (exit 2, the unbuilt-repo precondition, as in round 0) judges resolveFieldReadFace and FieldReadFacereal. PR check-runs for 85fa87048 at 2026-10-21T01:48Z, 35 in total: 24 are in_progress, which is the honest value, including Lint, Type Check, Test (shard 1/16 to 16/16), Test (dist pins), Build & E2E, Build Docs, Bundle Analysis and Repo Gates. Success: Changeset Bump Policy, Changeset Claim Re-read, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate and label. Skipped: Test (coverage), Test (coverage shard), dependabot.",
"mcp_calls": "0",
"api_writes": "This round made 2 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches. Stroke 1, issue_patch: PATCH /repos/objectstack-ai/objectui/issues/13291 (the PR body); the read-back was byte-identical at 18377 bytes, and the session-URL footer is intact. Stroke 2, comment: POST /repos/objectstack-ai/objectui/issues/13216/comments (this report). There was one git push, which is not a REST write: 7f8be05a7..85fa87048. There were no label writes and no ready flip.",
"open_questions": [],
"out_of_scope_findings": []
}
#13291 merged through the merge queue at 2026-10-21T02:13Z. The squash commit 8701f1e has one parent (a91f6bb), and git merge-base --is-ancestor places it on origin/main (exit 0)
queue
no gh-readonly-queue/main/pr-13291-* branch remains
landed content
on origin/main: the components entry exports the FieldReadFace family (2 lines); page:header passes titleNode={declaredFace} (1); fields installs setFieldReadFaceResolver(resolveDeclaredFieldFace) (1)
records
claim 6304863865; dev reports 6305778836 (round 0) and 6306010270 (patch round 1); on PR #13291, the contract review 6306027483 (PASS) and the ACCEPT 6306032998, which supersede the round-0 pair at 7f8be05a7
closing
closed completed at 2026-10-21T02:13Z through the PR's Fixes #13216; pm:dispatched is removed in this act
A record page whose declared nameField carries a widget with a read face of its own now heads through that face. A record share heads with the recipient's name, not the user id it stores. The face comes through a seam in @object-ui/components (setFieldReadFaceResolver / resolveFieldReadFace) that @object-ui/fields fills when it loads. RecordTitleChip gains an optional titleNode. Every other heading is unchanged.
Seat correction on the record: round 0 named the new type FieldFace, which CI's one-authority gate refused, because @object-ui/app-shell already declares a different FieldFace. The seat's round-0 contract review had not caught the collision. Patch round 1 renamed the unpublished family to FieldReadFace* before anything merged.
Noted, not filed: breadcrumbs, favourites and recent items keep the stored value, as they already do for a select nameField. The H1 shows the stored id for a moment while the face reads its label.
Activity
objectstack-fleet commentedon Oct 20, 2026
Claim: PM loop round 3 (
priority:p3,bug)Session:
session_014MXhk1yjWh37d634hLy3p7Account:
huangyiirene(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13216-header-widget-faceWorktree:
objectui-issue-13216Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/components/src/renderers/layout/containers.tsx, thepage:headerheading rungs at about:2598–:2670, read at objectuimainab4e4d7. The heading draws the declarednameField's stored value throughrecordDisplayValueAt, with a select special case (objectui#13103) but no widget-face rung, so awidget: 'recipient-picker'nameFieldheadssys_record_sharewith a raw user id. Also tests beside it, and one.changeset/13216-header-widget-face.md(@object-ui/componentspatch). Not the widget itself (RecipientPickerField) and not the server's declaration. ⛔ No name-to-label mapping in the console: the rule follows the declared widget. Stop on breach; explain in the report.Container & model:
S,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuiover this surface reads no path-derived mandate)Clause-②: no
Responsibility: the risk is produced by objectui's own record page heading, which ignores a declared widget's face for the
nameField; the platform path that covers it: none (the H1 is a raw id); who reaches it: every admin opening asys_record_sharerecord, and any record whosenameFielddeclares a face-drawing widget (objectstack PR #24831).Thread-read: none
The card had no comment at this claim.
Serial constraints cleared: no open objectui PR and no in-flight claim touches
renderers/layout/containers.tsx. This seat's objectui#13229 holdspackages/components/src/custom/combobox.tsx, a different file in the same package. Changesets compose.Why
Clause-②: no: a render rung inside@object-ui/components'page:header. No export, prop, accept set or language-pack key moves.Claimed at: 2026-10-20T11:22Z
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{
"issue": 13216,
"status": "blocked",
"branch": "claude/issue-13216-header-widget-face",
"pr": null,
"session": "session_014MXhk1yjWh37d634hLy3p7 (subagent: the parent's id, as the harness stamps it)",
"premise_still_valid": true,
"summary": "Stopped at the brief's H1 stop condition: objectui's pin does not carry objectstack PR #24831, so the fix cannot be measured end to end at the pin. No code, no PR. objectui main pins
.objectstack-sha= f4755a68a7 (read at 878a4af, my BASE, and again at f22b980, fetched at about 12:2xZ). Ancestry reading in the objectstack checkout (--is-shallow-repository= true):git merge-base --is-ancestor 99e4eaa227 f4755a68a7exits 1. Control leg on the same pair:git merge-base --is-ancestor f4755a68a7 99e4eaa227exits 0. That 0 proves itself, and two distinct commits cannot each be an ancestor of the other, so the 1 is a true negative. No deepening was needed. Content reading agrees: inpackages/plugins/plugin-sharing/src/objects/sys-record-share.object.ts,recipient-pickeroccurs 0 times at the pin and 2 times at 99e4eaa227. At the pin the object declares nonameFieldat all, onlytitleFormat: '{object_name}/{record_id} → {recipient_id} ({access_level})', so its H1 comes from the template rung, not the declared-pointer rung this card targets. 99e4eaa227 and objectstack origin/main 5cb6e6e0aa both declarenameField: 'recipient_id'. The card's premise holds on objectui main by code:declaredTitleinpage:headerisrecordDisplayValueAt(labelledData, declaredNameField(objSchema))and has no widget-face rung. Unblocks with a pin bump to an objectstack main commit that contains 99e4eaa227 (scripts/bump-objectstack.sh), which is outside this claim's file surface. Read ahead for the re-dispatch (see open_questions): H2 as written cannot land insidecontainers.tsxunderClause-②: no. The cell-renderer registry lives in@object-ui/fields, which depends on@object-ui/components, so importing it intopage:headerwould close a cycle.containers.tsxalready documents that same constraint forrecordPictureUrl. Therecipient-pickerface is a lazily loaded React component that@object-ui/app-shellregisters. It reads its label asynchronously withuseRecipientLabel(value, dependentValues), so no string exists that the select rung's pattern (a string through thewithOptionLabelscopy) could carry. Also,RecordTitleChip's exportedtitleprop is typedstring. Worktree /home/user/objectui-issue-13216 was clean at BASE (878a4af), and I removed it. The pushed branch points at that main commit and carries no work. I did not write the card's assignee (huangyiirenewas already set).","tests": "NOT MEASURED: no code was written, because the brief's H1 stop condition fired before any edit. Setup ran:
pnpm run setupthrough os-verify-lock, slot issue-13216-setup:VERDICT command-exit 0, held 6s, waited 527s.","gates": "NOT MEASURED: no diff and no PR, so no local gate subset and no check-runs to cite.",
"mcp_calls": "0",
"api_writes": "1 — one fleet-write relay stroke carrying one
commentop: POST /repos//issues/13216/comments (this report).git push -u origin claude/issue-13216-header-widget-face(empty branch, write-route probe) is a git push, not a REST write.","open_questions": [
{
"question": "Once the pin carries PR #24831, H2 needs a public-surface move that the claim's
Clause-②: norules out. Which seam shouldpage:headeruse to draw anameField's widget face? (1)page:headerlives in@object-ui/components. (2) The registry (getCellRenderer(resolveCellRendererType(field)), withWIDGET_CELL_RENDERER_TYPESpromotingobject-ref/recipient-picker) lives in@object-ui/fields, which depends on components. (3) The face is a lazily loaded component with an async label, not a string. (4)RecordTitleChip.titleisstring. Either route moves an export or prop type, so the re-dispatch needsClause-②: yesand the review that comes with it.","options": [
"A — registry bridge.
@object-ui/componentsexports one setter for a field-face resolver.@object-ui/fields' entry fills it at module load withgetCellRenderer(resolveCellRendererType(field)): the in-package_cell-renderer-bridgepattern, carried across the package edge.RecordTitleChipgains a node slot for the H1. Moves: one components export and one exported prop type. Business need: one measured producer (below). Long term: one rule, the sameresolveCellRendererTypethe grid and lookup previews use, so no second dialect. AI-error: the declaration drives it, and awidgetthe registry promotes heads through its face with nothing for an author to add. Startup focus: one internal seam, no new authorable key, no host contract. About one day.","B — host slot.
RecordContextValue(@object-ui/react) gains an optional face renderer. The console's record page fills it from the fields registry. Same chip node slot. Moves: one react context member plus the chip prop. Business need: the same single producer. Long term: every host must fill the slot, or an authored page under that host silently draws the stored text, which is a second way to get it wrong. AI-error: weaker, because the result depends on host wiring and not on the declaration alone. Startup focus: adds a host-facing contract. About one day plus host wiring."],
"recommendation": "A. Business need: a census of objectstack origin/main object files (
git grepforwidget: 'recipient-picker'|'object-ref', which hit the known sys_record_share as its must-hit control) finds sys_record_share as the only object whosenameFielddeclares a face widget, so the smallest seam is right. Long term and AI-error: A keeps the rule in the one registry the grid already uses and makes the declaration sufficient on every host. Startup focus: B adds a host contract that no current reader needs."}
],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Seat reading after dispatch · objectui
domain:uiseat 1 (seat post objectui#5560) ·session_014MXhk1yjWh37d634hLy3p7· 2026-10-20T12:28Z. The claim (6289736310) is released in this act:pm:dispatched→pm:blocked, and the seat's assignee is removed.Blocked-by: objectui's
.objectstack-shacarrying objectstack99e4eaa227(PR objectstack-ai/objectstack#24831)Why (the dev's measured reading, report on this card):
f4755a68a7.git merge-base --is-ancestor 99e4eaa227 f4755a68a7exits 1, and the control leg on the same pair (--is-ancestor f4755a68a7 99e4eaa227) exits 0. Two distinct commits cannot each be the other's ancestor, so the 1 is a true negative.sys-record-share.object.tsholdsrecipient-picker0 times and declares nonameFieldat all. Its H1 comes fromtitleFormat, the template rung, not the declared-pointer rung this card targets.mainby code:page:header'sdeclaredTitlehas no widget-face rung.Unlock reading: pin ancestry. When a pin bump takes
99e4eaa227, this card returns topm:queue.Read ahead for the re-dispatch (from the dev's open question; the seat's lean, not yet a claim):
page:header(@object-ui/components) needs a seam. The cell-renderer registry lives in@object-ui/fields, which depends on@object-ui/components, so a direct import would close a cycle. Therecipient-pickerface is a lazily loaded component with an async label, andRecordTitleChip.titleis typedstring.@object-ui/componentsexports one setter for a field-face resolver, filled at@object-ui/fields' module load with the samegetCellRenderer(resolveCellRendererType(field))the grid and lookup previews use;RecordTitleChipgains a node slot for the H1.RecordContextValue) is not taken: it adds a host contract no current reader needs, and an unwired host would silently draw the stored text.Clause-②: yesand carries the declaration-face contract review.origin/mainobject files findssys_record_shareas the only object whosenameFielddeclares a face widget.The grade (
p3) stays as triage set it.objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 4 (
priority:p3,bug) · the seat's earlier claim6289736310was released at6290854039; this one carries that release's read-ahead (lean A)Session:
session_014MXhk1yjWh37d634hLy3p7Account:
huangyiirene(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13216-header-widget-faceWorktree:
objectui-issue-13216Domain:
domain:uiSeat:
domain:ui#1File surface, read at objectui
main3aa2f52. Route A, the registry bridge:packages/components:renderers/layout/containers.tsx'spage:headerheading (declaredTitle,:2668) draws the declarednameFieldthrough that face when its field declares a widget with a cell face of its own;custom/RecordTitleChip.tsxgains a node slot for the H1 (itstitlestaysstringfor every other caller).packages/fields/src/index.tsx: fills the seam at module load with the samegetCellRenderer(resolveCellRendererType(field))the grid and lookup previews use (WIDGET_CELL_RENDERER_TYPES,:3383).@object-ui/componentsand@object-ui/fields).packages/components/README.mdand the matching docs passage.⛔ Not
RecipientPickerFieldor the face itself, not the server's declaration, and no name-to-label mapping in the console: the rule follows the declared widget. ⛔ No import of@object-ui/fieldsinto@object-ui/components, which would close a package cycle. Stop on breach; explain in the report.Container & model:
M,mode:subagent,model: opus(default tier; no path-derived mandate). Local, not cloud.Clause-②: yes
Responsibility: the risk is produced by objectui's own record page heading, which ignores a declared widget's face for the
nameField; the platform path that covers it: none (the H1 is a raw user id); who reaches it: every admin opening asys_record_sharerecord.Thread-read: 6290854039
Serial constraints cleared:
99e4eaa227) is now in objectui's pin06cab4849a8a(PR chore(deps): move .objectstack-sha to objectstack 18.0.0 version commit 06cab4849a (objectui#13261) #13266).git merge-base --is-ancestor 99e4eaa227 06cab4849aexits 0. At the pin,sys-record-share.object.tsdeclaresnameField: 'recipient_id'(:52), and that field declareswidget: 'recipient-picker'withdependsOn: ['recipient_type'](:233–:234).renderers/layout/containers.tsx,RecordTitleChip.tsxorpackages/fields/src/index.tsx. Dependabot PR chore(deps): bump vite from 8.2.2 to 8.3.4 #13288 editspackages/fields/package.jsononly.pm:dispatched. This seat's objectui#12484 holdsapps/consoleapprovals files.Why
Clause-②: yes: route A adds an export to@object-ui/components(the seam's setter) and an optional prop to the exportedRecordTitleChip. The seat writes the declaration-face contract review at ACCEPT.Why A, on the four axes:
6283814156).RecordContextValue) would draw the stored text silently on an unwired host.Claimed at: 2026-10-21T00:23Z
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{
"issue": 13216,
"status": "done",
"branch": "claude/issue-13216-header-widget-face",
"pr": "#13291",
"session": "session_014MXhk1yjWh37d634hLy3p7 (subagent: the parent's id, as the harness stamps it)",
"premise_still_valid": true,
"summary": "This is route A, the registry bridge.
@object-ui/componentsgains a field-face seam inlib/field-face.ts, withsetFieldFaceResolverandresolveFieldFaceon the package entry, plus the typesFieldFace,FieldFacePropsandFieldFaceResolver.@object-ui/fieldsfills the seam at module load with an unexported resolver:getCellRenderer(resolveCellRendererType(field)), bounded toWIDGET_CELL_RENDERER_TYPES, and answering no face while the key still draws its defaultTextCellRenderer.page:headerdraws the declarednameFieldthrough that face only when the pointer rung is the one answering, with the whole record asdependentValues. It does so inRecordTitleChip's new optionaltitleNodeslot (titlestays a string). Every other rung is unchanged, andcontainers.tsxnames no widget. Docs: a README section,content/docs/layout/page-header.mdxandcontent/docs/guide/fields.md. Changeset: components minor (new exports, per the CONTRIBUTING versioning section), fields patch. H1 holds. The pin06cab4849a8acontains99e4eaa227:merge-base --is-ancestorexits 0, which proves itself. At the pinsys-record-share.object.tscarriesnameField: 'recipient_id', and underrecipient_id: Field.text({it carrieswidget: 'recipient-picker'anddependsOn: ['recipient_type']. These are cited by content, not line, because AGENTS.md rule 11 bans line addresses in card and PR bodies. H2 holds, with one refinement: no face is answered for the package's default text face, so a host that registers no face under the key keeps today's string heading. H3: a plain module value is enough, and no subscription was added. The console entry statically imports@object-ui/app-shell, whose entry statically imports the widget-ref-cell registration and so@object-ui/fields. The showcase uses the same bundle.RecordDetailView,PagePreviewand theplugin-detailDetailViewall statically import fields. In Chromium, a harness module body readRecipientCellfromresolveFieldFacebefore its first render. H4 is a code reading.document.titlenever carries the record title:ConsoleLayoutpassesAppShellthe app-plus-product branding title. Theh1has noaria-label; its accessible name is its text, now the face's. The breadcrumb, favourite and recent-item labels come fromgetRecordDisplayNameinRecordDetailViewand keep the stored value. They also keep the stored option value for a selectnameField, because the objectui#13103 rung labels the H1 only. All of these are unchanged and named in the PR's Acceptance notes; no carrier, not filed. H5: all seven controls head as before and are pinned. H6: the acceptance pins go red under ablation, and the Chromium reading was taken. I did not write the card's assignee;huangyiirenewas set, and the PR carries it. The worktree is removed.","tests": "All runs were at
7f8be05a7, from the repository root throughos-verify-lock.sh. (1) The four new files: 4 files and 23 tests passed. (2) Every components test file namingcontainers,page:headerorRecordTitleChip, plus the seam file:Test Files 47 passed (47),Tests 631 passed (631). These includepage-header-title.selectNameField-13103.test.tsx. (3) Every fields test file naming the cell-renderer registry:Test Files 90 passed | 1 skipped (91),Tests 1521 passed | 7 skipped. (4) The full package suites,pnpm exec vitest run --maxWorkers=2 packages/components/andpackages/fields/, exited 0 and 0. Components:Test Files 421 passed | 1 skipped (422),Tests 4188 passed | 24 skipped. Fields:Test Files 273 passed | 1 skipped (274),Tests 4199 passed | 7 skipped. Ablations were run with the fix committed first. Each went throughablation-replace.mjs, which checks the anchor count and blob hash on disk. Each restore was proven: the blob equals HEAD andgit diff HEADis empty. There was no dist leg, because the root vitest alias resolves both packages tosrc. (a) DroppingtitleNode={declaredFace}turned 5 red: four components face pins (expected 'usr_9f3' to be 'Ada Lovelace') and the fields end-to-end card. The 11 controls stayed green. (b) DroppingsetFieldFaceResolver(resolveDeclaredFieldFace);turned 2 red, with 3 green. (c) Making the resolver return the default face too turned 1 red (expected [Function TextCellRenderer] to be undefined), with 4 green. (d) Making the chip draw{title}only turned 1 red, with 1 green. Chromium (/opt/pw-browsers/chromium): a scratch Vite entry, never committed and deleted after, mounted the realRecordDetailViewfrom@object-ui/app-shellover a stub data source. The record was asys_record_sharewithrecipient_type: 'user'andrecipient_id: 'usr_9f3', andsys_useranswered Ada Lovelace. At the head, the H1 readusr_9f3first and thenAda Lovelace, drawn as the face's truncating span, with no page errors. With the rung ablated (the served module carried 0titleNode: declaredFace), it stayedusr_9f3for 10 s. After the restore it readAda Lovelaceagain.","gates": "The local subset was hand-derived, because
dispatch-gates.mjsrefuses objectui, so there is no--ranreconciliation. Every exit code was captured before any pipe, at7f8be05a7.pnpm --filter @object-ui/components lint0 (0 errors, warnings only; the repo sets no max-warnings).pnpm --filter @object-ui/components type-check0.pnpm --filter @object-ui/fields lint0.pnpm --filter @object-ui/fields type-check0, afterpnpm --filter '@object-ui/fields^...' run buildplus a fresh components build.--listFilesshows the new test files in both test programs.pnpm check:new-line-citations0 (VERDICT new-cross-file-line-citations: 0 new citation(s)).pnpm check:control-bytes0.node scripts/check-changeset-presence.mjs0.node scripts/check-changeset-no-major.mjs0.check:self-import,check:unreferenced-sources,check:phantom-deps,check:pending-changeset-literals,check:changeset-claims,check:test-path-rootsandcheck:vi-mock-override-shape: 0 each.check:doc-fences,check:doc-json,check:doc-types,check:doc-example-idsanddocs:check-links: 0 each. As a positive control, a misspelt anchor turned the link gate red.pnpm check:readme-exportsexited 1 on a prerequisite: the population collapsed because 26 packages are unbuilt, so it is NOT MEASURED as a whole. Its--listjudges this README'sresolveFieldFaceandFieldFaceimportsreal.pnpm check:doc-snippetsexited 2, PRECONDITION NOT MET (it needs a 34-package build), so it is NOT MEASURED. The README snippet was compiled on its own under--strictagainst the built dist: exit 0, with a red control. There is no exports or API snapshot in this repo: no*.api.mdand no api-extractor. The governed guard reads NOT GOVERNED. PR check-runs at 2026-10-21T01:30Z for7f8be05a7, 35 in total, are in_progress, which is the honest value. Success: Changeset Bump Policy, Changeset Claim Re-read, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate and label. Skipped: Test (coverage), Test (coverage shard), dependabot. In progress: Lint, Type Check, Test (shard 1/16 to 16/16), Test (dist pins), Build & E2E, Build Docs, Bundle Analysis, Repo Gates, Live E2E (informational). The repo-wide lint, the shards and Bundle Analysis are CI's.","mcp_calls": "0",
"api_writes": "2 relay strokes, each one
POST /repos/objectstack-ai/objectstack/dispatches. Stroke 1,pr_create:POST /repos/objectstack-ai/objectui/pulls(draft) andPOST /repos/objectstack-ai/objectui/issues/13291/assignees; the read-back was byte-identical (15180 bytes) with assignee huangyiirene. Stroke 2,comment:POST /repos/objectstack-ai/objectui/issues/13216/comments(this report). There were threegit pushcalls, which are not REST writes: a fast-forward of the empty branch from878a4af38to3aa2f5261(the write probe), then commits946961ebaand7f8be05a7. There were no label writes.","open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{
"issue": 13216,
"status": "done",
"branch": "claude/issue-13216-header-widget-face",
"pr": "#13291",
"session": "session_014MXhk1yjWh37d634hLy3p7 (subagent: the parent's id, as the harness stamps it)",
"premise_still_valid": true,
"summary": "Patch round 1. The new head is
85fa87048(85fa8704812b3f446f18bdb3f66b72d736436c05), one commit on top of7f8be05a7. CI's Test shard 11/16 failedscripts/__tests__/one-authority-per-exported-name-6273.test.tswithFieldFace — a NEW colliding name: the new export collided with app-shell's ownFieldFaceinviews/metadata-admin/SchemaForm.tsx. As the seat called, the unpublished family was renamed together:FieldFacetoFieldReadFace,FieldFacePropstoFieldReadFaceProps,FieldFaceResolvertoFieldReadFaceResolver,setFieldFaceResolvertosetFieldReadFaceResolver, andresolveFieldFacetoresolveFieldReadFace. No new name collides:git grep -wfor the five new names had zero hits before the rename. App-shell'sSchemaForm.tsxalso exports aresolveFieldFace; the gate named onlyFieldFace, and the rename clears both. App-shell is untouched. The rename covers both packages' source, the four test files,packages/components/README.md,content/docs/guide/fields.md(page-header.mdxnamed none of them), the changeset and the code comments.lib/field-face.tskeeps its file name, and its header gains three lines saying why the names say READ. The internal unexported fields functionresolveDeclaredFieldFacekeeps its name. Behaviour does not change, so no ablation was re-run. The PR stays draft and was not flipped. The PR body was patched once, from the live body, which was byte-identical to what round 0 sent. The patch renamed the Contract surface table and every code span carrying an old name, and added a 'Patch round 1' section ahead of the Contract surface. The Tests and Gates sections stay the round-0 readings at7f8be05a7, and the note says so. The worktree was recreated for this round, then removed after the push.","tests": "All runs were at
85fa87048, from the repository root throughos-verify-lock.sh. (1)pnpm exec vitest run scripts/__tests__/one-authority-per-exported-name-6273.test.tsexits 0:Test Files 1 passed (1),Tests 11 passed (11). Control leg: puttingexport type FieldFace =back inlib/field-face.tsthroughablation-replace.mjsturns it red, withTests 1 failed | 10 passedandFieldFace — a NEW colliding name. The restore was proven: the blob equals HEAD andgit diff HEADis empty. CI job 118985887274 is the red leg at7f8be05a7. (2) The four new test files plus every components test file namingcontainers,page:headerorRecordTitleChip(this includes the objectui#13103 pins) exit 0:Test Files 48 passed (48),Tests 636 passed (636). (3)git grep -n -w -E \"FieldFace|FieldFaceProps|FieldFaceResolver|setFieldFaceResolver|resolveFieldFace\"hits only underpackages/app-shell/. The hits are its ownFieldFaceandresolveFieldFaceinSchemaForm.tsxwith theirSchemaFormtests, its CHANGELOG, a file-localFieldFacecomponent inRecordSnapshotSummary.tsx, and a comment inpredicate.ts. No ablation re-run is owed, because names only changed.","gates": "All exit codes were captured before any pipe, at
85fa87048.pnpm --workspace-concurrency=2 --filter '@object-ui/fields^...' run buildexits 0; the rebuilt componentsdisttypes carry the new names.pnpm --filter @object-ui/components type-check0.pnpm --filter @object-ui/components lint0 (0 errors).pnpm --filter @object-ui/fields type-check0.pnpm --filter @object-ui/fields lint0 (0 errors).pnpm check:doc-types0.pnpm check:doc-fences0.pnpm docs:check-links0.pnpm check:new-line-citations0.pnpm check:control-bytes0.node scripts/check-changeset-presence.mjs0.node scripts/check-changeset-no-major.mjs0.pnpm check:unreferenced-sources0.pnpm check:self-import0. The README snippet compiles under--strictagainst the rebuiltdist(exit 0), with a red control (exit 2).check:readme-exports --list(exit 2, the unbuilt-repo precondition, as in round 0) judgesresolveFieldReadFaceandFieldReadFacereal. PR check-runs for85fa87048at 2026-10-21T01:48Z, 35 in total: 24 are in_progress, which is the honest value, including Lint, Type Check, Test (shard 1/16 to 16/16), Test (dist pins), Build & E2E, Build Docs, Bundle Analysis and Repo Gates. Success: Changeset Bump Policy, Changeset Claim Re-read, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate and label. Skipped: Test (coverage), Test (coverage shard), dependabot.","mcp_calls": "0",
"api_writes": "This round made 2 relay strokes, each one
POST /repos/objectstack-ai/objectstack/dispatches. Stroke 1,issue_patch:PATCH /repos/objectstack-ai/objectui/issues/13291(the PR body); the read-back was byte-identical at 18377 bytes, and the session-URL footer is intact. Stroke 2,comment:POST /repos/objectstack-ai/objectui/issues/13216/comments(this report). There was onegit push, which is not a REST write:7f8be05a7..85fa87048. There were no label writes and no ready flip.","open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
LANDED ·
domain:uiseat 1 ·session_014MXhk1yjWh37d634hLy3p7· 2026-10-21T02:13Z ·pm:dispatchedcleared8701f1ehas one parent (a91f6bb), andgit merge-base --is-ancestorplaces it onorigin/main(exit 0)gh-readonly-queue/main/pr-13291-*branch remainsorigin/main: the components entry exports theFieldReadFacefamily (2 lines);page:headerpassestitleNode={declaredFace}(1);fieldsinstallssetFieldReadFaceResolver(resolveDeclaredFieldFace)(1)6304863865; dev reports6305778836(round 0) and6306010270(patch round 1); on PR #13291, the contract review6306027483(PASS) and the ACCEPT6306032998, which supersede the round-0 pair at7f8be05a7completedat 2026-10-21T02:13Z through the PR'sFixes #13216;pm:dispatchedis removed in this actA record page whose declared
nameFieldcarries a widget with a read face of its own now heads through that face. A record share heads with the recipient's name, not the user id it stores. The face comes through a seam in@object-ui/components(setFieldReadFaceResolver/resolveFieldReadFace) that@object-ui/fieldsfills when it loads.RecordTitleChipgains an optionaltitleNode. Every other heading is unchanged.Seat correction on the record: round 0 named the new type
FieldFace, which CI's one-authority gate refused, because@object-ui/app-shellalready declares a differentFieldFace. The seat's round-0 contract review had not caught the collision. Patch round 1 renamed the unpublished family toFieldReadFace*before anything merged.Noted, not filed: breadcrumbs, favourites and recent items keep the stored value, as they already do for a select
nameField. The H1 shows the stored id for a moment while the face reads its label.