Repository navigation
feat(devboard): Operate · Cells — list + 12-tab detail + manifest derivation (Batch 5 / T502–T506) - #34
Merged
Conversation
…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>
This was referenced Jun 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Batch 5 · Operate · Cells — the MVP's most complex page (~25%), built in
@gocell/devboard(previously an empty stub)./cellslist +/cells/:id12-tab inspector, all backed by a build-time manifest derived from the backendcell.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)
tools/cell-manifest/mirrorstools/codegen: purederive.ts+ IOindex.ts+ reverse-self-checkderive.spec.ts(26 tests incl. ai-robust §盲区自检 — unknown roles/waivers produce 0 false matches; determinism).packages/devboard/src/manifest/cells.generated.ts(/* eslint-disable */+ DO-NOT-EDIT banner, prettier-ignored). CI.github/workflows/cell-manifest-diff.ymlassertsgit status --porcelainclean → manual edits inexpressible.slice.yamlcontractUsages[].role:serve/publish→ produces,call/subscribe→ consumes; cross-cell consume→produce resolution yieldsdependsOnCells/requiredByCells. Derived for the 3 live cells (accesscore→configcore; auditcore→both; configcore→∅).types.ts); the generated file's: CellManifestannotation (from devboard's canonical./types) guards drift at@gocell/devboard typecheck.T503 —
/cellslistDemo/Durable badge, domain segmented filter + id/name search (
useCellsFilter), neutral tier chips. Keyboard-accessible row nav (<RouterLink>in first cell +aria-label, no@clickon<tr>),scope="col"headers.T504 —
/cells/:id12-tab inspector?tab=deep-link, single live tabpanel (Audit/Config don't fetch while hidden), unknown-id → accessible not-found.CellTabBar= ARIAtablist+useRovingTablist(Arrow/Home/End roving tabindex, APG).tabRegistryis 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/requestwith@gocell/contractstypes — never importing@gocell/audit/@gocell/config(cross-cell ban). loading/error/empty/data states + deep-link to the full pages. Tasks/Groups/AI tabs → honestUnavailablePanel(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: i18ncells.*block (zh-CN + en-US).apps/web:/cells+/cells/:idroutes (PDPread:cell, fail-closed) +@gocell/devboarddep.tools/cell-manifest(new) + CI workflow +yamlcatalog dep.packages/contracts/: not modified (consumed read-only; codegen diff verified clean).Backend gaps (ignored per directive — degraded, not faked)
GET /api/v1/admin/cellsUnavailablePanel"—", never fabricatedTest plan
pnpm -F @gocell/devboard test --run— 176 tests passpnpm -F @gocell/cell-manifest test --run— 26 tests (incl. reverse self-check + determinism)pnpm -w typecheck— clean (incl. en-USsatisfies 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/:idrouter assertions)pnpm -F @gocell/web build—/cells+/cells/:idemit separate lazy chunkspnpm codegen→git statusclean (contracts read-only)🤖 Generated with Claude Code