Skip to content

feat(devboard): Operate · Cells — list + 12-tab detail + manifest derivation (Batch 5 / T502–T506) - #34

Merged
ghbvf merged 9 commits into
developfrom
014-b5-cells
Jun 2, 2026
Merged

ghbvf merged 9 commits into
developfrom
014-b5-cells

Conversation

@ghbvf

@ghbvf ghbvf commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

Batch 5 · Operate · Cells — the MVP's most complex page (~25%), built in @gocell/devboard (previously an empty stub). /cells list + /cells/:id 12-tab inspector, all backed by a build-time manifest derived from the backend cell.yaml + slice.yaml — no backend endpoint required. Per the directive, backend gaps are ignored and implemented directly: fields with no data source degrade to "—"/UnavailablePanel, never fabricated.

Closes #16.

T502 — Cell manifest derivation (AI-robust Hard)

  • New tools/cell-manifest/ mirrors tools/codegen: pure derive.ts + IO index.ts + reverse-self-check derive.spec.ts (26 tests incl. ai-robust §盲区自检 — unknown roles/waivers produce 0 false matches; determinism).
  • Generates packages/devboard/src/manifest/cells.generated.ts (/* eslint-disable */ + DO-NOT-EDIT banner, prettier-ignored). CI .github/workflows/cell-manifest-diff.yml asserts git status --porcelain clean → manual edits inexpressible.
  • slice.yaml contractUsages[].role: serve/publish → produces, call/subscribe → consumes; cross-cell consume→produce resolution yields dependsOnCells/requiredByCells. Derived for the 3 live cells (accesscore→configcore; auditcore→both; configcore→∅).
  • The tool is self-contained (own types.ts); the generated file's : CellManifest annotation (from devboard's canonical ./types) guards drift at @gocell/devboard typecheck.

T503 — /cells list

Demo/Durable badge, domain segmented filter + id/name search (useCellsFilter), neutral tier chips. Keyboard-accessible row nav (<RouterLink> in first cell + aria-label, no @click on <tr>), scope="col" headers.

T504 — /cells/:id 12-tab inspector

?tab= deep-link, single live tabpanel (Audit/Config don't fetch while hidden), unknown-id → accessible not-found. CellTabBar = ARIA tablist + useRovingTablist (Arrow/Home/End roving tabindex, APG). tabRegistry is the single source of truth for tab order + id→component.

T505 — Audit / Configuration tabs (boundary-clean)

Live-fetch the same /api/v1/audit/ + /api/v1/config/ endpoints via @gocell/request with @gocell/contracts types — never importing @gocell/audit/@gocell/config (cross-cell ban). loading/error/empty/data states + deep-link to the full pages. Tasks/Groups/AI tabs → honest UnavailablePanel (no data source).

T506 — Interfaces ISP four sub-interfaces

Identity / Lifecycle / Status / Inventory cards + produces/consumes contract lists with neutral role pills.

Packages touched

  • @gocell/devboard (new cell impl): manifest + store + composables + 14 components (12 tabs + tab bar + 2 shared) + 2 views + README + exports.
  • @gocell/core: i18n cells.* block (zh-CN + en-US).
  • apps/web: /cells + /cells/:id routes (PDP read:cell, fail-closed) + @gocell/devboard dep.
  • tools/cell-manifest (new) + CI workflow + yaml catalog dep.
  • packages/contracts/: not modified (consumed read-only; codegen diff verified clean).

Backend gaps (ignored per directive — degraded, not faked)

Gap Frontend behaviour
No GET /api/v1/admin/cells Static cell.yaml-derived manifest (MVP plan per PRD §6)
Runtime QPS/p95/health/replicas (needs BR-001) UnavailablePanel "—", never fabricated
Tasks / SLOC / version / on-call (no source) Honest unavailable state
Audit/Config per-cell filter param absent Tabs show recent entries + deep-link to full page

Test plan

  • pnpm -F @gocell/devboard test --run — 176 tests pass
  • pnpm -F @gocell/cell-manifest test --run — 26 tests (incl. reverse self-check + determinism)
  • pnpm -w typecheck — clean (incl. en-US satisfies MessageSchema, generated-file drift guard)
  • pnpm -w lint — 0 issues (boundary self-check confirms devboard→access PDP exception allowed, audit/config cross-import blocked)
  • pnpm -w test --run — 85 files / 1162 tests pass (incl. new /cells + /cells/:id router assertions)
  • pnpm -F @gocell/web build — /cells + /cells/:id emit separate lazy chunks
  • pnpm codegen → git status clean (contracts read-only)
  • manifest regenerate → no diff (deterministic)

a11y note: /cells is auth+PDP-gated and PDP is fail-closed (BR-004 stub), so an e2e smoke can't render it yet — covered by component tests; e2e deferred with login/PDP (consistent with Batch 0's deferral note).

🤖 Generated with Claude Code

ghbvf and others added 9 commits June 2, 2026 21:13
…atch 5 / T502)

- tools/cell-manifest: pure derive.ts (humanizeDomain, parseCell, parseSlice,
  deriveProducesConsumes, buildManifest, renderManifestModule) + IO index.ts
  mirroring tools/codegen pattern; 26 fixture-based unit tests incl. all
  blind-spot reverse checks (unknown role, waiver contract, empty usages,
  no-slices cell, determinism)
- packages/devboard/src/manifest/types.ts: hand-written CellEntry/CellManifest types
- packages/devboard/src/manifest/cells.generated.ts: generated from 3 backend cells
  (accesscore produces=26 consumes=6 dependsOn=[configcore];
   auditcore produces=2 consumes=13 dependsOn=[accesscore,configcore];
   configcore produces=19 consumes=2 dependsOn=[])
- packages/devboard: full package.json (deps+devDeps), vitest.config.ts, tsconfig.json
- packages/devboard/src/stores/useCellsStore.ts: setup-style Pinia store wrapping
  CELL_MANIFEST with selectedId/cells/byId/selectedCell/selectCell; 7 tests
- packages/devboard/src/components/CellDurabilityBadge.vue: token-only pill with
  aria-hidden decorative dot; 6 tests
- packages/devboard/src/components/UnavailablePanel.vue: role=status muted panel; 4 tests
- packages/devboard/src/index.ts: barrel exporting types + CELL_MANIFEST + store + components
- packages/core i18n: complete cells: block added to both zh-CN and en-US
- .github/workflows/cell-manifest-diff.yml: CI guard (mirrors codegen-diff.yml)
- eslint.config.js: generated file excluded + cell-manifest vitest.config override
- .prettierignore: generated file excluded
- pnpm-workspace.yaml catalog: yaml ^2.6.0 added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- useCellsFilter composable: query + domain filter, sorted unique domains
- CellsListView: semantic table, segmented domain control, keyboard-accessible
  RouterLink in first cell column, neutral tier chip, CellDurabilityBadge
- 21 tests (10 composable + 11 view), typecheck and eslint clean

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lders (Batch 5 / T505)

Add cellAudit/cellConfig API clients (boundary-clean: direct HTTP via @gocell/request,
no @gocell/audit or @gocell/config imports) plus AuditTab/ConfigurationTab with
loading/error/empty/data states and RouterLink open-full deeplinks;
Tasks/Groups/AI degrade to UnavailablePanel (no fabricated data).
31 tests, 0 errors in owned files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add useRovingTablist composable (ARIA APG roving tabindex), CellTabBar
(generic ARIA tablist), and 7 manifest-backed tab components: Overview,
Interfaces (ISP), Wiring (SVG infra flow), Inventory, Slices, Contracts,
Dependencies. All degrade gracefully for unavailable runtime data (BR-001).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ch 5 / T504)

- CellDetailView integrates CellTabBar + 12-tab registry; ?tab= deep-link,
  single live tabpanel (Audit/Config don't fetch while hidden), not-found state
- tabRegistry: single source of truth for tab order + id→component
- apps/web: /cells + /cells/:id routes (PDP read:cell, fail-closed), @gocell/devboard dep
- decouple tools/cell-manifest from packages/devboard/src (own types.ts; the
  generated file's CellManifest annotation guards drift at devboard typecheck)
- devboard README: exports + derived-manifest + boundary (no audit/config import)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… cleanup

Six-dimension review fixes (Cx1/Cx2):
- a11y/Vue BUG: WiringTab aria-label used {{ }} mustache in a static attr
  (rendered literal string) → bound :aria-label
- design BUG: undefined CSS vars --bg-elevated (5 tabs)→--bg-raised,
  --bg-subtle/--text-* (CellsListView)→--bg-sunken/literal px (silent breakage)
- design: non-token radii 6px→var(--r), 2px→var(--r-sm)
- a11y: tab bar automatic activation (Arrow keys select; roving home stays in
  sync) + aria-controls only on the active tab (single live tabpanel)
- a11y: role=group domain filter aria-label; cell-detail back :focus-visible;
  OverviewTab heading ids scoped by cell.id
- boundary: drop unused @gocell/access dep (PDP is route-level); add
  tools/cell-manifest/README
- ts: drop redundant cast in derive.ts; onActivate accepts | undefined
- i18n: +cells.list.domainFilterLabel, -unused cells.overview.activity

Declined (with reasoning, see PR): assertNever on role switch (conflicts with
intentional/tested unknown-role resilience in a YAML-reading build tool);
Component→ConcreteComponent (Component is the idiomatic registry type).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address the four deferred review findings. F5/F6 declines re-confirmed
correct and left unchanged (assertNever would crash on unknown YAML roles;
ConcreteComponent yields 9 typecheck errors on SFC values — Component is
correct).

F1 (Cx2): Audit/Config tabs re-fetched on every tab re-entry because the
single-live-tabpanel unmounts hidden tabs. Lift recent-entries to a
session cache in useCellsStore (load-once actions, retry-after-error);
tabs read from the store. Data is global (no per-cell filter — BR gap),
so a single cache with no per-cell keying. +2 reproduction tests.

F2 (Cx2): cells.generated.ts duplicated every cell object into both
`cells` and `byId` (O(2N)). Drop byId from CellManifest (type + generator),
derive a Map at runtime in the store. Generated file 2151 -> 1112 lines;
regeneration deterministic; contracts untouched.

F3 (Cx3, scoped): no font-size token ladder — components hard-coded px.
Add --text-xs..2xl to core tokens.css; migrate devboard's 68 declarations
to tokens (11.5->xs, 12.5->base snap, <=0.5px imperceptible). The other
packages' 178 declarations are a tracked follow-up (cross-cell sweep).

F4 (Cx1): InterfacesTab borrowed cells.overview.* keys cross-page
(violates the i18n key-per-page rule). Add cells.interfaces.fields.* in
both locales; swap the 5 borrows.

Refs PR #34
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…meout

The `test` workflow failed on every PR #34 commit (pre-existing, not from
the F1-F4 fixes) with `[vitest-worker]: Timeout calling "onTaskUpdate"`
while all 1173 tests passed.

Root cause: eslint.config.spec.ts drives the ESLint Node API (incl. the
type-aware TS engine) across 42 cases. Under v8 coverage instrumentation
each lint is ~12x slower (10s standalone -> 120s in the coverage run),
dominating wall-clock and blocking the worker for 8-18s stretches, which
starves the vitest reporter RPC (onTaskUpdate) -> unhandled error -> exit 1.

Fix: exclude the root boundary project from the coverage run
(test:coverage = `vitest run --coverage --project '!root'`) and run it as
its own fast, uninstrumented step (test:boundary = `vitest run --project
root`, wired into the CI job). The coverage run drops 122s -> ~9s and the
RPC timeout is gone; the Hard boundary enforcement self-check still runs on
every CI. Coverage was never meaningful for that spec (it is a test file,
already excluded from coverage include).

Refs PR #34
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lls)

六维度 review 后修复 P1/P2(均 Cx1/Cx2,限 devboard + core i18n):

- AuditTab/ConfigurationTab: empty 态补 role="status"(与 loading 一致);
  数据表补 aria-label;"打开完整页" 链接补 :focus-visible
- InventoryTab: 修表头错标(计数列原为 "Slices" → 改 metric/count 两列头);
  :key 改用稳定字段(弃翻译串);表补 aria-labelledby
- CellsListView: 分段控件 + 搜索框 min-height 30px(PRD btn 30px 基线);
  补 prefers-reduced-motion;empty padding 32→28px(pad 24–28 基线)
- CellTabBar: 补 prefers-reduced-motion
- WiringTab: 装配图标题 <p> → <h3> + aria-labelledby(heading 语义/层级)
- CellDurabilityBadge: line-height 18px → 1.4、gap 5px → 6px(token 一致性)
- CellDetailView: not-found padding 32→28px
- i18n: 新增 cells.{audit,configuration}.tableLabel、cells.inventory.{metric,count}(zh-CN + en-US)

Cx3 项(tabRegistry 懒加载、tool/devboard 双份 types.ts 的 Hard 化)留待人工决策,未在本次修复。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Batch 5] Operate · Cells(核心差异化)

1 participant