# Audit Bundle Feature โ€” Design Document **id 44 / operator-mavis | 2026-09-17 14:19 BST | session 418281651208440** ## STATE ๐ŸŸจ Direction decided: **1** (FreshCards UI primitives โ†’ HQ, not the other way). ๐ŸŸจ Home page decided: **Task Bundle cards replace current Overview** (per operator call 2026-09-17 11:22 BST). ๐ŸŸฆ Build plan proposed (A one-off today โ†’ B persistent feature ~1.5 days โ†’ C auto-trigger ~2h โ†’ D weekly digest ~2h). ๐ŸŸฅ Awaiting: operator signoff on bundle shape (after A demo) + choice of version-check mechanism (manual / Dependabot / cron / webhook). --- ## TL;DR One view per task. Prompt + all related bulletins + reports + artifacts + chat reply, audit-style sections, not chronological. Home page of the panel becomes the list of these bundles. Tap โ†’ 7-section detail page. Reuses FreshCards' chunked-card + property + view model so we're not reinventing UI. --- ## 1. The HQ Bulletin Problem (background) - Bulletin = **event reports**, NOT the full chat answer. - Chat reply lives only in this chat window on operator's phone. - HQ **captures**: bulletins (curated events), heartbeats (alive pings), reports (end-of-turn summaries), prompts (input text), artifacts (uploaded files). - HQ does **NOT** capture: thinking blocks, raw tool outputs, retries, the chat reply text (unless explicitly posted as report). ## 2. The Connection Mechanism - Prompts connect to bulletins via **thread_id** (loose grouping by Mavis). - Plans connect to bulletins via **ref_plan** (tight grouping by task). - SPA per-thread view shows prompt + activity for one Mavis. - Timeline tab shows activity across all Mavis threads, chronological. ## 3. The Audit Bundle Feature **Why** (operator-locked): G wants one view per task that bundles prompt + activity + summary, audit-style. Stops the "stitch 5 tabs in your head" pain. **Shape (audit-style, sections per concern)**: ``` 1. PROMPT โ€” text operator sent (hq_prompts row) 2. CONTEXT โ€” who triggered, state at the time (RULES version, branch, repo) 3. ACTIONS โ€” chronological list of every HQ event (bulletins + reports + heartbeats) 4. ARTIFACTS โ€” files uploaded with descriptions 5. CHAT REPLY โ€” agent's full response to the prompt (already posted as report) 6. VERIFICATION โ€” did it ship? push status, build status, deploy status 7. CONNECTIONS โ€” parent/child plans, blocks/blocked-by, follows ``` ## 4. Where It Lives (operator-locked) - **Home page** โ€” replaces current Overview. - Each card = one Task Bundle. - Status chip on the card (in-progress / done / blocked / needs-you). - State banner at top: "12 tasks ยท 3 in progress ยท 2 need you ยท 7 done (last 7 days)". - Old Overview moves to a "Mavis" or "Agents" tab (same content, just not the default). ## 5. Build Approach โ€” Direction 1 - Bring FreshCards UI primitives INTO HQ (not the other way). - Reuse: chunked cards, filter chips, modal/inspector pattern. - Don't reinvent โ€” lift what's already built. - One thing to figure out: data source. FreshCards uses PocketBase / IndexedDB; HQ uses panel.db (SQLite). Two options: - **A.** Read both โ€” FreshCards server queries PB + panel.db, joins in server. Cleanest from "single pane" view. ~half day. - **B.** Mirror โ€” small cron syncs audit data from panel.db โ†’ PB nightly. Cleaner architecture, sync window lag. ~half day. - **C.** Lift FreshCards UI components into HQ, render against panel.db only. Fastest. ~half day. ## 6. FreshCards Architecture (id 11 research summary) - Pure React SPA, IndexedDB-backed, schemaVersion 5.0.0. - **18 PropertyTypes + 4 ViewTypes** (storage.ts is the canonical registry). - **VGM build pattern**: version baked at build time via vite define block (4 globals: `__FC_VERSION__`, `__FC_SCHEMA__`, `__FC_HASH__`, `__FC_DEPLOYED_AT__`). Exposed as `/api/version.json` for runtime introspection. - Single source of truth: provider.ts and dist/api/version.json share the same computation path. - Service worker synthesizes stub `/api/encryption/*` responses; encryption is client-side. ## 7. Gallery Relationship (id 8 research) - Gallery imports FreshCards as `file:../freshcards` (workspace dependency). - Bridge file `registry-to-freshcards.ts` (11977 B) translates Gallery data into FreshCards property shapes. - Same chunked-card model, shared via import. - This is the closest existing example of the npm-dep pattern within the FreshVibe ecosystem. ## 8. Vibecoder Vendor Pattern (id 9 research) - Vibecoder vendors fv-cms into its build (chrome source now lives IN vibecoder-standalone, renamed from freshvibe-cms โ†’ fv-chrome). - Source has `FV-CHROME-VERSION.txt` (currently 2.0.0) + `FV-CHROME-MANIFEST.json` (423 files). - Vendored copies have `FV-CHROME-VENDORED v{version} โ€” DO NOT EDIT IN PLACE` marker. - `vendor-fv-cms.py` exists but is **currently broken** (re-vendoring with new files removes them via the "remove missing files" loop โ€” known bug). - Alternative: **npm dependency model** is cleaner. We have operational muscle memory for vendoring. - Old `freshvibe-cms` repo is deprecated, frozen at v1.4.1. ## 9. Module / Versioning / Dynamic-Update Pattern (operator question validation) **Operator's understanding โ€” what's right:** - โœ… FreshCards becomes a "module" โ€” a self-contained package that consumers import. - โœ… It's versioned (v1.0.0, v1.4.0, v2.0.0). - โœ… FreshCards repo is the canonical source โ€” single place where updates happen. - โœ… HQ is a downstream consumer that pulls it in. - โœ… Pull-the-module is much easier than the substrate alternative (substrate = separate process HQ talks to). **Operator's understanding โ€” slightly off:** - "Dynamically update it whenever updates appeared" is **not magic**. The actual flow: 1. FreshCards repo publishes new version (v1 โ†’ v2) 2. HQ's package.json gets updated to point at v2 3. HQ rebuilds + redeploys 4. Now HQ has the new FreshCards code - Step 2 can be manual / Dependabot / cron / webhook. **Step 3 (rebuild + redeploy) is ALWAYS required.** You can't pull new code into a running app without restarting it. **Operator's understanding โ€” missing pieces:** a) **FreshCards isn't a module YET.** It's currently a standalone React app. To make HQ import it, we'd first have to extract the reusable bits (chunked cards, property types, view types) into a separate package. **One-time refactor.** b) **Closest existing example:** Gallery already imports FreshCards as `file:../freshcards` (workspace dep). Pattern works, but only between sibling repos on the same machine. c) **Version-check mechanism** โ€” how does HQ know a new FreshCards version exists? Four options: - Manual (operator reads changelog, bumps HQ) - GitHub Dependabot (auto-creates PR when new version ships) - Cron on HQ (weekly check + bulletin if new version) - Webhook (FreshCards repo notifies HQ on release) d) **Compatibility contract** โ€” when FreshCards goes v1 โ†’ v2, if v2 is breaking, HQ's existing usage might break. Semver discipline matters. **Operator's understanding โ€” wrong about:** nothing. Just incomplete on the "how" of dynamic updates and on the extraction step. --- ## Build Plan | Phase | What | Effort | |---|---|---| | **A** | One-off collation today (demo bundle on a recent task, markdown output) | ~10 min | | **B** | Persistent feature (DB tables + endpoint + SPA route + new home page) | ~1-1.5 days | | **C** | Auto-trigger (after every report, post pointer bulletin to bundle URL) | ~2 hours | | **D** | Weekly digest (Sunday-night cron, one bulletin with week's audit links) | ~2 hours | **Cumulative**: A alone = today, A+B = 1.5 days, A+B+C = 2 days, A+B+C+D = 2.5 days. **Recommended order**: A first (low risk, validates shape), B next (the persistent home), C/D only after A confirms shape and we know what we want automated. --- ## Decisions Pending 1. **Bundle shape sign-off** โ€” wait until A demo is reviewed. 2. **Version-check mechanism** โ€” manual / Dependabot / cron / webhook. Pick before FreshCards extraction. 3. **FreshCards extraction scope** โ€” which props/views become the module API surface. ## Open Questions - Does FreshCards extraction happen as a separate dispatch, or bundled with B? - Where do chat replies get captured? Currently only in this chat window on operator's phone. Options: (a) require agents to post reply as report, (b) capture from chat window via some mechanism, (c) leave as-is and accept that "Chat Reply" section is sometimes empty. - Does the auto-trigger (C) need operator approval per bulletin, or fire automatic? - What's the policy on the old Overview tab โ€” keep with same content, or also refresh with new UI? --- ## Sandbox State - Sandbox identity: id 44 / operator-mavis / session 418281651208440 - RULES version: mavis-kits v1.3.0 - HQ token: present, HTTP 200 on `/api/mavis/bulletins` - GitHub egress: PASS - Files written this turn: - `/workspace/.plan/418281651208440-audit-bundle-design.md` (this document) - Bulletin: not posted yet โ€” design phase, awaiting operator go for A demo. - No commits, no pushes, no other files modified. --- [id44] | end PROMPT โ€” audit bundle feature design