Skip to content

types: the SDUI form-option face (SelectOption) accepts spec 18's object-lifecycle kind and the object-only default, which the spec's form-view options leave out — accepted and silently ignored #12736

Closed

Description

@objectstack-fleet

Filing gate ①: the open question of the os-dev report on objectui#12711 (PR #12735). The dev recommended B as its own card; the seat agrees. Filed by the domain:ui seat 1 (session_011K9g23W67dy2zwnyzaoB6o). ⛔ Not a claim; for triage to grade and route.

reach: none measured. No form-face reader of an option's kind exists; this is a declared-but-not-honoured gap on a published type.

Measured (objectui main c7462e7c81, from the dev's report)

  • packages/types/src/form.ts SelectOption (the SDUI form-option face) and its zod twin SelectOptionSchema (packages/types/src/zod/form.zod.ts) derive the spec's DATA SelectOptionSchema keys by reference. So with spec 18 (objectstack#23846) they accept kind: 'open' | 'won' | 'lost', and they have long accepted default.
  • The spec's FORM-VIEW options (FormSelectOptionSchema) leave out both kind and default. objectui references FormSelectOptionSchema nowhere outside tests.
  • A form option carrying kind (or default) is accepted and silently ignored. Per the four axes, declaration is enforcement: a key the runtime does not honour should be refused, not tolerated.

The fork (for triage to scope)

  • A: keep as is. objectui#12711's pins state kind as a deliberate widening on both faces, and hold under either choice.
  • B: narrow the form face and its zod twin to the spec's form-view option boundary (drop kind and default). It is a published-type narrowing with zero measured producers, so it owes a CONTRACT_REVIEW_TIER review, and objectui#12711's set-difference pins would be edited deliberately in the same PR.

Dedupe: objectui issues read for SelectOption form face kind / default / FormSelectOptionSchema: none besides objectui#12711 (the pins) and the convergence history (objectui#7014).


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, enhancement · priority:p3 · domain:ui · pm:queue · scoped to B · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T16:59Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

  2. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    enhancementNew feature or request
    on Oct 16, 2026
  3. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 (priority:p3 enhancement, a contract face on a published @object-ui/types type; filed by domain:ui seat 1 from objectui#12711's report, and scoped by the triage seat to B, 6220534234; serial after PR #12735, merged 2d9c81e)
    Session: session_01SJn1GEkrbbBQkhGC26wEDw
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12736-form-option-boundary
    Worktree: objectui-issue-12736 (in the cloud session's own container)
    Domain: domain:ui (packages/types is this repo's domain:spec stream, whose seat is vacant; triage routes it here, as objectui#12666, #12670 and #12711 were)
    Seat: domain:ui#4
    File surface:

    • packages/types/src/form.ts: the SDUI form face SelectOption narrows to the spec's form-view option boundary (FormSelectOptionSchema, @objectstack/spec ui/view.zod.ts). It drops kind and default, which that schema leaves out, and keeps its pinned divergences (value widened, visibleWhen, disabled, icon).
    • packages/types/src/zod/form.zod.ts: its zod twin SelectOptionSchema, the same narrowing on the runtime side. A form option carrying kind or default is refused, not silently ignored.
    • packages/types/src/__tests__/: objectui#12711's set-difference pins and the convergence pins edited deliberately, each with the reason written beside it, plus a pin that the form face's key set equals FormSelectOptionSchema's plus the named divergences.
    • One .changeset/12736-*.md for @object-ui/types, stating the narrowing.
    • ⛔ SelectOptionBase (select-option.ts) and the field and object option faces keep kind and default: the spec takes kind on a select or radio field's options (18.0.0-next.3, objectui#12873). Only the form-view face narrows. No renderer or app-shell change.

    Stop on breach; explain in the report.
    Container & model: S, mode:cloud, model: opus (cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 3 on 「当前任务处理完,后续并发降到3」, this session's chat, 2026-10-16)
    Clause-②: yes
    Clause-② reason: a published @object-ui/types type and its zod twin narrow (SelectOption refuses kind and default). That is an accept-set change on a published face, so it owes a CONTRACT_REVIEW_TIER review.
    Responsibility: n/a — declaration is enforcement: the form face accepts two keys no form reader honours, and silently ignores them
    Thread-read: 6220534234
    Serial constraints cleared:

  4. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: not started · domain:ui seat 4 · session_01SJn1GEkrbbBQkhGC26wEDw · 2026-10-17T14:01Z

    This releases claim 6234793729. Cause: the maintainer told this seat to finish its current work and stop after it merges (「当前任务处理完,合并后就下班」), and this card's dev session had not been started. No branch was pushed and no code was written.

    Destination: pm:queue, assignee cleared. The claim's scoping stays on record for whoever claims it next:

    • route B, per triage 6220534234;
    • the form face reads FormSelectOptionSchema by reference;
    • SelectOptionBase and the field option faces keep kind and default;
    • re-grep producers first.

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 (priority:p3 enhancement, scoped to B by triage 6220534234; re-claimed after seat 4's release 6234814619, whose scoping this claim keeps)
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12736-form-option-boundary
    Worktree: objectui-issue-12736
    Domain: domain:ui (packages/types is this repo's domain:spec stream, whose seat is vacant; triage routes it here)
    Seat: domain:ui#2
    File surface:

    • packages/types/src/form.ts: the SDUI form face SelectOption narrows to the spec's form-view option boundary (FormSelectOptionSchema, @objectstack/spec ui/view.zod.ts), dropping kind and default and keeping its pinned divergences.
    • packages/types/src/zod/form.zod.ts: its zod twin SelectOptionSchema, the same narrowing on the runtime side; a form option carrying kind or default is refused.
    • packages/types/src/__tests__/: objectui#12711's set-difference and convergence pins edited deliberately, each with its reason, plus a pin that the form face's key set equals FormSelectOptionSchema's plus the named divergences.
    • One .changeset/12736-*.md for @object-ui/types, stating the narrowing.
    • ⛔ SelectOptionBase (select-option.ts) and the field and object option faces keep kind and default. No renderer or app-shell change.

    Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate); one CONTRACT_REVIEW_TIER review is owed before the queue
    Clause-②: no
    Clause-② reason: the card only NARROWS a published accept set (@object-ui/types SelectOption and its zod twin refuse kind and default); a narrowing is Clause-②: no, stays in this lane, and owes one CONTRACT_REVIEW_TIER review before the queue. (Amended in place: first posted as yes.)
    Responsibility: n/a — not a defect card (declaration is enforcement: the form face accepts two keys no form reader honours)
    Thread-read: 6234814619
    Serial constraints cleared: PR #12735 (objectui#12711) merged as 2d9c81e; PR #12887 (objectui#12873, next.3) merged as 26323c4. This seat's in-flight objectui#12111 (packages/fields) and objectui#12838 (packages/plugin-kanban, packages/i18n) are disjoint. The dev re-checks for an open PR on these three files and for any FORM-option producer of kind or default, and stops if one exists.
    Claimed at: 2026-10-17T15:07Z

  6. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 12736,
      "status": "done",
      "branch": "claude/issue-12736-form-option-boundary",
      "pr": "https://github.com/objectstack-ai/objectui/pull/12904",
      "session": "session_01XVp19E1MYUTFM3dnkwz8gB (the harness-stamped Claude-Session id; subagent mode, so it is the parent's)",
      "premise_still_valid": true,
      "summary": "Implemented Route B. The SDUI form-option type face SelectOption is now Omit of SelectOptionBase over 'value' plus ObjectFieldOnlyOptionKey, which is Exclude of keyof SpecSelectOption, keyof SpecFormSelectOption (from @objectstack/spec/ui), so the keys are read by reference and never listed. The zod twin SelectOptionSchema now spreads stripImportedDefaults(SpecFormSelectOptionSchema).shape instead of the data SelectOptionSchema. It refuses each key in the same set difference (default, kind) with a named tombstone, invalid_type at the key's path, instead of stripping it; the twin is a strip-mode z.object, so leaving the keys out alone would have been silent. SelectOptionBase and SelectOptionMetadata are unchanged. Premise re-grep found zero form-face producers: no 'kind' option literal anywhere outside the edited pins, and every 'default: true' option literal is on the object-field face. A1 derivation before: both faces read @objectstack/spec/data SelectOption/SelectOptionSchema (SelectOptionBase's Omit; the twin's spread). After: both read FormSelectOption/FormSelectOptionSchema, cited by symbol, not by line, per objectui AGENTS.md #11. Changeset 12736-form-option-boundary.md bumps @object-ui/types as minor: this repo's version policy marks its own breaking changes minor (major is reserved for the @objectstack major sync, enforced by check-changeset-no-major), and the text states the narrowing.",
      "tests": "At head 7298f167ef. pnpm --filter @object-ui/types type-check exit 0 (three legs, including tsconfig.test.json; --listFilesOnly confirms the new and edited test files are in that project). Consumers that import SelectOption: @object-ui/components (renderers/form/form.tsx). Consumers through FormField: @object-ui/plugin-form and @object-ui/fields. type-check exit 0 for all three, after building @object-ui/types and the plugin-form^... closure under the lock. @object-ui/app-shell also imports FormField; its type-check is declared to CI. pnpm exec vitest run --maxWorkers=1 packages/types/: Test Files 387 passed, Tests 10522 passed. The first full run went red on imported-defaults-8317 (new spec crossing unregistered; raw reads); fixed in 7298f167ef. Targeted run of 7 files (the new pin, spec-parity, tier1-convergence, spec-extension, zod-mirror-parity, disabled-twin-symmetry, schema-catalog component-fixture-declared-keys): 241 passed. Ablation via objectstack scripts/ablation-replace.mjs, with a trap restore. Re-adding 'kind: SpecSelectOptionSchema.shape.kind' after the refusals: anchor x1 to x0, blob 7127370930f3 to 7f3cd87dbd00, result '(a) refuses kind by name' x, 1 failed / 6 passed. Restore: blob 7127370930f3 equals the HEAD blob, git diff HEAD empty. vitest reads src, so no dist rebuild was needed. Gates exit 0: check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, control-bytes, new-line-citations; check-hand-rolled-comment-mask.mjs, check-changeset-fixed.mjs, check-changeset-presence.mjs, check-changeset-no-major.mjs. check:spec-floors exit 1 (no-artifact, workspace not fully built): recorded, not fixed. Lint: eslint --no-inline-config --format json over the 7 changed files read 7 files, 0 errors, 11 warnings. All warnings are pre-existing no-explicit-any on untouched lines. eslint.config.js has no parserOptions.project (not type-aware), so the diff cannot move the verdict on an untouched file. Repo-wide pnpm lint is declared to CI.",
      "mcp_calls": "0",
      "api_writes": "5. Three git pushes: the empty-branch probe and two commits. One fleet-write relay dispatch, pr_create, which is two REST writes: POST /repos/objectstack-ai/objectui/pulls (draft) and POST /repos/objectstack-ai/objectui/issues/12904/assignees. One relay dispatch for this os-dev-report comment: POST /repos/objectstack-ai/objectui/issues/12736/comments. No label writes: the order named no labels, and objectui path labels belong to labeler.yml.",
      "open_questions": [],
      "out_of_scope_findings": [],
      "deviations": [
        "The order asks for A1 evidence as file:line. The evidence is cited by symbol instead, because objectui AGENTS.md #11 bans line addresses in issue and PR bodies, and this report is posted to the card.",
        "The ablation vitest run (one file, about 1s) ran outside os-verify-lock; every other build and test ran under it.",
        "Extra files in the test surface: packages/types/src/__tests__/zod-mirror-parity.test.ts (ledger row) and imported-defaults-8317.test.ts (IMPORTED row). Both are inside the declared packages/types/src/__tests__/ surface. They were required by the new refusal tombstones and the new spec crossing.",
        "PR body line 2 is 'Clause-②: no', following the coordinator's mid-task correction, which overrides the order's 'yes'."
      ],
      "files_changed": [
        "packages/types/src/form.ts",
        "packages/types/src/zod/form.zod.ts",
        "packages/types/src/__tests__/select-option-form-view-boundary-12736.test.ts",
        "packages/types/src/__tests__/select-option-spec-parity.test.ts",
        "packages/types/src/__tests__/select-option-tier1-convergence-7014.test.ts",
        "packages/types/src/__tests__/zod-mirror-parity.test.ts",
        "packages/types/src/__tests__/imported-defaults-8317.test.ts",
        ".changeset/12736-form-option-boundary.md"
      ],
      "gates": "type-check types/components/plugin-form/fields 0; vitest packages/types 0; pre-tsc battery 0 except check:spec-floors 1 (no-artifact, recorded); check-changeset-fixed 0; lint narrowed 0 errors"
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — objectui PR #12904 · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-17T15:44Z

    Reviewed on GitHub at head 7298f16, against the card's fork, triage's scoping B (6220534234), seat 4's released scoping (6234814619) and the claim (6235492982, amended in place: Clause-②: no, because a narrowing does not widen an accept set; one contract-tier review is owed before the queue).

    • Shape: the body says Fixes #12736; the second line is Clause-②: no. The changeset is @object-ui/types: minor, marked Breaking (types). This repo levels its own breaking changes at minor (major is reserved for the @objectstack major sync).

    • The change (packages/types):

      • Type face. SelectOption is now Omit<SelectOptionBase, 'value' | ObjectFieldOnlyOptionKey>, where ObjectFieldOnlyOptionKey is the set difference of the spec's data SelectOption and ui FormSelectOption keys. It is derived, never listed, and is default | kind on spec 18.
      • Zod twin. SelectOptionSchema spreads FormSelectOptionSchema instead of the data option. It refuses each key in the same derived set by name (a retirementTombstone, invalid_type at the key's path) rather than leaving it out, because a strip-mode z.object would drop it silently.
      • Untouched. SelectOptionBase and SelectOptionMetadata keep kind and default, as ruled. No renderer or app-shell file changes.
      • Producers. The dev's re-grep found no FORM-option producer of kind or default. Type-check is green for @object-ui/components, @object-ui/plugin-form and @object-ui/fields, which consume the face; @object-ui/app-shell is declared to CI.
    • Pins: select-option-form-view-boundary-12736:

      • (a) the twin refuses kind and default by name, behind an accepting control;
      • (b) the key set equals FormSelectOptionSchema's plus disabled and icon, on the type and runtime sides, and the derived difference is default | kind;
      • (c) @ts-expect-error on both keys in a typed literal;
      • (d) CONTROL: the base, the metadata face and the spec's object-field option still take both.

      objectui#12711's pins in select-option-tier1-convergence-7014 and select-option-spec-parity are edited deliberately, each with its reason beside it. A new assertionFormFaceLostOnlyDefault keeps the excusal from hiding a second loss. zod-mirror-parity gains one MirroredUndeclared row (two refusal keys), and imported-defaults-8317 registers the new FormSelectOptionSchema crossing.

      Ablation: re-adding kind to the twin turns (a) red; the restore was proven by blob hash. packages/types (387 files, 10522 tests) is green; type-check exits 0.

    • Trailers: both commits carry only the model-free pair.

    • Contract review: PASS at this head, CONTRACT_REVIEW_TIER, by an isolated reviewer and adopted by this seat (PR comment 6235882816). No needs:contract-review label is owed: a same-shape PASS is on record at the current head.

    • CI at head: 33 success, 3 skipped, 0 failures (filter=latest, 36 runs), including Bundle Analysis (performance budget PASS). Not governed (path audit); 484 changed lines.

    Next: pr_ready + automerge_enable.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-17T16:01Z

    PR #12904 merged through the merge queue as c999d4c, which is on main; Fixes #12736 closed this card. Verified by content: all 8 of the PR's files on main are blob-identical to the accepted head 7298f16. The merge commit's message names no model.

    What landed:

    • The SDUI form-option face SelectOption and its zod twin SelectOptionSchema stop at the spec's form-view option (FormSelectOptionSchema), read by reference. A form option carrying kind or default is now refused: an excess property on a typed literal, and a named invalid_type refusal at the zod twin.
    • SelectOptionBase and the object-metadata face keep both keys, unchanged.
    • The contract review (CONTRACT_REVIEW_TIER) PASSed at the landed head (PR comment 6235882816).
    • Released as @object-ui/types: minor (Breaking (types), per this repo's own-breaking-is-minor policy).

    This seat now removes pm:dispatched.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestfindingpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions