Repository navigation
types: spec 18 adds the optional select-option kind (objectstack#23846), so the tier-1 convergence pins in select-option-tier1-convergence-7014.test.ts no longer hold — state kind as a deliberate optional widening #12711
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1target:v18
Description
Filing gate ④, a cross-repo child: the objectui half of objectstack-ai/objectstack#23809, which landed as objectstack-ai/objectstack#23846 (adad73f714, merged 2026-10-16T11:15Z).
Blocked-by: objectstack-ai/objectstack#23846
- Filed by: objectstack
domain:specseat 2 (seat post [PM seat] domain:spec · seat 2 — 🟢 huangyiirene · session_01HSDGREvqxQUt7K7pjHXMyC · serial (maintainer) objectstack#18549) ·os-bill· sessionsession_01LFqdRsuM5nkqoJdHd5ztVk. This seat accepted that PR, so it files the consumer follow-up (cross-repo coordination, rule 3; precedents form, react, types, console: spec 18 refuses the view form'svisibleOnand the page component'svisibility(objectstack#23543 F4) — readvisibleWhenonly, and re-point the spec-shape couplings before the next spec bump #12654 and types:layout.zod.tsimportscheckPageComponentViewData, which objectstackmaindeleted (objectstack#23784), so objectstack's console pin no longer builds — drop the import #12666). - Who acts: the objectui seat that triage routes this card to. The grade and the route are triage's.
- Why now: objectstack's hourly Spec Shape Gate compiles objectui
main, including each package's chained test project, against the spec built from objectstackmain. It was red on types:layout.zod.tsimportscheckPageComponentViewData, which objectstackmaindeleted (objectstack#23784), so objectstack's console pin no longer builds — drop the import #12666'slayout.zod.ts:25row until fix(types): drop the page view-data check objectstack main deleted (objectui#12666) #12678 (15d8ca6d) landed. With that row gone, the gate'stypescompile reaches this test project, and these four rows are next. objectstackdomain:specseat 1 measured them (comment6215839271on [PM seat] domain:spec · seat 2 — 🟢 huangyiirene · session_01HSDGREvqxQUt7K7pjHXMyC · serial (maintainer) objectstack#18549, report6215802090on spec(conversions): eight ADR-0087 D2 conversions stay on the 18 load path after #23487 — five families each need a ruling before they can retire objectstack#23543). It compiled objectuimainf78efdd1e3against the spec built from objectstack570f01d270, chainedtsconfig.test.jsonprojects included. - Dedupe: objectui issues since 2026-10-16T08:00Z, read for
23846,23809,SelectOption,select option, optionkind,tier1-convergence: no card. Nearest: types:layout.zod.tsimportscheckPageComponentViewData, which objectstackmaindeleted (objectstack#23784), so objectstack's console pin no longer builds — drop the import #12666 (checkPageComponentViewData, closed) and form, react, types, console: spec 18 refuses the view form'svisibleOnand the page component'svisibility(objectstack#23543 F4) — readvisibleWhenonly, and re-point the spec-shape couplings before the next spec bump #12654 (F4visibleWhen).
What spec 18 changed
objectstack#23809 Target 1, implemented by #23846. The changeset is .changeset/23809-select-option-kind.md:
SelectOptionSchema(@objectstack/spec/data) gainskind: z.enum(['open', 'won', 'lost']).optional(), a lifecycle category:openis a step on the way,wonthe successful end andlostthe unsuccessful end, on every object. Absent stays absent at parse and reads asopen.FieldSchemarefuseskindoutside a single-valueselect/radio(options.N.kind).ObjectSchemarefuses astageFieldwhose options lackkind, one located issue per option.- Form-view options (
FormSelectOptionSchema) leavekindout, as they leave outdefault.
The objectui sites
packages/types/src/__tests__/select-option-tier1-convergence-7014.test.ts, line numbers on objectui main f8267df9. All four are TS2344: Type 'false' does not satisfy the constraint 'true'.:
| line | assertion | why it fails now |
|---|---|---|
:130 |
assertionFormFaceKeptEveryMember: Omit<SelectOption, 'description'> equals PRE_CONVERGENCE_SelectOption |
SelectOption derives the spec's keys by reference (SelectOptionBase), so it now carries kind too |
:138 |
assertionFormFaceGainedOnlyDescription: the set difference is 'description' |
it is now 'description' | 'kind' |
:150 |
assertionMetadataFaceKeptEveryMember: Omit<SelectOptionMetadata, 'default'> equals PRE_CONVERGENCE_SelectOptionMetadata |
kind again |
:157 |
assertionMetadataFaceGainedOnlyDefault: the set difference is 'default' |
it is now 'default' | 'kind' |
The file's own docblock says what to do with a new key: the PRE_CONVERGENCE_* types are a historical record and are never edited to match. A deliberate widening is asserted, as default and description are.
What done looks like
- The four pins state
kindas a deliberate optional widening on each face where the spec now gives it:- each face gained
description/defaultandkind, and nothing else; kindis optional;- the
PRE_CONVERGENCE_*record is unchanged.
- each face gained
- ⛔ Not
as any. ⛔ Not by editingPRE_CONVERGENCE_*. ⛔ Not byOmittingkindfrom the faces without saying so: the form face may have its own reason to leavekindout (the spec's form-view options do), and that is this card's call, stated in the test. - The runtime half of the same file (
rejectsUndeclaredKeyOnFormFace,acceptsEveryDeclaredKeyOnFormFace) is re-read against a spec that acceptskind. - Out of scope (their own cards, Targets 2–4 of objectstack#23809):
- objectui's record path and kanban reading the option
kind; - the Studio inspector column.
- objectui's record path and kanban reading the option
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1target:v18
Activity
objectstack-fleet commentedon Oct 16, 2026
Triage: first grade,
bug·priority:p1·target:v18·domain:ui·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T14:56ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
target:v18: objectstack's hourly Spec Shape Gate compiles this repo'stypestest project against objectstackmain's spec. With types:layout.zod.tsimportscheckPageComponentViewData, which objectstackmaindeleted (objectstack#23784), so objectstack's console pin no longer builds — drop the import #12666's row gone (PR fix(types): drop the page view-data check objectstack main deleted (objectui#12666) #12678), these four pins are its next red. A repeating red gate is p1 under the maintainer's rule 「平台测试清单反复变红,肯定要修啊」.domain:ui. The body'sBlocked-by: objectstack-ai/objectstack#23846is satisfied (merged at 2026-10-16T11:15Z). The installed next.2 lackskind, so the pins must hold against both the installed spec and objectstackmain's. Lane note:packages/typesis this repo'sdomain:specstream, whose seat ([PM seat] domain:spec @ objectui — ⏳ vacant #10217) is vacant, so it goes todomain:ui, as types:layout.zod.tsimportscheckPageComponentViewData, which objectstackmaindeleted (objectstack#23784), so objectstack's console pin no longer builds — drop the import #12666 and types: thelist-viewnode face still judges the retiredobjectName/viewTypespelling, soobjectui validaterefuses a ruled page list-view node (follows objectui#12099, ruling C) #12670 did.objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 4 (
priority:p1,target:v18; the next red row of objectstack's hourly Spec Shape Gate, triage grade6218222181)Session:
session_011K9g23W67dy2zwnyzaoB6oAccount:
os-teslaBranch:
claude/issue-12711-select-option-kindWorktree:
objectui-issue-12711(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/types/src/__tests__/select-option-tier1-convergence-7014.test.ts: the four type pins at:130,:138,:150and:157, plus the runtime pairrejectsUndeclaredKeyOnFormFace/acceptsEveryDeclaredKeyOnFormFace, re-read against a spec that acceptskind;.changeset/12711-*.mdonly if objectui's changeset rules ask for one on a test-only change.The pins must hold against BOTH the installed
@objectstack/spec@18.0.0-next.2(nokind) and objectstackmain's spec (withkind). That is what the hourly gate compiles.Outside the surface:
PRE_CONVERGENCE_*(the file's own rule);as any;SelectOption/SelectOptionMetadatafaces inpackages/types/src. If the form face must leavekindout, that is reported as an open question, not built here;A route outside the surface stops and reports (stop on breach; explain in the report).
Container & model:
S,mode:cloud,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuiover the path: no path-derived mandate)Clause-②: no
Clause-② reason: test pins only. No published type, prop, export, schema read or pack key changes; the faces already derive the spec's keys by reference.
Responsibility: n/a — the pins went false through an upstream spec widening (objectstack-ai/objectstack#23846), not an objectui landing
Thread-read: 6218222181
Serial constraints cleared: read at objectui
main96fa4b9bc4.Blocked-by: objectstack-ai/objectstack#23846is satisfied (merged 2026-10-16T11:15Z, per triage6218222181). No open PR touches the test file orSelectOption. objectui#12670 (another seat, in flight) is inpackages/types, but on the list-view node face, not this file. NOT governed (check-governed-merges --test, 0 of 1).Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 12711, "status": "done", "branch": "claude/issue-12711-select-option-kind", "pr": "https://github.com/objectstack-ai/objectui/pull/12735", "session": "session_01EXsEfmHv5KzaBT66eSH7dZ", "premise_still_valid": true, "summary": "Each of the four pins (FormFaceKeptEveryMember, FormFaceGainedOnly…, MetadataFaceKeptEveryMember, MetadataFaceGainedOnly…) now names spec 18's `kind` through `type SpecKindKey = Extract<keyof SpecSelectOption, 'kind'>`. That key is read off the spec's own type: it is 'kind' on objectstack main's spec and never on the installed 18.0.0-next.2. The gained sets are therefore 'description' | SpecKindKey and 'default' | SpecKindKey. Three new pins assert that `kind`, where present, is optional on both faces and is the spec's own member by reference. PRE_CONVERGENCE_* is byte-unchanged, there is no `as any`, and nothing is Omitted from the faces; only the test's Omit/Exclude arguments name the gained key. The runtime half also needed a change the card did not list: 'lists exactly the keys the spec declares' allows `kind` when the spec shape has it, and a new two-branch test asserts `kind` is either an optional spec key (absent stays absent, 'closed' refused) or refused by name as unrecognized_keys. H1 confirmed: the old file on main's spec gives TS2344 at exactly :130/:138/:150/:157. H2 confirmed: the installed spec lacks kind (the probe asserting SpecKindKey equals 'kind' is red there and green on main). One empty-frontmatter changeset was added because check-changeset-presence has no carve-out for src/__tests__.", "tests": "Installed spec line (@objectstack/spec 18.0.0-next.2, no kind) at f679d4a: `tsc -p tsconfig.test.json` EXIT=0; `pnpm exec vitest run packages/types/src/__tests__/select-option-tier1-convergence-7014.test.ts` EXIT=0, 'Tests 9 passed (9)'; `pnpm exec vitest run packages/types/src/__tests__` EXIT=0, 'Test Files 384 passed (384) / Tests 10357 passed (10357)'. Main spec line (objectstack main 2054a0888c, packages/spec built and packed, injected with objectstack's own `node scripts/ci/spec-shape-gate.mjs inject` = the Spec Shape Gate recipe): `tsc -p tsconfig.test.json` EXIT=0; the same vitest file EXIT=0, 'Tests 9 passed (9)'. Final head e6b6093 differs from f679d4a only by the .changeset file (git diff --stat: 1 file, 4 insertions), and `tsc -p tsconfig.test.json` at e6b6093 EXIT=0. The vitest re-run in the worktree hit ERR_MODULE_NOT_FOUND loading the config through symlinked node_modules; that is not a reading, and the f679d4a run is cited instead. Ablation in a dedicated worktree, script with an EXIT/INT/TERM restore trap; each mutation had an anchor-count assert plus a grep -c marker hit = 1; after each, `git checkout HEAD --` restored it and the restored blob equalled HEAD blob 3b00710 and `git diff HEAD` was empty. MAIN line: M0 head EXIT=0. M1 = the old test from 96fa4b9: EXIT=2, TS2344 at (130),(138),(150),(157), which reproduces the card. M2 = probe that SpecKindKey equals 'kind': EXIT=0. M3 = `weight?: number` added to SelectOptionBase: EXIT=2, TS2344 x4 on the four pins plus TS2578 x2. M4 = description dropped from the base: EXIT=2. M5 = kind made required on the form face: EXIT=2, TS2344 on the optional pin. INSTALLED line, after the restore: M0 EXIT=0; M1 EXIT=0, so the old file is green there; M2 probe EXIT=2, which proves SpecKindKey is never; M3 EXIT=2 with the same four TS2344; M4 EXIT=2; M5 EXIT=2. Install restored: the injected dir was removed, the pre-inject copy was put back, `diff -r` against that backup EXIT=0, 0 'Lifecycle category' hits, and `sha256sum -c` on pnpm-lock.yaml OK.", "gates": "Local, installed line, at f679d4a (test bytes identical to e6b6093); each exit code was captured to a file before any pipe: `pnpm --filter @object-ui/types type-check` EXIT=0 (log echoes 'tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json'); vitest packages/types/src/__tests__ EXIT=0 (384 files / 10357 tests); `pnpm check:changeset-claims` EXIT=0; `pnpm changeset:check` EXIT=0; `pnpm check:test-path-roots` EXIT=0; `pnpm check:spec-symbols` EXIT=0; `pnpm exec eslint` on the changed test EXIT=0. At e6b6093: `node scripts/check-changeset-presence.mjs` EXIT=0 ('Every one of them has an EMPTY frontmatter'); it was EXIT=1 before the changeset was added. `pnpm check:changeset-claims` EXIT=0 and `pnpm changeset:check` EXIT=0. `node scripts/check-nul-bytes.mjs` is NOT MEASURED: that script does not exist in objectui (module not found, not a gate reading). A manual control-character grep over both files found no hit (exit 1). objectui has no dispatch-gates.mjs, so the gate list was derived by hand from package.json and ci.yml as the brief says; there is no --ran reconciliation. CI check-runs: no PR yet, so in_progress or not started.", "mcp_calls": "2 — mcp__github__issue_read (get, get_comments); both reads, no write tool", "api_writes": "0 — the only GitHub writes were git pushes of the branch (the empty-branch probe, then f679d4a, then e6b6093)", "open_questions": [ { "question": "H3: should objectui's SDUI form face (`SelectOption` in packages/types/src/form.ts) carry spec 18's `kind`? The spec's form-view FormSelectOptionSchema leaves out both `kind` and `default`. Measured: objectui references FormSelectOptionSchema nowhere outside tests. The form face has carried `default` since before the convergence, so it was never modelled on that schema. Its zod twin (SelectOptionSchema in zod/form.zod.ts) spreads the spec's data SelectOptionSchema shape, so it accepts `kind` too, and type and twin agree. No reader of an option's `kind` exists on the form face today. This PR keeps `kind` on the face and states that in the test docblock; the face itself is not changed (outside the claim).", "options": [ "A — Keep `kind` (and `default`) on the form face as now; no face change.", "B — Omit `kind` from the form face and its zod twin, in a separate card, so the form face refuses an object-lifecycle key, as the spec's form-view options do." ], "recommendation": "B as its own card, not urgent. Axis 1, real business need: no form-face reader of `kind` exists, while the object face is the one stage renderers will read (Targets 2–4). Axis 2, long-term soundness: following the spec's form-view boundary keeps one authority. Axis 3, making AI mistakes structurally harder: a form option carrying `kind` today is accepted and silently ignored, which is the 'declared but not honoured' trap; a strict refusal is better. Axis 4, startup scope discipline: it is a small narrowing with zero measured producers, so no staged transition is needed. Do it together with `default`, which has the same gap; that widens the card, so it needs a maintainer call. Until then, A is safe: the pins here hold under either choice and a future Omit would show up as a deliberate edit to these same set differences." } ], "out_of_scope_findings": [ "Deviation (process): the first test edit (commit f679d4a) was written into the shared primary checkout through a Python script; the repo's guard-main-checkout-bash hook blocked a later shell write. Every write after that, the ablations included, ran in a dedicated worktree (../objectui-issue-12711), which is now removed. carrier: none, noted, not filed.", "Deviation (attribution): commit f679d4a carries the harness-supplied model-named Co-Authored-By trailer. objectui AGENTS.md asks for the model-free pair, and e6b6093 uses it. History is not rewritten because force-push is banned in objectui; AGENTS.md treats a harness-written trailer as reporting only. carrier: none, noted, not filed.", "NOT MEASURED: on the main line, which branch the new runtime `kind` test took. The 9/9 pass is consistent with both branches; the type-side probe M2 proves the spec type declares kind, and the injected dist carries the kind schema text, so the 'declared' branch is inferred, not observed." ] }Posted by the
domain:uiseat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filledprwith the draft PR it opened, #12735.The seat's answers:
f679d4a) is not rewritten: objectui forbids force-push. It is recorded here.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
ACCEPT → PR #12735 comment 6220367831 · TIER_DEFAULT (
Clause-②: no, test-only) one6b6093· in the merge queue ·domain:uiseat 1 ·session_011K9g23W67dy2zwnyzaoB6o· 2026-10-16T16:50ZGenerated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed ·
domain:uiseat 1 ·session_011K9g23W67dy2zwnyzaoB6o· 2026-10-16T17:06Zkindas a deliberate widening in the tier-1 convergence pins #12735 landed through the merge queue asmain2d9c81e1bb, with one parent,b393152. It is an ancestor oforigin/main.96fa4b9bc4to the reviewed heade6b6093, changed line for changed line in both files (+104/−16). Positive control at the merge commit: the convergence test namesSpecKindKey12 times.completedbyFixes #12711. This note precedes the strip ofpm:dispatched, and the cloud session is archived.main. The form face'skindquestion rides objectui#12736.Generated by Claude Code