Repository navigation
finding(types, docs): exported *FieldMetadata types declare members FieldSchema refuses (pattern_message, min_date, starting_number, …), docs teach them, and no member-level pin covers the family #12242
Description
Ruled: 6137052265 · letter A (dueLike stays on the authoring face; the fork of 6135661503 resolved) · 2026-10-13T02:44Z
Ruled: 6135661503 · letter A · 2026-10-13T00:55Z
Filing class: ① product defect, a finding of class (b), the family close-out card for "objectui field metadata declares a key the spec's FieldSchema refuses". Reach: named producers, the field docs pages below, which teach authors and agents spellings the strict door refuses.
- Who acts: triage grades and routes. The declarations are in
packages/types/src/field-types.ts, and the pages are incontent/docs/fields/. - Why a family card: this is the family's third single-key card in one day (objectui#12156 for the
max_*keys, objectui#12157 for threelookuplegs, objectui#12213 forhelp). Each one retired its keys and left the rest of the family standing. The rule for this case is one card that covers every position, with an enumeration pin, not another single-key card. - Dedupe: two objectui issue searches, closed included. "FieldMetadata types declare members FieldSchema refuses census enumeration pin snake_case field metadata" returned 12 hits. "pattern_message starting_number auto_number field docs keys spec refuses text auto-number object field page" returned 1. None is open, and none covers the types member by member. The nearest are objectui#5761 (closed: a key-level parity guard for field DESIGNER payloads), objectui#6138 (closed: the docs pages declared their own interfaces) and objectui#4687 (closed: two
VectorFieldMetadatakeys). - Found by: the os-dev of objectui#12213 (PR objectui#12236, report
6123163546, out-of-scope finding 1). Widened and filed by thedomain:spec@ objectui seat (objectui#10217), sessionsession_0149MdowTfyuWZuSSESLUYnE.
The reading (objectui main after objectui#12157)
- The dev's measurement, on the installed
@objectstack/spec17.7.0:FieldSchema.safeParserefusespatternandpattern_messageon a text field,starting_number, andschemaon an object field, each withunrecognized_keys. The type valuesauto_numberandobjectgiveinvalid_valueattype; the spec spells the firstautonumber. Control: a text literal withlabel,maxLengthandinlineHelpTextis accepted. - This seat's census of snake_case members on the exported field metadata interfaces in
field-types.ts:mobile_fullscreen,visible_on,pattern_message,min_date/max_date(two interfaces),default_zoom,starting_number, plusreference_fieldandavatar_field. Triage measured those last two out of scope on objectui#12157: noFieldSchematwin, or a ruled shape. Thenever-typed members (min_rows,allow_addand the rest, each mapped to its camelCase key in the same file) are excluded too; they are already refused by type. A census for name only: neither the readers nor the spec twins were measured. - The docs:
text.mdxteachespattern/pattern_message,auto-number.mdxteachesstarting_numberandtype: 'auto_number', andobject.mdxteachesschemaandtype: 'object'. The dev read this.
What the close-out owes (triage decides)
One measured census of every member of every exported field metadata interface against FieldSchema. Each row gets one verdict: the spec's spelling by reference, retired (no reader, no twin), or a runtime-only hand-off typed on a package-local type (objectui AGENTS.md #0.1). Then one enumeration pin that fails on a new member with no verdict. The docs pages follow the verdicts.
Dedupe words: FieldMetadata member FieldSchema refuses · pattern_message starting_number default_zoom · auto_number type value spec autonumber · field docs teach refused keys
Activity
objectstack-fleet commentedon Oct 12, 2026
Triage: first grade,
bug·priority:p3·domain:spec·area:records, intopm:queue. The family closes member by member, on the file's ownneverconvention. No new enumeration gateTriage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T11:57Z. ⛔ Not a claim, ⛔ not a dispatch.domain:spec@ objectui, the retirement family of finding(types, docs): afile/imagefield'smax_sizeis declared and taught, but the widgets read onlymaxSize, so the size limit is silently dropped #12156, finding(fields): thelookupwidget readsallow_create,lookup_columns,lookup_page_sizeandavatar_fieldbefore the spec's camelCase keys, and app-shell producers and docs pages write the snake_case spelling #12157 and finding(types, plugin-form, docs): the record form reads a field's help ashelp || descriptionand never the spec'sinlineHelpText, which Studio writes; four field docs pages teachhelp, whichFieldSchemarefuses #12213. This is its closing card, so no more single-key cards are filed for it.help || descriptionand never the spec'sinlineHelpText, which Studio writes; four field docs pages teachhelp, whichFieldSchemarefuses #12213 shape), that position is the p2 class and is reported as such.field-types.tsalready retiresmin_rowsandallow_add: typedneverand mapped to its camelCase key. That gives a type-level refusal per member, with an ordinary pin each.auto_numberbecomesautonumber.reference_fieldandavatar_fieldstay out of scope, as measured on finding(fields): thelookupwidget readsallow_create,lookup_columns,lookup_page_sizeandavatar_fieldbefore the spec's camelCase keys, and app-shell producers and docs pages write the snake_case spelling #12157.neverconvention already refuses each member at the type.help || descriptionand never the spec'sinlineHelpText, which Studio writes; four field docs pages teachhelp, whichFieldSchemarefuses #12213 has PR fix(types,plugin-form,fields): the record form draws a field's inlineHelpText under its control, and help leaves BaseFieldMetadata (objectui#12213) #12236 open in the samefield-types.tsand docs, and is in the decision box now. This card sequences after it.packages/types/src/field-types.tsandcontent/docs/fields(domain:spec@ objectui); rationale: the family's close-out.objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 1 · 2026-10-12T12:35Z
Session:
session_0149MdowTfyuWZuSSESLUYnEAccount:
huangyiirene(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12242-field-metadata-familyWorktree:
objectui-issue-12242Domain:
domain:specSeat:
domain:spec#1File surface (on objectui
main923504f):packages/types/src/field-types.ts: the census members only (mobile_fullscreen,visible_on,pattern_message,min_date/max_date,default_zoom,starting_number, and any member the dev's measured census adds). Each retires on the file's ownneverconvention, mapped to its spec key. Where the spec key is not yet declared and a reader reads it, the spec key is declared by reference (triage6123790917).content/docs/fields/**: the pages that teach a census member or a type value the spec does not have.auto_numberbecomesautonumber;objectfollows the measured spec type set..changeset/12242-*.mdfor each touched published package.⛔ Not on it:
reference_fieldandavatar_field, measured out of scope on objectui#12157.helpleg (objectui#12213, in the decision box).Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
Container & model:
M,mode:subagent,model: default(dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate: the surface hits none of the 3 declared glob(s)"). The contract review atCONTRACT_REVIEW_TIERis owed before the queue, by an isolated subagent (this seat is not at that tier).Clause-②: yes
Ruling-ref:
6123790917(triage's direction on this card) · objectuiAGENTS.md#0.1 · objectui#12157 (reference_field/avatar_fieldout of scope)Responsibility:
packages/types(the exported field metadata interfaces) declares members the spec'sFieldSchemarefuses, andcontent/docs/fieldsteaches them | none: the spec door refuses each one by name, but the TypeScript face and the docs keep teaching them | authors and agents who follow the field docs pages or type a field literal against these interfacesThread-read: 6123790917
Serial constraints cleared: read on objectui
main923504f. The serial predecessor named by triage, PR objectui#12236 (objectui#12213), merged as923504f. Open objectui PRs objectui#12246, objectui#12229 and objectui#12196 touch neitherfield-types.tsnorcontent/docs/fields. objectui#7611 (domain:ui, cloud, in flight) declaresfield-types.tsonly where a line reads a retiring permission table, a disjoint region. objectui#12213's ruled follow-up, when it comes, touchesplugin-form/fieldsread sites, not these members.Why
Clause-②: yes: retiring members is narrowing. Declaring a spec key by reference where a reader needs it adds a member to an exported interface, which enlarges the public surface. Both legs owe the at-tier contract review.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{ "issue": 12242, "status": "done", "branch": "claude/issue-12242-field-metadata-family", "pr": "https://github.com/objectstack-ai/objectui/pull/12257", "session": "session_0149MdowTfyuWZuSSESLUYnE — subagent run, so this is the parent seat's id as the dispatch names it", "premise_still_valid": true, "summary": "Measured every member of every exported field metadata interface against FieldSchema (spec 17.7.0, main 923504f); the full table is in the PR body. The name-only lead was incomplete: the spec also refuses camelCase filterable, validate, pattern, currency, dueLike, idField, picker, subtitle, schema and normalize, and the type values auto_number, object, geolocation and grid. Retired as never tombstones: visible_on (to visibleWhen, now declared by reference), currency (to currencyConfig, declared by reference), and, with no target, filterable, min_date/max_date on both date types, default_zoom, starting_number, schema and normalize. AutoNumberFieldMetadata.type becomes autonumber and ObjectFieldMetadata.type becomes json. Readers moved: ObjectForm and sectionFields drop their visible_on reads (both already read visibleWhen). One p2 position was measured red and fixed: RecordDetailPanel and RelatedList (plugin-detail) forwarded only the retiring currency and dropped currencyConfig, so a spec fixed-EUR amount showed without its currency. Seven docs pages teach the spec's spellings. Kept under the stop condition and reported in open_questions: mobile_fullscreen, pattern, pattern_message, validate, dueLike, idField, picker, subtitle, and the geolocation type value.", "tests": "All runs are at HEAD 00f58c4 (git rev-parse --short HEAD), from the objectui repo root under os-verify-lock, unless noted. SUITES: 'pnpm exec vitest run packages/types/' exit 0, 373 files / 10217 tests passed. 'pnpm exec vitest run packages/plugin-form/' exit 0, 180 files; 2200 passed, 1 skipped. 'pnpm exec vitest run packages/fields/' exit 0, 249 files passed + 1 skipped; 4019 tests passed, 7 skipped. 'pnpm exec vitest run scripts/__tests__/' exit 0, 181 files passed + 2 skipped; 5541 tests passed, 2 skipped. The 9 tests outside scripts/ that name check-doc-component-types (schema-catalog x6, cli, core, plugin-gantt) exit 0, 9 files / 708 tests passed. 'pnpm exec vitest run packages/plugin-detail/' exit 1: 1 failed | 260 passed | 1 skipped. The failure is a timeout (15000ms budget, ran 34403ms) in record-details.hideFieldsUncast-9965 'resolved the mirror', mid-suite on a shared box. Rerun alone at the same HEAD: exit 0, 10/10 passed in 7s, so it is a load timeout, not a verdict. TYPE-CHECK after the dependency-closure build (turbo, 13/13 tasks, exit 0): @object-ui/types, fields, plugin-form, plugin-detail and plugin-grid each exit 0, with the 'type-check' script name echoed. plugin-detail was red once, TS2352 on the summaryChip.displayLocale-9453 cast carrying currency, before that fixture was re-spelled. GATES, each exit 0 with its own verdict line: check:doc-types 'Every documented component type is registered'; check:doc-json 'Every judged JSON node document on the scan surface passes the strict authoring face'; check:designer-field-key-parity 'designer-field-key-parity: OK'; check:spec-symbols; check:new-line-citations 'VERDICT new-cross-file-line-citations: 0 new citation(s)'; check:control-bytes 'OK'; changeset:check 'No changeset declares a major bump'; check:changeset-claims 'No pending changeset names a file this change touches'; check-changeset-presence '10 source file(s) of 3 released package(s) changed, and this change declares 3 changeset(s)'; check-changeset-no-major; check-doc-links 'Links are valid across 17 scan roots'; check-doc-example-ids '415 real reference(s) all resolve'; check-doc-fence-languages; check-governed-queue-guard --test 'NOT GOVERNED'. NOT MEASURED: check:doc-snippets and check:doc-examples, exit 2 (could not run: they need the whole package set built; CI builds it). Narrowed stand-in: all 14 ts blocks of the 7 touched docs pages compile --strict against the freshly built types/fields dist, and a planted control (min_date on DateFieldMetadata) fails with TS2322. Also NOT MEASURED: check:readme-exports, '407 self-import(s) could not be judged' on the unbuilt tree (no README or export touched). PINS: field-metadata-family-retired-12242.test.ts (types, 15 tests), ObjectForm.visibleWhen-12242.test.tsx (plugin-form), currencyConfigRelay-12242.test.tsx (plugin-detail; red before the fix on exactly RecordDetailPanel and RelatedList, cells [Tower, 1,234.50, 6,789.50] without the euro sign). ABLATIONS, each committed first, mutated via objectstack scripts/ablation-replace.mjs (anchor 1 to 0 and blob change verified on disk), and restored with blob == HEAD and an empty git diff HEAD: (1) the ObjectForm visible_on read put back: the pin goes red ('visible_on is no gate: the field is drawn: expected null not to be null'). (2) sectionFields 'meta?.visible_on ?? meta?.visibleOn' put back: 5 rows go red. (3) types 'currency?: never' changed to 'currency?: string': tsc -p tsconfig.test.json exit 2, TS2578 Unused @ts-expect-error at the _currency row. (4) The direction was NOT red: ObjectForm's computed-type gate restored from autonumber to auto_number left its pin GREEN, because the widget is display-only and sanitize strips both spellings. That draft change and its vacuous pin were removed; the position is under Acceptance notes.", "files_changed": [ "packages/types/src/field-types.ts", "packages/types/src/__tests__/field-metadata-family-retired-12242.test.ts (new)", "packages/plugin-form/src/ObjectForm.tsx", "packages/plugin-form/src/sectionFields.ts", "packages/plugin-form/src/sectionFields.blankGate-11262.test.ts", "packages/plugin-form/src/ObjectForm.visibleWhen-12242.test.tsx (new)", "packages/plugin-detail/src/RecordDetailPanel.tsx", "packages/plugin-detail/src/RelatedList.tsx", "packages/plugin-detail/src/__tests__/currencyConfigRelay-12242.test.tsx (new)", "packages/plugin-detail/src/__tests__/summaryChip.displayLocale-9453.test.tsx", "content/docs/fields/{date,datetime,location,vector,currency,auto-number,object}.mdx", "scripts/check-doc-component-types.mjs (exemption ledger entries for auto-number.mdx and object.mdx)", ".changeset/12242-types-field-metadata-family.md (@object-ui/types minor, BREAKING)", ".changeset/12242-plugin-form-visible-on.md (@object-ui/plugin-form patch)", ".changeset/12242-plugin-detail-currency-config.md (@object-ui/plugin-detail patch)" ], "deviations": [ "Files outside the claim's listed surface. plugin-detail RecordDetailPanel.tsx and RelatedList.tsx are p2 readers of the retiring currency member that never read the spec key (E3 (b) / E6); their pin, changeset and the summaryChip fixture come with them. scripts/check-doc-component-types.mjs holds per-page exemption entries that spell the retired type values, so the docs change could not pass check:doc-types without them (fixture triage). Both are named in the PR body.", "No new exported map constant. Each tombstone's @deprecated docblock names its replacement, as the grid tombstones' do. E2 measured that GRID_FIELD_RETIRED_KEYS exists for its two runtime refusals (the GridField alert and the FormFieldSchema aliasKeyRefusal arms), and this family has no such consumer. Only visible_on and currency have a twin to map to. Listed as an open question, so the seat can say whether that matches the triage ruling's 'mapped to its camelCase key'.", "The census went beyond the name-only lead. currency, filterable, schema and normalize retire too, and both type values change. The members that met the stop condition are kept and reported, not retired.", "A draft change moving ObjectForm's computed-type gate to 'autonumber' was reverted after ablation (4) showed it inert. The first commit's message still describes it; the PR title and body are accurate.", "The PR body's closing-keyword line for this card is kept as the dispatch prescribes, although the stop-condition positions remain open. If the seat wants them tracked on this card, that line should switch to the 'Part of' form (a seat edit; dev writes the body once).", "objectui has no scripts/pm/dispatch-gates.mjs (nor the check-half-states.mjs the role file mentions). The gate list was hand-derived from the dispatch, the root package.json and .github/workflows/repo-gates.yml.", "Commit trailers follow objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude) instead of the harness reminder's model-named Co-Authored-By line, per AGENTS.md's precedence clause." ], "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "2 REST writes, both through objectstack scripts/pm tools as objectstack-fleet[bot]: (1) the pr_create stroke via fleet-write/dispatch.mjs: POST /repos/objectstack-ai/objectstack/dispatches (transport, HTTP 204, run 38256970149), executed as POST /repos/objectstack-ai/objectui/pulls (draft, #12257) + POST /repos/objectstack-ai/objectui/issues/12257/assignees (huangyiirene); read-back: 14984 bytes sent, 14984 stored, identical. (2) This os-dev-report comment via post-stamped.mjs: POST /repos/objectstack-ai/objectui/issues/12242/comments. Not REST: git push of the branch, 3 times (the empty-branch write probe, 616cef5, and 00f58c4). Zero label writes, zero card or assignee writes.", "open_questions": [ { "question": "Runtime-only widget keys on the authoring face: mobile_fullscreen (stamped by ObjectForm, read by TextAreaField / RichTextField / the form renderer), idField, picker and subtitle (read by LookupField / UserField; typed on FormField by objectui#12130), and dueLike (the date cell renderers; also DetailViewFieldSchema.dueLike). FieldSchema refuses each by name, none has a spec twin, and removing any would drop a working capability. Where should they live?", "options": [ "A: move them off *FieldMetadata onto a runtime hand-off type (AGENTS.md #0.1), keeping the FormField / DetailViewField faces that already type them. The authoring face then stops offering keys no published object can carry.", "B: keep them on *FieldMetadata as declared objectui extensions, with each docblock and docs page saying the key is not publishable.", "C: propose spec adoption upstream for the ones with a real authored use (dueLike, idField, picker, subtitle), and keep mobile_fullscreen runtime-only." ], "recommendation": "A, with C for any key the maintainer wants authorable. Business need: each key has a live reader but no producer through a published object (the spec refuses them at the door). Long-term: #0.1 already rules runtime-only keys onto hand-off types. AI-safety: A stops the authoring face offering keys the publish door refuses, while B keeps that trap. Startup scope: A changes no behaviour and adds no surface." }, { "question": "pattern / pattern_message / validate on field metadata. The spec has no field-level twin. Its form for a regex check is an OBJECT-level validations[] rule {type: 'format', field, regex, message}, enforced on the server. The only reader is buildValidationRules, which reads the field-level keys and never the object rule. No in-repo producer was found; text.mdx teaches pattern / pattern_message.", "options": [ "A: retire all three as never, remove the buildValidationRules reads, and have text.mdx teach the object-level format rule (the server refuses the save with the rule's message; the client pre-check goes).", "B: as A, and also teach the form builders to pre-check the object's format rules on the client.", "C: keep them, pending a spec change that adds pattern to FieldSchema." ], "recommendation": "A. Business need: no producer exists and no published object can carry the keys; no test pins the client regex. Long-term: one contract (the object rule) instead of a client-only dialect. AI-safety: the strict spec shape is taught and the trap disappears. Startup scope: B adds new capability with no measured pull, so it should wait for one." }, { "question": "GeolocationFieldMetadata declares type 'geolocation', which is not a spec FieldType (FieldSchema answers invalid_value at type). The GeolocationField widget is distinct from location's LocationField. How should it be treated, by analogy with grid (objectui's own type, ruled by objectui#11610 / objectui#11070)?", "options": [ "A: rule it objectui's own widget type, like grid, and record that in its docblock.", "B: retire it from FieldMetadata, keeping only the field:geolocation widget id.", "C: map it onto the spec's location type." ], "recommendation": "A, unless the maintainer wants FieldMetadata limited to spec types; C would change widget behaviour." }, { "question": "The triage ruling says each member is 'typed never and mapped to its camelCase key'. This PR maps through each tombstone's @deprecated docblock and adds no exported map constant like GRID_FIELD_RETIRED_KEYS, because that constant exists for runtime refusals this family does not have. Is that acceptable?", "options": [ "A: yes, docblock mapping only (as shipped).", "B: add an exported FIELD_METADATA_RETIRED_KEYS-style map for visible_on and currency, even with no runtime reader." ], "recommendation": "A: a new export with no reader is an unpulled declaration surface." } ], "out_of_scope_findings": [ "class: c · reach: named producer, content/docs/fields/auto-number.mdx ('Mixed Format' block and the 'Format Placeholders' line '{Q} - Quarter (1-4)') · evidence: the spec's parseAutonumberFormat reads {Q} as {kind: 'field', field: 'Q'}, a record-field interpolation, and renderAutonumber({tokens: parseAutonumberFormat('{YY}Q{Q}-{000}'), seq: 1, now: 2024-03-15}) answers '24Q-001', where the page promises '24Q1-001'. The spec documents this renderer as the one both the engine and the SQL driver share. The page also teaches the 'format' shorthand where the spec says 'Prefer autonumberFormat on a new field'. · dedupe words: autonumber format Q quarter token · auto-number docs placeholder field interpolation · renderAutonumber 24Q-001", "carrier: none (承接者:无) · noted, not filed — sectionFields' name-string chain still reads the object schema's visibleOn, which FieldSchema refuses ('did you mean visibleOn -> visibleWhen?'): a dead read of a key no published object carries. In the PR body's Acceptance notes.", "carrier: none (承接者:无) · noted, not filed — resolveFieldCurrency (@object-ui/i18n) reads a field-level currency ahead of currencyConfig: a second spelling for field metadata, kept because the resolver serves presentation surfaces where currency is a spec key. Reported per E2, not extended.", "carrier: none (承接者:无) · noted, not filed — app-shell RecordDetailView's section build forwards currency without currencyConfig. Unmeasured whether DetailSection's enrichment from the object schema puts it back on the record page.", "carrier: none (承接者:无) · noted, not filed — ObjectForm's computed-type gate compares 'auto_number', a spelling no spec object carries. Inert: ablation (4) showed no user-visible effect.", "carrier: none (承接者:无) · noted, not filed — record-details.hideFieldsUncast-9965 'resolved the mirror' timed out once (34s against a 15s budget) in the full plugin-detail suite on a shared box, and passes alone in 7s. The flaky-test rule says look for the race, not the timeout; not investigated here." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
ACCEPT (partial landing) · PR objectui#12257 @
00f58c4· 2026-10-12T14:00Zdomain:spec@ objectui seat (objectui#10217) · sessionsession_0149MdowTfyuWZuSSESLUYnE. Checked against GitHub, not against the report (6125454268). Thread-read: 6125454268.Implemented-by:
claude/issue-12242-field-metadata-family· Reviewed-by:session_0149MdowTfyuWZuSSESLUYnE, plus the contract-review-tier record6125795502on the PR (PASS on head00f58c4c28026ef8db68e626aeaa0ccc8994b435,Local-runs: none).Checklist (head
00f58c4)main✓ · first linePart of #12242✓, switched by the seat so this card stays open for the kept positions. A body scan finds no closing keyword.Clause-②: yesat line start ✓ · PR assigneehuangyiirene✓.check-governed-mergesreads 0 of 21 paths governed, 925 changed lines (≤ 3000).mergeable_stateclean. Outside the claim's listed files are theplugin-detailforwarders (readers of the retiringcurrency, which the census added) and the doc-types gate ledger (fixture triage). The dev named both in the report and the PR body. The review accepted both (D1), and the seat accepts them as the claimant following its own change through.nevertombstones, each@deprecatedline naming the key to write:visible_on,filterable,currency,min_date/max_dateon both date types,default_zoom,starting_number,schema,normalize.visibleWhenandcurrencyConfigare declared by reference to the spec.auto_number→autonumber,object→json.visible_onreads inObjectFormandsectionFieldsare removed.RecordDetailPanelandRelatedListdroppedcurrencyConfig, so a fixed-EUR amount showed without its currency.@object-ui/typesminor (BREAKING, FROM → TO for every member and both type values),@object-ui/plugin-formpatch,@object-ui/plugin-detailpatch.00f58c4: 33 runs: 30 success, 3 skipped by design, 0 red. The eager-closure budget reads PASS, at 3129.1 KB of 3204.6 KB.Not landed here: the members the stop condition kept, and the
geolocationtype value. Those are the review's E-Q1 to E-Q3. They go to the decision box on this card in the next comment. The PR keeps them as they are today, so the merge decides none of them.The review's other flags:
currencyreaders:plugin-detailforwarders still passcurrencybesidecurrencyConfig.resolveFieldCurrencyreadscurrencyfirst, and the PR's Acceptance notes state why: the resolver also serves surfaces wherecurrencyis a spec key.reach:is not met. Carrier: none. Noted, not filed.RecordDetailView:currencywithoutcurrencyConfig.main7578323: the record page passes itsobjectSchematoDetailView's sections, andDetailSectionenriches each field from it throughENRICHED_FIELD_METADATA_KEYS, which listscurrencyConfig. So the reading says the currency comes back on the record page.auto-number.mdx{Q}token: filed as objectui#12258.auto_number/object). That is correct in that vocabulary, and nothing reads them as field metadata. Carrier: none. Acceptance notes only.record-details.hideFieldsUncast-9965timeout: one run under concurrent load, green alone and on CI. Noted on the seat post. With no red run on CI, nothing is filed.Landing:
pr_ready+automerge_enablethrough the relay in this act.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Decision box: the positions PR objectui#12257 kept ·
pm:dispatched→needs-user-decision· 2026-10-12T14:03Zdomain:spec@ objectui seat (objectui#10217) · sessionsession_0149MdowTfyuWZuSSESLUYnE. Thread-read: the seat's ACCEPT6125828299is the newest comment; the review record6125795502(E-Q1 to E-Q3) and the dev report6125454268(open questions 1 to 3) are the sources.State:
pm:dispatched→needs-user-decisionin this act. PR objectui#12257 lands withPart of, which decides none of these. At its merge the seat releases the card (Release:line, assignee cleared), and it waits here. Three independent questions; one answer line, e.g. 「Q1 A,Q2 A,Q3 B」.维护者速读
字段元数据(
*FieldMetadata)家族收口已落地大部分:11 个成员退役、2 个类型值改为 spec 拼写。还剩 9 个成员 + 1 个类型值:spec 的FieldSchema按名拒收它们,但界面里还有活的读者,删掉会丢功能,所以按停止条件保留,等你定方向。mobile_fullscreen、idField、picker、subtitle、dueLike):A 从对象字段的作者面挪到运行时交接类型(行为不变,只是类型上不再「教」发布不了的键);B 原地保留,文档注明不可发布。席位推荐 A。pattern、pattern_message、validate):spec 的写法是对象级validations[]的format规则,由服务端执行。A 退役这三个键,text.mdx改教对象级规则,前端的字段级正则预检随之移除;B 同 A,并新增前端对对象级format规则的预检。席位推荐 A。geolocation类型值(不是 spec 的FieldType):A 按grid先例定为 objectui 自有字段类型;B 从字段元数据类型里退役,保留field:geolocation控件注册;C 映射到 spec 的location(控件行为会变)。席位推荐 B。决策分析
一句话问题: 对象字段的类型面还在「教」九个 spec 发布时会按名拒收的键,以及一个 spec 没有的字段类型;它们背后各有活的界面读者,收口要先定每一类往哪里去。
Governing text:
AGENTS.md#0.1:「a key only the host writes at runtime is typed on a package-local hand-off type where its producer and consumer live, never on the authoring face (objectui#6356)」;以及「Change the spec only when it is genuinely wrong — deliberately, in@objectstack/spec, never by accreting renderer-side fallbacks.」5552700625):「本项目以协议为基准。所以开发应该对其协议,协议有问题应该立卡修改协议」。6123790917:按never惯例逐成员退役;⛔ 不新增枚举门禁。协议声明、是否改协议:
@objectstack/spec17.7.0 的FieldSchema不声明这九个键,也不声明geolocation类型;pattern的 spec 形是对象级validations[]{ type: 'format', field, regex, message }。所有选项都不改协议。若维护者认为某个键应当可作者化(如dueLike、picker),那是另立的 spec 卡,不是本卡的选项。前提(re-check 命令,各带阳性对照;objectui
main7578323):FieldSchema按名拒收这九个键和geolocation类型值:dev 在 spec 17.7.0 上逐一safeParse实测(报告6125454268的普查表,对照{ type: 'text', maxLength }被接受);复核记录6125795502交叉读过 spec。本席未重跑(共享检出未装依赖)。git grep -l mobile_fullscreen origin/main -- 'packages/*/src/**' ':!**/__tests__/**' ':!**/*.test.*'命中 7 个文件,dueLike同法命中 6 个;对照:ENRICHED_FIELD_METADATA_KEYS(plugin-detail的fieldEnrichment.ts)列出dueLike、idField、picker、subtitle。pattern的唯一读者是@object-ui/fields的buildValidationRules:git grep -n "field.pattern" origin/main -- 'packages/fields/src/**'命中index.tsx一处;对照:同文件命中rules.pattern。仓内生产者 0(dev 普查,测试与文档除外)。geolocation有活控件:git grep -n "'geolocation'" origin/main -- 'packages/*/src/**' ':!**/__tests__/**'命中fields控件注册、plugin-detail行内编辑、core记录标题等;仓内对象定义中的生产者未测。选项 × 真实代价 × 工作量:
*FieldMetadata挪到各自包内的运行时交接类型;FormField/DetailViewField等已声明它们的面不动domain:spec· 1 PR · 先例 PR objectui#12257(+762/−163)domain:spec· 1 PR(仅注释与文档) · 无先例never;删buildValidationRules的字段级读取;text.mdx改教对象级format规则domain:spec· 1 PR · 先例 PR objectui#12257format规则做预检grid(objectui#11610 / objectui#11070)定为 objectui 自有类型并在 docblock 记明domain:spec· 1 PR(注释) · 先例的理由是否适用未核FieldMetadata联合中退役GeolocationFieldMetadata,保留field:geolocation控件注册type: 'geolocation',界面无变化;代码里手写该类型的宿主编译报错domain:spec· 1 PR · 先例 PR objectui#12257(类型值退役)locationlocation与geolocation是两个不同控件,现有界面行为会变domain:spec· 1 PR · 无先例业务含义直译:
四轴(业务立场):
推荐:Q1 A,Q2 A,Q3 B(按①得出)。
grid先例的理由经核实同样适用于geolocation)。type: 'geolocation',本席测不到;Q3 的grid先例理由本席未读原裁决。裁后执行: 下一任
domain:spec席位按裁定重新认领本卡、派 1 个 dev,从main开Fixes #12242的 PR;入队前照例过达档契约复核。本席收班,不再派发。os-decision-facets
Prior rulings read: objectui
AGENTS.md#0.1 (hand-off types, objectui#6356); maintainer standing ruling objectstack-ai/objectstack#127085552700625(protocol as baseline); objectui#12242 triage direction6123790917;gridas objectui's own type (objectui#11610 / objectui#11070, cited by the dev, not re-read); thread: 6相关单与 PR: PR objectui#12257 · objectui#12156 · objectui#12157 · objectui#12213 · objectui#12258 · objectui#6356.
Generated by Claude Code
11 remaining items
objectstack-fleet commentedon Oct 13, 2026
Claim: PM loop round 2 · 2026-10-13T01:08Z
Session:
session_015YrgVw7e65cs1ndbebt46GAccount:
os-justinBranch:
claude/issue-12242-field-metadata-kept-positionsWorktree:
objectui-issue-12242Domain:
domain:specSeat:
domain:spec#1File surface:
packages/types/src/field-types.ts(the Q1 membersmobile_fullscreen,idField,picker,subtitle,dueLike; the Q2 memberspattern,pattern_message,validate;GeolocationFieldMetadataand its line in theFieldMetadataunion; ⛔ notAutoNumberFieldMetadata, which objectui#12282 holds next), the package-local hand-off types where each Q1 key's producer and consumer live and their readers (leads:packages/plugin-detail/src/fieldEnrichment.ts,packages/plugin-grid/src/relationalMetaKeys.ts,packages/core/src/utils/date-display.ts,packages/fields/src/widgets/readers, themobile_fullscreenlines ofpackages/plugin-form/src/ObjectForm.tsxandpackages/components/src/renderers/form/form.tsx),packages/fields/src/index.tsx(buildValidationRules' field-level reads only), the docs pages that teach these keys (content/docs/fields/text.mdx,date.mdx,datetime.mdx,content/docs/api/schema-reference.md, where they name them), the pins that read these, the touched packages' READMEs,.changeset/12242-*.md(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(default tier: a ruling implementation across several packages;dispatch-gates --tier --repo objectstack-ai/objectuianswered no path-derived mandate for these paths)Clause-②: yes
Responsibility:
objectui's *FieldMetadata authoring types declare eight members and one type value that @objectstack/spec FieldSchema refuses by name | the publish door (FieldSchema, strict) already refuses them, so no published object carries them | an author or agent typing field metadata through @object-ui/types; production pull 0 (ruling 6135661503 and the questions at 6125867738)Ruling-ref: 6135661503
Thread-read: 6135661503
Serial constraints cleared:
PR objectui#12257 (merged 10aba37) and PR objectui#12283 (merged 5b45c0d) touched field-types.ts and fields index.tsx, both landed; objectui#7611 (domain:ui, in flight) declares field-types.ts and ObjectForm.tsx only on lines that read a retiring permission table, a disjoint region; no open PR touches these paths (read in this act); objectui#12282 (pm:queue, same file) runs after this card's merge, recorded on the seat post's serial queueClause-② reads
yes: the narrowing (Q2'snevertombstones, Q3's union removal, Q1's members leaving the authoring face) owes the contract-tier review before the queue regardless, and a Q1 hand-off type that becomes newly exported would widen a public face. The dev measures the export closure in the report.Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
os-dev-report
{ "issue": 12242, "status": "needs_decision", "branch": "claude/issue-12242-field-metadata-kept-positions", "pr": "https://github.com/objectstack-ai/objectui/pull/12293", "session": "session_015YrgVw7e65cs1ndbebt46G — the container's own id (CLAUDE_CODE_REMOTE_SESSION_ID cse_015YrgVw7e65cs1ndbebt46G), which the relay stamped on the pr_create stroke", "premise_still_valid": false, "summary": "Ruling A is executed for every position but one, in draft PR objectui#12293 (first line `Part of #12242`). Q1: mobile_fullscreen, idField, picker and subtitle leave the *FieldMetadata types. mobile_fullscreen is typed on a package-local LongTextCarrierHandoff in @object-ui/fields. The three picker keys are declared on FormField, which LookupField reads them through, and app-shell's FlowReferenceField, a typed producer, now types its carrier on that hand-off. Q2: pattern, pattern_message and validate are never tombstones, buildValidationRules no longer reads them, and text.mdx teaches the object-level format rule. Q3: GeolocationFieldMetadata leaves the FieldMetadata union. The premise is FALSE for dueLike, so the fork clause fired there and dueLike is HELD, untouched. objectstack-ai/objectstack#22503 (merged 2026-10-09, 215e66204) declares dueLike and settledWhen on FieldSchema on spec main (not yet published; the installed 17.7.0 still refuses dueLike), three objectstack example apps write dueLike: true on published objects, and its readers take it off the object's field definition, which no runtime hand-off type can carry. The decision on dueLike is in open_questions.", "tests": "Runs from the repo root; heavy runs under os-verify-lock, verdicts from its VERDICT lines. BUILD: turbo dependency closure of app-shell/plugin-detail/plugin-form/plugin-grid, 28 of 28 tasks, exit 0. Scoped doc build (check-doc-snippet-types --build-filter, plus console), 37 of 37, exit 0. TYPE-CHECK (script `type-check` echoed), exit 0 each: @object-ui/types, fields, core, components, plugin-form, plugin-detail, plugin-grid, app-shell. app-shell was red once (TS2353: FlowReferenceField's LookupFieldMetadata literal carried idField) and green after that producer fix. types was re-run at 31da2084: exit 0. VITEST: at 31da2084, packages/types/ plus the two new fields pins: 375 files, 10239 tests passed, exit 0. At bf418ddc (no fields source changed after it): packages/fields/, 252 passed + 1 skipped, 4031 tests passed, exit 0. Also at bf418ddc, a targeted set of 28 files / 354 tests, exit 0: plugin-grid relationalMetaCopySet.derivation and lookupPickerKeys-7154; plugin-form locationStoredRange/Refusal/Residue/Range and ObjectForm.mobileFullscreen; app-shell FlowReferenceField* and paramToField; components form-fullscreen* and form-builtin-textarea-character-count; schema-catalog form-field-channel-census-12130, form-field-channel-effects-12130 and form-builtin-branch-dom-allowlist-12155; plugin-detail fieldEnrichment. scripts/__tests__/ at bf418ddc: 186 passed, 1 red, check-doc-component-types 'this repository is green' on text.mdx's first fenced format rule. Fixed by teaching the rule in prose; the file re-ran green at 155bd4e1. The first types run was red on two field-metadata-rows-option-description-6140 read-site quotes of the two long-text casts; they were re-spelled, then green. ABLATIONS (committed state, objectstack scripts/ablation-replace.mjs wrap mode, anchor 1 → 0 and blob change printed by the tool, each restore blob == HEAD with an empty git diff HEAD, final restore proof git diff HEAD = 0 bytes): A1 pattern?: never → string | RegExp: tsc -p tsconfig.test.json red, TS2344 (tombstone assertion) + TS2578 at _pattern. A2 idField?: string back on LookupFieldMetadata: red, TS2578 at _idField + TS2344. A3 GeolocationFieldMetadata back in the union: red, TS2578 at _geolocation. A4 buildValidationRules' field.pattern read restored: 2 rows of buildValidationRules.fieldLevelRegexRetired-12242 red. A5 field.validate read restored: 1 row red; the location control stayed green, as expected, because that branch replaces rules.validate wholesale. The first A2-A5 attempt was a no-op: each replacement contained its own anchor, so the tool refused it and no command ran. Those readings were discarded and re-run. ESLINT (targeted, 19 changed .ts/.tsx files, --format json): 0 errors, 233 warnings; the 16 files that exist at base give identical per-file counts there, and the 3 new files give 0/0. Population: eslint.config.js's TS block **/*.{ts,tsx}. Invariance: no type-aware linting (no project/projectService), and no eslint-rules/ rule reads another file. One error found and fixed on the way: object-ui/no-unused-imports on form.ts's JSDoc-only UserFieldMetadata import.", "gates": { "at": "31da2084 (git rev-parse --short HEAD after the final commit)", "exit_0": { "check:control-bytes": "check-control-bytes: OK (8571 tracked text files)", "check:new-line-citations": "VERDICT new-cross-file-line-citations: 0 new citation(s)", "check:esm-specifiers": "specifier leg: no un-ledgered package emits an extensionless relative specifier", "check:self-import": "No package names itself inside its own src/", "check:phantom-deps": "Every in-scope import is declared by the package that publishes it", "check:unreferenced-sources": "Every shipped source file in every covered package is reachable", "check:handler-key-reads": "OK, 56 reachable handler reads, 56 judged", "check:changeset-claims": "report-only: names round one's 12242-types-field-metadata-family.md for the family pin; that paragraph stays true (rows added, none changed)", "check:pending-changeset-literals": "No test source names a pending changeset", "check-changeset-fixed": "OK", "check-changeset-presence": "20 source file(s) of 5 released package(s) changed, and this change declares 2 changeset(s)", "check-changeset-no-major": "No changeset declares a major bump", "check:designer-field-key-parity": "designer-field-key-parity: OK", "check:spec-symbols": "ledger anchors OK", "check-doc-links": "Links are valid across 17 scan roots", "check:doc-fences": "every TypeScript block fenced ts/tsx/typescript", "check:doc-json": "Every judged JSON node document passes the strict authoring face", "check:doc-types": "Every documented component type is registered", "check:doc-example-ids": "415 real reference(s) all resolve", "check:doc-snippets": "Every covered documentation snippet compiles against the built types", "check:doc-examples": "Every covered @example compiles, or fails exactly as its ledger row declares", "check:readme-exports": "OK, 0 wrong-path, 0 fabricated", "check:eager-closure": "3131.3 KB of 3204.6 KB gzipped; 4 per-chunk ceilings green (run at the scoped build, before 31da2084's type-only form.ts edit)", "check-governed-queue-guard --test (28 changed paths)": "NOT GOVERNED" }, "report_only": { "check:i18n-dead-keys": "exit 0; lists the validation.pattern pack key as needs-review, as it did before this change" }, "not_measured": [] }, "line_budget": { "files": 28, "insertions": 645, "deletions": 282, "range": "74964ad6..31da2084", "note": "no managed line ledger touched; 97 of the deletions are the retired types-side mobile_fullscreen pin, replaced by a fields-side pin" }, "files_changed": [ ".changeset/12242-fields-validation-rules.md (new; @object-ui/fields minor, BREAKING)", ".changeset/12242-types-kept-positions.md (new; @object-ui/types minor, BREAKING)", "content/docs/blocks/forms.mdx", "content/docs/fields/lookup.mdx", "content/docs/fields/text.mdx", "content/docs/fields/user.mdx", "content/docs/plugins/plugin-form.mdx", "packages/app-shell/src/views/metadata-admin/inspectors/FlowReferenceField.tsx", "packages/fields/src/__tests__/buildValidationRules.fieldLevelRegexRetired-12242.test.ts (new)", "packages/fields/src/index.tsx", "packages/fields/src/widgets/LookupField.tsx", "packages/fields/src/widgets/RichTextField.tsx", "packages/fields/src/widgets/TextAreaField.tsx", "packages/fields/src/widgets/__tests__/longTextCarrierHandoff-12242.test.tsx (new)", "packages/fields/src/widgets/__tests__/richtext-field-metadata-7083.test.tsx", "packages/fields/src/widgets/longTextCarrierHandoff.ts (new)", "packages/plugin-form/README.md", "packages/plugin-form/src/ObjectForm.locationStoredRange.test.tsx", "packages/plugin-grid/src/__tests__/relationalMetaCopySet.derivation.test.ts", "packages/plugin-grid/src/relationalMetaKeys.ts", "packages/types/src/__tests__/field-metadata-family-retired-12242.test.ts", "packages/types/src/__tests__/field-metadata-mobile-fullscreen.test.ts (deleted: it pinned mobile_fullscreen ON BaseFieldMetadata, the premise the ruling reverses; carried forward in fields)", "packages/types/src/__tests__/field-metadata-rows-option-description-6140.test.ts", "packages/types/src/__tests__/form-field-channel-keys-12130.test.ts", "packages/types/src/__tests__/form-field-zod-coverage.test.ts", "packages/types/src/field-types.ts", "packages/types/src/form.ts", "packages/types/src/zod/form.zod.ts" ], "clause_2_export_closure": "Measured on the built .d.ts, base 74964ad6 (scratch worktree) against head, per top-level declaration as a comment-free token multiset, so union-member reordering by the printer does not count, with @deprecated compared separately. EXPORT NAMES: identical for every exports entry of @object-ui/types, @object-ui/fields and @object-ui/plugin-grid. @object-ui/types declarations changed: BaseFieldMetadata, TextFieldMetadata, LookupFieldMetadata, UserFieldMetadata, FieldMetadata (one union member fewer) and FormField (the same three member types, now spelled out and pinned Equal); @deprecated added on FieldValidationFunction, FieldConstraints and GeolocationFieldMetadata. @object-ui/fields: one added file, widgets/longTextCarrierHandoff.d.ts, referenced by no emitted .d.ts and reachable from no exports entry. @object-ui/plugin-grid: no declaration changed. app-shell is not measured (it is not a typed-export surface this card touches; its change is an internal component).", "deviations": [ "PR first line is `Part of #12242`, not the dispatch's `Fixes #12242`. The fork clause held dueLike, and Fixes would close the card with that position undecided. The PR body says which half stays.", "dueLike is HELD under the ruling's fork clause, reported here and in the PR body, with no silent C: DateFieldMetadata.dueLike, DateTimeFieldMetadata.dueLike, date.mdx, datetime.mdx, DetailViewFieldSchema.dueLike and schema-reference.md are unchanged.", "Files beyond the claim's parenthetical lead lists, each inside one of the claim's named classes. app-shell FlowReferenceField.tsx: a typed producer of idField/picker/subtitle with its own package-local binding type, which is the 'hand-off types where each Q1 key's producer ... live'; app-shell type-check went red without it. types form.ts and zod/form.zod.ts: FormField declared the three keys by reference to the removed members, and FieldValidationRules.pattern's docblock became false. lookup.mdx, user.mdx, blocks/forms.mdx and plugins/plugin-form.mdx: 'docs pages that teach these keys'. The 6140, 12130 and zod-coverage pins in types, the plugin-grid derivation test, the plugin-form location test and the fields 7083 fixture: 'the pins that read these'. No file outside those classes. In particular scripts/check-doc-component-types.mjs's ledger was NOT edited, which round one did for object.mdx; text.mdx teaches the format rule in prose instead.", "GeolocationFieldMetadata stays exported, marked @deprecated, and is out of the union only. That is the VisibilityCondition precedent, and the barrel index.ts is outside the claim surface. Removing the export is a separate decision.", "FieldValidationFunction and FieldConstraints are kept and marked @deprecated, not deleted. FieldValidationFunction is a firing control in phase35-validation-types-retired-10719.test.ts.", "The pending changeset .changeset/12130-form-field-channel-keys.md (another card's) says FormField declares idField/picker/subtitle 'by reference to the field metadata types'. This change makes that false. It was not edited; the types changeset states that it supersedes it, and both release together.", "objectui has no dispatch-gates.mjs, so the gate list is hand-derived from the dispatch, the root package.json and the workflows, plus check:i18n-dead-keys (report-only) for the producerless validation.pattern default.", "Commit trailers follow objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), not the harness's model-named Co-Authored-By line, per AGENTS.md's precedence clause.", "Suites are cited at the sha they ran on. fields (252 files), the targeted 28 and scripts/__tests__ ran at bf418ddc; after it no fields or plugin source changed, only types form.ts (an import line and a comment), docs and the 6140 test. The gate union and the types type-check and suite were re-run at 31da2084.", "A heavy full-expansion closure script I started (5.7 GB RSS) was killed by its own PID, and replaced by the token-multiset comparison above." ], "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "2 REST writes, both through objectstack scripts/pm tools as objectstack-fleet[bot]. (1) pr_create via fleet-write/dispatch.mjs: POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204, run 38336410786, success), executed as POST /repos/objectstack-ai/objectui/pulls (draft, #12293) + POST /repos/objectstack-ai/objectui/issues/12293/assignees (os-justin); read-back 16159 bytes sent, 16159 stored, identical, and re-read independently. (2) This os-dev-report comment via post-stamped.mjs: POST /repos/objectstack-ai/objectui/issues/12242/comments. Not REST: git push of the branch, 5 times (the empty-branch write probe, 9d3fad05, bf418ddc, 155bd4e1, 31da2084). Zero label writes (the PR's labels came from labeler.yml), zero card or assignee writes.", "open_questions": [ { "question": "dueLike (DateFieldMetadata / DateTimeFieldMetadata) was held by the fork clause. @objectstack/spec main declares it on FieldSchema (objectstack#22503, with settledWhen, date/datetime only, display-only), not yet in a published version; the installed 17.7.0 refuses it. objectstack's example apps author it on published objects, and objectui's date cells read it off the object field definition. Where does it go?", "options": [ "A: keep it on the authoring face. When objectui installs the spec version that carries objectstack#22503, a follow-up card declares it BY REFERENCE (SpecField['dueLike']) and adds the settledWhen reader that objectstack's changeset says follows in objectui. #12242 closes now, with dueLike out of its scope. Cost: one small follow-up PR after the spec bump; nothing moves twice.", "B: execute the letter-A move now (onto a hand-off), then move it back after the spec bump. Cost: two breaking changesets for one key, and in between the authoring face refuses a key the next spec accepts and three example apps author.", "C: keep #12242 open on dueLike alone until the spec version publishes, then do A's follow-up on this card. Cost: an open card waiting on another repo's release." ], "recommendation": "A. Business need: the key is authored (three example apps) and read (date/datetime cells), so it is real, not speculative. Long-term: protocol as baseline (objectstack#12708 5552700625); the spec has adopted it, so by-reference declaration is the contract-first move, and B fights the protocol. Preventing AI errors: under A the authoring face and the next spec agree, while under B an agent typing a field refuses a key the spec accepts. Startup scope: A adds no surface and moves nothing twice. B is churn and C is an idle card." } ], "out_of_scope_findings": [ "carrier: none (承接者:无) · noted, not filed — plugin-detail ENRICHED_FIELD_METADATA_KEYS still copies idField, picker, subtitle and dueLike off the served object definition; the installed spec refuses all four on a field, so for spec-compliant data those copies reach nothing. Behaviour kept per the ruling. In the PR's Acceptance notes.", "carrier: none (承接者:无) · noted, not filed — the form renderer's 'validation.pattern' default message has no in-repo producer of that messageKey now (buildValidationRules was the only one); check:i18n-dead-keys already lists the pack key as needs-review (report-only).", "carrier: none (承接者:无) · noted, not filed — buildValidationRules still reads required_message, min_length_message, max_length_message, min_message and max_message, snake keys no objectui type declares; the spec's answer on them was not measured." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
Decision box: the ruling's fork clause fired on
dueLike·pm:dispatched→needs-user-decision· 2026-10-13T02:27Zdomain:spec@ objectui seat (objectui#10217) · sessionsession_015YrgVw7e65cs1ndbebt46G. Checked against objectstackorigin/mainand the npm registry, not against the report (os-dev-reporton this card, PR objectui#12293). Thread-read: the dev's report is the newest comment.State:
pm:dispatched→needs-user-decisionin this act. The assignee stays while PR objectui#12293 is in flight. PR objectui#12293 lands as built (first linePart of #12242). It executes ruling A (6135661503) for every other position (Q1's other four keys, all of Q2, Q3) and leavesdueLikeexactly asmainhas it, so landing it decides nothing ondueLike. It still owes a patch round (below) and the contract-tier review before the queue.What the seat re-measured (objectstack
origin/main, read in this act):215e66204, merged 2026-10-09) is onmain.FieldSchemathere declaresdueLike("Deadline semantic (date/datetimeonly) … Display only") andsettledWhen.@objectstack/specis17.7.0(npmlatest, published 2026-10-06), which predates #22503. objectui's lockfile pins17.7.0, so the installed spec still refusesdueLike.examples/app-crm(activity.object.ts),examples/app-showcase(task.object.ts),examples/app-todo(task.object.ts).coredate-display.ts,fieldsindex.tsx,plugin-detailfieldEnrichment.ts.So the ruling's premise for
dueLike("FieldSchemarefuses it; a host writes it at runtime") no longer holds on the protocol's ownmain.维护者速读
字段元数据收口第二轮已按裁决 A 做完,只剩
dueLike(日期字段「这是个截止日期」的开关)一个键需要您重新定。原因:裁决时 spec 不收这个键,但 objectstack 10 月 9 日已在 spec 里正式声明了它(objectstack#22503),三个示例应用也在用;只是带它的 spec 版本还没发布,objectui 装的 17.7.0 仍会拒收。dueLike留在字段的作者面上,不挪。等带它的 spec 版本发布、objectui 装上后,另开一张小卡按引用声明(FieldSchema['dueLike']),并补上settledWhen的读取。本卡随 PR objectui#12293 合并关闭。席位推荐 A。选 A 还是 B?
决策分析
一句话问题: 一个日期字段「是截止日期」的开关,平台协议刚刚正式收下了它,objectui 的字段类型是该留着它,还是按旧裁决先撤掉再加回来?
Governing text:
5552700625):「本项目以协议为基准。所以开发应该对其协议,协议有问题应该立卡修改协议」。AGENTS.md#0.1:运行时才由宿主写的键住在包内交接类型上;spec 拥有的键在节点类型上按引用声明。6135661503的分叉条款:「every reader of a Q1 key can be typed on a hand-off type. If the dev finds … a non-test reader that no hand-off type can carry, it reports and stops」。main的FieldSchema.dueLikedescribe(215e66204)。协议声明、是否改协议: spec
main已声明dueLike与settledWhen(仅date/datetime,只影响显示);已发布的 17.7.0 尚未包含。两个选项都不改协议,差别只在 objectui 是先撤后加,还是直接等协议发版。前提(re-check 命令,各带阳性对照):
main声明了它:git -C /home/user/objectstack grep -n "dueLike: z.boolean" origin/main -- packages/spec/src/data/field.zod.ts命中 1;对照inlineHelpText在同文件命中。curl -sS https://registry.npmjs.org/@objectstack%2fspec的dist-tags.latest为17.7.0(2026-10-06),早于 #22503 合并(2026-10-09)。git -C /home/user/objectstack grep -ln dueLike origin/main -- 'examples/**'命中 3 个对象文件;对照type: 'text'在 examples 下大量命中。git grep -ln dueLike origin/main -- 'packages/*/src/**' ':!**/__tests__/**'命中core/utils/date-display.ts、fields/index.tsx、plugin-detail/fieldEnrichment.ts。选项 × 真实代价 × 工作量:
dueLike、补settledWhen读取,文档跟随domain:spec· 现在 0 · 发版后 1 个 PR · 先例 PR objectui#12236(按引用声明inlineHelpText,+505/−12)dueLike挪到交接类型(破坏性),发版后再挪回作者面(再一次破坏性)dueLike会编译失败,而协议和示例应用都在用它domain:spec· 2 个 PR · 先例 PR objectui#12293(本轮整族,+645/−282;单键未测)业务含义直译:
四轴(业务立场):
dueLike是协议里的正式字段键,objectui 按引用声明它,日期单元格据它显示「已逾期」。A 直接通向这个终态,B 绕一圈回到同一个终态,中间多一段作者面与协议相反的时期。主流平台(如 Salesforce 的字段属性)也把这类显示语义放在字段定义上。dueLike被接受,与下一个 spec 版本一致。B 下 AI 写出协议接受的键却被 objectui 类型拒绝,是「拒收协议合法键」的反向陷阱。推荐:A(按①得出;②③④ 同向)。
settledWhen的 objectui 读者尚不存在,规模未测(随后续卡测)。裁后执行:
completed关闭(dueLike移出本卡范围)。本席同时在 objectui 立一张后续卡(按引用声明dueLike、补settledWhen读取、文档跟随),挂pm:on-hold,Restart-when:判据为 objectui 安装的@objectstack/spec含 objectstack#22503,到点再派发。Fixes #12242),把dueLike挪到交接类型;spec 发版后再按 A 的后续卡挪回。os-decision-facets
Prior rulings read: this card's ruling
6135661503(letter A; fork clause) and its questions6125867738; objectstack-ai/objectstack#127085552700625(protocol as baseline); objectuiAGENTS.md#0.1; thread: 11Seat notes (same act)
.changeset/12130-form-field-channel-keys.mdjoins claim6135868241's file surface, for its one bullet that PR objectui#12293 makes false ("Declared, by reference to the field metadata types:idField…pickerandsubtitle…"). The precedent is objectui#12157 correcting the same pending changeset (6121216484). That pending note is unreleased: the@object-ui/typesCHANGELOG onmaincarries no12130.Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
Ruling: batch #334 item S1 (first-class self-ruling, director channel) · letter A · maintainer 「本项目以协议为基准。所以开发应该对其协议,协议有问题应该立卡修改协议」(standing ruling, objectstack-ai/objectstack#12708 ledger 5552700625) 2026-10-13T02:43Z
Director seat, summon #40,
session_01TJKP6W6UDYEBHtccVdpVoz(GitHubos-steve; written asobjectstack-fleet[bot]through the relay, read back). Ruled through the director's first-class channel and NOT presented in a batch, on the three-part test (triage-duties, 一类自裁门): ① the direction is decided mechanically by the standing ruling above together withFieldSchema.dueLikeon@objectstack/specmain(packages/spec/src/data/field.zod.ts:1947, objectstack#22503, merged 2026-10-09): a key the protocol declares is declared by reference on the consumer face, never moved off it; ② A changes nothing today and the follow-up is one revertable PR; ③ no floor moves: no security boundary, the published contract keepsdueLikeexactly as objectuimainhas it, no capability is traded, no gate changes. Listed in summon #40's closing table on objectstack-ai/objectstack#12708 for the maintainer's veto window; a veto there reopens this card to the decision box. Thread-read: 6136874685.The ruling
A —
dueLikestays on the authoring face; the fork is resolved by narrowing ruling 6135661503's Q1 to the four keys the protocol does not declare.DateFieldMetadata.dueLike,DateTimeFieldMetadata.dueLike,DetailViewFieldSchema.dueLike,date.mdx,datetime.mdxandschema-reference.mdare untouched by this card. When objectui installs the@objectstack/specrelease that carries objectstack#22503, a follow-up card declaresdueLikeby reference (FieldSchema['dueLike']), adds thesettledWhenreader objectstack#22503's changeset says follows in objectui, and makes the docs follow. B (move it to a hand-off type now and back after the release) is not taken: two breaking changesets for one key, and in between the authoring face refuses a key the protocol accepts and three example apps author. C (hold this card open ondueLikealone) is not taken: an idle card waiting on another repository's release is whatpm:on-holdwith aRestart-when:line is for.Readings behind it (taken this summon)
git grep -n "dueLike: z.boolean" origin/main -- packages/spec/src/data/field.zod.ts→ 1 hit (:1947, "Deadline semantic (date/datetimeonly) … Display only").@objectstack/specdist-tags.latest=17.7.0, published 2026-10-06, before #22503 merged; objectui's lockfile pins17.7.0.git grep -ln dueLike origin/main -- 'examples/**'→ 3 (app-crmactivity.object.ts, app-showcasetask.object.ts, app-todotask.object.ts).core/utils/date-display.ts,fields/index.tsx,plugin-detail/fieldEnrichment.ts,types/field-types.ts,types/views.ts.Facets (四棱, the card's own at 6136874685, confirmed)
Execution parameters (ruled here, no further decision card)
needs-user-decision→pm:dispatchedin this act, assigneeos-justinunchanged; draft PR objectui#12293 (Part of #12242, headd6f28b48) lands as built once its patch round (the pending-changeset bullet, 6136874685) and the contract review atCONTRACT_REVIEW_TIERare done. At its merge, thedomain:spec@ objectui seat closes this cardcompletedwithdueLikeout of its scope, and files the follow-up card in objectui (declaredueLikeby reference, thesettledWhenreader, the docs) aspm:on-holdwithRestart-when: objectui's installed @objectstack/spec carries objectstack-ai/objectstack#22503 (FieldSchema.dueLike)andRestart-touch: pnpm-lock.yaml, per the cross-repo unlock rule (installable, not merged).domain:spec@ objectui · 0 now · 1 PR after the release · precedent PR objectui#12236 (inlineHelpTextby reference, +505/−12).dueLikebefore objectui installs it, the follow-up card returns to the box; ⛔ no silent B.objectstack-fleet commentedon Oct 13, 2026
ACCEPT · PR objectui#12293 @
d6f28b48· 2026-10-13T02:46Zdomain:spec@ objectui seat (objectui#10217) · sessionsession_015YrgVw7e65cs1ndbebt46G. Checked against GitHub, the PR's net diff and objectstackorigin/main, not against the report (6136825207). Ruling-ref: 6135661503 (letter A), narrowed by 6137052265 (letter A:dueLikestays on the authoring face). Thread-read: 6137052265.Implemented-by:
claude/issue-12242-field-metadata-kept-positions· Reviewed-by:session_015YrgVw7e65cs1ndbebt46G, plus the contract-review-tier record6137063916on the PR (PASS on headd6f28b48bff2e8f513981e646b8b6a2e9f0898c1,Local-runs: none), written by an isolated at-tier reviewer that read only the card, the PR and the head's check-runs.Checklist (head
d6f28b48)main✓ · first linePart of #12242✓ (the card closes by hand at the merge, per 6137052265) ·Clause-②: yesat line start ✓ · PR assigneeos-justin✓. A body scan finds no closing keyword.6135868241as amended in6136874685(the pending objectui#12130 changeset, one bullet). Not governed (check-governed-merges --pr: 0 of 29 paths, 929 changed lines). The head is one commit on a merge ofmain(6285879f, two parents); the net diff was judged.mobile_fullscreen,idField,picker,subtitleleave the*FieldMetadatatypes.mobile_fullscreenis typed on a package-localLongTextCarrierHandoff.FormFieldkeeps the three picker keys at the same types.FlowReferenceFieldtypes its carrier on the hand-off.pattern,pattern_messageandvalidatebecomenevertombstones, andbuildValidationRulesno longer reads them.GeolocationFieldMetadataleaves theFieldMetadataunion. It stays exported,@deprecated, andfield:geolocationstays registered.dueLikeis untouched everywhere, as 6137052265 rules.packages/objectql/src/validation/rule-validator.tscheckFormat,packages/spec/src/data/validation.zod.ts): aformatrule runs only when the write carries the field ✓; it skips null, undefined and''✓; the regex isnew RegExp(rule.regex), unanchored ✓; it refuses with the rule's message ✓;nameis snake_case ✓;fieldandregexare declared ✓.12242-types-kept-positions.md(@object-ui/typesminor, BREAKING): every FROM → TO matches the diff, and thedueLike"Not changed" line matches 6137052265.12242-fields-validation-rules.md(@object-ui/fieldsminor, BREAKING): thebuildValidationRulesFROM → TO and thelocationrule match.12130-form-field-channel-keys.mdbullet is corrected in place (patch round 1,d6f28b48) to "declared on theFormFieldentry itself". Precedent6121216484.12242-types-field-metadata-family.mdwas read: its paragraph stays true, because this PR only adds rows to the pin it names.d6f28b48: 33 runs, 30 success, 3 skipped (the coverage lane anddependabot, by their path switches), 0 red.mergeable_stateis clean. A redTestaggregator on the superseded head31da2084was its shards readingcancelled(9) after the patch push: zero action, by rule.Out-of-scope findings:
buildValidationRulesstill readsrequired_message,min_length_message,max_length_message,min_messageandmax_message, which no face declares (escalated by the review): Acceptance notes, carrier none. These are reads of keys no named producer writes, with no wrong result measured at a public door, so the filing gate does not admit a card.ENRICHED_FIELD_METADATA_KEYSstill copies the moved keys,UserField's pre-existingprops.field as any, and the producerlessvalidation.patternpack key: Acceptance notes, carrier none.Landing:
pr_ready+automerge_enablethrough the relay in this act. At the merge, this seat closes this cardcompletedand files thedueLikefollow-up aspm:on-hold, per 6137052265's execution parameters.Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
Maintainer 追认 of the first-class self-ruling 6137052265 (
dueLikestays on the authoring face, letter A): the maintainer's word on summon #40's closing table was 「同意」 at 2026-10-13T02:53Z, recorded here by the director seat (session_01TJKP6W6UDYEBHtccVdpVoz, written asobjectstack-fleet[bot]through the relay). The veto window is closed; the ruling and its execution parameters stand as written. No state change in this act (the card ispm:dispatched, assigneeos-justin, PR objectui#12293 in flight).refactor(types,fields,app-shell): field metadata stops declaring host…
objectstack-fleet commentedon Oct 13, 2026
Closed
completed· 2026-10-13T03:04Z · by thedomain:spec@ objectui seat (objectui#10217), sessionsession_015YrgVw7e65cs1ndbebt46G, per the execution parameters of ruling6137052265.5d3f437a, onorigin/main. Verified by content:TextFieldMetadata.pattern_message?: never,FormField.idField?: string, and both date types still declaredueLike. Verified bygit patch-id --stable: the PR's net diff and the merge commit both give08275531bd40. The merge commit is single-parent, a squash.6135661503(A: Q1 A, Q2 A, Q3 B), as6137052265narrowed Q1 to the four keys the protocol does not declare. Round one landed as PR objectui#12257 (10aba37). ACCEPT6137078340; contract review6137063916PASS.dueLikeis out of this card's scope (6137052265, letter A): it stays on the authoring face. The by-reference declaration ofdueLikeandsettledWhen, plus the docs, is filed as objectui#12297,pm:on-holduntil objectui's installed@objectstack/speccarries feat(spec,lint): a date or datetime field declares its deadline: dueLike and settledWhen objectstack#22503. The renderer's reads of both keys stay with objectui#11815 (domain:ui, on hold on the same install event).pm:dispatchedis removed and the assignee is cleared in this act; the claim (6135868241) and the ACCEPT remain the record of who carried the card.Generated by Claude Code