← Cycles
Design · c114

Governance Phase II

activethe lab carries c118 and c121; product-session decisions recorded in the Outcome 2026-10-26; `object-model.md` still describes 2026-10-09created 2026-10-09· last activity 2026-11-05· mode: archaeology (the model is already in the intents, the c64/c65/c79 mocks and the live qdash pages; surface it) → assemblage (compose those pieces into one dashboard)

Build the Phase II governance dashboard for qdash around the object model the `../intents` repo describes, so that Findings, Policies, Scope, Groups, Exceptions, Enforcement and Frameworks appear as one coherent system rather than fourteen features

New in this cycle: S1 Finding detail on the fixture world: evidence above the line, the organ below, Respond with reach; Ignore and Create exception live

Why

Mark Peterson's qpoint-io/intents repo (fourteen Observe/Enforce intents, two PRs merged 2026-10-09) is the Plan-stage artifact of the AI-native SDLC playbook: the "what and why" of the governance surface, upstream of spec and implementation. Read together they are not fourteen features. They are one object model with one invariant repeated in every file: historical evidence is immutable, current state is mutable, and every state change records who, when and which policy change caused it.

qdash today has /findings, /policies, /compliance and /framework built on an older vocabulary (Control, pack, workflow status) that predates the intents. The design site has three earlier passes at the same territory (c64 control center, c65 policy catalog and config shapes, c79 finding lifecycle) that were never reconciled. Phase II is the moment to reconcile them: form the model first, then let every page be a view onto it.

This is the methodology applied directly. Design is assemblage; the first formative step is identifying the pieces. The intents name the pieces. The work is composition.

Objective

  1. One object model, written down, that the intents, qdash and the design site all agree on: objects, relationships, lifecycle states, what is stored versus derived, and the vocabulary crosswalk from the intents' terms to qdash's.
  2. One fixture world (the Vanta MCP story every intent uses, plus the OWASP LLM02 and Finance/Engineering group stories) that every mock renders, so the model can be felt before it is built.
  3. A surface map: every object has one home, every relationship one traversal, every state change renders through one lifecycle-history organ. Navigation under Govern settled.
  4. Mocks on the design site for the eight surfaces the intents imply, each with empty/minimal/typical/overflow states and captures, reviewed one at a time.
  5. The three gating decisions (scope precedence, re-evaluation triggers, proof of enforcement) ruled and written back to the intents repo, with the missing Exceptions intent drafted.
  6. Port to qdash feat/new-pages after Mark's picks, with layer extractions, contract types and a backend gap list for engineering.

Done = a practitioner can walk the Vanta story end to end on qdash (session → finding → policy → scope change → re-evaluation → resolved with cause) and every screen on the way uses the same words for the same things.

Scope

  • ../intents: read-only source; feedback goes back as a PR or issue (open questions answered, Exceptions intent).
  • Design: this record, plan.md, object-model.md, app/data/governance-fixture.ts, a _meta model page, mocks under app/pages/pages/ (registry phase to be named), captures.
  • Layer: extractions as they graduate (lifecycle history, recommended-vs-configured severity, coverage state, scope path, change preview).
  • qdash feat/new-pages: port after review; types/api/ grows Policy, Scope, PolicyGroup, Exception, Resolution, FindingEvent.
  • market-analyst: problem:findings-resolution-workflow, problem:safe-to-enforce, problem:unreviewed-mcp-surface, problem:personal-vs-enterprise-accounts, problem:unsanctioned-external-services, problem:prove-posture-over-time, problem:fleet-scale-compliance-state.
  • Plan: plan.md

Key Changes

kick-off (2026-10-09): the playbook thread became this cycle (initial-prompt.md). Read all fourteen intents plus README; grounded against qdash's current contract types (Finding, FindingWorkflow, Control), its four governance pages and seven API routes, the design site's c64/c65/c79 mocks, the layer's security/compliance/data parts, and seven matching problems in the registry. Plan written with six phases (plan.md).

rulings (2026-10-09): D1–D6 ruled in conversation (CSS specificity, forward-only re-evaluation that can reopen, two enforcement states, the intents' words, all eight mocks, design leads).

Phase 0 (2026-10-09): object-model.md written: the invariant, the chain, eleven objects with stored/derived split, relationship table, five lifecycles, what each ruling does to the model, the fixture world (three stories from the intents' own examples), the crosswalk (intents ↔ qdash contract ↔ design-site mocks ↔ layer), seven gaps for the intents repo, and the Source note mapping intents to seven registry problems. Awaiting Mark's read and Mark Peterson's "that is what I meant."

Phase 1 (2026-10-09): the model on a page. app/data/governance-fixture.ts (the three stories as one world; pure functions applicability() for D1, foldFinding() over append-only FindingEvents, applyChange() + re-evaluation for D2/D3, coverage() for frameworks; rulings are inputs, RULED the defaults) and /pages/phase4/governance-model (rulings as switches, the chain with live counts, ten object cards stored-vs-derived, the Vanta story run to its end in seven frames, the lifecycle organ, the effective-policies probe, derived coverage). Verified in the browser: the story reaches its end under every ruling and the alternatives differ where the intents say they should (broad wins: the Team A exception loses and A is only resolved by enforcement; manual only: A waits for a person; config is proof: B resolves on publish). Three captures via scripts/shot-programs/c114-governance-model.json (ruled, d1=broad-wins, d3=config-is-proof), subject page/governance-model. Registered in page-registry.ts under collapse c114-governance; moved from _meta to the new Phase 4 the same afternoon (D7) with a Phase 4 index and a card on /pages, and recaptured at the new route. Committed as d84d131ac.

Phase 2 (2026-10-09): the surface map. surface-map.md: homes (one per object; Scope, Enforcement, Exceptions and Change deliberately not pages), traversals (one per relationship), the intents × surfaces matrix (every intent has one primary surface; re-evaluation shows as organ rows and preview counts), the Govern rail proposal (Findings · Policies & Frameworks with Policies / Frameworks / Groups views; /compliance redirects), the eight surfaces as blocks with what carries over, what is new and the four states each mock renders, the organ's placement, the five-question check per surface, and the open questions the mocks will settle. Rendered as grey boxes at /pages/phase4/governance-wireframes (registry governance-wireframes, captured as c114-governance-wireframes). Committed as 2465c12c8.

Phase 3 · S1 Finding detail (2026-10-09): /pages/phase4/finding-detail on the fixture world at the story's end, four states by ?findingId= (F-A typical · F-S01 minimal · F-S04 overflow · F-NOPE unknown). Blocks per surface-map.md: crumb + header with Resolve ▾, the band, What happened (sunken, immutable), Why it violates (computed: paths, exceptions considered, still a violation now), the lifecycle organ, related findings, the Respond aside with derived reach. Ignore (required duration, the blank-reason warning with Confirm / Cancel / Don't ask again, then Done / Create an exception) and Create exception (scope picker with specificity, derived preview, re-evaluation) act for real against a page-local world; verified in the browser on F-S04: the organ gained its rows, the finding went Resolved: ignore, then the exception made it Allowed and "still a violation" turned no. Fixture gained the overflow history (F-S04: two Ignores, expiry, revoke, Enforced, reopen on CH-G1, a third Ignore revoked) and a Team GRC observe entry. Four captures. S1 reuse inventory in surface-map.md §5. Lesson: the design dev server served a stale transform of the new page (no edit after creation reached it; an unchanged touch nuxt.config.ts did nothing; a real one-line config change restarted it in place and fixed it, reverted after). Committed as b9b7e3f14.

Phase 3 · S2 Findings (2026-10-09): /pages/phase4/findings from the live listing's pieces per the D8 inventory: the four severity cards (past SLA fourth), the filter bar on URL state (?status=&sev=&fw=&policy=&team=&q=&view=), group rows per policy (severity tag with ink while open, ribbon, severity cells, harness pills, framework tags, sorters) with the policy section and the member rows on expand, and the adjudication card (subject · applies via · clock with Ignore / Create exception / Block, evidence beside the lifecycle) with Ignore live. Changed: Open and Resolved as independent toggles (Open default), Grouped ⇄ Individual on the ink switch, the group header linking to the policy, a status / resolution column and a last-event cell, the finding id linking to S1; the handling select retired; groups with nothing under the filters disappear and the page says how many. Fixture gained frameworksFor, the c79 SLA clock (slaClock, SLA_RUBRIC) and withOverflow (400 deterministic findings). Seven captures: default, with-resolved, individual, filtered, empty, overflow, expanded (group open, first member's card). Verified in the browser: expand, the card, the Ignore warning and Confirm (the row leaves the Open view and returns under Resolved). Committed as 5429239a2; deployed the same afternoon.

Phase 3 · S3 Policy detail (2026-10-09): /pages/phase4/policy-detail, four states by ?policyId= (P-MCP typical · P-SENS-SANITIZE rich · P-TRANSPORT applied nowhere · P-NOPE unknown). The layer shell's header, meta strip and condition disclosure copied where they fit (its Exceptions block is not seated: old scope words, no resource; a slot is the layer follow-up); beneath: Definition, Severity as the recommended / configured pair with Set and Reset (live), Where it applies as scope paths with specificity, enforcement at each scope, population, overlap and conflict callouts and the effective-for-a-person probe, Enforcement per scope with reach and observe-first guidance, Exceptions (resource · scope · reason · until · by · revoke), Groups, Frameworks as mapped requirements, Findings, History as the organ. Every section tagged with its delivery phase (Mark Peterson's 2 Foundation / 3 Organization / 4 Applicability). The change sheet is S6 and S8b drawn in place: add / remove scope, enforce / observe per scope, add / revoke exception; previewChange() dry-runs the change on a clone and reports population, reach (broadens / narrows), duplicate paths, equal-specificity conflicts (apply blocked until resolved), findings that resolve / reopen / resolve as Enforced, and the observe-first counts; the audit line shows the History row it adds. Fixture: why · fails · rule on every policy, P-TRANSPORT (no scope), scope-add / scope-remove changes, scopeRows, overlaps, policyHistory, previewChange, scopeValues. Five captures including the sheet open. Verified in the browser: the sheet's preview and apply (Team: Legal added, History row), severity Reset, the Enforce and Create exception previews. Committed as 5a797bbb8.

Phase 3 · S4 Policies & Frameworks (2026-10-09): /pages/phase4/policies, one area with three views on the ink switch (?view=policies|frameworks|groups). Policies: the Control Center's category sections and rows kept (D8); severity as effective with the recommended value and an inline Reset (live); the activation toggle replaced by an Applies column (organization-wide · N groups · Not in scope) with the enforcement summary; framework tags; open findings → S2; group by Category ⇄ Policy Group (then "Not in any group"); chips for severity, capability, in scope, framework; search. Frameworks: the Compliance listing's row kept; one list with Tracked (live, changes no policy); derived coverage counts per framework; open findings through mapped policies. Groups: S7's list (policies · scope with population · state · enforcement summary · open; New group, Duplicate as seams). Fixture: tracked on Framework, framework-track change, applicabilitySummary, withManyPolicies (the 69-policy overflow). Seven captures. Verified in the browser: Reset clears the override, group-by shows the four groups then the ungrouped, Track flips ISO to Tracked. Committed as 81a127765.

Phase 3 · S5 Framework detail (2026-10-09): /pages/phase4/framework-detail, five states (?frameworkId=owasp-llm typical · iso-27001 untracked · soc2 no mapped policies · iso-27001&state=overflow 93 controls · NOPE). Mark's steer: the earlier framework page (qdash /framework, c56 mock) is the starting point, the new phase takes precedence. Kept from it: the title row, the table shape, all ten OWASP risks with their fit notes (Requirement.note, shown beneath the state), and its satisfying controls, which the catalog now carries as ten policies (nineteen total; P-PROVENANCE and P-SPEND left unassigned, so three policies read Not in scope). Changed: Activate → Track (changes no policy, live); the hand-set addressability dot → the derived coverage state; one controls cell → capability · configuration · findings as three cells; added the gap-reason column, the summary band, the Gaps list never hidden, coverage filter chips, the "What coverage means" disclosure and the risk-taxonomy caveat; retired the per-control toggles, Activate all, the progress bar. Fixture: sourceTerm and description on Framework, SOC 2 (no mappings), gapReasons, withManyRequirements. Five captures; S4 captions and copy updated for the larger catalog. Lesson: the two-day-old dev server was serving stale transforms and the machine was at load 10 from Spotlight and fseventsd; Mark restarted the server (fresh process picks up new pages without a nudge). Committed as 1fbc18f78.

Phase 3 · S7 Policy Group (2026-10-09): /pages/phase4/policy-groups, four states (?groupId=G-ENG typical · G-DRAFT draft · G-OLD retired · G-NOPE). Header with the state pill and Duplicate · Activate / Retire / Re-enable; the band; Scope with the change sheet (S6 reused); Policies as references with severity, capability, enforcement in this scope, open in scope and "also in", Add from the catalog and remove per row; Overlaps naming every other active group that shares people, the shared policies and any equal-specificity enforcement conflict, plus the effective-policies probe with this group's policies in bold; History as the organ. The sheet previews population, re-evaluation and conflicts for scope, membership, state and duplicate; Duplicate creates a draft referencing the same policies and opens it. Fixture: draft state, createdAt / createdBy, G-DRAFT and G-OLD, the group-change record (create · scope · policyIds · state) in applyChange, four group history rows. Five captures. Verified in the browser: the scope preview, adding Restricted file access (policies 4 → 5, History row), Duplicate opening the new draft, Activate flipping it active. Committed as 04ddb4cab; deployed (live record 2026-10-09T21:33Z, all eight Phase 4 pages).

fixture · reach per device (2026-10-09): the S7 sheet surfaced that the four open sanitization findings sat under organisation-wide enforcement already confirmed on every device, so any change touching the policy previewed them resolving as Enforced. D3 is now per device: EnforcementState.reach.pending names the devices enforcement has not reached, and applicability() returns configured (with pendingDevice) for a subject on one of them. The sanitization enforcement is confirmed on 97 of 100 with the three devices behind F-S01..F-S03 pending; those findings read Open · pending, S1 says "not yet on mac-eng-07", S3's Findings block counts 3 pending, and the group sheet previews no Enforced resolutions. Captions updated; every shot recaptured. Committed as 0f5cbcb66.

