Skip to content

Commit 671611e

Browse files
os-zhuangclaude
andauthored
feat(showcase): nav separator + badge specimens; correct the §3 item-8 verdict (#1878) (#3694)
Adds the two nav-affordance specimens to the showcase Analytics group (`nav_sep_reports` separator + `badge: 'NEW'`/`badgeVariant: 'secondary'` on Hours by Status) and corrects the naming-drift recheck, which twice published a wrong verdict for this item. The keys are LIVE. UnifiedSidebar delegates the whole app-navigation tree to NavigationRenderer (UnifiedSidebar.tsx:437), which implements separator (:906) and badge/badgeVariant (:983-985); processedNavigation only reorders and pins, spreading every other key through. Browser-verified against an UNMODIFIED objectui checkout: the divider draws and the NEW pill renders. No objectui change was needed -- the port this PR was originally going to make would have duplicated existing capability. Both wrong rounds shared one shape: a strong negative claim ("the component was deleted", "nobody imports it") resting on a search whose results were silently truncated (head -3) or filtered (a pathspec glob that never matched the nested path). The doc now carries a methodology note: a grep can only prove presence; for "does authoring this key do anything", author it and look. Showcase suite 58/58 green. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent bd68f08 commit 671611e

4 files changed

Lines changed: 54 additions & 13 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
---
3+
4+
feat(showcase): add nav `separator` + `badge`/`badgeVariant` specimens, and correct the §3 recheck's item-8 verdict (#1878)
5+
6+
The recheck twice claimed these keys were unconsumed, both times from a faulty
7+
search. Settled empirically: `UnifiedSidebar` delegates the app-navigation tree
8+
to `NavigationRenderer`, which implements all three — the specimen renders
9+
against an unmodified objectui checkout. Docs/examples only; releases nothing.

docs/audits/2026-07-naming-drift-recheck.md

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ stale. Three real problems remain, two of them a coupled pair that produces
3131
| 5 | **page `label``title`** | **🔴 FORWARD-DRIFT — live** | spec `label` is required (`page.zod.ts:303`); the region/SDUI renderer reads `schema.title` with no fallback (`page.tsx:503-507`). Zero `schema.label` reads in `page.tsx` |
3232
| 6 | page `visibility` | **ALIGNED** (item stale) | spec folds `visibility``visibleWhen` (`page.zod.ts:116,126`); `react/src/SchemaRenderer.tsx:285` consumes `visibleWhen`, `:294` still honors raw `visibility` |
3333
| 7 | dashboard `title` vs `label` | **ALIGNED** (item stale) | renderer dual-reads `title \|\| label` (`plugin-dashboard/.../DashboardRenderer.tsx:782`, `DashboardGridLayout.tsx:278`). Widget-level keys additionally hard-fail via a `.strict()` schema + naming error map (`dashboard.zod.ts:273,98-123`, #1894) |
34-
| 8 | app `accentColor` / `badgeVariant` / `separator` | **SPLIT**`accentColor` aligned; the other two are **surface-conditional** | #1894 declared all three to match objectui's `NavigationRenderer`. `accentColor` is consumed on the live path (`app-shell/src/layout/ConsoleLayout.tsx:171`, `PageHeader.tsx:46`, `apps/console/src/hooks/useBranding.ts:25`). `badge`/`badgeVariant`/`separator` **are fully implemented** — but only in `layout/src/NavigationRenderer.tsx` (`:906` separator, `:983-985`/`:1024-1025` badge), which is a *publicly exported, SDUI-registered* component (`navigation-renderer`), **not** the console's own app sidebar. `UnifiedSidebar` — the component that actually renders `app.navigation` in the console — renders no badge and has no separator branch (`separator` is merely recognized as "no href" by `AppContent.tsx:849` and excluded by `nav-target.ts:17`) |
34+
| 8 | app `accentColor` / `badgeVariant` / `separator` | **ALIGNED** — all three live (item stale) | `accentColor`: `app-shell/src/layout/ConsoleLayout.tsx:171`, `PageHeader.tsx:46`, `apps/console/src/hooks/useBranding.ts:25`. `badge`/`badgeVariant`/`separator`: implemented in `layout/src/NavigationRenderer.tsx` (`:906` separator, `:983-985`/`:1024-1025` badge) — and `UnifiedSidebar` **delegates the whole app-navigation tree to that component** (`UnifiedSidebar.tsx:437`, passing `processedNavigation`, which only re-orders/pins and spreads every other key through). **Browser-verified** against an unmodified objectui checkout with a showcase specimen: the separator draws and a `badge: 'NEW'` + `badgeVariant: 'secondary'` pill renders |
3535
| 9 | action `disabled``enabled` | **RESOLVED 2026-07** | fixed across all six rendering surfaces (objectui#2863); showcase specimen `showcase_archive_task` (#3643) |
3636
|| flow `http` vs `http_request` | **ALIGNED** (item stale) | spec enum carries `http` marked canonical (`automation/flow.zod.ts:32`); the runtime registers `HTTP_TYPE = 'http'` (`service-automation/src/builtin/http-nodes.ts:48`) |
3737
|| skill `requiredPermissions` vs `permissions` | **NOT A DRIFT** — mis-filed | `requiredPermissions` **never existed** on `SkillSchema`; the spec key is and was `permissions` (`ai/skill.zod.ts:121`). The original audit described prose/label drift in the docs, not a spec-vs-runtime mismatch |
@@ -86,21 +86,48 @@ fix for this whole class; the per-item wiring below is the tactical one.
8686
3. **`os doctor`** pointed `reference_filters` at the removed `referenceFilters`
8787
instead of the live `lookupFilters` — corrected (framework).
8888

89+
4. **app `badge`/`badgeVariant` + nav `separator` — NOT a drift; nothing to do.**
90+
*(This entry twice carried a wrong verdict before it was settled empirically —
91+
see "A note on how this item was got wrong", below.)* All three are consumed:
92+
`NavigationRenderer` implements them, and `UnifiedSidebar` delegates the whole
93+
app-navigation tree to it (`UnifiedSidebar.tsx:437`). Proven end to end by a
94+
showcase specimen (`nav_sep_reports` + `badge: 'NEW'` on Hours by Status)
95+
rendering correctly against an **unmodified** objectui checkout.
96+
8997
**Recorded, not fixed (each needs an owner decision):**
90-
4. **app `badge`/`badgeVariant` + nav `separator` — surface-conditional, do NOT
91-
prune.** The capability is fully built in `NavigationRenderer` (public export
92-
+ SDUI `navigation-renderer`); what is missing is the same three affordances
93-
in `UnifiedSidebar`, the component that actually renders `app.navigation` in
94-
the console. So an author's `badge: '3'` works if the nav is rendered through
95-
the SDUI component and silently vanishes in the console shell — a
96-
*surface-dependent* no-op, the hardest kind to diagnose. Disposition: port the
97-
three branches into `UnifiedSidebar` (reference implementations already exist
98-
at `NavigationRenderer.tsx:906,983-985`), not prune the keys.
9998
5. **`skill.permissions` has no gate** — mis-filed as naming drift; it is an
10099
aspirational-config item (§4). The ledger marks it `live` on the evidence of a
101100
*preview renderer* while the identically-unenforced `tool.permissions` is
102101
`dead` + `authorWarn`. An author writing `skill.permissions` gets silence
103102
where they should get a warning.
104103
6. **`agent.knowledge` is inert at runtime** — naming is fixed, but RAG resolves
105104
its sources from the LLM tool call, not from the authored block. Wire or mark
106-
experimental.
105+
experimental. *(Both 5 and 6 are now tracked in #3686; the ledger was made
106+
honest about them in #3685.)*
107+
108+
## A note on how item 8 was got wrong — twice
109+
110+
Worth recording, because the failure mode is generic and this document exists to
111+
stop exactly this class of error.
112+
113+
**Round 1.** `git grep -rln "NavigationRenderer" | head -3` returned three
114+
CHANGELOG/ROADMAP hits, and that was read as "the component was deleted." The
115+
`head -3` had truncated the real source hit further down the alphabet.
116+
→ Published claim: *"NavigationRenderer no longer exists."* **False.**
117+
118+
**Round 2.** `git grep -n "NavigationRenderer" -- 'packages/*/src' 'apps/*/src'`
119+
returned nothing, and that was read as "the component is an orphan, nobody
120+
imports it." The pathspec glob never matched the nested
121+
`packages/app-shell/src/layout/UnifiedSidebar.tsx`.
122+
→ Published claim: *"live nav renders no badge; port the branches."* **Also false.**
123+
124+
**Round 3 (settled).** Author a specimen, boot the real stack, look at it. The
125+
separator drew and the badge rendered — against an *unmodified* renderer.
126+
127+
Both wrong rounds share one shape: **a strong negative claim ("X does not
128+
exist", "nobody consumes X") resting on a search whose result set was silently
129+
truncated or filtered.** A grep can only ever prove presence; absence needs
130+
either an exhaustive search you have verified is exhaustive, or — better, and
131+
decisive here — a runtime observation. For liveness work specifically: when the
132+
question is "does authoring this key do anything", the cheapest *sound* answer
133+
is usually to author it and look, not to grep for readers.

docs/audits/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Spec moved to `dataset`+`values`/`dimensions`, but: the **chart view variant** +
4747
### 3. 🟠 Naming drift → silent no-ops (spec key ≠ consumed key)
4848
field `maxLength`/`minLength`/`referenceFilters`/`maxRating`; page `type``pageType` & `label``title` & `visibility`; dashboard `title` vs `label`; app `accentColor`/`badgeVariant`/`separator` (renderer reads, **not in spec**); action `disabled``enabled`; flow `http` vs `http_request`; skill `requiredPermissions` vs `permissions`; agent `knowledge.{topics→sources}`; webhook `object``object_name`, `isActive``active`.
4949

50-
**✅ Rechecked 2026-07-27 — six of nine were already resolved; the list was stale, not the code.** Closed: `referenceFilters` (→ `lookupFilters`, #2377), `maxRating` (→ `max`), page `visibility` (→ `visibleWhen`), dashboard `title`/`label` (renderer dual-reads; widget keys hard-fail via `.strict()`, #1894), flow `http` (canonical), agent `knowledge.topics` (alias folded, #1891), webhook keys (#3489); action `disabled` fixed across all six rendering surfaces (objectui#2863 + #3643); skill `requiredPermissions` was **never a drift** (mis-filed prose drift). **Still real, fixed in the recheck pass:** the coupled page pair `type`→`pageType` + `label`→`title` (mis-renders every non-record page today) and two snake-only `max_length` readers. **Left as decisions:** app `badge`/`badgeVariant` + nav `separator` are implemented in `NavigationRenderer` (SDUI) but missing from `UnifiedSidebar`, the console's own app sidebar — a surface-dependent no-op, port rather than prune; `skill.permissions` has no gate (belongs in §4); `agent.knowledge` is inert at runtime. Full per-item evidence: [`2026-07-naming-drift-recheck.md`](./2026-07-naming-drift-recheck.md).
50+
**✅ Rechecked 2026-07-27 — six of nine were already resolved; the list was stale, not the code.** Closed: `referenceFilters` (→ `lookupFilters`, #2377), `maxRating` (→ `max`), page `visibility` (→ `visibleWhen`), dashboard `title`/`label` (renderer dual-reads; widget keys hard-fail via `.strict()`, #1894), flow `http` (canonical), agent `knowledge.topics` (alias folded, #1891), webhook keys (#3489); action `disabled` fixed across all six rendering surfaces (objectui#2863 + #3643); skill `requiredPermissions` was **never a drift** (mis-filed prose drift). **Still real, fixed in the recheck pass:** the coupled page pair `type`→`pageType` + `label`→`title` (mis-renders every non-record page today) and two snake-only `max_length` readers. **Also confirmed aligned:** app `badge`/`badgeVariant` + nav `separator` are live — `UnifiedSidebar` delegates the app-navigation tree to `NavigationRenderer`, which implements all three (browser-verified with a showcase specimen; an earlier revision of this annotation claimed otherwise from a faulty grep — see the recheck doc's methodology note). **Left as decisions:** `skill.permissions` has no gate and `agent.knowledge` is inert at runtime — ledger corrected in #3685, enforce-or-prune tracked in #3686. Full per-item evidence: [`2026-07-naming-drift-recheck.md`](./2026-07-naming-drift-recheck.md).
5151

5252
### 4. 🟠 Aspirational config (rich spec, zero runtime) — prune or mark `experimental`
5353
field enhanced-type configs (barcode/qr/slider/rating/color/location) + governance (encryption/masking/audit/dataQuality); object `enable`/versioning/partitioning/cdc/softDelete/search; agent autonomy (memory/guardrails/structuredOutput/lifecycle); tool `outputSchema`; job `retryPolicy`/`timeout`; theme rtl/density/touchTarget; translation `messageFormat:'icu'` (no ICU engine); **portal (entire)**; webhook non-HMAC auth.

examples/app-showcase/src/ui/apps/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,12 @@ export const ShowcaseApp = App.create({
9494
{ id: 'nav_revenue_pulse', type: 'dashboard', dashboardName: 'showcase_revenue_pulse', label: 'Revenue Pulse (filtered)', icon: 'sliders-horizontal' },
9595
{ id: 'nav_charts', type: 'dashboard', dashboardName: 'showcase_chart_gallery', label: 'Chart Gallery', icon: 'layout-dashboard' },
9696
{ id: 'nav_report_tabular', type: 'object', objectName: 'showcase_task', viewName: 'tabular', label: 'Task List', icon: 'table' },
97-
{ id: 'nav_report_summary', type: 'report', reportName: 'showcase_hours_by_status', label: 'Hours by Status', icon: 'sigma' },
97+
// Nav-affordance specimens (framework#1878 §3 recheck): `separator`
98+
// draws a divider; `badge` + `badgeVariant` render a pill on the item.
99+
// Both are consumed by NavigationRenderer, which UnifiedSidebar uses to
100+
// render the app navigation tree — dogfooded here so the wire stays hot.
101+
{ id: 'nav_sep_reports', type: 'separator' },
102+
{ id: 'nav_report_summary', type: 'report', reportName: 'showcase_hours_by_status', label: 'Hours by Status', icon: 'sigma', badge: 'NEW', badgeVariant: 'secondary' },
98103
{ id: 'nav_report_chart', type: 'report', reportName: 'showcase_hours_by_status_chart', label: 'Hours by Status (Chart)', icon: 'bar-chart-3' },
99104
{ id: 'nav_report_matrix', type: 'report', reportName: 'showcase_status_priority_matrix', label: 'Status × Priority', icon: 'grid-3x3' },
100105
{ id: 'nav_report_joined', type: 'report', reportName: 'showcase_task_overview', label: 'Task Overview', icon: 'layers' },

0 commit comments

Comments
 (0)