feat(dashboard): usage source-health parity, host-card cleanup, and opt-in runtime debug - #120
Merged
Conversation
…pt-in runtime debug
ADR-0023's sourceHealth field covered only the two secondary/corrective local
sources (OpenCode's SQLite store, Codex's thread ledger) and never the primary
Claude/Codex transcript roots themselves — an unreadable or missing
~/.claude/projects or ~/.codex/sessions still silently read as an ordinary
empty result, the exact failure class ADR-0023 exists to close, just left
open on the two sources every installation actually depends on. Verified the
fix is grounded, not invented: Anthropic documents the Claude transcript path
directly (Data usage page, hooks' transcript_path field); Codex's rollout
directory is real and load-bearing for `codex resume`; the Codex ledger and
OpenCode's db are real but undocumented internals, confirmed only via their
own upstream bug trackers.
Also traced and fixed a related Observability gap: runtime process discovery
had no way to explain "why didn't this controller show up" short of reading
source, and the Usage "by host" panel had drifted from a two-host binary
(claude vs codex) to three supported hosts without adjusting its layout or
labeling.
* Usage source-health parity (ADR-0023 §7)
- usage-index.mjs: new rootHealth() reports ok/absent/degraded for the
Claude and Codex transcript roots, with fs error codes (ENOENT, EACCES,
ENOTDIR) as the bounded reason — same vocabulary already used for
OpenCode/codexLedger.
- sourceHealth now carries all four fields: claude, codex, opencode,
codexLedger.
- Dashboard renders by HOST, not by field: three chips for three hosts.
Codex's chip folds its transcript-root and thread-ledger statuses
together (worse status leads, both sub-statuses stay visible in the
chip's detail text) instead of appearing as a fourth, confusingly
"duplicate" Codex entry.
- Tests: root-health ok/absent/degraded (including an unreadable-root
ENOTDIR case) in usage-index.test.mjs; updated dashboard.test.cjs
fixtures/assertions for the new grouping.
* Usage "by host" panel cleanup
- All three hosts (claude/codex/opencode) always render, grayed out via
the existing .idle styling when a host has no sessions in the window —
never hidden based on whether `ak setup --<host>` was ever run. The
scorecard reflects observed transcript evidence, not inferred setup
state.
- Cards now fit one row (.pcard min-width 190px -> 130px) instead of
wrapping OpenCode onto its own row.
- Replaced the static, now-inaccurate "claude vs codex" label with a live
"N active of 3" count.
- OpenCode gets its own dot color (purple) instead of silently sharing
Claude's orange.
* Opt-in runtime discovery debug flag
- process-sessions.mjs: AK_RUNTIME_DEBUG=1 traces the controller-discovery
pipeline stage by stage (survey row count, per-PID host classification,
nested-child exclusions, cwd resolution, final result count) to
$XDG_STATE_HOME/agentic-kit/runtime-debug.log.
- Mirrors the existing AK_STATUSLINE_DEBUG contract: off by default,
owner-only 0600, bounded/reset at 64 KiB, diagnostic failures can never
break discovery. Narrower redaction than the statusline diagnostic by
necessity: raw argv/command strings are still never logged, but cwd
paths are, since resolving "why didn't project X show up" is the flag's
entire purpose and a local directory path isn't a secret.
- AK_RUNTIME_DEBUG_FILE overrides the log path (test/operator seam).
- Tests: opt-in gating, stage coverage, argv redaction, owner-only mode,
and unwritable-sink safety in live-process-sessions.test.mjs.
* Docs
- ADR-0023: updated §7 (host-grouped chip rationale, grounding citations)
and §5 (AK_RUNTIME_DEBUG), update note, Consequences, References.
- USAGE-SCORECARD-METRICS.md, TROUBLESHOOTING.md, adr/README.md synced to
the four-field/three-chip model and the new debug flag.
- TRANSCRIPTS.md / USAGE-SCORECARD-METRICS.md: re-anchored file:line
citations that drifted from the usage-index.mjs edits (verified against
tests/kit/doc-citations.test.mjs).
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
sourceHealthcovered only the two secondary/corrective sources (OpenCode's SQLite store, Codex's thread ledger) and never the primary Claude/Codex transcript roots — an unreadable~/.claude/projectsor~/.codex/sessionsstill silently read as an ordinary empty result. NewrootHealth()closes that gap with the sameok/absent/degradedvocabulary (fs error codes as the bounded reason). Verified grounded, not invented: Anthropic documents the Claude transcript path directly; Codex's ledger and OpenCode's db are real but undocumented internals, confirmed via their own upstream bug trackers.AK_RUNTIME_DEBUG=1traces controller discovery stage-by-stage to a bounded, owner-only log — mirrors the existingAK_STATUSLINE_DEBUGcontract, built to debug an Observability gap (a live controller process not surfacing) without needing print-debugging every time it recurs.Test plan
pnpm run check(typecheck + lint + markdown lint + build + full test suite) passes locallytests/kit/usage-index.test.mjs(root-health ok/absent/degraded incl. ENOTDIR),tests/kit/live-process-sessions.test.mjs(debug flag opt-in/redaction/unwritable-sink),tests/dashboard.test.cjs(grouped-chip fixtures)🤖 Generated with Claude Code