Phase 4 · the review walk (2026-10-09): /pages/phase4/review-walk reads app/data/c114-review.ts (eight stops in dependency order: where to look with every state linked, what to look for, the captures by subject from the atlas manifest, and the questions each mock raises with what it does today; cross-cutting questions on the delivery phasing and the model; the rulings so far and Mark Peterson's delivery phases up top; progress counted from rulings). Rulings are recorded in the data file and in Decisions here as they land, so the page is the living review record. Thirty-five questions open at the start. Committed as eac972b12; deployed (live record 2026-10-09T21:58Z).

parked for the weekend (2026-10-09): PICKUP.md written; the walk resumes Monday 2026-10-12 with a fresh agent. Ten c114 commits today, all deployed; nothing of the cycle's uncommitted.

composed mocks · the harness (2026-10-14): Mark: "similar to phase 3, we're going to be building composed mocks starting with finding details" (prompt · plan), then "I haven't provided any direction, so just build the 'harness' for now".

  • What was built:
    • c100's Stage 3 workspace for Governance: /pages/phase4/mock (index of the surfaces, composed or not), /mock/finding-detail (S1: the shell, the shared world and the finding the URL names; nothing composed) and /mock/parts (an empty parts bin).
    • Shell: layouts/governance-mock.vue with GovernanceMockSidebar, which mirrors qdash's current rail (MONITOR · GOVERN + SECURE · ADMIN, EXP hidden, Inventory / Organization as disclosures; an item links only when its surface has a mock; exact-match lighting, as in qdash). The MOCK bar GovernanceMockBar carries finding (F-A · F-S01 · F-S04 · F-NOPE), delivery phase (2 · 3 · 4), show parts, reset world and the parts bin.
    • World: useGovernanceMock() holds the fixture at the story's end in useState, so changes persist across mocks until reset. It exposes act() (applyChange under RULED), finding (folded), all and to() (links keep findingId / dp / parts).
    • Manifest: app/data/governance-parts.ts (SURFACES, PARTS = []).
    • Reused unedited from c100: LandingMockSlot, useSlotVariant.
    • Registry: three phase4 entries. The Phase 4 index has a "Composed mocks" section.
  • Verified in the browser: the knobs write the URL, F-NOPE renders the honest absence, the disclosure opens, links carry the knobs, and there are no console errors. act() / reset are not exercised until a part acts.
  • The S1 slot and variant table in mocks-plan.md is a proposal awaiting Mark's direction. Uncommitted.

S1 in Illustrator (2026-10-14): Mark wanted the Finding detail page in Illustrator as a starting point for manual design work, with every text field already created; it doesn't need to match exactly. No MCP server drives desktop Illustrator: the plugin catalog has nothing, and the registry's Adobe connector is Adobe's cloud tools. So I added scripts/illustrator-export.mjs.

  • What it does: headless Chrome reads one region's boxes and text, and the script writes an ExtendScript that rebuilds it as live objects.
    • Rectangles (rounded where the CSS is) and one-sided rules.
    • One text frame per text block with its styled runs: Inter / Consolas, weight, size, leading, case.
    • Translucent colours flattened over what is behind them.
    • Layers page · boxes · text.
  • Run through osascript … do javascript "#include …" in Illustrator 2026.
  • Output in illustrator/: c114-finding-detail.jsx + .ai (F-A, light, 1440px viewport: 25 shapes, 97 text frames, no style misses). Checked against a screenshot of the page.
  • Mark, same day: "let's turn this into a skill" → /illustrator (.claude/skills/illustrator/SKILL.md). The script gained:
    • --run: builds in the newest Illustrator and leaves the document open
    • --check: a PNG to compare against the page
    • --click: opens menus and sheets first
    • an overwrite guard: an existing .ai needs --force, and the run stops if that file is open with unsaved changes
    • fallbacks for ▾ and similar glyphs
    • better line detection
  • Tested on F-S04 with the Ignore sheet open.
  • 2026-10-16: S3 Policy detail, P-MCP, built with /illustrator (illustrator/c114-policy-detail.{ai,jsx}: 57 shapes, 198 text frames). The script gained closed-<details> handling, form-field values, margin spaces and underlines.

S3 configuration (2026-10-18): Mark: "for the policy details page, I don't see any place for custom configurations per policy, is that correct?" It was correct, and deliberate: surface-map.md S3 dropped qdash's PolicyConfig shapes because no intent asks for them, but that decision never reached the review walk. Then: "take a look at ../qcontrol policy listing page. The expand rows have much better policy configuration. Take a look at that and add something similar."

  • Fixture.
    • app/data/governance-policy-config.ts holds the config for 14 of the 19 policies, copied from the qdash catalog (P5–P17). Shapes: lists for P-MCP, P-PROVIDERS, P-TOOL-ALLOW and P-PROVENANCE; detectors for P-SENS-*, P-DATA-BOUNDARY, P-CREDENTIALS, P-FILES, P-PROMPT-INSPECT and P-OUTPUT; levels for P-SANDBOX and P-TRANSPORT; a threshold for P-SPEND.
    • World.configs holds it, and a new config-set Change kind records each edit.
    • applicability() adds configAllows: a global list entry, or a detector switched off for a finding's data class, means the activity no longer violates.
    • A config change re-evaluates the open findings it touches (D2).
  • S3.
    • A Configuration section sits after Definition, tagged delivery phase 2 with G7 and its own jump pill.
    • It seats the layer's PolicyConfigListEditor, DetectorList, LevelSelect and Threshold as they are.
    • "Seen, not on the list" comes from the policy's findings, the way qdash's pending destinations work.
    • Detector hits are counted from the policy's findings, so the layer's "last 24h" caption doesn't match the count.
    • Edits apply at once, add a History row and say what re-evaluation did. Threshold edits are debounced into one row, and no-op toggles are skipped.
    • Policies with nothing to configure say so.
  • Records. G7 is in object-model.md §10. S3.6 in c114-review.ts asks: is a global allow-list entry the same as an org-wide exception? Should configuration be per scope? Should edits preview first? There is also a composition note on the page.
  • Verified in the browser.
    • P-SENS-SANITIZE: switching SSN off resolved F-S01 and F-S04 as Policy changed (4 open became 2) and added a "config set" History row.
    • P-MCP: adding Vanta MCP to the sanctioned list re-evaluated nothing, since both its findings were already resolved.
    • P-TRANSPORT, P-SPEND and P-ACCT render their shapes, or the empty line.
    • No console errors.
  • Other session. A concurrent session is composing S3 in the harness (mock/policy-detail, part/PolicyScope) in the same tree; it can seat the same editors from World.configs.
  • Uncommitted.

composed S3 · Where it applies (2026-10-18): Mark: "c114, policy detail. We'll be building the revised page section by section. I think we can combine the 'where it applies' and the 'enforcement' sections. Also, let's use our standard uxTable here." Asked where, he answered "the composed mocks". Then: "let's lose the white backgrounds and use a simple title with a hairline, per section." (prompt · plan)

  • The page. /pages/phase4/mock/policy-detail, S3 in the harness (SURFACES gains its mock; registry mock-policy-detail). It takes a new ?policyId= knob (P-MCP · P-SENS-SANITIZE · P-TRANSPORT · P-NOPE) in useGovernanceMock() and the MOCK bar. Sections follow the surface mock's order. Each is a title over a hairline with no card. The ones not composed yet say so.
  • First part, GovernancePartPolicyScope. It merges Where it applies and Enforcement into one UxTable. Each scope path is one row: scope · via (direct or group link) · spec · people · enforcement level with reach · open findings and exceptions in this scope · Enforce / Back to observe / remove. An enforcement entry whose scope no path assigns shows as "not assigned". The overlaps callout and the effective-for-a-person probe stay under the table. Below delivery phase 4 it shows one organization-wide row. A non-enforceable policy reads "observe only" and has no buttons.
  • Acting. A row emits the Change it would make. Until the S6 sheet is composed, the page shows it in a small stand-in panel with previewChange() counts, Apply and Cancel. Add scope says the picker comes with the sheet.
  • Verified in the browser. Enforce on Team: Engineering previewed, applied, and the row became configured · 0 of 40 (the probe followed). Checked dp 2, P-TRANSPORT (not in scope), P-SENS-SANITIZE, P-NOPE, and the parts bin following the policy knob.
  • Dev server. The SSR side served stale transforms twice (the client bundle was current). A real one-line nuxt.config.ts change restarted it each time, and was reverted.
  • Same day, Mark: "rename where it applies to Scop + enforcement and let's make these title 22 px". The section is now Scope + enforcement, and every section title is text-22.
  • Mark: "that table doesn't look quite right, let's use our usTable components including the header". It is now UxTableList with UxTableListColumnHeader sorters (Scope sorts by specificity, the default), with the 3px rules above and below the rows as in qdash's FrameworkRequirements. The delivery-phase 2–3 single row uses the same components.
  • Mark: "grab the new configuration section from the old page (another agent added)". It is now GovernancePartPolicyConfiguration (dp 2), seated after Definition. It holds the same PolicyConfig* editors on World.configs. An edit applies at once through act(), which now returns the applied result so the part can say what re-evaluated. Verified: adding Vanta MCP to P-MCP's sanctioned list re-evaluated nothing (both its findings were already resolved).
  • Mark asked about the effective-for-a-person probe ("do we need that?"). The question is open; the probe is still under the table.
  • Mark: "let's add the sticky pill bar for sub items". The governance-mock layout now mounts qdash's sticky band (UxStickyBand title, as qdash's default layout does). The page header is the layer's UxPageTitle (qdash PageHeader's settings), and NavJumpPills sticky sits under the Band placeholder with one pill per section. Scrolled, the title pins compact on row 1 and the pills dock under it; the scroll-spy and jumps work. The MOCK bar no longer sticks (it would sit over the band).
  • Mark: "let's give the configuration section a white bg similar to a surface item", then "leave the title out of the white bg". The Configuration content now sits on a DataSurfacePanel-style card (rounded-12 border bg-surface p-5), with the title over its hairline above it.
  • Dev server: the fresh :3000 still missed edits, so it now runs from the design-polling launch config (CHOKIDAR_USEPOLLING), started from the app's preview.
  • Mark: "let's move the exceptions over to the new page and use the UxTable - with header". It is now GovernancePartPolicyExceptions (dp 4), seated after Scope + enforcement with its own pill. It is a UxTableList with UxTableListColumnHeader sorters: Allow · Scope · Reason · Until · Added by, plus a UxClose that revokes a live exception. Live exceptions come first and revoked ones are dimmed. Add exception and revoke emit request. ScopeRequest gained exception-add / exception-revoke + exceptionId, and the page's stand-in panel builds the revoke change with its preview. Add waits for the S8b sheet. Verified after the 12:20 reboot (a fresh :3000 picked everything up):
    • P-MCP: the live GRC row shows first, and the revoked Team A row is dimmed with no X.
    • The header sort works.
    • Revoking E-GRC: the panel previews 0 resolve / 0 reopen, and Apply dims the row as revoked 2026-11-01.
    • At dp 2 the section shows its one-line note.
    • P-TRANSPORT shows the empty line, and its Add opens the stand-in.
    • No console errors.
  • Row actions, per Mark's notes. "make the icon larger", then "do we have a fat x?": the layer has plus-fat and check-fat but no X, so the row X is now a fat X (stroke 3, round caps). It is drawn inline because the SSR icon lookup missed a newly added app/assets/svg-icons file. It is a layer icon candidate for Phase 5. Sized 22 → 16 → "14 px". Mark: "add a 'remove' to the left of the x". The label sits inside the same button: "remove" on scope rows, "revoke" on exceptions (the row stays as a dimmed record), "clear" on an enforcement-only row.
  • Mark asked twice what "Effective for a person" was for, then: "let's remove it". The probe is gone from PolicyScope, along with its state and imports. The question it answered belongs to a finding (S1 Why it violates) or a person's page ("policies that apply to this person"), not the policy page.
  • Overlaps → D9 (Decisions). The Overlaps callout is gone from Scope + enforcement. A D9 tie now reads on both rows: "stricter than Environment: Production · wins for 1 person" and "Device group: Production Macs is stricter · overrides this for 1 person". The policy knob gained P-PROVIDERS (the fixture's tie). The model page shows D9 as a fourth ruling, and its probe explains the tie. The record page's empty Applicability gained outranked: []. S6.2 is ruled moot in c114-review.ts.
  • Mark: "let's use our standard hairline for these sections, the current one isn't dark enough". Every section title now uses the layer's .hairline (border-b-stroke-strong) instead of border-stroke.
  • Mark: "will you build the scrolled sticky nav in illustrator for me?" Output: illustrator/c114-policy-detail-sticky-band.{ai,jsx}. It is the pinned band with "Scope + enforcement" active: the compact 15px title row, the pill bar, and the backing strip with its bottom rule. 4 shapes, 14 text frames, no style misses, and the check image matches the page. scripts/illustrator-export.mjs gained two things for it:
    • --only "sel,…": keep only what sits inside those elements and fit the artboard to them, for pinned pieces with no single wrapper.
    • Inset box-shadow rings (the c106 active pill) carried as strokes.
  • Mark: "let's turn off wrapping" (the pill read "Scope + / enforcement" in a narrow window). The layer's NavJumpPills pills got whitespace-nowrap in q-nuxt-layer. It is uncommitted and unreleased, so qdash and deploys get it with the next layer release. The design dev server already shows it, and at 900px every pill stays one line.
  • Mark's redraw of the pinned pill bar: "re-do the highlighted items to look like" (a screenshot), then "end items should have rounded corners to match the bg". In the layer's NavJumpPills, compact (pinned) state only:
    • The active item is a flat primary/10 block with purple text: no ring, square corners, and it fills the bar's height. All items are 12px semibold with 7px × 10px padding, so selecting never changes a width.
    • The bar has no padding and clips its items (overflow: hidden), so a first or last active item rounds with the bar's ends.
    • Bar 32px. Checked at 2× with Scope + enforcement, Definition and History active.
    • The rest state is unchanged. It is uncommitted and unreleased in q-nuxt-layer, together with the nowrap fix, and reaches qdash's detail pages on release.
  • Mark: "can we populate a synthetic view with a few exceptions". The MOCK bar gained an exceptions knob on S3: as is · populated (?exc=many, kept across mock links).
    • Populated adds withExceptions(world, policyId) from the fixture: six real Exception records (E-DEMO-<policy>-n) across team, user, agent, device-group and environment scopes. One is dated, one indefinite, one expired (amber), one revoked.
    • The resource kind follows what the policy matches: MCP servers for P-MCP, data classes for P-SENS-SANITIZE.
    • The page adds them to the shared world and removes them when the knob is off. Revoke works on them.
    • Verified: P-MCP shows 8 rows, revoking GitHub MCP works, off returns to 2, and no console errors.
  • Mark: "let's bring the findings table in and I don't see any reason not to duplicated the table from the findings listing page–scoped to this policy though". It is now GovernancePartPolicyFindings (dp 2), seated after Frameworks with its pill.
    • It duplicates S2's member table (the live qdash listing's pieces, D8), rewritten from S2's render function as a template: Severity · Finding · Subject · Detected · Status · Last event · SLA, the Adjudicate expand row with the card (subject, applies via, remediation clock and verbs, the Ignore capture, evidence | lifecycle).
    • It has S2's Open / Resolved toggles (Open by default), an open · resolved count, and "all in Findings →" (S2 filtered to the policy).
    • Ignore acts at once on the shared world. Verified on P-SENS-SANITIZE: 4 open → 3 open after an Ignore, and no console errors.
  • Mark: the policy id in the crumb ("what is that second item…"), then "make it so, let's also remove the definition, that will be part of the band". The trail is now "Policies / ", as on qdash's detail pages, and the Definition section and its pill are gone. The Band placeholder says it will carry the definition (what it tests, why it matters, what fails it, what happens on failure).
  • Mark: "let's update the left nav to link to the pages", then "just link to a blank page if not exists". Every item in the mock rail now links, including the Inventory and Organization sub-items:
    • It goes to its listing's composed mock, or to a blank page in the mock shell: /pages/phase4/mock/[...slug].vue, titled with the rail label and saying "Not composed yet.".
    • The rail lives in governance-parts.ts (MOCK_NAV, MOCK_SUBMENUS, navSlug, navLabel). Items light on an exact match, and a disclosure starts open when you're on one of its items.
    • Composed routes win over the catch-all.
    • Verified: 19 links, the blank page for Inventory › MCP Servers, the composed S3 page, and no console errors.
  • Mark: "let's bring in the history section–using our uxTable including header". It is now GovernancePartPolicyHistory (dp 2), the last section, on UxTableList with UxTableListColumnHeader sorters: When (newest first) · By · Change · Detail · Id. A row's DOM id is its change id. Verified: P-MCP shows 5 rows, and a revoke from the Exceptions table added row 6 at the top. No console errors. Every S3 section except Band, Severity, Groups and Frameworks is now composed.
  • Groups, after a talk-through ("talk to me about the groups section", then "yes, fold it in"). The separate section would have listed the group rows Scope + enforcement already shows, so it was folded into that table:
    • Each group link has a hover card (GovernanceMockGroupCard, mock-local, CSS hover, a layer candidate): purpose · scope · policy count · state · the policies it bundles with this one.
    • Groups that include the policy but assign nothing (draft, disabled, retired) show as dimmed rows: "draft · not applied", "retired".
    • At delivery phase 3 the table lists the policy's groups as membership rows, since a group's scope arrives in phase 4.
    • "Add to group" sits by "Add scope" and opens the S6 stand-in (group-add).
    • The Groups placeholder and its pill are gone.
    • Verified: P-ENTERPRISE's draft and retired rows, P-MCP at dp 3, Add to group, the hover card on a real hover, and no console errors.
  • Group vs scope talk-through ("what's the diff between group and scope?", "should they be combined?"): a scope is a where, and a policy group is a named set of policies sent to a scope. Kept separate in the model. Then Mark: "let's rename group to policy group". It is the intents' own term, and it stops the clash with groups of people or devices (a team, a device group). Done on the composed mock:
    • "Add to policy group" and the phase 3 wording.
    • The stand-in panel.
    • A "Policy group" label on the hover card.
    • "Device group" stays, since it is a scope. The record pages are untouched.
  • Mark: "should we rename the column 'Assigned by' to 'Policy Group'?", then "make it so". The column is now Policy group. A row with no policy group shows a muted dash: "— set on this policy" (a direct scope) or "— none" (a leftover enforcement entry, still with "clear"). Such rows sort last on that column. Verified on P-MCP and P-PROVIDERS, with no console errors.
  • Mark: "Let's add the findings page". Composed S2 at /pages/phase4/mock/findings (SURFACES S2 mock, registry mock-findings), so the rail's Findings item opens it and lights.
    • It holds S2 in the qdash shell on the shared world: header, severity cards (past SLA fourth), the listing bar (Open / Resolved, framework chips, policy / team chips, search, Grouped ⇄ Individual), the grouped ledger with its policy-in-context section, and the member table. Filters ride the URL, and clear keeps the mock's knobs.
    • The member table and adjudication card are now one shared part, GovernancePartFindingsTable (optional Policy column). The row model moved to app/data/governance-finding-rows.ts. S3's Findings section uses the same table.
    • Policy links go to the composed S3. S3's "all in Findings →" lands here filtered to the policy. Finding ids still open the S1 record (S1 is not composed yet).
    • Verified with headless Playwright, because the browser pane now refuses :3000, which another chat's server owns: rail link and lit state, cards 5 high · 4 past SLA, 2 groups, group expand → Adjudicate card, the Individual view with Policy, S3 → filtered (16 of 19), and no console or hydration errors.
  • Mark: "let's lose the high / medium / low bar". The composed Findings page dropped its four severity cards (high · medium · low · past SLA) and the ?sev= filter they drove. Severity still reads in each group row and each finding, and past SLA in the group's count. Verified headlessly with no console errors. The S2 record keeps its cards.
  • Mark: "rename grouped -> Group by policy". The view switch on the composed Findings page now reads Group by policy · Individual.
  • Search, after "what's the filter do?": two text searches overlapped (the "filter findings…" box above the table, and the ledger's "Policy + Findings" header search on policy names). Mark: "remove the other one not attached to the table". The box is gone. The header search now carries the broad match (id · policy · resource · user · team · harness) through ?q=; "priya" gives 4 of 19. It exists in the Group-by-policy view only.
  • Mark: "let's remove : 5 of 19 findings · 2 policies". The count is gone, and the view switch sits at the bar's right edge. Verified headlessly with no console errors.
  • Mark: "add ... overflow to the finding titles". In the Individual view the Finding column was squeezed and titles ran into Policy: the inner row's 180px minimum overflowed a narrower cell, and the title couldn't shrink in its flex row. In the shared GovernancePartFindingsTable the row is now min-w-0 and the title truncates with … (full text on hover). A 200px cell minimum was tried, then dropped: "let's do truncation instead of forcing width". Checked at 1440 and 1100 and on S3, with no console errors.
  • Mark: "let's lose the adjudicate column". The shared GovernancePartFindingsTable dropped its Adjudicate / Close button column (and the label CSS). The row itself opens the adjudication card, as UxTableListExpandRow toggles on row click. Verified on both pages: columns end at SLA, and a click on F-S01 opens its card.
  • Mark: "let's copy the policies listing pages from the live app". The live qdash /policies page (its "Control Center") is now copied to /pages/phase4/mock/policies (SURFACES S4 mock, registry mock-policies), so the rail's Policies item opens it.
    • The four fed components are copied with their markup unchanged into app/components/governance/live/ (ControlsFrameworks, ControlsPolicies, PolicyConfig, ControlsCustom, ControlsEvidence).
    • Only qdash-specific pieces were swapped: the P10 served-egress branch, StateEmpty and Panel (inlined). The API-wired control editor and the Govern sheet are not copied.
    • app/composables/useControlCenterMock.ts re-sources the live useControlCenter on the shared world:
      • the frameworks strip comes from tracked frameworks and their mapped policies (activate is framework-track);
      • the policy rows come from the fixture's 19 policies by category, with effective severity, mapped frameworks, the G7 configs (edits are config-set) and live exceptions (remove is exception-revoke, add is exception-add);
      • on / off stays the live app's browser-local activation, a mock-wide map first set from whether the policy applies anywhere. The model would derive State from scope instead (review S3.1), so this page reintroduces the toggle the S4 record retired.
    • "Full details →" opens the composed S3.
    • Verified headlessly: OWASP 88% (14 / 16), 9 categories over 19 policies, toggling Unsanctioned MCP gives 1 of 3 active and OWASP 81% with a Required gap, the row opens its sanctioned-servers editor, and no console errors.
  • Mark: "Yes, copy the live Compliance page into the mock the same way". The live qdash /compliance page is now copied to /pages/phase4/mock/compliance (SURFACES S4f, registry mock-compliance), so the rail's Compliance item opens it.
    • The seven components are copied with their markup unchanged into governance/live/: ComplianceAttention, ComplianceFrameworksListing, ComplianceInstrumentedCards, ComplianceProjectedCards, ComplianceEvidenceExport, plus qdash's lib AttentionStrip and AttentionMessage. Panel is inlined, and fmtN became toLocaleString.
    • app/composables/useComplianceMock.ts re-sources useCompliance on the shared world:
      • framework rows: active = tracked (activate is framework-track), violations are live (open findings under the framework's mapped policies), completeness = requirements fully covered;
      • instrumented cards for tracked frameworks, with real requirement ids as "Controls firing";
      • the unmapped-findings attention chip;
      • the live ledger's projected cards and tooltips.
    • "Details + Configuration" opens the S5 surface mock, since S5 is not composed. Card links go to the composed Findings page filtered to the framework.
    • Verified headlessly: 1 unmapped chip, OWASP active at 4 violations and 40% (4 / 10), activating ISO 27001 moves it to Active with its card, and no console errors once the attention link became a string.
  • Mark: "let's ... the descriptions on overflow instead of wrapping". The Control Policies Description column and the instrumented framework card's description are now one line, ending in … with the full text on hover. The framework listing already truncated.
  • Mark: "the add button collision". The copied frameworks strip's "Add Framework" tile collapsed and overlapped "Control Policies" whenever it wrapped onto its own row. Its height comes from min-h-[100px], which the design site's Tailwind never generated from the copied file. The two min-heights are now inline styles. Checked with OWASP and ISO active at 760px: the tile is 100px and clears the heading. The other arbitrary classes in governance/live/ (h-[3px], text-[9px], max-w-[260px], max-w-[760px]) apply.
  • Mark: "for policies, instead of opening in place, link to the policy details page". The Control Policies rows are plain rows now: a click opens the composed S3 for that policy. The in-place expand (severity, config editors, exceptions, Full details) is dropped, and the lede reads "open a row for the policy's details". The toggle cell still only toggles. Verified: the toggle gives 2 → 1 of 3 and stays on the page, and a row click lands on S3 for P-MCP.
  • Concurrently, another session reworked PolicyScope (Assigned by column, the level as the control, override notes, row menu; spec, people and readiness left the table).
  • Uncommitted.

composed S1 · Finding detail (2026-10-19): built from Mark's Illustrator screenshot (illustrator/c114-s1-finding-detail-design.webp) and his notes: "the table should be our uxTable with the appropriate header", "details strip, let's try to re-use any components like the framework item", "upper right–actions section … here's where the actions go", "session - re-use the existing transcript component", "related findings - related means two things here: any findings from the same session, any findings related to the same policy this finding violated". (prompt · plan)

  • /pages/phase4/mock/finding-detail is composed on the shared world, top to bottom as drawn:
    • the crumb "Findings /" (UxPageTitle, pins in the band) over the rule;
    • the title policy · resource (24px, so it fits on one line with its status pill and the actions) with Resolve · Block · Ignore (UxButton kind="stroke") at the upper right. Resolve opens the record's Create exception capture (S8b, with the derived preview), Ignore its S8 capture (duration required, reason recommended), Block an S6 stand-in. The first two act through act(), so S2 and S3 see the result. Mark: "there may be changes";
    • What happened (the evidence) and Why it violates (the policy's description), side by side over the hairline;
    • then four new parts, each world + state and in PARTS:
      • GovernancePartFindingHistory: the record's Lifecycle on UxTableList with sorters, Time · Actor · What → State · Cause, oldest first. The cause's change id links to S3's History row;
      • GovernancePartFindingDetails: Severity (SecuritySeverityTag) · Status · User (UxAvatar) · Team · Endpoint (EndpointPawn) · Policy · Policy group(s) · Framework(s) (ComplianceTag, the framework item);
      • GovernancePartFindingRelated: Same session and Same policy, each a compact UxTableList (Severity · Finding · User · Status), five shown with the count; a row opens that finding here;
      • GovernancePartFindingSession: View Full Session over the layer's TranscriptPanel. The world records sessions but not turns, so app/data/governance-transcript.ts builds them: an opening turn, a turn per finding the session generated at its evidence moment (an MCP tool call, the pasted value masked, the account's whoami), a closing turn.
  • Mark, mid-build: "let's also add the policy or policy groups this violated to the details section". Details gained Policy (links to the composed S3) and Policy group(s): the groups through which the policy reached this subject (its applicability paths), each with S3's group hover card, or "none · set on the policy" / "not in scope now".
  • statusLabel / statusPill moved into governance-finding-rows.ts, shared by the header and Details.
  • The shared GovernancePartFindingsTable and the composed Findings page now open the composed S1 inside the shell, keeping the knobs (they opened the S1 record).
  • Verified headlessly on :3000: F-A (resolved: enforced, four rows, F-C in the same session S-1), F-S01 (open · pending, 15 on the same policy, two policy groups), F-S04 (nine rows), F-NOPE (honest absence). Ignore on F-S01 → Resolved: ignore with a third row; Resolve on F-S03 → E-U created, Resolved: allowed; Block opens the stand-in; S3's finding rows land on the composed S1; the parts bin renders all four. No console errors.
  • Uncommitted.

composed S3 · overview strip, Severity, Frameworks (2026-10-19): Mark: "for the policy page, let's flesh out the missing severity and frameworks sections; add an overview strip replacing the band based on the screenshot" (illustrator/c114-s3-overview-design.webp). (prompt · plan)

  • The overview strip replaces the Band (GovernancePartPolicyOverview, above the jump pills): What it tests · Why it matters · What fails it · What happens on failure (derived from the enforcement action), then Framework(s) as ComplianceTags, Organization Severity editable in place over "Recommended : …", and Findings as the open count in a box, coloured and labelled by the most severe open finding (P-SENS-SANITIZE: 4 · High; P-MCP: 0 · Open).
  • GovernanceMockSeverityPicker: the severity tag with a ▾ and a native select over it. Picking the recommendation is a severity-reset, anything else a severity-override, through act(). The overview and the Severity section share it, so both and History move together. It never re-evaluates (D2).
  • Severity (GovernancePartPolicySeverity): two UxTableList rows, Qpoint recommended (definition version) and Organization (the picker, set by, when, stricter / softer than recommended), with "clear" back to the recommendation. Under them, the open findings generated at another severity, which keep theirs.
  • Frameworks (GovernancePartPolicyFrameworks): one sortable UxTableList row per mapped requirement: framework item (grey gap tag and a dimmed row when the framework isn't tracked) · requirement id and label (fit note on hover) · contributes (observe, or observe + enforce; + process when procedural) · shared with (the other policies mapped) · tracked · framework → (S5's surface mock).
  • In a table column the tag's shield <img> (no intrinsic width) counts as 0 at min-content, so the pill clipped by its 10px. The cell's wrapper is width: max-content. Layer follow-up: give ComplianceTag's shield an explicit width.
  • Every jump pill now points at a composed section. frameworkTags() moved into governance-finding-rows.ts, shared with S1's Details.
  • Verified headlessly: P-MCP, P-SENS-SANITIZE, P-PROVIDERS (three OWASP requirements), P-TRANSPORT (none mapped), P-NOPE; on P-MCP, picking Medium resets, Critical overrides, clear resets, each a History row; the parts bin renders the three parts. No console errors.
  • Uncommitted.

c118 · the Oct 19 model in the lab (2026-10-20): c118 (policy structure and publishing) now draws the 2026-10-19 product session's landings in this cycle's lab: RULED runs the Oct 19 world (policy mode Off / Observe / Enforce, mode and advanced exceptions by org / team / user context with the narrowest winning, a policy snooze, resolve with a reason, no stored groups or per-scope enforcement), and C114_RULED keeps c114 as ruled through 2026-10-18 for the Phase 3 record pages and as the model page's alternative. The live Policies copy's toggle became a three-state Mode column. The record and the change list are in c118's lab-plan.md (Log); this cycle's rulings D0–D9 are unchanged.

Outcome

(at completion)

Product-session decisions

What the Qpoint Product sessions did to this cycle's object model, as of 2026-10-26. The cycle is still open, so this records the model's movement, not the cycle's result. Attendees: Mark Parson, Mark Peterson (advisor), Rob Genova, Tyler Flint. Transcripts are extracted in market-analyst: f06500e3 (2026-10-12), 04e3d850 (10-14), 154b2679 (10-19), 5c8785e2 (10-21), 5b4bae13 (10-23). Status words: ruled, direction, open, superseded. A later session wins over an earlier one.

The story. This cycle read fourteen intents as one object model: Policy, Scope, Policy Group, Exception, Enforcement State, Finding. It drew that model across eight surfaces. Over two weeks of sessions the model got smaller.

  • Scope and Policy Group stopped being objects.
  • Enforcement moved from a policy × scope table to a mode on the policy.
  • Exceptions became the only way to vary a policy.
  • Ignore and Block left the finding.

c118 and c121 built each step in this cycle's lab, so the lab now runs a model this cycle's object-model.md doesn't describe. That document still reads as of 2026-10-09.

This cycle's rulings, and what became of them

  • D0 Model first. Stands. The sessions argued about the model before any page.
  • D1 Scope precedence by specificity. The cascade stands as "the narrowest context wins" (Oct 19). It now runs among exceptions on a policy rather than among scopes.
  • D2 Re-evaluation is forward-only and can reopen. Stands. Turning a policy Off resolves its open findings as Policy Changed (c118 Q9).
  • D3 Configured vs confirmed. Reach stands as propagation per Policy Config version (c121 D11). Superseded in part: a finding no longer resolves "as Enforced". Its outcome is stamped at detection, and confirmation resolves an Observed finding "now enforced" (c121 D16).
  • D4 Vocabulary. Policy, Framework, Finding, Resolution and Exception stand. Scope is gone as an object (c118 Q2). Open: on 2026-10-23, Mark Peterson put a framework's control (and control family) above our policies, with "control intents" alongside them. That clashes with D4's use of Control as qdash's internal word for the rule.
  • D5 All eight surfaces. S7 Policy Group is retired into the team page's Policies section (c118 L5). S6 and S8's Ignore and Block are gone, and S3's per-scope enforcement table is retired (c118 L2).
  • D6 Engineering. On 2026-10-23, Tyler said he and Kamal are down to single-digit items on Symbiote and Qcontrol, so the backend can start soon. Configuration goes in Postgres and events in ClickHouse. The UI's job is to generate the config Qcontrol loads: datasets first, then rules.
  • D9 The stricter wins on ties. Stands for mode exceptions (c118 W.5). It's on c121's feedback list as our answer to the intent's open question.

What the sessions settled about the model

  • Resolving a finding closes the past; preventing recurrence is the policy's job (Oct 12). Ruled. Resolve records a decision and never changes enforcement (Oct 23, c121 D10).
  • One policy per area of concern. It holds its definition, severity, mode, exceptions and knobs (Oct 19). Ruled.
  • Mode on the policy, Off · Observe · Enforce, with an optional Until (Oct 19, then Oct 21). Ruled.
  • Exceptions by org, team or user (Oct 19). In v1 an exception changes mode only (Mark Peterson, Oct 23); exceptions that change a policy's knobs come later; device groups wait for MDM. Ruled.
  • Policy groups emerge from exceptions and are never managed (Oct 19, confirmed Oct 21). Ruled.
  • Frameworks: deferred (Oct 14), then made the entry point and the only predefined grouping (Oct 19, Oct 21). They're the subject of the 2026-10-26 session. Direction.
  • Inside a policy: explicit rules and implicit intent questions (Oct 23). Explicit means conditions and operator-defined lists. Implicit means questions judged at run time, each with a probability threshold and the context it needs. Direction. Neither this cycle's model nor the intents have this layer yet.

Superseded by the sessions

  • Policy groups mapped to teams as the core organizing model, with policies also assignable to a team directly (Oct 14). Gone on Oct 19.
  • Exceptions deferred past the private beta (Oct 14, open). Instead they became the only nuance mechanism (Oct 19).
  • Sentinel as a separate, non-deterministic layer (Oct 12). On Oct 19 it is the one rules engine. On Oct 23 deterministic and intent-based rules can sit in the same policy.
  • Ignore on a finding, with a required duration (§5). It became a snooze on the policy (Oct 19), then a mode with an Until (Oct 21).

Decisions

  • D0 Model first (Mark, 2026-10-09). The intents are read for the object model and how the pieces interact, not executed one intent per page. Mocks follow from the model.
  • D1 Scope precedence (Mark, 2026-10-09): CSS specificity. Global rules apply everywhere; a more specific scope (team, then user or device) overrides a broader one; an exception is a more specific allow. Proposed addendum: two assignments at equal specificity with different settings are shown as a conflict for the practitioner to resolve, never picked silently (the intents forbid silent resolution). (Replaced by D9, 2026-10-18.)
  • D2 Re-evaluation triggers (Mark, 2026-10-09): forward-only, can reopen. A change to policy, scope, group, exception or enforcement re-evaluates the open findings it touches. A finding that no longer violates resolves as Policy Changed with its evidence kept; a later change can reopen it with a cause. Adding scope never evaluates historical activity retroactively. Severity changes reprioritise only.
  • D3 Proof of enforcement (Mark, 2026-10-09): two states. Enforcement configured and enforcement confirmed are distinct. A finding resolves as Enforced only on confirmation (qdash observed the block, redaction or redirect). The enforcement control shows reach ("97 of 100 devices enforcing"), not just on/off.
  • D4 Vocabulary (Mark, 2026-10-09): the intents' words. Policy, Framework, Finding, Resolution, Scope, Exception everywhere a practitioner reads. Control stays the internal name of the executable rule in qdash.
  • D5 Scope and sequence (Mark, 2026-10-09). All eight mocks, in dependency order, Observe and Enforce together.
  • D6 Engineering (Mark, 2026-10-09). Backend work has not started; design leads and the Phase 5 gap list is engineering's first input. No fixed date.
  • D8 The model is the base; existing work is reused where it fits (Mark, 2026-10-09). Every surface is designed from the object model and the surface map. Where qdash or the design site already has a piece that fits that design — the findings listing's group rows, expand row, adjudication card, composable and deep links; the older /policies, /compliance and /framework pages; the c79 / c65 mocks — the piece is reused as it is rather than rebuilt. Where a piece contradicts the model (status vocabulary, the framework strip activating policies, an Ignore without a duration) it changes or retires. Each mock opens with a keep / change / add / retire inventory of the existing pieces (S2's is in surface-map.md §5).
  • D7 Registry phase (Mark, 2026-10-09): Phase 4 — Governance. c114's pages live under /pages/phase4/ (PagePhase 'phase4', index at app/pages/pages/phase4/index.vue), not _meta. The model page moved there the same day.
  • D9 Equal-specificity ties (Mark, 2026-10-18): the stricter wins. Overlapping scopes cascade (D1: org → team → user, the more specific decides). When two scopes at the same specificity disagree (a person in two teams, two groups on one scope, a team and an agent, an environment and a device group), Enforce beats Observe. Nothing is left for an admin to resolve, so the composed S3 drops its Overlaps callout and notes a tie on the rows it touches. It replaces D1's "show as a conflict" addendum. In the fixture it is Rulings.d9 (stricter-wins, with conflict kept as the alternative on the model page), STRICTNESS and Applicability.outranked. It also settles S6.2 as moot. Mark: "we should treat overlaps as cascading precedence. Org -> team -> user–with the right most receiving precedence", then "yes" to "ties go to the stricter".

Visual record

76 captures — heroes, page slices, and full-page renders. Click to view.

Ruled: specific wins, forward-only re-evaluation that can reopen, configured → confirmed. Finding A allowed at step 1, B pending then Enforced, C ignored until 31 Oct and back; the probe shows Priya's equal-specificity conflict
Ruled: specific wins, forward-only re-evaluation that can reopen, configured → confirmed. Finding A allowed at step 1, B pending then Enforced, C ignored until 31 Oct and back; the probe shows Priya's equal-specificity conflict open page →history · 3 moments →
D1 alternative, broad wins: the Team A exception loses to the organisation-wide assignment, so Finding A stays open and is only resolved by enforcement
D1 alternative, broad wins: the Team A exception loses to the organisation-wide assignment, so Finding A stays open and is only resolved by enforcement open page →history · 3 moments →
D3 alternative, config is proof: Finding B resolves as Enforced the moment the block is published, before any device confirms it
D3 alternative, config is proof: Finding B resolves as Enforced the moment the block is published, before any device confirms it open page →history · 3 moments →
Phase 2: the Govern rail today vs proposed, then S1 Finding detail as blocks — evidence above the line, the organ below, Respond as an aside with reach counts
Phase 2: the Govern rail today vs proposed, then S1 Finding detail as blocks — evidence above the line, the organ below, Respond as an aside with reach counts open page →
S1 typical: F-A at the end of the Vanta story — allowed by the Team A exception, reopened when it was revoked, Enforced on confirmation; four organ rows, two related, Respond with reach counts
S1 typical: F-A at the end of the Vanta story — allowed by the Team A exception, reopened when it was revoked, Enforced on confirmation; four organ rows, two related, Respond with reach counts open page →history · 2 moments →
S1 minimal: a sanitization finding with only its detect row; enforcement is confirmed in the scope but has not reached this device, so the finding is Open · pending (D3); 15 related
S1 minimal: a sanitization finding with only its detect row; enforcement is confirmed in the scope but has not reached this device, so the finding is Open · pending (D3); 15 related open page →history · 2 moments →
S1 overflow: nine organ rows — two Ignores, an expiry, a revoke, Enforced, a reopen when GRC went back to observe, a third Ignore revoked; related shows 5 of 15 and says so
S1 overflow: nine organ rows — two Ignores, an expiry, a revoke, Enforced, a reopen when GRC went back to observe, a third Ignore revoked; related shows 5 of 15 and says so open page →history · 2 moments →
S1 unknown id: honest absence, the count of findings the world knows, a way back
S1 unknown id: honest absence, the count of findings the world knows, a way back open page →history · 2 moments →
S2 typical: the story’s end — 5 open findings in 2 policies, Open on by default, grouped; the Vanta policy has nothing open and is not listed, the page says so
S2 typical: the story’s end — 5 open findings in 2 policies, Open on by default, grouped; the Vanta policy has nothing open and is not listed, the page says so open page →history · 9 moments →
S2 expanded: the sanitization policy open — its section (description, severity with the recommended value, counts, upcoming deadlines) over the four member rows, and the first member’s adjudication card: subject, applies via, the clock with Ignore / Create exception / Block, evidence beside the lifecycle
S2 expanded: the sanitization policy open — its section (description, severity with the recommended value, counts, upcoming deadlines) over the four member rows, and the first member’s adjudication card: subject, applies via, the clock with Ignore / Create exception / Block, evidence beside the lifecycle open page →history · 9 moments →
S2 with Resolved included: the Vanta policy returns with its two enforced findings; group rows show the resolved count beside the open cells
S2 with Resolved included: the Vanta policy returns with its two enforced findings; group rows show the resolved count beside the open cells open page →history · 9 moments →
S2 Individual: the same members flat with policy as a column; the filters unchanged
S2 Individual: the same members flat with policy as a column; the filters unchanged open page →history · 9 moments →
S2 filtered to nothing: the counts stay honest and clear is one click
S2 filtered to nothing: the counts stay honest and clear is one click open page →history · 9 moments →
S2 empty: no findings at all — the all-clear with the policies still evaluating
S2 empty: no findings at all — the all-clear with the policies still evaluating open page →history · 9 moments →
S2 overflow: 400 findings over eight policies, groups collapsed, harness pills capped at two plus N
S2 overflow: 400 findings over eight policies, groups collapsed, harness pills capped at two plus N open page →history · 9 moments →
S3 typical, the Vanta policy: severity overridden to High over a Medium recommendation, three scope paths (org-wide direct, two groups), enforcement confirmed org-wide and for Finance with Engineering observed, one exception live and one revoked, the story’s four changes in History; every section tagged with its delivery phase
S3 typical, the Vanta policy: severity overridden to High over a Medium recommendation, three scope paths (org-wide direct, two groups), enforcement confirmed org-wide and for Finance with Engineering observed, one exception live and one revoked, the story’s four changes in History; every section tagged with its delivery phase open page →history · 4 moments →
S3 with the change sheet open (S6): adding Team: Legal — the preview says who it reaches, that it broadens, who is reached twice, and that no finding changes
S3 with the change sheet open (S6): adding Team: Legal — the preview says who it reaches, that it broadens, who is reached twice, and that no finding changes open page →history · 4 moments →
S3 rich: organisation-wide sanitization — enforcement confirmed on 97 of 100 devices (three behind the open findings still pending) with GRC set back to observe, 16 findings, two framework requirements, the GRC change in History
S3 rich: organisation-wide sanitization — enforcement confirmed on 97 of 100 devices (three behind the open findings still pending) with GRC set back to observe, 16 findings, two framework requirements, the GRC change in History open page →history · 4 moments →
S3 applied nowhere: in the catalog, no scope, no group, no findings — State reads Not in scope and Add scope is the only door
S3 applied nowhere: in the catalog, no scope, no group, no findings — State reads Not in scope and Add scope is the only door open page →history · 4 moments →
S3 unknown id: honest absence with the catalog size and a way back
S3 unknown id: honest absence with the catalog size and a way back open page →history · 4 moments →
S4 Policies view: the catalog by category (nineteen policies, the earlier framework page’s controls included) — severity as effective with the recommended value and Reset where overridden, the Applies column (organization-wide · groups · Not in scope) with the enforcement summary, framework tags, open findings
S4 Policies view: the catalog by category (nineteen policies, the earlier framework page’s controls included) — severity as effective with the recommended value and Reset where overridden, the Applies column (organization-wide · groups · Not in scope) with the enforcement summary, framework tags, open findings open page →history · 6 moments →
S4 Policies grouped by Policy Group: each group’s policies under its scope, then the policies in no group
S4 Policies grouped by Policy Group: each group’s policies under its scope, then the policies in no group open page →history · 6 moments →
S4 Frameworks view: OWASP tracked and ISO not, each with its type, requirement count, derived coverage (fully · partially · not) and open findings through mapped policies
S4 Frameworks view: OWASP tracked and ISO not, each with its type, requirement count, derived coverage (fully · partially · not) and open findings through mapped policies open page →history · 6 moments →
S4 Frameworks with none tracked: the catalog still shows what each would cover; tracking is a declaration
S4 Frameworks with none tracked: the catalog still shows what each would cover; tracking is a declaration open page →history · 6 moments →
S4 Groups view (S7’s list): four groups with policies, scope and population, state, enforcement summary and open findings; Legal duplicated from Finance
S4 Groups view (S7’s list): four groups with policies, scope and population, state, enforcement summary and open findings; Legal duplicated from Finance open page →history · 6 moments →
S4 filtered to nothing: the catalog size stays visible, clear is one click
S4 filtered to nothing: the catalog size stays visible, clear is one click open page →history · 6 moments →
S4 overflow: 79 policies over nine categories, section rows carrying the in-scope count
S4 overflow: 79 policies over nine categories, section rows carrying the in-scope count open page →history · 6 moments →
S5 typical, OWASP LLM Top 10 tracked: all ten risks as the earlier page broke them down, with their fit notes — four fully addressable, six partially (injection, supply chain, poisoning, prompt leakage, vectors and misinformation need process Qpoint cannot provide); each mapped policy with capability, configuration and findings as distinct cells; the gap reasons in their own column
S5 typical, OWASP LLM Top 10 tracked: all ten risks as the earlier page broke them down, with their fit notes — four fully addressable, six partially (injection, supply chain, poisoning, prompt leakage, vectors and misinformation need process Qpoint cannot provide); each mapped policy with capability, configuration and findings as distinct cells; the gap reasons in their own column open page →history · 3 moments →
S5 ISO 27001, untracked: three Annex A controls, one fully covered through three data-handling policies, one partial (access control is also procedural), one procedural only
S5 ISO 27001, untracked: three Annex A controls, one fully covered through three data-handling policies, one partial (access control is also procedural), one procedural only open page →history · 3 moments →
S5 SOC 2 with no mapped policies: every criterion not addressable, every one listed under Gaps
S5 SOC 2 with no mapped policies: every criterion not addressable, every one listed under Gaps open page →history · 3 moments →
S5 overflow: all 93 Annex A controls of ISO 27001 with the coverage filter chips; the summary band carries the counts
S5 overflow: all 93 Annex A controls of ISO 27001 with the coverage filter chips; the summary band carries the counts open page →history · 3 moments →
S5 unknown id: honest absence with the catalog size and a way back
S5 unknown id: honest absence with the catalog size and a way back open page →history · 3 moments →
S7 typical, Engineering AI Controls: four policies as references (three also in the baseline), enforcement decided per scope, the baseline named as the overlap with Priya reached twice and no conflict, the probe showing her policies through this group in bold, and the membership change in History
S7 typical, Engineering AI Controls: four policies as references (three also in the baseline), enforcement decided per scope, the baseline named as the overlap with Priya reached twice and no conflict, the probe showing her policies through this group in bold, and the membership change in History open page →
S7 with the change sheet open: changing the group’s scope — who it would reach, what re-evaluates, duplicate paths and conflicts, the audit line
S7 with the change sheet open: changing the group’s scope — who it would reach, what re-evaluates, duplicate paths and conflicts, the audit line open page →
S7 draft: Contractors AI Controls — three policies, a scope no one is in yet, applies nothing until Activate
S7 draft: Contractors AI Controls — three policies, a scope no one is in yet, applies nothing until Activate open page →
S7 retired: the spring pilot read-only, its retirement in History, superseded by the baseline
S7 retired: the spring pilot read-only, its retirement in History, superseded by the baseline open page →
S7 unknown id: honest absence with the group count and a way back
S7 unknown id: honest absence with the group count and a way back open page →
The review walk at the start of Phase 4: no question ruled yet; progress, the rulings so far, the delivery phases, then S1 with its states, what to look for, captures and four open questions
The review walk at the start of Phase 4: no question ruled yet; progress, the rulings so far, the delivery phases, then S1 with its states, what to look for, captures and four open questions open page →history · 2 moments →
c114 full
open page →history · 3 moments →
c114 full
open page →history · 3 moments →
c114 full
open page →history · 3 moments →
c114 full
open page →
c114 full
open page →history · 2 moments →
c114 full
open page →history · 2 moments →
c114 full
open page →history · 2 moments →
c114 full
open page →history · 2 moments →
c114 full
open page →history · 9 moments →
c114 full
open page →history · 9 moments →
c114 full
open page →history · 9 moments →
c114 full
open page →history · 9 moments →
c114 full
open page →history · 9 moments →
c114 full
open page →history · 9 moments →
c114 full
open page →history · 9 moments →
c114 full
open page →history · 4 moments →
c114 full
open page →history · 4 moments →
c114 full
open page →history · 4 moments →
c114 full
open page →history · 4 moments →
c114 full
open page →history · 4 moments →
c114 full
open page →history · 6 moments →
c114 full
open page →history · 6 moments →
c114 full
open page →history · 6 moments →
c114 full
open page →history · 6 moments →
c114 full
open page →history · 6 moments →
c114 full
open page →history · 6 moments →
c114 full
open page →history · 6 moments →
c114 full
open page →history · 3 moments →
c114 full
open page →history · 3 moments →
c114 full
open page →history · 3 moments →
c114 full
open page →history · 3 moments →
c114 full
open page →history · 3 moments →
c114 full
open page →
c114 full
open page →
c114 full
open page →
c114 full
open page →
c114 full
open page →
c114 full
open page →history · 2 moments →

Artifacts

Qpoint Brand Style Guide