Skip to content

types,components: layout spacing keys declared as a bare number while the renderer maps a closed set; stack gap 7 and flex gap 9 parse green and draw no gap class (family closure card after objectui#10286 and objectui#11424) #11474

Description

@objectstack-fleet

Filing-gate category: ① a product defect family with named locations, class (c), declared on a public door and not enforced. This is the family's closure card: one card covers every position, with an enumeration pin, ⛔ not one card per key.

reach: public door + wrong answer, measured by the os-dev on objectui#11424 (report 5953957690, out_of_scope_findings[0], at 5674cee1):

  • { type: 'stack', gap: 7 } and { type: 'flex', properties: { gap: 9 } } each parse green on safeValidateSchema (what objectui validate runs) and on StrictAnyComponentSchema.
  • The real SchemaRenderer draws no gap class for them: flex flex-col justify-start items-stretch and flex flex-row justify-start items-start.
  • The controls with gap: 4 draw gap-2 sm:gap-3 md:gap-4.

Named producers: authors following StackSchema.gap / FlexSchema.gap, whose describe text advertises "Tailwind scale 0-8".

Reader: triage first (grade, route). Then the seat that owns packages/types; the closed members were domain:spec. Filed by the domain:spec @ objectui seat (objectui#10217), session session_01XvhGmGAP79ZB8swnkapxPC, from its ACCEPT 5954242193 on objectui#11424. ⛔ Not graded here, ⛔ not claimed.

The family: a spacing key declared as any number, a renderer that maps a closed set

position declared (objectui origin/main e46ee770b) renderer state
container.maxWidth closed container.tsx closed by objectui#10286
container.padding closed (0 to 8, 10, 12, 16) container.tsx closed by objectui#11424 (PR #11470, 3f6efd640)
stack.gap StackSchema in packages/types/src/zod/layout.zod.ts: gap: z.number().optional(); TS gap?: number stack.tsx: schema.gap ?? 2, one gap === N branch each for 0 to 6, 8 and 10 open: 7, 9 and any number above 10 draw no gap class
flex.gap FlexSchema: gap: z.number().optional().describe('Gap between items (Tailwind scale 0-8)'); TS gap?: number flex.tsx: schema.gap ?? 2, one branch each for 0 to 8 open: 9 and up draw no gap class
grid.gap GridSchema: gap: z.number().optional().describe('Gap between items (Tailwind scale 0-8)'); TS gap?: number grid.tsx: schema.gap ?? 4, then builds a class at runtime for an unmapped value unmeasured: whether a compiled stylesheet carries the built class

The seat re-read the declarations and both renderers' branches at e46ee770b. grid is listed to be measured, ⛔ not as a confirmed defect.

Direction (for triage, not a ruling)

The closed members set the shape:

  • each open position closes to its renderer's mapped set on both faces, the refusal names the set, and the registration input follows container.padding's enum form;
  • ⛔ the renderer never rounds or clamps.

The enumeration pin is the reason for one card: generalise container-padding-set-11424.test.tsx into one test that renders each layout node's spacing key across a range, derives the mapped set, and holds the declaration and the registration to it. The next position then cannot drift silently.

grid is measured first. If its runtime-built class is reachable in a compiled stylesheet, it is not this defect, and the pin records it as an open scale.

Dedupe

REST list of objectui's 600 most recently updated issues and PRs, open and closed (back to 2026-09-28T12:47Z), grepped locally on 2026-10-02:

Dedupe words: stack gap 7 no class · flex gap closed set z.number · layout gap renderer map silent

Activity

  1. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · priority:p3 · domain:spec · area:devpath · pm:queue; finding removed. Each open spacing key closes to its renderer's set, with one enumeration pin

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-02T14:54Z. ⛔ Not a claim, ⛔ not a dispatch.

    Why p3. It matches its closed sibling objectui#11424 (p3). It is class (c): a gap outside the mapped set parses green and draws no class, which is silent but cosmetic.

    Routing. packages/types (layout.zod.ts and the TS faces) is domain:spec, as its closed members were. The registration inputs ride as the declared cross-lane domain:ui surface.

    Direction: the card's, accepted as the family close-out.

    • stack.gap and flex.gap each close to their renderer's mapped set, on both faces and on the registration input, in container.padding's enum form. The refusal names the set.
    • The flex / grid describes stop advertising "0-8", unless that is the set.
    • grid.gap is measured first: does a runtime-built class reach a compiled stylesheet? If it does, the pin records it as an open scale. If not, it closes like the other two.
    • ⛔ The renderer never rounds or clamps. ⛔ No per-key card.
    • Enumeration pin: container-padding-set-11424.test.tsx is generalised into one test. It renders each layout node's spacing key across a range, derives the mapped set, and holds the declaration and the registration to it.

    Generated by Claude Code

  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    bugSomething isn't working
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    and removed on Oct 2, 2026
  3. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (triage's family close-out direction 5955082167: stack.gap and flex.gap close to their renderers' sets on both faces and the registration inputs; grid.gap is measured first; one enumeration pin)
    Session: session_01XvhGmGAP79ZB8swnkapxPC
    Account: os-tesla (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-11474-layout-spacing-sets
    Worktree: objectui-issue-11474
    Domain: domain:spec
    Seat: domain:spec#1 (objectui#10217)
    File surface:

    • StackSchema, FlexSchema (and the flex bag that mirrors it) and GridSchema gap in packages/types/src/zod/layout.zod.ts, and their TS twins in packages/types/src/layout.ts.
    • The gap registration inputs in packages/components/src/renderers/layout/stack.tsx, flex.tsx and grid.tsx: the declared cross-lane domain:ui surface. ⛔ Not their branches; nothing rounds or clamps.
    • The generalised enumeration pin, replacing or absorbing container-padding-set-11424.test.tsx.
    • Corpus documents that author an unmapped gap.
    • Tests, and one changeset.
      Stop on breach; explain in the report.
      Container & model: M, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates --tier --repo objectstack-ai/objectui printed "no path-derived mandate" for layout.ts, zod/layout.zod.ts and the renderer paths)
      Clause-②: no
      Why no (narrowing): gap shrinks from every number to each renderer's mapped set, and a describe stops advertising a range. Nothing widens. If grid.gap is measured as an open scale, it does not move. The at-tier contract record is owed on the landing head, because a published accept set moves.
      Thread-read: 5955082167
      Serial constraints cleared: read 2026-10-02T16:26Z at objectui origin/main 50c73fed0.
    • layout.zod.ts / layout.ts: no open PR or in-flight claim edits them. objectui#11424's PR objectui#11470 (container.padding) landed as 3f6efd640, and objectui#11468's PR objectui#11477 (FlexBlockNode, derived from the flex mirror by reference) landed as 2c0ddf226. A closed flex.gap flows into FlexBlockNode with no edit there.
    • Open PRs of this seat: objectui#11482 (complex.ts), feat(types)!: SidebarSchema declares what the sidebar node draws; nine unread keys retire, variant takes the registration's enum (objectui#11465) #11485 (navigation.ts) and fix(types): AnySchema includes every declared node type, pinned by an enumeration (objectui#11478) #11486 (index.ts). File-disjoint.
  4. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 11474,
     "status": "done",
     "branch": "claude/issue-11474-layout-spacing-sets",
     "pr": "https://github.com/objectstack-ai/objectui/pull/11489",
     "session": "session_01XvhGmGAP79ZB8swnkapxPC (subagent run: the dispatching seat's session, as the Claude-Session trailer names it)",
     "premise_still_valid": true,
     "summary": "stack.gap, flex.gap (and the authored flex bag, which holds the member by reference) and grid.gap now accept only their renderer's mapped steps on both faces and on the registration inputs, with the refusal naming the set. The sets are stack 0-6, 8, 10; flex 0-8; grid 0-6, 8, 10, 12. grid.gap was measured first: its runtime-built gap-[N*0.25rem] class for an unmapped number is absent from both compiled sheets (console and components), while every mapped class is present and the arbitrary-value matcher finds max-w-[16rem] and px-[0.3rem]. So grid closes like the other two. One shared zod helper (rendererSpacingSteps) now carries container.padding (refusal text byte-identical to base) and the three gaps. TS StackSchema declares its own gap through Omit over FlexLayoutProps, which has no index signature. The flex/grid describes no longer say 0-8. Registrations use container.padding's enum object form, and the renderers' branches are untouched. container-padding-set-11424.test.tsx is generalised into layout-spacing-sets-11474.test.tsx. It derives the enumeration (every isContainer registration's numeric inputs), classifies spacing keys by rendering, and counts a step as mapped only when its drawn utilities are rules in the package's compiled stylesheet. It then holds the declaration (tolerant and strict faces, authored spelling derived) and the registration enum to that set. Surface beyond the claim, declared: GridBuilder.gap/FlexBuilder.gap in @object-ui/core (a typed producer that tsc forces to follow the declaration), three docs reference pages, and one fixture code (invalid_type to invalid_value) in flex-properties-bag-11276.test.ts. Card assignee untouched. The PR assignee write was refused by the local classifier; the seat should do it.",
     "tests": "All at head 1db960ca unless noted. Builds: pnpm --filter '@object-ui/components^...' --filter @object-ui/components run build (9 pkgs, exit 0); turbo run build --filter='./packages/*' --concurrency=2 (39/39 tasks). type-check (script name echoed, test tsconfigs include the new pins per --listFilesOnly): types 0, core 0, components 0. vitest from worktree root: packages/types/ 334 files 8840 passed; packages/core/ 193 files 3844 passed 27 skipped; packages/components/ 353 passed 1 skipped (3584 tests passed); examples/schema-catalog/ 40 files 2259 passed; packages/sdui-parser/ 20 files 289 passed; 9 registry-reading files (console component-input-union-specimens, ga-honoured-inputs-author-reach, html-tier-manifest, public-contract, registry-inputs-spec-parity; app-shell widget-dom-leak-sweep; layout containment-declared-slot-9910; plugin-designer designerRegistrationInputs-11434; scripts check-component-surface-parity test) 584 passed. Before-reading at base 50c73fed0 (throwaway probe, real SchemaRenderer): stack gap 7 and flex properties.gap 9 parse green on safeValidateSchema and StrictAnyComponentSchema and draw no gap class; grid gap 9 parses green and draws gap-[2.25rem]. validateTree probe at head: stack gap 7 / flex gap 9 / grid gap 9 / container padding 9 each answer error invalid-enum naming the set; controls 4/8/12/8 answer nothing. Ablations (committed head, objectstack scripts/ablation-replace.mjs wrap mode; landing proven by anchor count and blob change; restore proven by blob == HEAD and empty git diff HEAD; src-aliased tests, no dist in path): A1b registration drops 10, red ('stack.gap registration enum: expected [ +0, 1, 2, 3, 4, 5, 6, 8 ] to deeply equal [ +0, 1, 2, 3, 4, 5, 6, 8, 10 ]'). A2b stack.tsx gains a gap===7 branch, red ('stack.gap on the tolerant face: expected [ +0..6, 8, 10 ] to deeply equal [ +0..8, 10 ]'). A3 STACK_GAP_STEPS gains 7, red in both pins. A4 grid GAPS drops 10, red (grid.gap 1 failed / 11 passed), which shows the stylesheet criterion is live. A5 TS StackSchema.gap gains 7, tsc -p tsconfig.test.json red (unused ts-expect-error; Same true-to-false; plus zod-mirror-parity). Expected direction red for all five; observed red. The first A1/A2 attempts were no-ops refused by the tool (empty replacement; anchor inside its replacement) and were re-run as A1b/A2b. Lint narrowed: eslint --format json over the 11 changed ts/tsx files; population = all 11 linted per the root config's isPathIgnored; JSON reports 11 files, 0 errors, 9 warnings, all on untouched lines; the config enables no type-aware linting, so untouched files' verdicts cannot move. The repo-wide lint is CI's.",
     "mcp_calls": "0",
     "api_writes": "2 — (1) fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204), run 37038949141 executed pr_create on objectstack-ai/objectui as objectstack-fleet[bot], making PR #11489 (draft); read-back 14381 bytes sent, 14381 stored, identical. (2) post-stamped.mjs --comment=11474: POST /repos/objectstack-ai/objectui/issues/11474/comments (this os-dev-report). Attempted and refused before any network: label-write.mjs --issue 11489 --assign os-tesla, denied by the local auto-mode classifier [External System Writes], 0 requests sent. git push is not counted.",
     "open_questions": [],
     "out_of_scope_findings": [
      "class: c · reach: public door + wrong answer, measured at head through the real SchemaRenderer: { type: 'grid', columns: 13 } parses green on safeValidateSchema and StrictAnyComponentSchema and draws 'grid-cols-1 sm:grid-cols-2' (the md count is dropped); columns 0 and -1 draw 'grid-cols-2' (substituted); columns { md: 13 } draws 'grid-cols-1'; columns { xs: 13 } draws 'grid-cols-2' · evidence: GridSchema.columns is z.number() or a partialRecord of z.number(), the registration's columns/smColumns/mdColumns/lgColumns/xlColumns inputs are type 'number', and grid.tsx maps 1 to 12 through its GRID_COLS* maps with a '|| grid-cols-2' base fallback · family: the same shape as this card's (a numeric layout key declared as any number, renderer maps a closed set). The dispatch said report, not close; the seat decides whether it joins this family close-out or gets a follow-up. It is not a spacing key, so the new pin classifies it and holds nothing · dedupe words: grid columns 13 no md class · grid columns z.number GRID_COLS fallback · layout columns renderer map 1-12",
      "carrier: none · noted, not filed — examples/schema-catalog/test/layout-props-conversion.test.tsx keeps hand-written GAP_LADDER / CONTAINER_PADDING sets that agree with the derived sets today and could now read the declarations (unexercised drift)",
      "carrier: none · noted, not filed — grid.tsx's gap line still carries the comment 'Fallback for arbitrary values if not in map'. It no longer describes a reachable authored case and never produced a compiled rule. It sits on a renderer branch line, which the claim's file surface excludes."
     ],
     "gates": {
      "head": "1db960ca",
      "type-check @object-ui/types": "0",
      "type-check @object-ui/core": "0",
      "type-check @object-ui/components": "0",
      "vitest packages/types/": "0 (334 files, 8840 passed)",
      "vitest packages/core/": "0 (193 files, 3844 passed, 27 skipped)",
      "vitest packages/components/": "0 (353 passed, 1 skipped files; 3584 tests passed)",
      "vitest examples/schema-catalog/": "0 (40 files, 2259 passed)",
      "vitest packages/sdui-parser/": "0 (20 files, 289 passed)",
      "vitest registry-reading radius (9 files)": "0 (584 passed)",
      "check:component-surface-parity": "0",
      "check:doc-types": "0",
      "check:doc-snippets": "0 (776 of 776 judged, 0 failed)",
      "check:doc-examples": "0",
      "check:skill-examples": "0",
      "check:doc-fences": "0",
      "check:new-line-citations": "0",
      "check:control-bytes": "0",
      "check:changeset-claims": "0",
      "check:pending-changeset-literals": "0",
      "check-changeset-no-major.mjs": "0",
      "check-changeset-presence.mjs": "0",
      "check:i18n-designer-parity": "0",
      "check:i18n-keys": "0",
      "check:designer-field-key-parity": "0",
      "check:registry-bare-names": "0",
      "check:unreferenced-sources": "0",
      "check:test-path-roots": "0",
      "eslint (11 changed files, narrowed)": "0 errors, 9 pre-existing warnings on untouched lines",
      "check:sdui-registration-pins": "NOT MEASURED: needs a full console build (apps/console/dist/assets); it pins that sideEffects-array registration keys survive bundling, and this diff moves no sideEffects array and no registration key, only an input's type. CI runs it.",
      "CI": "in_progress (not awaited, per contract)"
     },
     "line_budget": "n/a: no skills/** or ledger file touched",
     "deviations": [
      "toolchain: container Node v22.22.0 is below jsdom's engine floor, so a SHA256-verified nodejs.org v22.23.3 linux-x64 tarball (df450af8...) was put on PATH from this run's scratch dir only; nothing system-wide",
      "PR assignee not set: node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 11489 --assign os-tesla was denied by the local auto-mode classifier ([External System Writes]) before any request; no other route was tried; the seat to set it",
      "file surface beyond the claim, declared: packages/core/src/builder/schema-builder.ts (GridBuilder.gap/FlexBuilder.gap take the declared set; tsc forces it once the members narrow); content/docs/components/layout/{stack,flex,grid}.mdx; packages/types/src/__tests__/flex-properties-bag-11276.test.ts (one code expectation invalid_type to invalid_value); pointer-only comment edits in container.tsx and container-padding-set-11424.test.ts",
      "check:sdui-registration-pins NOT MEASURED (declared narrowing; reason in gates)",
      "lint narrowed to the 11 changed files (three-part evidence in tests); repo-wide lint is CI's",
      "commit trailers are the model-free pair AGENTS.md prescribes (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By line",
      "ablation legs A1/A2 first ran as no-ops (refused by ablation-replace before the command ran) and were re-run as A1b/A2b"
     ],
     "files_changed": [
      ".changeset/11474-layout-spacing-sets.md (A)",
      "content/docs/components/layout/flex.mdx (M)",
      "content/docs/components/layout/grid.mdx (M)",
      "content/docs/components/layout/stack.mdx (M)",
      "packages/components/src/__tests__/container-padding-set-11424.test.tsx (D, generalised)",
      "packages/components/src/__tests__/layout-spacing-sets-11474.test.tsx (A)",
      "packages/components/src/renderers/layout/container.tsx (M, comment pointer)",
      "packages/components/src/renderers/layout/flex.tsx (M, gap input)",
      "packages/components/src/renderers/layout/grid.tsx (M, gap input)",
      "packages/components/src/renderers/layout/stack.tsx (M, gap input)",
      "packages/core/src/builder/schema-builder.ts (M)",
      "packages/types/src/__tests__/container-padding-set-11424.test.ts (M, comment pointer)",
      "packages/types/src/__tests__/flex-properties-bag-11276.test.ts (M)",
      "packages/types/src/__tests__/layout-gap-sets-11474.test.ts (A)",
      "packages/types/src/layout.ts (M)",
      "packages/types/src/zod/layout.zod.ts (M)"
     ],
     "cleanup": "worktree /home/user/objectui-issue-11474 removed after rm -rf node_modules (git worktree remove exit 0, no --force); remote branch head 1db960ca equals the local head that was removed; no dev server or background process was started"
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR #11489 (head 17cbfb394a6e7506eacdfdf0d461ea2bf082c118) for this card. From the domain:spec @ objectui seat (objectui#10217), session session_01XvhGmGAP79ZB8swnkapxPC, 2026-10-02T17:47Z. Report 5957503910.

    Contract face.

    What the seat checked in the diff:

    • The three sets match each renderer's branches, as the record re-derived:
      • stack 0–6, 8, 10;
      • flex 0–8;
      • grid 0–6, 8, 10, 12.
    • grid was measured first, as triage asked. No runtime-built class is in either compiled sheet, so grid closes like the other two.
    • container.padding's refusal and describe are byte-identical to base, on the shared helper.
    • Scope beyond the claim, accepted as declared:
    • The renderers' branches are untouched.
    • PR shape: draft, base main, first line Fixes #11474. No other closing keyword names another card.
    • The changeset: types, components and core each minor, with the breaking meaning stated. Its set table and migration line match the diff.

    Out of scope, one line each:

    • (c) grid.columns (and the responsive values) parses any number while the renderer maps 1–12: filed objectui#11491.
    • Acceptance notes: the schema-catalog test's hand-written GAP_LADDER / CONTAINER_PADDING, and the stale "Fallback for arbitrary values" comment in grid.tsx.

    The PR's assignee is not set. The dev's label-write --assign was refused by its local write classifier. The seat does not perform a write a subagent was refused; it is reported to the maintainer. Landing does not depend on it.

    Landing: not governed (check-governed-queue-guard --test over the 18 paths: none matched). Checks on this head: 43, with 40 success, 3 skipped and 0 red. mergeable_state is clean. Ready and auto-merge follow in this same act.

  6. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #11489 merged through the queue as 4abc0aafa. From the domain:spec @ objectui seat (objectui#10217), session session_01XvhGmGAP79ZB8swnkapxPC, 2026-10-02T18:05Z.

    • Reviewed head = landed head: the at-tier record 5958044040 (PASS) names 17cbfb394a6e7506eacdfdf0d461ea2bf082c118, and nothing was pushed after it. All 43 check-runs on that head were green (40) or expected skips (3) before enqueue.
    • On main, by content:
      • In packages/types/src/layout.ts, gap reads 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 on FlexLayoutProps, 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 on StackSchema and 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 on GridSchema.
      • In packages/types/src/zod/layout.zod.ts, container.padding and the gaps go through the shared rendererSpacingSteps helper.
    • By git patch-id --stable: the PR's net diff against its merge base 50c73fed0 and the landed commit agree (ea26b1fd7df4).
    • This card: closed completed by the PR's Fixes line, and pm:dispatched is removed in this act. The family's next member, grid.columns, is objectui#11491, waiting on triage.
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:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions