Reports
A time-windowed Reports section for qdash. It gives C-level people, auditors and others who see data but get no controls what the dashboard already shows, as documents they can hand on. The two categories are Security (Posture) and IT (Inventory, Deployment status). Every report reads one window: rolling, calendar or custom from–to, with a comparison period.
New in this cycle: The Compliance report
Why
qdash's /reports is a placeholder (DesignInProgress). The people who need to know how AI risk and rollout are trending don't work in the operator pages, and those pages don't agree on time:
- Findings and DLP follow the 7d pill.
- Posture, compliance and alerts are all-time.
Nothing offers a calendar period or a custom range. The problem registry's strongest reporting problem is "I can't hand my board or my auditor a report", recurring at Moto and Tiled.
Objective
Three things, mocked in the phase-4 lab, reviewed one at a time, then ported to qdash /reports:
- A Reports catalog.
- Three reports (Security · Posture, IT · Inventory, IT · Deployment status), each with one window in its header, and every section labelled in window, over window or as of.
- A reusable window picker: rolling, calendar and custom presets, compare, data-range edges, and the window in the URL.
Done also means:
- Print/PDF, CSV and JSON exports.
- The picker extracted to the layer.
- The backend gaps handed to Tyler:
from/to, history beyond 90 days, snapshots, sensor version and health.
Scope
- Cycle docs:
cycles/c128.reports/(plan, data inventory, thread files) - Lab mock:
app/pages/pages/phase4/mock/reports/(catalog and three reports)- the window picker's demo page
- a history extension to the lab world
- c78 pieces carried forward:
app/components/report/,app/data/report-fixtures.ts - Layer: the window picker (working name
UxTimeWindow), plus the report header if it stabilises - qdash:
pages/reports.vueand acomposables/reports/domain onfeat/new-pages, ported after review - Out:
- scheduled delivery and retained snapshots (recorded as follow-ons)
- c78's Board report
- framework evidence pages (c123)
Key Changes
- kick-off (2026-11-03):
- Cycle created from Mark's prompt.
- Two read passes:
- every qdash page's data and time handling
- the layer and design pieces for time, history and export, prior report cycles, and the problems and personas in market-analyst
data-inventory.mdmaps each candidate section to its source, time basis and gaps.plan.mdsets out rules R1–R6, decisions D1–D10, four clarifying questions and Phases 0–7.- Waiting on Mark's rulings before Phase 1.
- Uncommitted.
- answers (2026-11-03): Mark answered the four clarifying questions. Details are in
plan.mdunder Clarifying questions.- "Non-operator" is not a role. It means C-level and other people who see data but get no controls. Reports therefore hold no controls and must make sense on their own.
- Findings/SLA is a section of Posture.
- The Board report folds into the
/reportscatalog's top band: one sentence for the window, one highlight per report, and the trend in words. Its composite score is dropped. - History of 3–12 months comes when the backend is connected. The mock is designed for 12 months.
- rulings (2026-11-03): Mark ruled D1–D10. Details are in
plan.mdunder Decisions.- Defaults kept:
- the mock goes in the phase-4 lab
- rolling, calendar and custom windows, defaulting to the last 30 days
- compare with the previous period
- scope is the org, with an optional Team
- print/PDF, CSV and JSON this cycle
- c78 closes into c128
- the org's timezone
- D5 overturned: the window is shared with the global
when:pill, not separate. The picker becomes the pill's panel in the layerFilterand in qdashuseGlobalFilter, and every operator page has to take any window. The backend needsfrom/tofor every page. - Shared default: 30 days everywhere (Mark). qdash
DEFAULT_PERIODmoves from7dto30dat the port.
- Defaults kept:
- downloads move to Reports (2026-11-03): Mark ruled that downloads and reports are handled in Reports now.
- The "Forensic why-trail & evidence export — preview" panel is gone from the lab's Compliance page (
phase4/mock/compliance.vue), along with the subtitle's evidence-export sentence.GovernanceLiveComplianceEvidenceExportstays in the tree, unused, as the source for Phase 4. - At Mark's word, the panel is also out of qdash
/compliance(crates/qdash/ui/app/pages/compliance.vueonfeat/new-pages), along with the same subtitle sentence and the unuseddownloadbinding.- Checks:
npm run checkis clean, and vitest passes 593/593.:3030/compliancerenders with no console errors and no export panel. components/compliance/EvidenceExport.vueanduseCompliance().downloadstay in the tree, unused, as the source for the Reports port.- Until Reports ships, findings JSON/CSV can still be downloaded from the findings export card on
/integrations. - qdash is uncommitted.
- Checks:
- The old phase-0 mock
/pages/compliance.vueis left as an archive. - c123's X4 (merging the two evidence exports) now lands in Reports.
- The "Forensic why-trail & evidence export — preview" panel is gone from the lab's Compliance page (
- Phase 1, window picker (2026-11-03): the picker is built design-local, and its demo is at
/pages/phase4/time-window(a new Reports section on the Phase 4 index).- Model:
app/utils/time-window.tsis pure, with no Vue. Spec → resolved civil dates in the org timezone, plus compare, coverage, labels and URL encoding.- The defaults (30d, previous period) are left out of the URL, so the old
?period=7dstill reads. scripts/c128-time-window-check.mtsholds 9 checks: rolling, calendar, to-date compare, the month-end clip, coverage, the year compare, custom ranges, the year boundary, the URL round trip and the org-timezone anchor. All pass.
- The defaults (30d, previous period) are left out of the URL, so the old
- Parts:
app/components/time-window/holds Calendar, Panel, Popover, Pill (thewhen:pill, with FilterItem's chrome) and Line (the report header line).app/composables/useTimeWindow.tskeeps the window in the URL or locally. - Demo:
- One URL-synced window drives both the pill and a report line.
- The panel is laid flat across seven worlds: 90 days, 12 months kept, 16 months kept, fresh install, before the data, across the new year, month to date.
- A table shows every preset resolved.
- Calls made:
- Last 24 hours and All time stay in the presets, because the window is shared and operators had them.
- Presets apply in one click; a custom range and a compare change wait for Apply.
- A to-date period compares with the same days of the period before (Nov 1–2 vs Oct 1–2).
- A year compare the data can't support falls back to the previous period.
- The compare button reads "A year earlier".
- Finding for Tyler: with exactly 12 months of retention, same-period-last-year is never available. The year before any window starts before the data. Comparing Q3 with the Q3 before needs about 16 months. This pulls against Mark's 3–12 months.
- Checked in the browser:
- presets, the custom pick, Apply, URL sync, and every scenario's text
- dark and light themes
- phone width: the panel fits at 343px, and the calendar shows the month the window ends in
- no console errors
The design site's own nav still overflows at 375px. That was already true before this cycle, and it widens the emulated layout. - Gotcha: functions imported from
~/utils/time-windowand used only in a template were dropped from the compiled<script setup>("$setup.isBakeable is not a function"). They are now read through local bindings (fmtDay,bakeable). - Uncommitted. Mark's review is next, then Phase 2 (chassis and catalog).
- Model:
- Phase 2, chassis and catalog (2026-11-03, started on Mark's word): Reports now has pages in the lab shell: the catalog at
/pages/phase4/mock/reportsand the three reports at/reports/posture,/reports/inventoryand/reports/deployment.- The report world (
app/data/reports-c128.ts) holds twelve months of daily history (Oct 30, 2025 to Oct 29, 2026) that ends on the lab's present, so a report agrees with the page behind it (R3).- The last 30 days of spend are the cost tour's ledger to the dollar: $5,865, Home's window.
- The fleet ends at Home's 100 hosts: 97 fully monitored, 3 partial, 0 unmonitored.
- The harnesses and models come from the ledger; the MCP servers are the lab's listing.
- Before that the history is generated and seeded, so it's the same on every load: a rollout from 8 to 100 hosts, posture 53 → 78 with a March dip and the Oct 21 eval-run dip, 571 findings with fix times by severity (SLA targets are c78's placeholders: 7, 30, 90 and 180 days), and
first_seendates for inventory. - Readers implement R2: flows sum in the window, states read at its end, trends span its days. Days before history begins come back null (R6).
- Specs and readers (
app/data/reports-c128-specs.ts):- Each report's sections carry a question, a time basis, a qdash source and a status: live, staged or missing.
- The readers produce the lede sentence, the lead metric with its change, the spark, the trend in words, the worst line and the facts.
- The catalog card, the Board band and the report verdict all read the same reader.
- Chassis parts (
app/components/reports/):- BasisTag: "in window", "over the window" or "as of Oct 29". It reads "current state" in amber when the window ends before the data does, since there are no snapshots yet.
- Section: title, question, tag, staged or "not in qdash yet", and the source line.
- Verdict: sentence, then number and change, spark, trend words and facts. Sparks are scaled to the window's own range.
- Footer: window, data through, timezone, generated, and the read-only note.
- Card: c78's mini-doc briefing, its provisional lean.
- SummaryBand: the Board fold-in. One derived sentence, three highlights, and the trend in words; no composite score.
- The catalog has the shared
when:pill, the Board band, then Security (Posture) and IT (Inventory, Deployment status). Links carry the window. - A report page has the breadcrumb title, Print/PDF and CSV·JSON stubs (Phase 4), the window line, the verdict, every section with a few real figures where the reader has them ("Phase 3 draws this section"), and the footer. A window with no data shows the window line's reason and the report's outline, with no sections.
- Checked in the browser:
- the catalog, all three reports, Q3 on Posture (76 ▲ 4 vs Q2, "current state" tags), year to date on Deployment (85 → 100%, no year-earlier data so no change), and a window before the data
- the spend matches Home
- light and dark themes
- no console errors
- Lab-wide, not changed here: the lab shell's rail doesn't collapse at phone width, and it highlights only exact paths, so Reports isn't lit on a report page.
- Uncommitted. Next is Phase 3: Posture first, one report at a time, preview → build → Mark's review.
- The report world (
- Phase 3 · Posture (2026-11-03, on Mark's word): all eight Posture sections are drawn, in
app/components/reports/posture/Body.vue. It is mounted from/reports/posture, while the other two reports keep the Phase 2 outline.- Posture score:
ReportsLineChartdraws one point a day with the comparison window as a dashed ghost aligned day for day (the c103 F6 idea). Days before the data are hatched. Start, end, low and high are shown with their dates. - What lowers the score: points lost by factor. They sum to 100 − 78, the state today.
- Critical and at-risk harnesses: installs under 80 with person, endpoint and top factor.
- Findings and SLA:
- the auditor's table by severity: target, opened (with its change), resolved, open at end, past target
- opened and resolved per day
- a past-target list on the window's last day, worst severity first, then oldest
- Data protection: sensitive opens and secrets in content against the comparison, split by kind.
- Egress: allowed, observed only and blocked. Blocks begin in July, when enforcement began, and a sentence explains the split. Risky destinations are listed.
- Policies in force: counts by mode and the mode changes in the window, read from the lab's governance world, so they match /policies.
- Framework evidence: counts by state for the tracked frameworks, with no % (c123). Read from the lab world, linking to Compliance.
- World extension (
reports-c128.ts, on its own seed so the Phase 2 numbers didn't move):POSTURE_FACTORS,AT_RISK,GUARD_DAYS(DLP and egress per day), splits, finding titles and harnesses,pastTargetAt,findingsPerDay. - Checked in the browser: last 30 days, Q3, all time, 24h with no comparison, and a custom range that starts before the data (hatched, comparison shown as —). No console errors.
- Uncommitted. Mark's review of Posture is next, then Deployment status, then Inventory.
- Posture score:
- deploy (2026-11-03): deployed live at Mark's word ("it's all our lab").
- What shipped:
npm run deploy→ deployd39dd67b12, built from designc400dd2afewith 23 uncommitted paths included: all of c128 plus other sessions' lab edits. Layer 0.9.37. 6,258 routes prerendered in 1,023 s. - The first attempt collided with another session's deploy over
.nuxt-deployand aborted at cleanup. That other deploy never published. - Checked live on design-f39.pages.dev:
/pages/phase4/mock/reports/and the posture, deployment and inventory reports, plus/pages/phase4/time-window/, all return 200. Posture on?period=last-quarterrenders (76 ▲ 4). - The slow build came from the prerender crawler following about 19k query-string lab URLs. c129 fixed that (build 17.5 → about 4 min) and deployed again as
bd48264c3e, built from0a2cb25691plus the same uncommitted paths, so c128 stays live.
- What shipped:
- histories (2026-11-04): at Mark's word, the histories caught up with the deploy.
- c128 has a story and pickup (
app/data/cycle-stories-survey/c128.json). c78's story now reads closed into c128, with its pickup removed. - Archived cycles no longer show the c124 audit's "ready to close" note, on the story page or in the explorer (
StoryView.vue,cycle-stories-mock.ts). The audit is dated, so anything closed after it was still being told to close. - c128 stays out of HISTORY.md because it's still active. c78's entry is there. Both are uncommitted.
- c78 closed into c128: its Outcome is written, it has a HISTORY entry, and it's off CYCLES.md. It has no captures.
- Uncommitted.
- c128 has a story and pickup (
- intents PR 5 and PR 6 (2026-11-05): c123's thread
intents-pr5evaluated both against Reports: evaluation, plan, Phase 6. PR 5 (merged) changes the Framework evidence section. PR 6 (open) would replace the three live reports with four generated PDFs and overturn three 2026-11-03 rulings, so that part waits on Mark. PR 6 merged the same day, and Mark ruled: PR 6's four reports (Inventory, Findings, Compliance, Executive Summary) replace our three, as living pages rather than generated PDFs. That reverses this cycle's rulings that Findings is a section of Posture and that the Board folds into the catalog. The work is in the plan's Phase 6, framework section first. - Four living reports (2026-11-05): built from c123's thread
intents-pr5, on PR 6's questions. Inventory (reports/inventory/Body.vue), Findings, Compliance and Executive Summary replace Posture, Inventory and Deployment status; the old URLs read the report their content moved to. R1–R6 hold.- Findings read the lab's own 22 (
data/reports-c128-findings.ts; Mark, 2026-11-05), with their real team, policy, outcome, reopens and reasons, so a report agrees with the pages (R3). The seeded 571 are gone. SLA goes, replaced by mean time to resolve on PR 6's definition. - Data protection and Egress stay, inside Findings (Mark, beyond PR 6). Their data is still seeded.
- Compliance reads c123's
enforcementPosture,exceptionsReadandpostureHistory, and never adds frameworks together. Compliance Score stays out. - Enforce-pilot candidates (
reports/Pilots.vue) are rule-based and show their evidence, or say why there are none. - A Team filter on every report, and Download PDF as a print of the page. CSV, JSON and the evidence pack are out for v1.
- The Board band left the catalog for the Executive Summary. Posture's own body and the summary band are deleted.
- Open calls are in c123's
intents-pr5-review.md.
- Findings read the lab's own 22 (
Visual record
10 captures — heroes, page slices, and full-page renders. Click to view.









