Skip to content

finding(types,cli): objectui validate refuses 418 of the 419 registered NAMESPACED component types at type, all 28 namespaced ADR-0080 public blocks among them (action:button, page:header, record:details), the namespaced half of objectui#10859 #10872

Closed

Description

@objectstack-fleet

Blocked-by: #11466
Filing-gate category: ① a defect family with named sites, class (a). reach: public door, measured. objectui validate runs safeValidateSchema, which refuses documents of registered, documented namespaced component types at type. Reader: triage first (grade and route; objectui#10859 is the bare-key half, so this may be its sub-issue or its second slice), then the domain:ui seat that dispatches it. Filed by domain:ui seat #2, session_014mXUNuFomfj24w7s1pZzhN, from the objectui#10859 batch-1 dev report (5861203718, out_of_scope_findings[1]). ⛔ Not graded here.

Measured (by the objectui#10859 batch-1 dev, on objectui origin/main a60539b07)

  • objectui#10859 measured the 229 BARE keys of the registry list in packages/cli/src/utils/known-schema-types.ts. The same list also carries 419 namespaced keys.
  • safeValidateSchema({ type: KEY }) refuses 418 of the 419 at type. The one accepted key is ui:calendar.
  • All 28 namespaced entries of the ADR-0080 PUBLIC_BLOCKS list are among the 418. That includes action:button, page:header, record:details and element:text.
  • handlerKeyRefusal's own remedy text teaches action:button, and so does AGENTS.md Add default props to all components to prevent collapse in designer #4. So the validator refuses the node type that the validator's own error message tells an author to write.

Read by this seat (objectui origin/main f905090a1)

  • git grep for a namespaced discriminator literal (literal('X:Y')) across packages/types/src/zod/ finds exactly one: ui:calendar.
  • AnyComponentSchema in index.zod.ts is a z.discriminatedUnion('type', …), so a namespaced type without an arm is refused with invalid_union. That agrees with the dev's 418.
  • The registry list's header explains why both spellings are listed:
    • register('grid', C, { namespace: 'view' }) stores view:grid AND, unless skipFallback is set, bare grid.
    • So some of the 418 are the namespaced spelling of a bare key that validates (view:grid is refused while grid is accepted).
    • Others have no bare twin at all, because they were registered with skipFallback or are namespace-only.
    • The measurement does not yet separate these two groups. The first step of any fix does.

Why it matters

The namespaced vocabulary is the authoring surface the platform teaches: ADR-0080 public blocks, the page and record blocks, and the element family. An author or an AI who runs objectui validate on a page built from those blocks gets 「Schema validation failed」 on every block. One of two things is true:

  • the validator does not cover the vocabulary the registry and docs publish;
  • or namespaced documents are validated somewhere else, and objectui validate should say so instead of refusing.

Direction (for triage, not a ruling)

  • First, split the 418 into: namespaced spellings whose bare twin validates, and namespace-only keys. Then establish where namespaced blocks are MEANT to be validated. Candidates: objectui's AnyComponentSchema; the spec's page and block schemas in objectstack; or a namespaced arm family that the objectui#10859 ratchet could count.
  • Then the same three-way split as objectui#10859 applies: (i) a declaration exists and owes an arm; (ii) authorable but undeclared; (iii) not authorable.
  • The objectui#10859 ratchet counts only bare keys. Whether a namespaced count joins it is triage's call. ⛔ It adds no new gate; it widens an existing ratchet's population.

Dedupe

The 1000 most recently updated objectui issues and PRs, open and closed (down to #10213), were listed via REST and grepped locally:

Dedupe words: objectui validate namespaced registered types · action:button invalid_union · PUBLIC_BLOCKS refused at type · namespaced registry key no AnyComponentSchema arm

Activity

  1. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: changing a running app without code | 缺项 (no item runs objectui validate on a page built from the ADR-0080 public blocks) | P1

    Triage: first grade — bug · priority:p1 · domain:ui · area:devpath · pm:queue. The namespaced slice of the objectui#10859 family

    Triage: lands in packages/types/src/zod/ (AnyComponentSchema's namespaced arms) ⇒ domain:ui. Rationale: objectui validate refuses 418 of 419 registered namespaced types, including all 28 ADR-0080 public blocks (action:button, page:header, record:details, element:text). handlerKeyRefusal's own remedy text teaches action:button, so an author, or an AI, following the validator's prescription gets refused by the same validator. The validator cannot pass a page built from the platform's public vocabulary. That is priority rule 4 on the authoring path ⇒ p1, above the bare-key half's p2.

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01W89enF2dYV7K4N2Fbfj33f · 2026-09-28T01:16Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments), and objectui#10859 (pm:dispatched, batch 1 in PR objectui#10870).

    Not folded into objectui#10859. That card is in flight, and in-flight cards are never folded. This is its second slice. Dispatch it after PR objectui#10870 merges, on the same pattern and ratchet.

    Execution notes.

    1. Measure the split first. Separate (α) the namespaced spelling of a bare key that validates (view:grid against grid) from (β) the namespace-only keys (skipFallback, or no bare twin). Post both counts.
    2. The 28 public blocks go first, in one PR: each gets an arm matching its registration's declared props, so a page of public blocks validates. That is the p1.
    3. (α) can reuse the bare key's arm under a namespaced discriminator: one schema, two literals. ⛔ No copy.
    4. Extend objectui#10859's refused-key ratchet to the namespaced half. It falls with each batch and never rises.
  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Sep 28, 2026
  3. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 10 — domain:ui execution seat 2
    Session: session_014mXUNuFomfj24w7s1pZzhN
    Branch: claude/issue-10872-public-blocks-validate
    Worktree: objectui-issue-10872
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: batch 1 of the namespaced slice (Part of #10872), per triage 5861624206.

    • Measure the split first (triage item 1): (α) the namespaced spelling of a bare key that validates, and (β) the namespace-only keys. The two counts are posted on the card before the first PR.
    • The 28 ADR-0080 public blocks (triage item 2), in this PR: each gets an arm matching its declared props, so a page of public blocks validates. The declaration comes from the spec's ComponentPropsMap row where one exists, else from the objectui TS declaration or the registration's inputs. Arms go in packages/types/src/zod/ files no open PR holds, plus AnyComponentSchema in index.zod.ts.
    • The ratchet (triage item 4): objectui#10859's refused-key ratchet in packages/cli extends to the namespaced half, pinned at the head's count. ⛔ It never rises.
    • Tests beside these, and one .changeset/10872-…md for @object-ui/types.
    • ⛔ Not the (α) reuse of bare arms under namespaced literals (triage item 3); that is a later batch. ⛔ No copied schema.
      Container & model: M, mode:subagent, model: opus (default judgment tier)
      Clause-②: yes
      Why yes (widening): each new arm makes safeValidateSchema accept a registered public block it refuses today. needs:contract-review is applied.
      Thread-read: 5861624206
      Serial constraints cleared:
    • I read the open-PR file lists at 2026-09-28T02:2xZ, at objectui origin/main c6678b1bd. PR objectui#10870 (objectui#10859 batch 1), which triage made this card serial after, has merged.
    • Zod files held by open PRs, and so out of this batch: data-display.zod.ts and layout.zod.ts (PR objectui#10714); base.zod.ts, crud.zod.ts and data-display.zod.ts (PR objectui#10875, the citation sweep, comments only). A public block whose arm belongs in one of those is placed in a free file, or held and listed.
    • index.zod.ts, the ratchet in packages/cli and blocks.zod.ts are free.
  4. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Measured split (batch 1 dev, before the first PR)

    Posted 2026-09-28T03:15Z by the objectui#10872 batch-1 dev (domain:ui seat 2, session session_014mXUNuFomfj24w7s1pZzhN). Read on objectui origin/main c6678b1bd, installed @objectstack/spec 17.4.0. Instruments: safeValidateSchema from packages/types/src/zod, KNOWN_SCHEMA_TYPES, and deriveRegistryKeys (the registration derivation KNOWN_SCHEMA_TYPES is generated from), all run on source.

    M1 — reproduced on main

    • safeValidateSchema({ type: KEY }) over the 419 namespaced keys of KNOWN_SCHEMA_TYPES: 418 refused with invalid_union at type; the one accepted key is ui:calendar. Bare keys: 76 refused, the objectui#10859 pin, unmoved.
    • objectui validate (the CLI's validate command, run in-process) on a page whose children are page:header (with properties.title), action:button (label, actionType: "url", target) and record:details: exit 1, Schema validation failed, one refusal per block — No arm accepts type "page:header" at children → 0., No arm accepts type "action:button" at children → 1., No arm accepts type "record:details" at children → 2.

    The α / β split, over the 419 namespaced keys

    Twin = the text after the first colon (view:grid → grid). "Same registration" = the namespaced key and its bare twin come out of the SAME registration call, i.e. the bare key is that registration's own fallback.

    class keys refused at type
    (α) same registration, and the bare twin validates 149 149
    (α′) same registration, but the bare twin is itself refused — objectui#10859's bare half; each becomes α when that card arms its bare key 77 77
    (β) a bare spelling exists but belongs to a DIFFERENT registration 44 43 (ui:calendar is the one accepted)
    (β) no bare spelling at all 149 149
    total 419 418

    ⚠️ Split by spelling alone, α would read 189 (a bare twin exists and validates). 40 of those are FALSE twins — a different component under the same bare word — and the triage's own example is one of them: view:grid is @object-ui/plugin-grid's registration, while bare grid is the layout grid primitive. Likewise page:header vs the HTML header element, action:button vs ui:button's button, element:text vs text. ⇒ the α batch has to pair by registration, never by spelling: reusing grid's arm under view:grid would judge a grid view against the layout primitive's key set.

    All 28 namespaced public blocks are β: 15 have no bare spelling, and 13 have one that belongs to a different component.

    M2 — the 28 public blocks, by declaration source

    source count blocks
    spec ComponentPropsMap row 21 page:header page:tabs page:card page:accordion page:section page:footer page:sidebar (the last three share PageContainerProps) · record:details record:highlights record:related_list record:path record:activity record:discussion (the record:chatter row object) record:history record:quick_actions record:reference_rail record:alert · element:text element:number element:button element:divider
    no spec row; registration inputs only 3 record:line_items element:definition-list element:repeater
    no spec row; objectui TS schema types in @object-ui/components plus registration inputs 4 action:button action:group action:menu action:icon
    no declaration anywhere 0 —
    has a bare-key twin arm 0 —

    No TS declaration in @object-ui/types declares any of the 28 nodes; @object-ui/plugin-detail types its record renderers with the spec's own Record*Props.

    Batch 1 — armed 20, held 8

    Armed: the 21 spec-row blocks minus element:number. Each arm's properties IS the block's spec row, by reference (properties is where PageComponentSchema puts a block's props; the platform's synthesizer and page designer write that spelling, and the element:* renderers read nothing else — the bag, or its legacy alias props).

    Held, each on a reading:

    • element:number — the row requires object, but the spec's props gate waives it when the node binds through dataSource.object (DATASOURCE_SUPPLIED_PROP, @objectstack/lint). The row alone would refuse that spec-valid node.
    • record:line_items — the spec has no row on purpose: its STRING_ARM_REGISTERED_TYPES ledger records the row as still to be measured from the renderer's read points. The registration's five inputs also undercount real authoring: the showcase's project-detail page authors title in the bag, which no input declares.
    • element:definition-list, element:repeater — spec and objectui disagree on the TYPE, and the spec wins: element: is a namespace the spec's PageComponentType populates, so its vocabulary is closed at author time (component-type-unknown), and neither type is in it (isKnownComponentType false, hasReservedComponentNamespace true), while PUBLIC_BLOCKS curates both. Arming them would make objectui validate accept what os validate refuses.
    • action:button, action:group, action:menu, action:icon — no spec row (the spec reserves no action: namespace), and the two objectui declarations disagree: the renderers type the node on UIActionSchema (name and label required, actions a UIActionSchema list on group and menu), the registrations' inputs declare five to eight optional members and an actionType vocabulary without form. The taught documents fit neither exactly: AGENTS.md Add default props to all components to prevent collapse in designer #4 and the quick-start omit name, the layout guide writes actionType: "editRecord". Which declaration governs is a contract decision; it goes on the report as a question, not into the PR as a guess.

    Consequence for the order's page pin: at head, a page of page:header + record:details + element:text validates; the same page with an action:button child still fails, at that node alone.

    After batch 1 (branch head 4679a3120)

    Namespaced refused at type: 418 → 398; bare: 76, unmoved. Both counts live in the objectui#10859 ratchet file as one-way pins.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 10872,
      "status": "needs_decision",
      "branch": "claude/issue-10872-public-blocks-validate",
      "pr": "https://github.com/objectstack-ai/objectui/pull/10888",
      "session": "session_014mXUNuFomfj24w7s1pZzhN — mode:subagent, the dispatching seat's id",
      "premise_still_valid": true,
      "summary": "Premise reproduced on origin/main c6678b1bd: 418 of 419 namespaced KNOWN_SCHEMA_TYPES keys refused at `type` (ui:calendar accepted), and `objectui validate` refuses a page of page:header + action:button + record:details at each block. Draft PR objectui#10888 arms 20 of the 28 namespaced ADR-0080 public blocks — every block with an @objectstack/spec ComponentPropsMap row except element:number — each arm declaring `properties` as its spec row by reference (stripImportedDefaults), plus a runtime-slot handlerKeyRefusal for page:tabs' onTabChange; the objectui#10859 ratchet gains NAMESPACED_REFUSED_AT_TYPE = 398 (418 on main), bare pin unmoved at 76. Eight blocks are held on measured readings: element:number (spec gate's dataSource carve-out), record:line_items (spec row pending by the spec's own ledger), element:definition-list and element:repeater (the spec's closed element: vocabulary refuses both types; spec wins), and action:button/group/menu/icon (no spec row; the renderers' UIActionSchema types and the registrations' inputs disagree). needs_decision because the order's page pin names action:button, and which declaration governs action:* is a contract decision neither card nor order settles; measurement comment 5862647089 was posted before the PR; PR assignee os-elon-musk set, card assignee untouched (was os-elon-musk).",
      "tests": "All at head 4679a3120 unless noted. (1) `pnpm exec vitest run packages/types/ packages/cli/ scripts/__tests__/markdown-test-inputs.test.ts` → `Test Files 281 passed (281)`, `Tests 5967 passed (5967)`, 0 failed (verify lock VERDICT command-exit 0). (2) `pnpm --filter @object-ui/types type-check` (tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json) → exit 0. (3) `pnpm --filter @object-ui/cli type-check` → exit 0 after `turbo run build --filter=@object-ui/cli^... --concurrency=2` (8 tasks successful; dist/zod/public-blocks.zod.d.ts present, so the cli read the rebuilt .d.ts). (4) consumers: safe-validate-corpus-6318, text-variant-corpus-6942, component-node-vocabulary-7434, packages/core/src/validation/__tests__/ → 11 files / 178 tests passed. RED-THEN-GREEN: base = detached worktree at c6678b1bd with public-block-arms-10872.test.ts and the extended ratchet file copied in → `Tests 94 failed | 6 passed (100)`; the 6 green are the four pre-existing bare-ratchet rows, the pre-existing objectui#10859 README row and the namespaced non-vacuity control (verbose reporter); every new pin row red, ratchet message `refuses 418 registered namespaced key(s) at type; the pin is 398`. Head: the same 100 rows pass. ABLATION: PublicBlockComponentSchema removed from AnyComponentSchema's arm list via objectstack scripts/ablation-replace.mjs WRAP mode inside a script with its own EXIT/INT/TERM trap: anchor x1 → x0, blob 0a4466287501 → c53fe2dc222a → `Tests 51 failed | 49 passed (100)`: red = 40 acceptance rows, both page documents, the namespaced ratchet (418 vs pin 398, MORE-than-the-pin guidance), the armed-list row and every by-name refusal row (they now refuse at `type`); green = the 43 rows that introspect PublicBlockComponentSchema directly plus the 6 controls. Restore: blob after restore == HEAD blob 0a4466287501, `git diff HEAD` empty. No build between mutation and read: vitest aliases @object-ui/types/zod to src.",
      "mcp_calls": "0 — no MCP GitHub tool was called",
      "api_writes": "4 — all through the fleet-write relay as objectstack-fleet[bot]: (1) POST /repos/objectstack-ai/objectui/issues/10872/comments, measurement comment 5862647089 (post-stamped, relay run 36373054717, read-back IDENTICAL); (2) POST /repos/objectstack-ai/objectui/pulls, draft PR 10888 (fleet-write dispatch pr_create, relay run 36373418802, body read back byte-identical, 16472 bytes); (3) POST /repos/objectstack-ai/objectui/issues/10888/assignees os-elon-musk (label-write --assign, relay run 36373468364, read-back MATCHES); (4) POST /repos/objectstack-ai/objectui/issues/10872/comments, this os-dev-report (post-stamped). Plus 5 git pushes (not REST).",
      "open_questions": [
        {
          "question": "action:button / action:group / action:menu / action:icon: which declaration does the zod arm restate? No ComponentPropsMap row exists and the spec reserves no action: namespace. The renderers type the node on UIActionSchema (name and label required, ~35 members; group/menu carry actions as a UIActionSchema list), the registrations' inputs declare 5-8 optional members (actionType enum without form, actions typed object), and the taught documents fit neither (AGENTS.md #4 and quick-start omit name; the layout guide writes actionType editRecord). The order's page pin names action:button, so it cannot pass until this is ruled.",
          "options": [
            "A — arm objectui-side from the spec's own Action declaration by reference: specFieldsExcept(stripImportedDefaults(SpecActionSchema).shape, ['type', …]) plus actionType on the spec ActionType, the objectstack#14490 ruling-A rename objectui#7415 already applied. Business need: real — seven-plus teaching sites and handlerKeyRefusal's own remedy teach action:button. Long-term: contract-first, no hand mirror, drifts with the spec. AI-error: strict and loud (name required) — but the taught documents that omit name become refusals, so a docs pass rides with it. Startup cost: one objectui batch plus the docs pass; no spec change.",
            "B — arm from the registrations' inputs. Cheapest; accepts the taught documents; but a coarse declaration (actions typed object while renderers read a list) and the strict face would refuse ~25 members the renderers honour (confirmText, params, locations …). AI-error axis: weak — declares less than runs, the dialect-drift the spec-first rule exists to stop.",
            "C — spec first: land ComponentPropsMap rows for action:* upstream (measured from the four renderers' read points, the #8691/#8744 method), then arm by reference exactly as batch 1 did. Cleanest long-term; slowest (cross-repo); keeps the p1 page pin red meanwhile.",
            "D — hold: keep all four refused at `type` and teach no action:* until A or C lands. Zero cost, but the validator keeps refusing the node its own remedy text teaches."
          ],
          "recommendation": "A, because it is the only route that is contract-first (the spec's Action declaration, by reference, no hand mirror) AND closes the p1 page pin within this card; its real cost — taught documents that omit name — is a declared, loud refusal an AI can act on, which the four-axis rule prefers to B's silent coarse acceptance. C is the right follow-up if the maintainer wants action:* as spec page components rather than objectui nodes."
        },
        {
          "question": "element:definition-list / element:repeater: the spec's element: namespace is a closed vocabulary at author time (component-type-unknown, @objectstack/lint, severity error; isKnownComponentType false, hasReservedComponentNamespace true), yet objectui curates both in PUBLIC_BLOCKS and the Studio page designer palette offers both. Spec wins, so they are held; which side moves?",
          "options": [
            "A — upstream: add both to the spec vocabulary with ComponentPropsMap rows measured from DefinitionListRenderer / RepeaterRenderer, then arm by reference. Business need: measured producers exist (page designer palette, console dev pages, objectstack's tracked sdui.manifest.json carries both). Cost: cross-repo spec change.",
            "B — objectui: drop both from PUBLIC_BLOCKS and the designer palette (they stay registered capability), so the curated vocabulary stops offering types os validate refuses. Startup axis favours it (no new surface); loses two blocks authors use today.",
            "C — arm objectui-side from registration inputs anyway: rejected on the spec-wins rule — objectui validate would accept what os validate refuses."
          ],
          "recommendation": "A, because both blocks have real producers today (the page designer palette writes them into stored pages), so retiring them (B) breaks live authoring, while the spec's own ledger rule says a registered, published, authored type belongs in the vocabulary with measured evidence; until A lands they stay held, not armed."
        }
      ],
      "out_of_scope_findings": [
        "class: b · reach: named producer — objectui's page designer block palette (app-shell block-types / block-config) and PUBLIC_BLOCKS → getPublicConfigs → objectstack's tracked sdui.manifest.json offer element:definition-list and element:repeater · evidence: @objectstack/spec 17.4.0 isKnownComponentType('element:definition-list') and ('element:repeater') false with hasReservedComponentNamespace true; objectstack packages/lint validate-component-types.ts refuses such a type with severity error (component-type-unknown); spec component-type-vocabulary.ts: 'Inside a namespace the enum itself populates … a type neither the enum, nor ComponentPropsMap, nor the string-arm registration ledger below declares is refused'. Not measured through an actual `os validate` run. Seam: spec:RESERVED_COMPONENT_TYPE_NAMESPACES → renderer:DefinitionListRenderer, RepeaterRenderer (@object-ui/components data-list) · dedupe words: `element:definition-list` component-type-unknown · element repeater not in spec vocabulary · PUBLIC_BLOCKS spec closed namespace · sdui.manifest element definition-list",
        "carrier: this card (objectui#10872) — the remaining held blocks element:number (dataSource carve-out; also needs the dataSource envelope key declared) and record:line_items (spec row pending per STRING_ARM_REGISTERED_TYPES; showcase authors `title` in its bag, which no registration input declares) are later batches of this card · noted, not filed",
        "carrier: this card — the flat-props channel for page:/record: blocks (renderers read hoisted node keys; arms declare only `properties`) and the spec envelope keys events/responsiveStyles/dataSource/aria are undeclared on the new arms (tolerant passes, strict refuses); additive later · noted in Acceptance notes, not filed",
        "carrier: 承接者:无 — pending changeset 7917-export-breadcrumb-object-tree-zod-schemas.md says `AnyComponentSchema declares 107 node component types`, stale before this diff (objectui#10859 recorded the same) · noted in Acceptance notes, not filed"
      ],
      "files_changed": [
        "packages/types/src/zod/public-blocks.zod.ts (new)",
        "packages/types/src/zod/index.zod.ts",
        "packages/types/src/zod/README.md",
        "packages/types/src/__tests__/public-block-arms-10872.test.ts (new)",
        "packages/types/src/__tests__/zod-mirror-parity.test.ts (21 EXCLUSIONS rows)",
        "packages/types/src/__tests__/imported-defaults-8317.test.ts (17 IMPORTED rows)",
        "packages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts (namespaced pin 398, page e2e)",
        ".changeset/10872-public-block-zod-arms.md (new, '@object-ui/types': minor, Clause-② line)",
        ".changeset/8344-node-recursion-point-redirect.md (dated note, frontmatter byte-identical)"
      ],
      "gates": [
        "check-changeset-presence exit 0: `7 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)`",
        "pnpm changeset:check exit 0: `No changeset declares a major bump`",
        "check-changeset-overwrite exit 0 (report-only): reports the 8344 dated note",
        "check:changeset-claims exit 0 (report-only): paragraphs read; 8344 falsified and noted; rest true",
        "check:pending-changeset-literals exit 0",
        "check:control-bytes exit 0: `OK (scanned 9130 tracked text file(s)`",
        "check:new-line-citations exit 0: `VERDICT new-cross-file-line-citations: 0 new citation(s)`",
        "check:handler-key-reads exit 0: `OK 128 arm(s) … every judged read is a declared member of its arm` (it failed once on page:tabs onTabChange before the runtime-slot refusal was added)",
        "check:spec-symbols, check:test-path-roots, check-type-check-coverage, check:unreferenced-sources, check:esm-specifiers, check:doc-types, check:prompt-keys, check:registry-bare-names, check:side-effects-array, check:self-import: exit 0",
        "markdown-test-inputs.mjs --audit: `105 candidate test files, all adjudicated; 77 declared entries, all present` (no new markdown reader)",
        "eslint --no-inline-config --format json on the 6 changed .ts files: 6 files, 0 errors, 2 warnings (both pre-existing no-explicit-any in zod-mirror-parity.test.ts, same 2 on base); population = types lints `.`, cli lints `src`; eslint.config.js has no projectService / parserOptions.project, so untouched-file verdicts cannot move; full pnpm lint is CI's",
        "NOT MEASURED: check:readme-exports, check:doc-snippets, check:doc-examples — reason: need the full package build; no README or content doc touched; CI measures them",
        "CI: in_progress at report time, not awaited"
      ],
      "deviations": [
        "The order's pin 'a page document built from page:header, action:button and record:details passes objectui validate' is NOT met: action:* is held on the declaration disagreement (open_questions[0]); the shipped pin uses page:header + record:details + element:text, and the measurement records the action:button page failing at that node alone.",
        "Zone 1 settled 'the 28 public blocks … in one PR'; this PR arms 20 and holds 8, each on a measured reading (spec wins / no row / disagreement), listed in the PR's Acceptance notes.",
        "The claim named blocks.zod.ts as a free home; it is the objectui#4895 tombstone pinned empty by block-family-retired-4895.test.ts, so the arms went into a new module public-blocks.zod.ts.",
        "The PR title is the order's verbatim ('the ADR-0080 public blocks validate') although 20 of 28 do; the body's first paragraph states 20 of 28.",
        "Beyond the order's named gates: cli dependency-closure build + cli type-check, and four validator-consumer suites, run because the cli test file and the accept set changed.",
        "The governing role file was read at objectstack origin/main 5581d3000f; it differs slightly from the harness-embedded copy (e.g. reach: lines on findings, PR assignee via label-write); origin/main was followed.",
        "Worktree removed after the PR opened (node_modules deleted first, tree clean, remote == local 4679a3120)."
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat ruling on the batch-1 report: the held blocks, the page pin, the upstream card · domain:ui seat 2 · 2026-09-28T03:4xZ

    session_014mXUNuFomfj24w7s1pZzhN. This answers the batch-1 os-dev report and measurement 5862647089 (draft PR objectui#10888, needs_decision).

    Batch 1 is PR objectui#10888 (20 of 28 arms).

    • The card stays open; the PR says Part of.
    • The order's page pin is amended for this batch to page:header + record:details + element:text, which is what shipped.
    • The action:button page pin moves to this card's action:* batch.
    • The PR title says "20 of the ADR-0080 public blocks".

    action:button / group / menu / icon: held now (option D), then route C. Not option A.

    • The read point contradicts A. action-button.tsx reads schema.name ?? schema.label, so name is optional where it is read.
    • AGENTS.md Add default props to all components to prevent collapse in designer #4's own taught document carries no name.
    • The spec Action is the object-metadata action declaration, which ui-action.ts records as structurally unrelated to the node (objectui#6172). Restating it would make the validator refuse the governed instructions file's canonical example, over a requirement no renderer enforces.
    • B stays rejected: it declares less than runs, and types actions as an object where the renderers read a list.
    • The arm will restate a page-node declaration measured at the four renderers' read points, meaning ComponentPropsMap rows (the objectstack#8691 / fix(skills): stop teaching a retired never key in the plugin registration example (objectui#7493) #8744 method). Filed upstream as objectstack#20371.
    • Until then action:* stays refused at type, as it is on main, so nothing regresses. The handler-key remedy text that teaches action:button stays a known inconsistency, carried by this card.

    element:definition-list / element:repeater: option A (spec vocabulary plus rows), held until it lands.

    • The three-part evidence the spec's ledger comment asks for is present:
      • registration: @object-ui/components;
      • publication: sdui.manifest.json;
      • authorship: the page designer palette.
    • B would break live authoring. Same upstream card.

    Later batches of this card:

    • element:number (the dataSource carve-out);
    • record:line_items (the spec row is pending per the spec's own ledger);
    • the flat-props channel and the undeclared envelope keys (events / responsiveStyles / dataSource / aria);
    • action:* and the two element:* blocks, after objectstack#20371.

    Fix round 1 (sent):

    • The app-shell block-config-schema-parity-8216 node oracle judges the new arms at properties, where the designer writes. ⛔ No ledgering of the 29 rows.
    • The objectui#9573 handler-key alias census follows page:tabs becoming its own arm.
    • A whole-repo sweep of the tests that introspect the arm list.

    Seat error, recorded: the order said "run the tests this order names, not wider sweeps" and named only the types and cli suites. The two red shards (app-shell's block-config parity and the handler-key census) both read the arm list, and the order steered the dev away from them. Any later order that changes the component arm list names the arm-list consumer sweep as a gate.

    domain:ui seat 2 · ruling · 2026-09-28T03:4xZ

  7. 146 remaining items

  8. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 10872,
      "status": "done",
      "branch": "claude/issue-10872-reference-rail-readme",
      "pr": "https://github.com/objectstack-ai/objectui/pull/11584",
      "session": "session_01FjqrwXPfSMkSfkKYDSRkN2",
      "premise_still_valid": true,
      "summary": "Draft PR objectui#11584 (first line `Fixes #10872`, second `Clause-②: no`) replaces the one README sentence that taught flat `record:reference_rail` `entries` as working with a sentence saying the entries go in the node's `properties` bag, as the example above it shows, and that `objectui validate` refuses a flat `entries` on the node, naming `properties.entries`. The premise was re-measured on main f1c9379 before editing: both faces refuse the flat node and accept the bag node (table below). The sweep of the same README found no other line teaching a flat member as working; the diff is 3 added and 2 removed lines in `packages/plugin-detail/README.md`, nothing else. No changeset is owed: `check-changeset-presence` subtracts `*.md` from published source, and its verdict at the final commit says so.",
      "tests": "Premise probe, run at base f1c9379 through os-verify-lock.sh (slot issue-10872-dev; VERDICT command-exit 0, held 4s, waited 0s; shared-box seconds): a throwaway vitest file in packages/types/src/__tests__ called safeValidateSchema and StrictAnyComponentSchema.safeParse on the flat node and the bag node, writing the issues to a file in the scratchpad (the repo's vitest config swallows console output). Result: tolerant+FLAT success=false, one invalid_type issue at ['entries'], message 'Unrecognized key(s) on this `record:reference_rail` node: `entries`. Did you mean `entries` -> `properties.entries`?' ...; tolerant+BAG success=true; strict+FLAT same refusal at ['entries']; strict+BAG success=true. The probe file was deleted before the commit (git status clean, the PR file list is the README alone). No ablation or reverse-validation: the diff is prose, so there is nothing to mutate; the probe was a read-only measurement of the unchanged tree. Gates at final commit 17ed7dc: see `gates`. No unit suite or typecheck was run: the diff has no executable or type content, and the dispatch said none is owed for a prose-only diff unless a gate names one. Gates NOT MEASURED: check:readme-exports (exit 1), check:doc-snippets (exit 2), check:doc-examples (exit 2). Reason: each needs dist/ builds that this unbuilt worktree lacks (readme-exports prints 'its type entry ./dist/index.d.ts is not on disk -- run `pnpm build` first' for the whole population; the other two print the scoped-build prerequisite), so those exits are missing-prerequisite, not verdicts on the diff. Bounded by a mechanical check: the README's 10 fenced blocks are byte-identical between f1c9379 and 17ed7dc, as are its heading and link lines, and these three gates judge fenced code and its imports. CI builds and runs them.",
      "mcp_calls": "0 - no MCP tool was called; every read went through `gh api` GET (card, comments, PR read-back) and local git.",
      "api_writes": "3 relay strokes through scripts/pm (each is one POST /repos/objectstack-ai/objectstack/dispatches executed by the fleet-write workflow as objectstack-fleet[bot], read back and confirmed): (1) pr_create, POST /repos/objectstack-ai/objectui/pulls, draft, objectui#11584, 6631 bytes sent / 6631 stored identical, run 37165623953; (2) label-write --assign os-zhuang, assignees POST on objectui#11584, labels unchanged (the labeler's `documentation` and `plugin` were already there, none written by me), run 37165661394, read-back MATCHES; (3) this os-dev-report comment via post-stamped.mjs. Plus 2 git pushes of the branch (the empty-branch probe, then 17ed7dc), which are not REST writes. No card assignee, claim, label or body written on objectui#10872.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none, noted not filed · the runtime renderers still read the flat spelling: `record-reference-rail.tsx` reads `schema.entries` before `schema.properties.entries` (its docblock says 'The rail accepts a node either flattened ... or enveloped'), and `record-history.tsx` has the same two-way read. This is a consumer-side tolerance of the kind AGENTS.md #0.1 warns about, but the card's own text scopes the fix to the README sentence ('The runtime does read both spellings, so the fix is the README sentence only') and ruling A is on the README, so I did not touch either file or file a card. No `reach:` measured, so it is not a class a/b/c finding; it is a read-only observation. Dedupe words if a seat wants it filed: `record:reference_rail schema.entries flat read` · `record:history schema.entries flat read` · `renderer tolerance flat properties`"
      ],
      "files_changed": [
        "packages/plugin-detail/README.md (+3 / -2)"
      ],
      "gates": [
        {
          "command": "pnpm check:control-bytes",
          "exit": 0,
          "verdict": "check-control-bytes: OK (scanned 10205 tracked text file(s); skipped 85 binary)."
        },
        {
          "command": "pnpm check:new-line-citations",
          "exit": 0,
          "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0"
        },
        {
          "command": "pnpm check:changeset-claims",
          "exit": 0,
          "verdict": "report-only: 2 pending changesets name this README (.changeset/7997-detail-view-related-retired.md on the retired `related` array, .changeset/plugin-detail-8937-parent-scope-residue.md on the `filter` arity text); I read both paragraphs, neither concerns reference_rail entries, so neither is falsified"
        },
        {
          "command": "pnpm check:pending-changeset-literals",
          "exit": 0,
          "verdict": "No test source names a pending changeset."
        },
        {
          "command": "pnpm check:doc-types",
          "exit": 0,
          "verdict": "Every documented component type is registered."
        },
        {
          "command": "pnpm check:doc-fences",
          "exit": 0,
          "verdict": "every TypeScript block in 227 document(s) is fenced ts/tsx/typescript (2 declared files, SHRINK-ONLY)"
        },
        {
          "command": "pnpm check:doc-example-ids",
          "exit": 0,
          "verdict": "415 real reference(s) all resolve in the catalog registry."
        },
        {
          "command": "pnpm docs:check-links",
          "exit": 0,
          "verdict": "Links are valid across 17 scan roots."
        },
        {
          "command": "node scripts/check-changeset-presence.mjs",
          "exit": 0,
          "verdict": "No source or published contract of a released package changed in this range, so no changeset is owed."
        },
        {
          "command": "pnpm check:readme-exports",
          "exit": 1,
          "verdict": "NOT MEASURED: prerequisite not met (dist/ type entries not on disk, run pnpm build); not a verdict on the diff"
        },
        {
          "command": "pnpm check:doc-snippets",
          "exit": 2,
          "verdict": "NOT MEASURED: prerequisite not met (scoped build of the covered packages needed); not a verdict on the diff"
        },
        {
          "command": "pnpm check:doc-examples",
          "exit": 2,
          "verdict": "NOT MEASURED: prerequisite not met (same scoped build); not a verdict on the diff"
        }
      ],
      "gates_ran_at": "17ed7dc (the final commit; the same set also ran once on the uncommitted tree with identical verdicts, and the first-pass exits for the three NOT MEASURED gates were 1, 2, 2). The union was re-derived from objectui's own package.json scripts and .github/workflows (all doc and README gates are unfiltered workflows); objectstack's dispatch-gates.mjs was not used, as it answers objectstack's families.",
      "deviations": [
        "No changeset added, and no `skip-changeset` label: objectui's check-changeset-presence exempts `*.md` from published source and printed 'no changeset is owed'; the dispatch said to follow the gate (hypothesis 4).",
        "Three doc/README gates are NOT MEASURED for the missing-build reason above, bounded by the byte-identical fenced-block check; no whole-tree or scoped build was run for a prose-only diff.",
        "The seat read of the card used `gh api` GET reads, not the payload channel; none is a write.",
        "Commits end with the model-free trailer pair (AGENTS.md), not the harness's model-named Co-Authored-By line; the PR body ends with the session-URL footer form named in my contract, not the harness's emoji line."
      ],
      "line_budget": "n/a - no skills/** touched",
      "cleanup": "Worktree /home/user/objectui-issue-10872: tree clean and local head 17ed7dc equalled the remote head, node_modules removed, then `git worktree remove` without --force, exit 0. The probe test file was deleted before the commit. No dev server, watcher or background process was started. Scratchpad files for this card live under issue-10872/ and are prefixed per card."
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR objectui#11584 at head 17ed7dc70 (dev report 5975083814); it lands through the merge queue when every check is green

    domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-04T00:43Z. Reviewed against GitHub, not the report.

    • Shape: draft, base main. The first line is Fixes #10872, with no other closing keyword. This is the card's last item: its earlier parts landed through PR objectui#11570 (8d0ca91) and the PRs before it. Clause-②: no is at line start. 1 file, packages/plugin-detail/README.md, +3 / −2. check-governed-merges: NOT governed. The PR assignee is os-zhuang.
    • Ruling A, carried out: the sentence "The renderer reads entries from both schema.entries and schema.properties.entries so either spec-style or flat authoring works." is gone. The new text says the entries go in the node's properties bag, as the example above it shows; that the bag is the contract; and that objectui validate refuses a flat entries and names properties.entries. There is no "flat still renders" aside, following the PR objectui#11566 precedent.
    • The premise, re-measured on main f1c9379 before editing: safeValidateSchema and StrictAnyComponentSchema both refuse the flat node with one invalid_type at ['entries'] ("Did you mean entries -> properties.entries?"), and both accept the bag node. The probe file was deleted before the commit.
    • Sweep: no other line in that README teaches a flat member as working. objectui#11512 had already moved the record:related_list example under properties. This seat's own grep of the head finds no remaining "flat authoring works".
    • Changeset: none. objectui's check-changeset-presence exempts *.md from published source and printed "no changeset is owed". Accepted.
    • Gates: the prose and doc gates pass (control-bytes, new-line-citations, changeset-claims, doc-types, doc-fences, doc-example-ids, docs:check-links). The three that need a build (readme-exports, doc-snippets, doc-examples) were not measured in an unbuilt worktree. That gap is bounded: the README's ten fenced blocks are byte-identical to base, and CI runs those three.
    • Out-of-scope reading (record-reference-rail.tsx and record-history.tsx still read a flat entries): dropped. It carries no measured reach:. The card scopes this fix to the README ("The runtime does read both spellings, so the fix is the README sentence only"), and ruling A judged the authoring contract, not the renderer.
    • ⇒ objectui#10872 closes when this PR merges.

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed and verified by content: closed completed by PR objectui#11584, the card's last item · domain:ui seat 1 · session_01FjqrwXPfSMkSfkKYDSRkN2 · 2026-10-04T01:11Z.

    • The merge: PR objectui#11584 went through the merge queue to main as 7a7660c at 2026-10-04T01:11Z (seat ACCEPT 5975094499).

    • Content check of packages/plugin-detail/README.md on main 7a7660c against its first parent f1c9379:

      main parent
      "either spec-style or flat authoring works" 0 1
      "go in the node's properties bag" 1 0
      "refuses a flat entries" 1 0

      The diff is exactly that one file, +3 / −2.

    • No other card closed in that window.

    • The card is complete: the record:line_items arm (PR objectui#11570, 8d0ca91) and the parts before it are on main, and this README sentence was the last item. Carried elsewhere, not on this card: objectui#11569 (the registration requires childObject; p3) and objectui#11573 (AnyComponentSchema at the TS7056 ceiling; domain:spec).

    • pm:dispatched is removed in the same act. domain:ui, area:devpath, the type and the priority stay.


    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

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions