← Design · c138

fable-audit/README.md

The Fable `/live` gets main's Audit log

2026-11-12. Done in ../qcontrol/crates/qdash/ui on feat/new-pages, the Fable app behind PR qpoint-io/qcontrol#713. It is committed as d274b9306 (25 files, all under app/**/live and pages/live.vue) and pushed to feat/new-pages on 2026-11-13, so PR qpoint-io/qcontrol#713 carries it. Asked for in live-parity-plan.md under "Out of this plan": both sides of #713 changed the live files, so a merge with main would drop the Audit log unless it was carried across first.

The source. Main @ 8677b44ed. The Audit log arrived in one PR, #757. Later PRs (#765, #772, #787 and #835) changed only audit-events.ts.

What was carried

MainFable homeHow
lib/live/audit-events.ts + test (46 cases)same pathwhole, with a provenance line
composables/useLiveEvents.ts + test: two buffers, one entity indexcomposables/live/useLiveEvents.tswhole: the Fable copy was unchanged from the merge-base
lib/live/retention-settings.ts + test: per-view keys qdash.live.retention.v1 / qdash.audit.retention.v1same pathwhole
events.ts pluginPreview: reads data, falls back to payloadsame paththe one hunk, plus main's three plugin-data specs
EventTable.vue audit variantEventTable.vue, fed by lib/live/event-rows.ts liveAuditRowmain read auditField / auditSummary / auditMetadata / pidForEvent in the template; here the row carries audit: { activity, summary, metadata, decision, gap } and pid (bible R8)
EventDetail.vue categoriesOnlylib/live/event-context.ts detailContextParts(…, { categoriesOnly })the Type chip is evidence, not a filter
FilterPopover.vue categoriesOnly, right-anchored panelsameas main
RetentionControls.vue "Audit buffer" / "Event buffer"same, fed by composables/live/retention.ts useLiveRetention(isAudit)keyed by view, as main
live.vue: third tab, note, placeholder, tableEvents, tab-switch resetWorkspaceTabs, FilterBar, eventList.ts useLiveEventList(isAudit) (clearKinds on switch), selection.ts (tableEvents), live.vue (the note, close and jump on switch)page script 47 lines (R9 guide is 60)
live.vue banner: "N new audit entries", "Viewing older entries", "Jump to latest"; selecting no longer freezes the tailEventStream.vueas main
live.vue .live-details fixed overlay below xl; EventDetail resize handle xl-onlySplitPane.vue (a wrapper that is display: contents at xl)as main

Left out. Main's mobile page height (100dvh-5.5rem) and its .live-header wrap rules. They fit main's mobile shell, and the Fable default.vue has no md: breakpoint. auto_tap also stays: main removed it in #743, before the merge-base, and the Fable app re-gained it from the gen-2 UI. That removal is a separate cleanup.

Vocabulary. The Fable app's c92 word "Harness" is kept for the column, the rail and the chips. Main says "Agent".

Checks

  • npm test in crates/qdash/ui: 75 files, 658 / 658, and bible-check: clean.
  • No vue-tsc is installed in the tree, so no typecheck ran.
  • Browser checks on :3030 with sentinel-audit.jsonl. The fixture was made by make-sentinel-fixture.mjs: 26 events, 16 Sentinel rows in the screenshot's mix (http 7 · llm 6 · mcp 2 · file 1), from claude-cli pid 58638, with one inference denied by "Secret in prompt". What the browser showed:
    • The tabs read Events 26 · Tally 26 · Audit log 16.
    • Searching activity=Inference reproduces Mark's screenshot: four rows, one denied, with "Rules: Secret in prompt".
    • The Harness column hides once the detail narrows the table below 640 px.
    • The Type chip is disabled on audit rows.
    • Switching tabs closes the detail, clears the family filter and keeps the search.
    • The Events tab now previews Sentinel's data fields (model, method, authority, path).
    • Live mode shows "Event buffer" on Events and "Audit buffer" on the Audit log. The audit limit saves only under qdash.audit.retention.v1, and Reset clears it.
    • At 1100 px the detail opens as an overlay.

Captures

All captures are 1440 × 900 scaled to 800 px, except the overlay, which is 1100 px.

Files in qcontrol (mine, all under crates/qdash/ui/app)

  • New: lib/live/audit-events.ts, lib/live/audit-events.test.ts.
  • Modified:
    • components/live/: EventDetail, EventStream, EventTable, FilterBar, FilterPopover, RetentionControls, SplitPane, WorkspaceTabs;
    • composables/live/: eventList, retention, selection, stream, useLiveEvents (+ test);
    • lib/live/: event-context (+ test), event-rows (+ test), events (+ test), retention-settings (+ test);
    • pages/live.vue.

Other sessions' uncommitted work in the same tree is not mine and is left alone: crates/qdash/README.md, crates/qdash/ui/README.md, pages/compliance.vue, devenv.nix, crates/qdash/docs/how-it-works.md.

Qpoint Brand Style Guide