Skip to content

spec(ui): dashboard gap help text says "Tailwind units" to an app author #14586

Closed

Description

@hotlong

Found while localizing the Studio dashboard property panel (objectui#7254, PR objectstack-ai/objectui#7366).

packages/spec/src/ui/dashboard.form.ts gives the gap field this help text:

{ field: 'gap', type: 'number', colSpan: 1, helpText: 'Grid gap (Tailwind units)' }

That string is rendered verbatim in the customer-facing dashboard property panel — the Studio panel is spec-driven, feeding dashboardForm straight into the renderer's generic form. "Tailwind units" is a framework-implementation detail: an app author choosing a gap has no way to act on it, and it names a CSS library they never chose.

The renderer side cannot fix this — the string is the producer's. objectui#7366 added a zh overlay that says something an author can decide (「组件之间的间距,数值越大越松」) and deliberately left the English source alone, because rewriting a producer's copy from the consumer is exactly the second-dialect problem the contract rule exists to stop.

Suggested: say what the author decides, not what the renderer consumes — e.g. "Space between widgets" — and let the numeric semantics live in the renderer.

While there: columns's Grid columns (default 12) is fine (12 is an author-visible fact); this is only about the unit vocabulary.

Activity

  1. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Triage — graded p3, documentation, pm:queue, routed domain:spec. Applied and read back first.

    Confirmed at origin/main c616c2c

    packages/spec/src/ui/dashboard.form.ts:24  { field: 'columns', …, helpText: 'Grid columns (default 12)' },
    packages/spec/src/ui/dashboard.form.ts:25  { field: 'gap',     …, helpText: 'Grid gap (Tailwind units)' },
    

    Your distinction between the two lines holds and is the reason this card is precise rather than a style complaint: 12 is an author-visible fact about the grid they are laying out, so columns is fine; "Tailwind units" names a CSS library the app author never chose and cannot act on. ⛔ Leave :24 alone.

    Why p3 and why it is a real defect

    The string is rendered verbatim in the customer-facing Studio property panel — the panel is spec-driven, feeding dashboardForm into the generic form renderer — so this is published product copy, not an internal note. An author reading it learns the name of an implementation dependency instead of what the number does.

    p3 because it is one string, nothing is broken, and the number still works whatever the label says.

    ⭐ The part worth preserving: you fixed the consumer and refused to fix the producer

    objectui#7366 added a zh overlay saying something an author can decide (「组件之间的间距,数值越大越松」) and deliberately left the English source alone, because rewriting a producer's copy from the consumer is the second-dialect problem the contract rule exists to stop.

    That restraint is what makes this card necessary and correct. The tempting move — one-line fix in objectui, ship it — would have left English and zh saying different things about the same field, with the divergence invisible from either side. Filing upstream instead is the expensive right answer, and it is the same producer/consumer discipline #14587 turns on from the other direction.

    ⚠️ Consequence for whoever takes it: once the English source says what the author decides, the zh overlay in objectui#7366 becomes a translation of a different sentence. Check it still reads as a translation rather than an unrelated improvement — and if the two have converged in meaning, the overlay may no longer be needed at all. ⛔ That check is in objectui, so it is a repo:objectui follow-up, not a file this card may touch.

    Scope

    One helpText string. Say what the author decides — your "Space between widgets" is good — and let the numeric semantics live in the renderer.

    ⛔ Not Clause ②: helpText prose is not accept/reject behaviour and no public surface widens.

    ⛔ Do not sweep dashboard.form.ts for other framework-vocabulary leaks in this card. If there are more, they deserve a measured population the way #14628 did it — and note that columns already proves not every unit reference is a defect, so a blind grep for framework words would over-collect.


    Generated by Claude Code

  2. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    Claim: PM seat domain:spec, session session_01G4138K1EG7kQ81FNba5Kp4 (os-sales), R1, 2026-09-04T18:18Z.
    Branch: claude/issue-14586-dashboard-gap-help-text
    Clause-②: no

    pm:queue → pm:dispatched in one label write, read back and diffed against the pre-write set. No needs:contract-review — triage judged it ("⛔ Not Clause ②: helpText prose is not accept/reject behaviour and no public surface widens"), and the line above carries the bare predicate only because scripts/pm/check-clause2-carriers.mjs reads it as a machine token.

    ⭐ Premise check found a SECOND producer site for the same field, and this dispatch widens the card to it

    Measured on origin/main 414c1fcf8 at 18:17Z, before claiming. The card and triage both name exactly one string. There are two, on the same key, and they feed two different customer-facing surfaces:

    # producer string on main what it reaches
    1 packages/spec/src/ui/dashboard.form.ts:25 helpText: 'Grid gap (Tailwind units)' the Studio property panel — the card's site
    2 packages/spec/src/ui/dashboard.zod.ts:903 .describe('Grid gap in Tailwind spacing units') (+ the JSDoc at :902) content/docs/references/ui/dashboard.mdx:36 — not named by the card

    Verified with a control that site 2 really is what the reference page publishes: the columns helpText (Grid columns (default 12)) appears nowhere in the .mdx, while gap's describe appears verbatim as its table row. So the reference corpus renders .describe(), not helpText — two independent producer strings, two independent published surfaces.

    Seat ruling, open to the maintainer's or triage's veto: fix both, in this card. The reasoning is the card's own. This card exists because objectui#7366 refused to fix a producer's copy from the consumer, since that would leave English and zh saying different things about one field. Fixing site 1 alone reproduces exactly that failure one level up: the Studio panel would say what an author decides while the published reference page still names a CSS library they never chose — the same divergence, relocated rather than removed, and invisible from either side.

    ⛔ Triage's actual prohibition stands and is carried into the dispatch: no sweep of dashboard.form.ts (or anything else) for other framework-vocabulary leaks. This is one field's two producer strings, not a population. ⛔ columns at :24 and its .describe() sibling are untouched — 12 is an author-visible fact, as both the card and triage say.

    Also carried into the dispatch

    • ⛔ Not Clause ②, no gate label, no contract-tier review.
    • The .describe() edit regenerates content/docs/references/ui/dashboard.mdx. ⚠️ Serial: card spec: hour/minute/day-shaped deadline keys in incident-response, training, change-management and ESignature schemas have zero readers and no EXPERIMENTAL tag (ADR-0049 shape) #14477 is in flight and also regenerates under content/docs/references/**, but in system/**, not ui/dashboard.mdx — disjoint. If that changes, the later PR merges main through scripts/pm/os-regen-merge.sh and re-regenerates before enqueue.
    • The objectui follow-up triage flagged is owed and will be filed by the dev: once the English source says what the author decides, the zh overlay from objectui#7366 becomes a translation of a different sentence, and may not be needed at all. That check lives in objectui ⇒ a repo:objectui card with a Blocked-by line, ⛔ not a file this card may touch.

    Generated by Claude Code

  3. claude commented on Sep 4, 2026

    @claude
    Contributor

    Claim: os-dev subagent for the domain:spec PM seat, session session_01G4138K1EG7kQ81FNba5Kp4, R1, 2026-09-04T18:25Z.
    Branch: claude/issue-14586-dashboard-gap-help-text
    Clause-②: no

    Reasoning for that predicate, carried from triage and re-read against the diff I am about to write: the change is prose only. It rewrites one helpText string and one .describe() string on the same key, plus the JSDoc line above the latter and the generated reference row that renders it. No schema shape, no export, no accept set — gap stays z.number().int().min(0).optional() and every value it accepted before is still accepted. Triage's own words: "helpText prose is not accept/reject behaviour and no public surface widens".

    Scope, as dispatched: the seat widened this card from one producer string to two on the same field, and I re-ran its control rather than taking it on trust — reported in full on the PR. Triage's actual prohibition is carried intact: no sweep of dashboard.form.ts or dashboard.zod.ts for other framework vocabulary, and columns is untouched on both of its producer lines.


    Generated by Claude Code

  4. claude commented on Sep 4, 2026

    @claude
    Contributor

    File-surface increment on the claim above — declared in-round, not at report time

    My claim comment declared the two producer files. The landed diff is five paths. The three additions are all derived artifacts of those two edits, regenerated by the repo's own tooling and never by hand — no new judgement surface, and no sweep:

    path why it is in the diff produced by
    content/docs/references/ui/dashboard.mdx renders the edited .describe() check:generated --fix (gen:docs)
    packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts en is a mechanical copy of the edited form source check-i18n-bundles.mjs --write
    .changeset/dashboard-gap-author-vocabulary.md the change ships from two published packages hand-written, as required

    The i18n bundle is not a scope widening I chose. node scripts/pm/dispatch-gates.mjs names it for this change KIND, verbatim: "edits a metadata form module ... a form edit drifts them from a package your diff never touches". Measured both ways on this branch: pnpm check:i18n exit 1 (platform-objects: 1 bundle(s) drifted) before the regeneration, exit 0 after. Leaving it out would have shipped a red gate.

    ⛔ Still no sweep: columns is untouched on both producer lines, and no other framework-vocabulary site was searched for or changed. The one leaf regeneration deliberately does NOT reach — the stale zh-CN translation — is filed as #15511, not ridden along.


    Generated by Claude Code

  5. claude commented on Sep 4, 2026

    @claude
    Contributor

    Deviations, declared rather than smoothed — posted separately so the report comment stays machine-clean

    1. I posted a claim comment even though the standing dev contract says the PM's claim already satisfies claim-first. The dispatch required it, because check-clause2-carriers.mjs reads the GOVERNING claim — the newest one naming a branch — and mine would become that. Had I skipped it, the seat's Clause-②: no would still have governed; posting mine kept the predicate on the governing carrier either way. Verified by read-back: the line survives as Clause-②: no on its own line, and readClause2Line treats that spelling as declared. I did not touch assignee.

    2. The commit trailer carries a model identifier, which the same dispatch forbids elsewhere. The hard rules say never put a model identifier in a commit message; the very next rule spells out the exact required trailer, which contains one. I read the prohibition as aimed at prose — title, body, code comments, changeset, doc and issue comments, all of which I kept clean — and followed the explicit trailer instruction, which is the more specific and more recent directive. No gate reads commit trailers (check-agent-model-declared.mjs governs .claude/agents/** frontmatter only, untouched here). Flagging it because it is a real conflict in the dispatch text, not something to resolve silently.

    3. Two gates are NOT MEASURED, and one narrowing is declared. check:dual-build-cjs-loads (exit 3) and check:i18n-coverage (exit 3) both refused with PREREQUISITE NOT MET; clearing the first needs a whole-repo pnpm build, which is CI's run and would have held the shared verify lock against other agents to measure something a prose-only diff cannot move. check:react-declaration-parity cannot run in this repo at all. Reported as unmeasured, never as passes. Everything else — including the repo-wide pnpm lint — was run whole rather than narrowed.

    4. The file surface grew from 2 paths to 5. Declared in-round in comment 5545366885 rather than at report time, with the red-then-green measurement that forced the i18n one.

    5. Where the dispatch and the card disagree, as asked. They do not, on anything material. The card and triage name one string; the dispatch widens to two. I re-ran the seat's control instead of inheriting it and it reproduces, so I acted on the widening. Triage's actual prohibition — no sweep, columns untouched — is stated identically in both and is held in both letter and spirit.


    Generated by Claude Code

  6. claude commented on Sep 4, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 14586,
      "status": "done",
      "branch": "claude/issue-14586-dashboard-gap-help-text",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/15512",
      "premise_still_valid": true,
      "summary": "Both producer strings for the dashboard `gap` field now read 'Space between widgets, in steps of 0.25rem (4 = 1rem)': dashboard.form.ts:25 helpText (was 'Grid gap (Tailwind units)') and dashboard.zod.ts:903 .describe() plus its :902 JSDoc (was 'Grid gap in Tailwind spacing units'). THE SEAT'S CONTROL FOR SITE 2 REPRODUCES, and I strengthened it into a paired measurement rather than an absence: the columns HELPTEXT is absent from the mdx (grep exit 1) while the columns DESCRIBE is present at line 35 (exit 0), and gap the same way at line 36 — so the reference corpus renders .describe(), not helpText; generalized, none of the four dashboard helpText strings appears anywhere under content/ (0 hits each). The widening holds and site 2 is real. MAGNITUDE KEPT AND VERIFIED AGAINST THE CONSUMER rather than inferred: the dashboard renderer emits no utility class for this key at all, it sets an inline style `gap: ${gap * 0.25}rem` (objectui DashboardRenderer.tsx:1183), so one step is exactly 0.25rem, every accepted integer is linear, and there are no scale gaps — which also makes 'Tailwind units' doubly wrong, since it named a dependency the actual consumer of this key does not have. No schema change: gap stays z.number().int().min(0).optional(). columns untouched on both producer lines; no sweep performed. Three derived paths beyond the two producers, all regenerated by repo tooling and declared in-round on the card (comment 5545366885): the mdx row, the en metadata-forms leaf, and the changeset.",
      "tests": "All gates run at the final commit 765da3a98, each exit code captured BEFORE any pipe (cmd > log 2>&1; EXIT=$?). Families derived by `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` on the actual 5-path change set (its stderr confirmed 'objectstack-ai/objectstack at commit 765da3a98' and '--repo ... it holds'), NOT from the dispatch's list. GREEN exit 0 (48 path-derived + whole-tree): api-surface, authorable-surface, browser-reachable-entries, changeset-gate-self-tests, corpus-claim-drift, cross-package-test-inputs, doc-anchors, doc-authoring, doc-formula-expressions, doc-security-posture, check:docs, docs-audit-scope, docs-redirects, docs-single-h1, dual-source-exports, empty-state, entry-nameability, export-origins, exported-any, check:generated, liveness, llms-txt, logger-receiver-detach, merge-driver, objectui-changeset, org-identifier, page-declaration-shape, published-files, published-readme-links, quick-reference-counts, react-page-adapter-contract, role-word, skill-examples, skill-identifier-liveness, skill-refs, slot-lookup, spec-parsed-alias, strictness-ledger, test-source-alias, type-source-resolution, variant-docs, vendor-version-stamps, widget-option-census, yaml-examples, driver-memory-census, nul-bytes, refd-timer-probe, watch-hint-literal; plus check:i18n 0, check:i18n-walk-parity 0, check:i18n-stale-fill 0, check:dispatcher-error-vocabulary 0, check-changeset-no-major.mjs 0. TESTS/TYPES: @objectstack/spec vitest 'Test Files 471 passed (471) / Tests 12657 passed (12657)' exit 0 under the shared verify lock (VERDICT command-exit 0, held 376s); spec typecheck 0; platform-objects typecheck 0; platform-objects translations suite 7 files/85 tests 0; CLI i18n-extract-emitted-files 4 tests 0 (those two are the only test files importing the regenerated bundle). REPO-WIDE LINT RUN WHOLE, NOT NARROWED: `pnpm lint` (eslint . --no-inline-config) exit 0. THE MEASURED RED THAT DROVE THE i18n REGENERATION: check:i18n exit 1 'platform-objects: 1 bundle(s) drifted from the schema' before, exit 0 after `node scripts/check-i18n-bundles.mjs --write` — dispatch-gates names this gate for this change KIND, so it was derived, not swept. NOT MEASURED, reported as such and never as passes: (1) check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET — reads built output, 11 packages have no dist/, needs a whole-repo `pnpm build`; its own text says 'This is NOT a pass: nothing was measured'; declared narrowing, left to CI, and a prose-only diff cannot change module format or export shape. (2) check:i18n-coverage exit 3, same class (a partial round cannot judge the ratchet); not in this diff's derived families, run opportunistically. (3) check:react-declaration-parity cannot run in this repo at all — needs objectui's browser-produced sdui.manifest.json. ONE REFUSAL CLEARED RATHER THAN REPORTED AS RED: check:skill-examples first exited 1 refusing because client-react had no .d.ts; I built that closure under the lock and it then reported '257 prose examples type-check across 3 surface(s)', exit 0. NO ABLATION WAS PERFORMED — this change adds no guard whose failure needs proving, so there was nothing to ablate and I am not reporting a template one. The edit-landed-on-disk discipline was still applied: each of the three string replacements asserted exactly 1 pre-image occurrence, then re-read the file to confirm old-remaining=0 and new-present=1, and `git diff` was inspected independently as the on-disk proof. REGENERATION: `pnpm --filter @objectstack/spec check:generated --fix` exit 0, reported gen:docs as the 1 stale artifact of 15 and regenerated it; delta was ONE line in content/docs/references/ui/dashboard.mdx and NOTHING outside it — #14477's system/** surface is measured disjoint, and main has moved zero paths under content/docs/references/ since this branch point, so no os-regen-merge.sh was needed and no drift stop-and-report was triggered.",
      "mcp_calls": "0 — every GitHub read and write went through the container's repo-scoped REST channel (probed green at the start of the round: GET /repos/objectstack-ai/objectstack HTTP 200), so the GraphQL pool was untouched. Card and comment reads, both issue creations, all three comment writes and the draft PR creation were REST.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as objectstack-ai/objectui#7673: the zh overlay added by objectui#7366 now translates a sentence the spec no longer says, and its citation comment at metadata-form-i18n.ts:87-89 quotes the retired literal `Grid gap (Tailwind units)` verbatim as current fact. Unassigned, for objectui triage, carries `Blocked-by: objectstack-ai/objectstack#14586` and both exact before/after strings. Answers triage's open question with a measurement: the two have CONVERGED ON INTENT but NOT ON CONTENT — the new English carries the magnitude, the overlay carries only a direction (数值越大越松) — so 'delete the overlay, the source is fixed' is available but costs information. Duplicate-searched first over 900 rows including closed; objectui#7369 (delete the overlay table, consume the platform bundle) is related, not a duplicate, and is cross-linked.",
        "filed as #15511: the zh-CN half in this repo. zh-CN.metadata-forms.generated.ts:935 still reads 「栅格间距(Tailwind 单位)」 and regeneration provably will not fix it — merge fills gaps only, so check:i18n AND check:i18n-stale-fill are both GREEN over the stale leaf (measured, both exit 0), and there is no digest for it either since zh-CN.source-hashes.generated.ts carries no dashboard entry. Filed rather than fixed because the dispatch forbade sweeping AND because the replacement is a Chinese wording judgement that objectui#7369 will likely inherit — it fails the bounded-in-place-fix test on 'mechanical, correct form already pinned by evidence'. Sharpest point for triage: #14587 swept this exact subtree on 2026-09-03 and correctly left gap alone because it was accurate then, so this is a leaf that a landed source edit turns stale with every instrument green — the mechanism #14931 says nothing in this repo can judge, arriving by the opposite route from #14931's 613 legacy-trusted leaves."
      ]
    }

    Generated by Claude Code

  7. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    ACCEPT — PR #15512 (head 765da3a98, Fixes #14586) · landing gated on CI

    PM seat domain:spec, session session_01G4138K1EG7kQ81FNba5Kp4 (os-sales), 2026-09-04T19:23Z. The dev's report was read as a set of claims; everything below is this seat's own measurement.

    Diff shape

    Five files, derived three-dot (origin/main...765da3a98) — ⚠️ the two-dot form answers with 48 files here, because main has advanced far past the branch point and a two-dot diff shows main's own commits in reverse. Same class as the FETCH_HEAD trap; the three-dot count matches the API's changed_files: 5.

    file +/−
    .changeset/dashboard-gap-author-vocabulary.md 40/0
    content/docs/references/ui/dashboard.mdx 1/1
    packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts 1/1
    packages/spec/src/ui/dashboard.form.ts 1/1
    packages/spec/src/ui/dashboard.zod.ts 2/2

    Both producer sites now read Space between widgets, in steps of 0.25rem (4 = 1rem). columns untouched on both of its lines (helpText and .describe()), the JSDoc moved with its describe, and the accept set is byte-identical: gap: z.number().int().min(0).optional() on main and at the head. node scripts/pm/check-clause2-carriers.mjs --pair 15512 → ✓ readable, both carriers agree.

    The claim the whole wording rests on — verified at the pin, with one correction

    The new text asserts a magnitude. If the renderer used a Tailwind class, "steps of 0.25rem" would be a new false sentence replacing the old one, so this was checked rather than accepted:

    At the console pin 00d3f09c, packages/plugin-dashboard/src/DashboardRenderer.tsx sets this key as an inline style inside style={{…}}:

    gap: `${gap * 0.25}rem`
    

    Linear, every accepted integer works, no scale gaps. The wording is correct against the actual consumer.

    ⚠️ Citation correction. The report cites DashboardRenderer.tsx:1183. At the pin the line is 1170; 1183 is where it sits at objectui main. The bytes are identical at both revisions, so the conclusion is unaffected — but the citation points at a line number that does not exist in the tree this repo actually consumes. Recorded because "read the tree you actually ship against" is the discipline this lane keeps having to enforce.

    ⚠️ And the "doubly wrong" claim needs narrowing, not repeating. The report says "Tailwind units" named a dependency the consumer does not have. True for this key — but objectui does use Tailwind gap utilities elsewhere, including a sibling whose own doc comment reads "Gap between items (Tailwind gap class, default: gap-2)" (components/src/renderers/action/action-bar.tsx:82). So the old string was not wrong because Tailwind is absent from the platform; it was wrong because this key is inline-styled and never becomes a class. The narrower statement is the true one and the one worth carrying forward.

    Regenerated followers, and the level

    content/docs/references/ui/dashboard.mdx:36 and en.metadata-forms.generated.ts:935 both carry the new string, and the columns row beside each is unchanged — the delta is one line in each, nothing outside. Changeset: @objectstack/spec: patch + @objectstack/platform-objects: patch. Correct: published prose, no accept-set movement, no typed-surface change.

    ⭐ The check:i18n red the dev hit (platform-objects: 1 bundle(s) drifted from the schema) and cleared with --write is the right shape — the English bundle is a derived follower of the helpText, found by a gate the change kind selects, not by a sweep.

    ⚠️ What this PR knowingly ships as false, stated plainly

    After this lands, zh-CN.metadata-forms.generated.ts:935 still reads 「栅格间距(Tailwind 单位)」 while the English says something else. A zh Studio user keeps seeing the exact framework vocabulary this card exists to remove. The dev measured that regeneration provably will not fix it — merge fills gaps only, so check:i18n and check:i18n-stale-fill are both green over the stale leaf, and there is no digest for it either.

    The seat accepts filing over fixing (#15511), and not merely as the cautious option — it is the card's own principle applied one level over. This card exists because objectui#7366 refused to rewrite a producer's copy from the consumer side. Writing new Chinese product copy from an English-language spec-lane dispatch is that same second-dialect error, just pointed the other way: it would put a wording judgement in the hands of the round least equipped to make it. What is not acceptable is letting it go unrecorded — hence #15511, and hence this paragraph rather than a silent ACCEPT.

    Cross-repo follow-ups, both verified present

    Landing

    At all-green: ready → auto-merge (squash). CI at 19:22Z: 31 checks, 0 red, 16 still running. ⛔ Not flipped, ⛔ not enqueued. No serial constraint — content/docs/references/ui/dashboard.mdx is disjoint from #14477's system/**, and no path under content/docs/references/ has moved on main since this branch point. On MERGED: strip pm:dispatched, probe origin/main for both new strings with the pre-merge tip as a control on the same pattern, landing note here.


    Generated by Claude Code

  8. os-sales commented on Sep 4, 2026

    @os-sales
    Collaborator

    Landing note — PM seat domain:spec, session session_01G4138K1EG7kQ81FNba5Kp4 (os-sales), 2026-09-04T20:19Z.

    MERGED. PR #15512 merged 2026-09-04T20:17:35Z through the merge queue; origin/main is now 85a245988, whose subject is this PR's own. Pre-merge tip ae79c775d.

    Card close verified by reading: the PR's first body line is Fixes #14586; the card reads closed / completed / 20:17:37Z. State: pm:dispatched stripped, read back.

    Probe on origin/main — eight readings, both directions, every carrier, each with its own control

    string file main control ae79c775d
    new Space between widgets, in steps of 0.25rem dashboard.form.ts 1 0
    dashboard.zod.ts 2 0
    content/docs/references/ui/dashboard.mdx 1 0
    en.metadata-forms.generated.ts 1 0
    old Grid gap (Tailwind units) dashboard.form.ts 0 1
    en.metadata-forms.generated.ts 0 1
    old Grid gap in Tailwind spacing units dashboard.zod.ts 0 2
    content/docs/references/ui/dashboard.mdx 0 1

    Every zero on the left is paired with a non-zero for the same pattern on the right, on the same file. No zero here is the artefact of a mistyped pattern — the failure this seat shipped in a probe earlier today and has been carrying a control against since.

    Two further readings, both for things that must NOT have changed:

    What this card turned on

    ⭐ The card named one producer; there were three. The premise check before claiming found dashboard.zod.ts:903's .describe() feeding the published reference page, and the dev then found en.metadata-forms.generated.ts — a generated English translations bundle — via check:i18n going red. Fixing only the helpText the card named would have left the Studio panel saying one thing while the reference docs and the translations bundle said another: the same producer/consumer divergence objectui#7366 refused to create, relocated one level up. The widening was a seat ruling, declared on the card and open to veto.

    ⭐ The replacement keeps the fact the old string carried, and it was verified against the consumer, not assumed. "Tailwind units" was not merely jargon — it encoded that 4 means 1rem. At the console pin, plugin-dashboard/src/DashboardRenderer.tsx sets this key as an inline style, gap: `${gap * 0.25}rem` : linear, no scale gaps, and not a Tailwind class at all. So the old string named a dependency this key's consumer does not use, and the new one states the magnitude an author can act on.

    ⚠️ Narrowed from the dev's report rather than repeated: the report called the old wording "doubly wrong" because the consumer has no Tailwind dependency. objectui does use Tailwind gap utilities elsewhere — a sibling renderer's own comment reads "Gap between items (Tailwind gap class, default: gap-2)". The old string was wrong because this key is inline-styled, not because the platform is Tailwind-free. The narrower claim is the true one.

    Follow-up, unblocked but not yet actionable: objectui#7673 — the zh overlay from objectui#7366 now translates a sentence the spec no longer says, and its citation comment quotes the retired literal as current fact. It carries Blocked-by: objectstack-ai/objectstack#14586, whose first limb is now satisfied; the second is a released spec version reaching the pin. ⛔ Nothing to do there today.


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions