From 899bc74e0648cf8cc7d774181e2f8e439505eace Mon Sep 17 00:00:00 2001 From: Timomak Date: Sun, 26 Jul 2026 16:45:40 +0200 Subject: [PATCH 1/9] docs: add InterviewCopilot execution packet --- design.md | 867 ++++++++ docs/implementation/phase-execution-packet.md | 1918 +++++++++++++++++ 2 files changed, 2785 insertions(+) create mode 100644 design.md create mode 100644 docs/implementation/phase-execution-packet.md diff --git a/design.md b/design.md new file mode 100644 index 00000000..94bb821c --- /dev/null +++ b/design.md @@ -0,0 +1,867 @@ +# InterviewCopilot Product and Interface Design + +Status: Living working specification + +Last updated: 2026-07-26 +Theme: **Quiet Signal** + +This document is the source of truth for the InterviewCopilot product experience. It records confirmed codebase constraints, resolved product decisions, open questions, interaction behavior, and the visual system. Decisions will be resolved one at a time and logged here before implementation. + +## 1. Product thesis + +InterviewCopilot should become a calm, mode-aware interview HUD: it listens to or sees the interview, identifies the current task, and reveals only the next useful layer of assistance. + +It should feel like a quiet instrument rather than a chat application, IDE, dashboard, or cyberpunk overlay. + +The initial product model has two independent axes: + +1. **Interview mode:** Coding, System Design, or Behavioral. +2. **Input channel:** Audio, screenshot, or manual text. + +AI provider and model are implementation choices. They belong in advanced preferences and must not be presented as interview modes. + +InterviewCopilot is a **Live interview copilot first**. Practice is not part of the initial product surface or navigation. It may be evaluated later as a deliberately separate experience, but Practice requirements must not add density, steps, or review features to the Live interface. + +The initial experience is optimized for **Senior and Staff+ software engineers**. Default assistance assumes the candidate can handle fundamentals and instead emphasizes ambiguity reduction, technical judgment, trade-offs, production constraints, leadership, and organizational impact. The product may remain usable at other levels, but it will not flatten its defaults to serve every candidate equally. + +The product position is: + +> **The invisible live copilot for Staff+ engineering interviews—across coding, system design, and behavioral.** + +Within this position, *invisible* means that the InterviewCopilot overlay is excluded from ordinary screen sharing and recording on explicitly qualified configurations. Staff-level judgment across the full interview loop is the substantive reason to believe it is more than another capture-private coding-answer overlay. Neither half is sufficient alone: capture privacy without judgment is a utility, while judgment without a quiet live experience is ordinary interview preparation software. + +The customer-facing promise is deliberately broader than a single conferencing brand: + +- **Headline:** “Stay private while you share your screen.” +- **Qualifier:** “InterviewCopilot is designed to stay out of ordinary macOS screen shares and recordings. Coverage varies by application and capture mode; verify your setup before an interview.” + +Google Meet may appear as a verified compatibility result, but it does not define the product category or headline. The product never describes itself as universally undetectable and does not claim protection from proctoring, process inspection, device monitoring, or other anti-cheating controls. + +Capture privacy is release-critical but universal undetectability is not a defensible product claim. Supported conferencing, recording, operating-system, and display configurations require a maintained compatibility matrix and repeatable release testing. A configuration that cannot exclude the overlay from ordinary user-authorized capture must not be represented as supported. + +InterviewCopilot does not promise invisibility to websites, browsers, interview platforms, proctoring software, process monitors, enterprise device management, accessibility or input-event monitoring, or a person inspecting the local computer. It must not tamper with monitoring software, hide or disguise its process, spoof device or browser state, intercept a platform's telemetry, suppress platform warnings, or otherwise attempt to evade anti-cheating or proctoring controls. Qualification is limited to documented operating-system content-protection behavior and ordinary screen/window capture paths. + +## 2. Confirmed codebase constraints + +These are facts established against upstream `main` at +`9dcb4b2d39607273a8528a24657cdb4f5bfc3412`. A separate uncommitted prototype +is present in the planning worktree; prototype-only behavior is called out as +such and is not an implemented or verified baseline. + +- The application is Electron 29, React 18, TypeScript, Vite, Tailwind, and Radix UI. +- The main window is frameless, transparent, always on top, hidden from the taskbar, present on all workspaces, and protected from screen capture where Electron supports it. +- The current implementation calls `BrowserWindow.setContentProtection(true)`, but this is not a cross-platform guarantee. Electron documents that it maps to `WDA_EXCLUDEFROMCAPTURE` on supported Windows versions and `NSWindowSharingNone` on macOS, while modern macOS applications using ScreenCaptureKit can still capture the protected window. The transparent Windows window also requires direct regression testing rather than an assumption that display affinity succeeds. +- The user has directly observed that the current macOS build is excluded during both entire-display and specific-window sharing in Google Meet. The exact browser version and macOS version have not yet been recorded, so these are proven regression baselines for the tested Meet path rather than evidence that every macOS capture implementation is protected. +- The upstream initial window is 800 × 600 with a 750 × 550 minimum, and renderer content reports its dimensions back to Electron and can resize dynamically. The prototype lowers the minimum to 320 × 80; the target shell dimensions remain specified in section 5. +- Upstream does not reliably pass pointer events through every transparent area. The prototype explores computed-surface mouse passthrough, but that approach has not been accepted or regression-tested. +- Upstream creates the window with `show: true` and conditionally hides it through opacity. The prototype explores an explicitly hidden launch and `Control+Shift` shortcuts; neither is an established baseline. +- The renderer currently has queue, solution, and debug states rather than a durable interview-session model. +- Screenshots are the only live interview input. There is no recorder, transcript model, speaker attribution, voice activity detection, or audio state in configuration. +- Upstream settings store a legacy API key, legacy provider and per-stage model names, language, and opacity. Mode and session preferences do not exist. +- The prototype adds Claude Code and Codex subscription-provider selection and uses only the selected provider. It still retains legacy API-key/provider paths and therefore does not satisfy the launch provider boundary. +- Prototype subscription calls are one-shot: Claude disables session persistence and Codex runs ephemerally. Provider-managed conversation compaction therefore cannot operate across InterviewCopilot requests until this integration is replaced with persistent resumable sessions. +- Current screenshots are written as plaintext files under the application data directory. The main configuration is plaintext JSON with owner-only file permissions. An unused `electron-store` instance contains a hard-coded encryption key, which does not provide meaningful protection. +- Tailwind has no semantic color or spacing tokens. Visual styling is composed from repeated black, white-alpha, blue, and red utility classes. +- The interface uses many 10px and 11px labels. This is too small for glanceable interview use. +- Inter is loaded from Google Fonts. A production-ready desktop build should bundle required fonts or use native system fonts rather than depend on a network request. +- Existing uncommitted work in the repository is user-owned and must be preserved during implementation. + +## 3. Experience principles + +### 3.1 Glanceable before comprehensive + +The first response must be usable within two seconds of looking at the overlay. Deeper detail is progressively disclosed. + +### 3.2 Stable under pressure + +Controls must not shift when screenshot counts, transcript length, or processing state changes. The primary action remains in a predictable location. + +### 3.3 State is never mysterious + +When InterviewCopilot surfaces an answer or control, its state is unambiguous. It does not remain visible merely to report background listening, capture, or processing state. + +### 3.4 Mode changes behavior + +Coding, System Design, and Behavioral use the same shell but have different inputs, answer schemas, renderers, and follow-up actions. A mode is not just a different system prompt. + +### 3.5 Invisible externally, legible to its user + +The overlay should be visually restrained, but its own state and controls must remain legible. Discretion must not create ambiguity. + +### 3.6 Shortcut-first, visibly operable + +Global keyboard shortcuts are first-class controls for the main live interactions because the user must be able to capture evidence and request help without focusing or revealing the overlay. Every shortcut action also has a visible, keyboard-accessible control when the overlay is open; shortcuts accelerate the product but do not create inaccessible hidden-only functionality. Shortcut hints remain concise and appear in Settings, tooltips, and appropriate empty states rather than beside every repeated control. + +### 3.7 Local-feeling and privacy-explicit + +The interface must plainly distinguish local capture/transcription from data sent to an AI provider. Retention and deletion controls must be understandable without reading legal copy. + +## 4. Theme: Quiet Signal + +### 4.1 Character + +Quiet Signal is the committed InterviewCopilot visual character: calm, precise, discreet, and trustworthy. It avoids gamer aesthetics, large neon glows, decorative gradients, fake terminal motifs, and conversational clutter. + +The visual hierarchy comes from luminance, spacing, typography, and a narrow accent edge—not from large blocks of saturated color. + +### 4.2 Color tokens + +| Token | Value | Use | +|---|---:|---| +| `canvas` | transparent | Electron window outside interactive surfaces | +| `surface-strong` | `rgba(8, 10, 13, 0.94)` | Dock and primary HUD | +| `surface` | `rgba(13, 17, 23, 0.92)` | Answer panels | +| `surface-raised` | `#111720` | Menus, popovers, active cards | +| `surface-hover` | `#171E28` | Hover and selected rows | +| `border` | `rgba(183, 192, 204, 0.16)` | Default boundary | +| `border-strong` | `rgba(183, 192, 204, 0.28)` | Focused or raised boundary | +| `text-primary` | `#F4F7FB` | Main answer and control text | +| `text-secondary` | `#B7C0CC` | Supporting information | +| `text-muted` | `#8590A0` | Metadata and inactive content | +| `signal` | `#6EE7C1` | Global primary action and ready state | +| `coding` | `#6EE7C1` | Coding mode marker | +| `system-design` | `#A78BFA` | System Design mode marker | +| `behavioral` | `#F4C76B` | Behavioral mode marker | +| `info` | `#70B7FF` | Neutral progress and links | +| `danger` | `#FB7185` | Destructive actions and failures | + +Mode colors are identifiers, not separate themes. They may appear on the mode icon, a 2px active edge, a status dot, and selected controls. The primary content surface remains neutral. + +Primary buttons use `signal` with `#06110E` text. System Design and Behavioral do not recolor every primary button; mode color and action hierarchy remain separate concepts. + +### 4.3 Typography + +- UI font: native system sans (`-apple-system`, `BlinkMacSystemFont`, `Segoe UI`, sans-serif). +- Code font: native system monospace (`SFMono-Regular`, `Cascadia Code`, `Consolas`, monospace). +- Settings provides independent content text-size presets: **Small** at 13px / 19px, **Default** at 14px / 21px, and **Large** at 16px / 24px. +- The content preset applies consistently to answers, agent chat, transcripts, and code. It does not resize window chrome or control labels; density controls that geometry separately. +- Primary answer default: 14px / 21px, regular. +- Controls: 13px / 18px, medium. +- Section heading: 13px / 18px, semibold. +- Metadata: 12px / 16px, medium. +- No required information may be smaller than 12px. +- Use sentence case. Avoid all caps except very short transcript speaker labels. + +### 4.4 Geometry and spacing + +- Base spacing unit: 4px. +- Common gaps: 4, 8, 12, 16, and 24px. +- Settings offers two density presets. **Compact** is the default with 32px controls and a 44px primary rail. **Comfortable** uses 40px controls, a 52px primary rail, and the next larger spacing token at dense interaction boundaries. +- Density changes spacing and hit-target geometry only. It never hides actions, changes answer structure, alters shortcuts, or changes the current workspace state. +- Minimum pointer target: 32 × 32px. +- Control radius: 8px. +- Panel radius: 12px. +- Dialog radius: 16px. +- Use a 1px border plus restrained shadow for elevation. +- Use 16px backdrop blur on the primary HUD. Avoid nested blur layers. + +### 4.5 Motion + +- Hover and press transitions: 120ms. +- Panel expansion and state changes: 180ms. +- Use ease-out for entrances and ease-in for exits. +- No bounce or decorative continuous animation. +- Waveform motion is allowed only while audio is actively being captured. +- Respect `prefers-reduced-motion`; state must remain understandable without motion. + +InterviewCopilot does not add a separate High Legibility, high-contrast, or reduced-transparency theme at launch. Quiet Signal's default tokens must carry the required readable contrast without a second visual system. + +### 4.6 Iconography + +Use Lucide, which is already installed. Icons use a consistent 16px size in surfaced controls and 14px in compact metadata. Pair unfamiliar icons with labels until the user has learned the interaction. Do not use emoji as interface icons. + +Keyboard shortcuts use native macOS symbols (`⌃`, `⌥`, `⇧`, `⌘`, `↵`) in the interface while searchable labels and accessibility text spell out Control, Option, Shift, Command, and Return. Keycaps are quiet secondary metadata rather than raised skeuomorphic buttons. + +## 5. Window and shell architecture + +The interface has four deliberate window states. + +### 5.1 Fully hidden + +- The application launches fully hidden and contributes no visible pixels. +- A global visibility shortcut reveals or hides the compact bar. +- Hiding the overlay during an active session does not pause listening, processing, or session context. + +### 5.2 Compact bar + +- Target height: 44px. +- Target width: approximately 320–520px depending on visible controls. +- Its dimensions are automatic rather than user-resizable. +- Before a session, it contains mode selection and **Start Interview**. +- During a session, it presents the locked mode, listening/processing state, compact input status, primary contextual action, Reset access, and More. +- During a session, the permanent action set is Record, Screenshot, Chat, and Submit, followed by the compact context-status indicator. Reset is available under More rather than occupying the repeated live-action row. +- It remains at the user's chosen screen position until hidden with the visibility shortcut. +- It is the collapsed state after an answer is dismissed. +- The main Content View pill is the drag surface. Its neutral background, brand label, and mode/status area can drag the window; action buttons, attachment chips, fields, and other interactive descendants retain their own pointer behavior and never initiate a drag. The compact answer and expanded workspace expose the same familiar pill/header drag surface. +- Position is remembered per display. If a remembered display is disconnected or its work area changes, the bar is clamped fully onto the nearest available display. +- Keyboard movement remains available for precise nudging. + +Concept: + +```text +[InterviewCopilot] [Coding] [Record 00:18] [Camera 2] [Chat] [Submit] [Full context] [HotKeys] [More] +``` + +Record shows capture state and elapsed time. Screenshot shows the pending or session screenshot count. Chat opens the compact composer. Submit uses the universal `Control+Shift+Enter` flow and is disabled only when neither a draft nor selected pending evidence exists. The context indicator uses the states defined under AI provider settings. HotKeys opens the shortcut panel. More contains Reset and other infrequent session actions. + +### 5.3 Compact answer + +- Target width: approximately 520px. +- Shows the immediate answer and one active supporting section. +- Expands from and retains the compact bar. +- Avoids vertical scrolling for the first useful answer whenever possible. +- Opens automatically when a generated answer becomes useful and can be collapsed back to the compact bar. +- Width is stable and height grows with content up to a display-relative cap; overflow then scrolls inside the answer region. +- It is not manually resizable. + +### 5.4 Expanded workspace + +- Target width: approximately 760px, constrained to the active display. +- Used for complete code, diagrams, transcript review, story editing, agent chat, and preferences. +- Expansion is explicit and reversible. +- Window dimensions persist separately from the compact-answer state. +- This is the only manually resizable state. Its size is remembered per display and clamped to the available work area when display geometry changes. + +### 5.5 Session control model + +Before a session, the compact bar presents mode selection and **Start Interview**. There is no separate End Interview control. After Start Interview, the selected mode locks and the bar switches to live status and actions. **Reset** is the only explicit terminal lifecycle action; hiding, collapsing, or expanding the overlay does not change session state. + +The pre-session mode selector is a three-part segmented control with Coding, System Design, and Behavioral visible simultaneously. It uses the mode accents only for the active segment and supports arrow-key navigation. The bar grows to its pre-session width rather than collapsing the three initial modes into a menu. A larger mode chooser becomes appropriate only if future custom or specialist modes exceed the available bar width. + +The compact bar is the persistent command rail whenever the overlay is visible. A global visibility shortcut is required. Provider, model, and language controls never appear in the live bar. The active Coding language may appear as read-only metadata in a generated answer. + +Reset stops audio capture, cancels in-flight processing, discards the active provider conversation, seals the completed session into local History, clears every artifact from the active HUD and working context, and returns the product to its pre-session Start Interview state. It preserves preferences, provider configuration, reusable profile or Story Bank data, and the archived History entry. + +The user selects a mode before Start Interview. That mode remains locked until Reset and appears as compact status in the active bar. Changing mode therefore always begins from a clean session state. + +Within the active session, InterviewCopilot retains the complete local sequence of transcript segments, screenshots, detected questions, answers, follow-ups, and explicit interviewer constraints. The selected provider owns one persistent resumable conversation for the life of that interview session. The initial provider turn receives the complete applicable starting context; subsequent turns send new inputs and changes into the same conversation, where the provider retains and automatically compacts working history as needed. Behavioral and System Design initialize with the complete candidate dossier and active opportunity context; Coding excludes both under D-037. The active session and provider conversation identifier are saved locally so a crash or accidental quit can offer Resume or Reset on relaunch. + +The primary live loop is capture-first and shortcut-friendly: + +1. The user manually starts or resumes recording and may manually take one or more screenshots. The global Record action starts or resumes microphone and system-audio capture together; invoking it while both are active pauses both. +2. Finalized transcript segments and screenshots appear as pending input artifacts; neither capture action silently generates an answer. +3. The user invokes the mode-specific answer action, including through the existing `Control+Shift+Enter` shortcut pattern. InterviewCopilot sends the applicable new evidence into the current persistent agent and streams the result into the curated mode-specific layout. +4. Recording and screenshot capture remain available after every answer. Later turns add evidence to the same interview conversation and current question branch unless the user explicitly starts a new branch. +5. The user may open the agent composer and submit a typed message by itself or together with newly captured transcript and screenshots. This is another turn in the current provider conversation, not a separate chat session. + +Every answer action and composer submission automatically preselects all finalized transcript segments and screenshots captured since the previous successful agent turn. These pending artifacts appear as individually removable attachment chips before submission. Removing a chip excludes that artifact from the upcoming turn without deleting it from the local session; it remains pending until submitted, explicitly discarded, or intentionally excluded from agent context. Previously accepted artifacts remain available through the persistent provider conversation and are not redundantly attached again. + +Submitting with no typed message sends the selected pending evidence as a mode-specific answer request. Submitting with text sends the message and selected pending evidence together. When no pending evidence is selected, the message is a text-only turn with the current agent. A submission with neither text nor selected evidence is disabled. + +The default main-interaction shortcut map is: + +| Action | Default global shortcut | +|---|---| +| Show or hide InterviewCopilot | `Control+Shift+H` | +| Start/resume or pause both recording sources | `Control+Shift+R` | +| Capture the primary display | `Control+Shift+S` | +| Capture and diagnose the current Coding implementation | `Control+Shift+D` | +| Reveal and focus the compact agent composer | `Control+Shift+C` | +| Submit pending evidence and optional message | `Control+Shift+Enter` | +| Move the answer view | `Control+Shift+Arrow keys` | +| Navigate answer sections and scroll active content | `Control+Option+Arrow keys` | +| Reset the active interview | `Control+Shift+Backspace` | + +Record deliberately takes the mnemonic `R`; the destructive Reset action moves away from the easily repeated recording key. All shortcuts are user-remappable in Settings, with conflict detection and a restore-defaults action. + +`Control+Shift+C` reveals the overlay if necessary and opens a compact composer attached to the current HUD rather than expanding the full workspace. It focuses the message field, exposes the removable pending-evidence chips from D-043e, and preserves the last curated answer behind or above it. Invoking the shortcut again focuses the already-open composer rather than closing it. Closing the compact composer returns to the exact prior hidden, compact-bar, or answer state without changing recording or session state. + +The compact composer is a multiline field. `Enter` inserts a newline. `Control+Shift+Enter` is the single universal Send/Submit action whether or not the composer is focused: when a draft exists, it sends that message with the selected pending-evidence chips; without a draft, it submits the selected pending evidence as a mode-specific answer request. With neither a draft nor selected evidence, it performs no provider request and visibly indicates that input is required. `Control+Enter` has no special behavior. A visible Send button provides the equivalent pointer-accessible action. + +`Control+Shift+Arrow keys` moves the entire current answer view without focusing it. Movement repeats smoothly while a key is held, respects the usable display bounds, and updates the remembered position for that display. It does not scroll answer content or change the active section. + +The **HotKeys** button opens a translucent panel anchored to the Content View pill. The panel groups commands into Session, Capture, Agent, Answer navigation, Window, and Accessibility; shows every current binding; allows inline rebinding; detects system and in-app conflicts before saving; and provides Reset all to defaults. Closing it returns focus to the originating HotKeys button. It is available before and during a session and never pauses recording or processing. + +Completed sessions are retained as searchable local History. History is deliberately absent from the live shell and main navigation; it is available only under **Settings → History**. Reset clears the active interview experience but archives the completed session rather than deleting it. Archive contents, retention controls, and at-rest protection are resolved separately. + +Each History entry retains its mode, timestamps, finalized transcript with available speaker attribution, detected questions, interviewer constraints, generated answers, code, diagrams, summaries, follow-ups, and compressed screenshots. Raw microphone or system-audio recordings are never archived. Temporary audio buffers are discarded after transcription. + +History entries remain indefinitely until the user explicitly deletes them. InterviewCopilot does not automatically expire or prune completed sessions based on age. + +Settings → History supports search, opening an archived session, deleting one session, deleting all History, and exporting one session as Markdown or structured JSON. Markdown export includes referenced image assets in a companion folder or bundle; JSON preserves the typed session structure. Tags, favorites, multi-select, and bulk export are out of scope initially. + +All persisted active-session recovery data and archived History use application-level encryption at rest. The encryption key is generated per installation and stored through macOS Keychain or Windows Credential Manager, not alongside the encrypted database. Search indexes and cached screenshot representations must not create plaintext copies. Export deliberately decrypts the selected session into the user-chosen destination. + +### 5.5 Input tray + +Screenshots and transcript segments share one collapsible input tray. + +- Screenshots collapse into a stable `Camera 3` control rather than consuming horizontal width. +- Screenshot input captures the operating system's current primary display in full. Region, active-window, and per-session display selection are intentionally unsupported. +- Expanding it reveals a horizontal carousel with always-discoverable remove actions. +- The latest transcript remains visible as a maximum two-line preview. +- Partial transcript text is muted; finalized text is primary. +- The user can edit or select the detected question before invoking an answer. +- When screenshot and transcript evidence conflict, the screenshot is authoritative. Spoken content may supplement compatible constraints but does not override visible requirements. With no screenshot present, the transcript becomes the primary question source. + +### 5.6 Answer workspace + +- The first tab is always the shortest immediately useful response. +- Answer generation is progressive. On Submit, the workspace creates stable section shells immediately and streams each usable section as its content arrives; it never waits for the complete response before showing useful content. +- Streaming may fill independent sections concurrently, but it must not reorder visible sections or repeatedly reflow the reading position. A quiet in-section live indicator distinguishes incomplete content and disappears when that section is final. +- Completed sections remain readable and interactive while other sections continue. A late section or diagram cannot block an earlier speakable answer, approach, or correction. +- Only one main content region is active at a time. +- Agent chat is a secondary input surface inside the expanded workspace. The curated answer renderer remains primary; opening chat does not replace it with a generic terminal or chronological agent transcript. +- A typed chat turn uses the same locked interview mode, provider, model, prompt policy, applicable personal context, current question branch, and persistent provider conversation as shortcut-generated answers. +- Responses to chat turns populate the applicable curated answer sections when they satisfy the current mode schema. Conversational clarification that does not map to a structured section remains visible in a compact chat exchange without replacing the last curated answer. +- Curated response sections are individually collapsible. One section is keyboard-active at a time. `Control+Option+Left/Right` moves to the previous/next section, collapses the section being left, expands the destination, and scrolls its header into view. `Control+Option+Up/Down` scrolls vertically inside the active section without changing sections. Manual header activation toggles any section without changing provider context. + +### 5.7 Capture-privacy qualification + +Capture privacy is a tested platform capability, not a UI setting or an inferred consequence of calling Electron's content-protection API. + +- The qualification unit is an exact tuple of operating-system family and supported release range, display mode, InterviewCopilot window mode, capture API or application, capture scope, and relevant application version. +- Every candidate tuple must be exercised with a deterministic, high-contrast moving marker in the overlay. Automated or reproducible capture inspection must prove that the marker never enters captured frames while ordinary underlying content remains visible. +- Full-display capture, individual-window capture, browser-tab sharing, operating-system screenshots, built-in screen recording, and supported third-party conferencing/recording paths are distinct cases. A pass in one does not imply a pass in another. +- macOS is the only launch engineering and capture-privacy qualification target. Windows and Linux application support and capture qualification are deferred to a later phase. +- The existing macOS build has already passed real entire-display and specific-window screen-sharing tests and both behaviors must be preserved as launch regression baselines. Electron's documented ScreenCaptureKit limitation means these results cannot be generalized to every application or version without testing. +- Entire-display, specific-window, and browser-tab sharing remain separate macOS qualification paths. The first two have an observed working baseline; browser-tab sharing and every named launch application still require explicit verification. +- Google Meet is the only conferencing product in the initial launch qualification matrix. A final test of the release build on the supported macOS and browser versions is a mandatory release gate. Zoom, Microsoft Teams, and other sharing or recording products are deferred and must not inherit the Google Meet claim without their own tests. +- Do not add an application-agnostic “Test My Setup” flow at launch. Arbitrary capture software cannot be meaningfully certified by a generic self-test, and the extra setup would add disproportionate complexity. Keep verification limited to explicitly qualified integrations. +- The implementation safeguard is centralized in `electron/captureProtection.ts`. Every InterviewCopilot `BrowserWindow` must call `applyCaptureProtection` immediately after creation and whenever a lifecycle path can recreate or materially reconfigure the window. A unit guard ensures that helper always invokes `setContentProtection(true)`. Removing, bypassing, or weakening this helper is a release-blocking change and still requires the external Google Meet regression test because unit coverage cannot inspect captured frames. +- Settings → Privacy & Capture includes a guided Google Meet verification. It walks the user through entire-display and specific-window sharing with a conspicuous animated test marker and requires confirmation from Meet's remote presentation view or a second participant/device for each scope. The app never infers a pass from the local preview alone. +- A completed guided test stores a local verification record containing the InterviewCopilot version, macOS version, browser name/version, tested Meet scopes, timestamp, and user-confirmed result. Settings then shows **Google Meet verified on this Mac** with the tested scopes and date. The state is **Not verified** before testing, **Verification failed** after any failed scope, and **Retest required** after an InterviewCopilot update that touches window/capture behavior or after a macOS/browser major-version change. This status is evidence for the recorded configuration, not a universal guarantee. +- Future Windows qualification requires Windows 10 version 2004 or newer because that is where `WDA_EXCLUDEFROMCAPTURE` is documented, but no Windows capture-privacy claim belongs in the macOS-focused launch. +- Microsoft explicitly describes display affinity as a content-protection aid rather than DRM or a security boundary. InterviewCopilot must not extrapolate a passing ordinary-capture test into platform or local-process undetectability. +- Linux capture stacks and compositors vary substantially and are unqualified until separately proven. +- Release CI must retain golden capture artifacts and fail the capture-privacy gate when the overlay appears in any supported captured frame. Manual qualification remains necessary for external applications whose capture pipeline cannot be automated reliably. + +Primary documentation inputs: + +- [Electron `BrowserWindow.setContentProtection`](https://electronjs.org/docs/latest/api/browser-window) +- [Microsoft `SetWindowDisplayAffinity`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity) +- [Apple ScreenCaptureKit](https://developer.apple.com/documentation/screencapturekit) +- Secondary detail uses tabs or disclosure panels, not a long stack of equally weighted sections. +- Copy actions remain visible on focus and hover and are keyboard accessible. +- Streaming begins with the concise response before deeper sections complete. + +## 6. Mode specifications + +### 6.1 Coding + +Primary action: **Solve** + +Tabs: + +1. **Answer:** A concise explanation the candidate can say immediately. +2. **Plan:** Algorithm, alternatives, edge cases, and clarifying questions. +3. **Code:** Implementation, read-only language label, line numbers, and copy action. +4. **Explain:** Walkthrough, complexity, tests, and likely follow-ups. + +Contextual actions: Simpler approach, Optimize, Find bug, Explain selection, Test edge cases, and Predict follow-up. + +Debugging is a follow-up state inside Coding rather than a top-level interview mode. + +Every Coding request has an explicit user-selected intent: Analyze, Generate Code, Debug, or Follow-up. InterviewCopilot does not classify later screenshots or speech into an intent automatically. The selected intent determines the response schema and primary action before provider processing begins. + +`Control+Shift+D` is a dedicated **Fix current code** intent within an active Coding question branch. It captures the operating system's current primary display and immediately submits that new screenshot to the current persistent agent. It does not include unrelated staged artifacts, which remain pending, and it never falls back to Analyze, Generate Code, or full answer regeneration. + +The agent compares the screenshot with the current problem, constraints, generated solution, and prior fixes, then returns a targeted diagnostic response: detected issue, minimal correction, corrected snippet or patch, and a short explanation. The existing approach and full solution remain intact. The fix appears as a new versioned Fix card/section associated with the current answer. If no defect can be identified confidently, the result says so and requests a more useful screenshot rather than inventing a change. Outside an active Coding branch, the action is unavailable and explains why; there is no cross-mode fallback. + +**New Question** creates a clean Coding problem workspace inside the same interview session. It closes the prior problem branch, clears its active screenshots and problem-specific working context from the input tray, and preserves the complete interview-level transcript, prior question branches, and History chronology. Follow-up always attaches to the current problem branch. + +Generated code is read-only inside InterviewCopilot. The Code tab provides Copy, Regenerate, Debug, and Explain actions plus normal text selection, but no editing, execution, terminal, or test runner. The interview platform or external IDE remains the place where the candidate changes and runs code. + +For the primary Senior/Staff+ audience, Coding answers should prioritize communicating assumptions, choosing between viable approaches, production-quality failure handling, testing strategy, and maintainability—not only reaching the expected algorithm. + +After Solve, Coding opens on Answer with a two-to-four-bullet approach, one key trade-off, and one-line time and space complexity. Full code streams into the adjacent Code tab and never displaces the concise first view. + +First-class Coding language families are Python 3, JavaScript/TypeScript, Java, Go, C++, and C#. Rust, Swift, Kotlin, Ruby, SQL, and R remain selectable as best-effort languages. First-class support requires dedicated prompt fixtures, syntax rendering, response parsing, representative interview-problem regression tests, and debugging coverage; best-effort languages do not carry the same quality guarantee. + +Coding language is a global preference under Settings. Every Coding session snapshots the current preference at Start Interview and uses it for the whole session. Changing the global preference while a session is active applies to the next Coding session rather than mutating the active one. + +### 6.2 System Design + +Primary action: **Design** + +Tabs: + +1. **Clarify:** Functional requirements, nonfunctional requirements, constraints, and clarification questions. +2. **Estimate:** Traffic, storage, bandwidth, and explicit assumptions. +3. **Architecture:** Read-only generated architecture diagram with inspectable components. +4. **Data & APIs:** Data model, events, and endpoint contracts. +5. **Deep Dives & Trade-offs:** Bottlenecks, consistency, failure modes, migration, and scaling path. + +Every design uses this sequence. The model may leave a section intentionally concise when it is not material, but it may not reorder the workflow or invent an unrelated document structure. + +Estimate defaults to two to four calculations that materially influence the architecture, each with visible assumptions and units. It avoids exhaustive or decorative arithmetic. A Deepen estimates action can request storage, bandwidth, cache, cost, or other secondary calculations when relevant. + +Design generates all five sections immediately from the available screenshot, transcript, and session context. Clarify lists the questions that should be asked and labels every inferred answer as an assumption, but it does not gate Architecture or require manual confirmation. Later interviewer answers can be supplied through Follow-up and used to regenerate affected sections. + +System Design Follow-up is agent-directed. The agent analyzes each new constraint, determines its dependency blast radius, updates only the sections that should change, and preserves unaffected work. It may regenerate the full architecture when a constraint invalidates the foundation. Every revision returns a concise What changed summary covering assumptions, estimates, components, APIs/data, and trade-offs that materially changed. The user does not manually select sections to refresh. + +The architecture view is a structured, read-only node-and-edge rendering rather than a flat model-generated image. Each component can expose purpose, scale, alternatives, and failure behavior. The user may inspect, zoom, pan, or regenerate the diagram but cannot move, rename, add, remove, reconnect, copy, or export elements inside InterviewCopilot. + +Diagram nodes use a vendor-neutral vocabulary such as Client, Gateway, Service, Queue, Stream, Worker, Cache, Database, Object Store, Search Index, and External System. Cloud-specific products may be mentioned as implementation examples in component details but do not replace the generic architecture labels or introduce provider-logo dependency. + +The Architecture tab provides no standalone diagram export. Diagram data remains part of the archived session and whole-session Markdown/JSON export, but there is no Mermaid, SVG, PNG, or image-copy action for the diagram itself. + +For the primary audience, the mode must support ambiguous requirements, cross-team boundaries, migration paths, operational ownership, cost, and explicit trade-off narratives in addition to component selection. + +### 6.3 Behavioral + +Primary action: **Coach answer** + +Tabs: + +1. **Answer:** A concise, conversational response outline. +2. **STAR:** Situation, Task, Action, and Result structure. +3. **Evidence:** Metrics, decisions, ownership, and concrete details to mention. +4. **Follow-ups:** Likely challenges and suggested response angles. + +Behavioral includes a private Story Bank. Stories are structured evidence, not only generated prose. The live answer should default to glanceable talking points rather than a paragraph intended to be read verbatim. + +For the primary audience, prompts and evidence should emphasize technical leadership, influence without authority, strategy, conflict, mentoring, organizational leverage, and measurable business or reliability outcomes. + +The Story Bank lives inside a canonical Markdown candidate dossier, logically named `candidate-profile.md`. InterviewCopilot stores the document encrypted at rest, presents it through a friendly editor under Settings, and supports explicit Markdown import/export. The agent receives the Markdown content as the authoritative reusable candidate context. + +An agent-guided conversation creates and maintains the dossier. It can start from an empty profile or imported resume, interview the user about roles, projects, decisions, conflicts, failures, leadership, scope, and measurable outcomes, identify missing evidence, and draft the final Markdown for review. The user can resume the conversation later to refine or add stories. + +Recommended document structure: + +1. Candidate summary and target roles. +2. Career timeline and role scope. +3. Technical strengths and domains. +4. Projects and measurable outcomes. +5. Leadership principles and working style. +6. Story Bank entries with competencies, STAR evidence, metrics, and provenance. +7. Known constraints, weak areas, and claims not to make. + +Each story carries provenance such as `verified`, `user-edited`, or `synthetic-draft`. + +The global **Allow synthetic stories** setting is off by default. When off, Behavioral mode uses only verified or user-edited dossier evidence and states when no suitable story exists. When on, the agent may create a realistic fallback consistent with the candidate's documented roles, seniority, technologies, and scope. It saves the new story to the dossier as `synthetic-draft`, shows a subtle Synthetic label in the live answer, and reuses the same facts for future consistency. Synthetic stories are never silently promoted to verified. + +Verified and user-edited stories use only dossier-backed facts and metrics. When a real outcome was not measured or recorded, the answer stays qualitative rather than inventing precision. A synthetic story may include plausible synthetic metrics when the setting is enabled; those values inherit the story's Synthetic label and are saved with it so later answers do not drift. + +Answer opens with concise talking points suitable for glancing while speaking. An optional **Full Answer** view expands those same facts into polished conversational prose. Changing format must not introduce new events, technologies, scope, outcomes, or metrics; both views are renderings of the same selected Story Bank entry. + +Opportunity-specific context is maintained separately from the candidate dossier as a Markdown document logically named `interview-context.md`. It contains company, role/title, level, job description, competency focus, interview-loop notes, and user instructions. It is edited under Settings → Profile & Context, stored encrypted locally, and preserved across Reset. The Behavioral agent receives both `candidate-profile.md` and the selected interview context so durable candidate facts are not contaminated by one opportunity. + +Settings may hold multiple named opportunity contexts, such as `Stripe — Staff Engineer`, with exactly one active selection. The active selection persists across Reset and is snapshotted into each archived session so later edits do not rewrite historical context. Selecting or editing an opportunity while a session is active applies to the next session. + +The candidate dossier and active opportunity context are available to Behavioral and System Design. Behavioral uses them for story selection and phrasing; System Design uses relevant domain experience, target level, company context, and role expectations to calibrate depth and examples. Coding never receives either document and remains grounded in the problem evidence, session context, and global language preference. + +## 7. Voice and transcript experience + +Voice is part of the session shell, not a separate transcription screen. + +Required visible states: + +1. Microphone off. +2. Listening. +3. Speech detected. +4. Transcribing. +5. Question detected. +6. Preparing answer. +7. Ready. +8. Audio or permission error. + +Recommended baseline behavior: + +- Local transcription is the default. An optional cloud fallback may be enabled by the user for unsupported hardware, insufficient local performance, or accuracy problems. +- InterviewCopilot never silently changes from local to cloud transcription. The active transcription path is visible in Audio settings and session status. +- Transcription is the only model-driven capability required to run locally. Diarization, question detection, summarization, context reasoning, conflict resolution, and answer generation are delegated dynamically to frontier models through the user's configured subscription. +- Every new session initializes both system audio and microphone as off. Start Interview creates the session but does not capture audio until the user explicitly enables at least one source. +- Once enabled, a source is captured continuously until the user pauses it, disables it, or resets the session. +- Pause/Resume stops or restarts new capture without discarding context or ending the session. Hiding or collapsing the overlay does not pause capture. +- System audio and microphone are separate channels with independent user-controlled activation. Either source may be enabled or disabled before or during the session without resetting context. +- The global Record action is a deterministic master toggle for both sources: when both are actively capturing it pauses both; when either source is inactive or paused it starts or resumes both. The visible per-source controls may still disable or re-enable microphone and system audio independently after the master action. +- Question detection updates the transcript candidate but never submits an AI answer request automatically. +- The compact bar waits for the user to invoke the mode-specific primary action: Solve, Design, or Coach answer. +- Question detection surfaces a reviewable candidate question and a visible Answer action. +- System-audio segments default to `INTERVIEWER` and microphone segments default to `YOU`. +- Frontier-model diarization separates voices when a single channel contains multiple speakers, such as an in-person interview captured through the microphone. +- Uncertain attribution is explicitly marked rather than silently guessed. The transcript view lets the user correct a segment label, and that correction updates session context and archived History. +- The microphone control shows elapsed listening time and a restrained waveform. +- A privacy indicator states whether transcription is local or remote. +- Session audio retention is off by default; transcript retention is a separate setting. +- Spoken AI output is out of scope for the first voice release. + +## 8. Loading, error, and recovery behavior + +- InterviewCopilot is fully silent. Recording, screenshot capture, submission, completion, cancellation, and errors use visual state only; the app emits no UI sounds, spoken responses, or haptic feedback. +- Primary actions change to a clear progress state and expose Cancel. +- Cancel interrupts only the active provider turn. It does not Reset the interview, discard submitted context, close the persistent provider conversation, or roll back completed output. +- Each answer section may complete independently. Completed sections remain final; an interrupted partial section remains visible with an `Incomplete` state rather than disappearing. +- After cancellation or partial failure, offer **Continue unfinished** for only the interrupted or failed sections. It resumes from the existing provider conversation and request identity, so evidence already accepted into context is not submitted as a duplicate question. +- If a deeper section fails, preserve already completed content. Whole-response Retry appears only when no usable section completed or the provider session itself must be recovered. +- Uncertain interpretation never blocks generation and does not produce a numeric confidence score. The agent makes a best-effort answer, states only assumptions that materially affect it, and may add a compact **Questions to ask the interviewer** section when clarification would change the solution or recommendation. +- A user correction sent through chat becomes a context delta on the current question branch. The agent revises only affected sections and preserves unaffected output. +- Permission errors link directly to a short resolution step. +- A disconnected provider never masquerades as a generic processing failure. +- Permission and provider failures are inline, scoped, and recoverable. Disable only the affected action, preserve the active session and all local context, and show the exact next action: **Open System Settings** for a denied macOS permission or **Reconnect** for provider authentication, followed by **Retry**. +- Declining microphone permission leaves screenshots, typed chat, and other permitted inputs usable. Declining screen-capture permission leaves audio and typed chat usable. A provider outage prevents new answer turns but does not prevent reviewing existing output or managing local pending evidence. +- Do not trap the user in repeated permission dialogs or generic toast loops. After denial, request again only from an explicit user retry. +- Reset always means clear the entire live session and return to Start Interview; it is not reused for question-level actions. +- Destructive session actions require confirmation only when unsaved reusable context would be lost. + +## 9. Preferences and onboarding + +First run uses one compact setup checklist rather than a tutorial carousel: + +1. Detect Claude Code and Codex installation/authentication state. +2. Require the user to select and successfully authenticate exactly one subscription provider. +3. Continue directly to the pre-session compact bar and **Start Interview**. + +Microphone, system-audio, and screen-capture permissions are not requested speculatively during onboarding. Request each permission in context when the user first invokes the feature, explain the immediate reason in one sentence, and keep unrelated features usable if the user declines. + +Preferences are grouped into: + +1. General. +2. Profile & Context. +3. Audio. +4. AI provider. +5. Privacy. +6. Prompts and templates. +7. History. +8. Advanced. + +Provider diagnostics and raw model identifiers belong in AI provider or Advanced. They must not crowd the live HUD. + +Answer intelligence supports subscription-authenticated Claude Code and Codex only. InterviewCopilot does not expose OpenAI, Anthropic, or Gemini API-key provider configuration. Settings detects CLI installation and subscription authentication independently for Claude Code and Codex. Optional cloud transcription is configured separately under Audio and does not reintroduce a general answer-provider API-key flow. + +InterviewCopilot has no product plans, credits, quotas, or feature entitlements. Every shipped feature is available in the open-source application; users are responsible only for access to their selected Claude Code or Codex subscription. Legacy credit counters, subscription portal surfaces, out-of-credits events, and paywall-era copy are migration debris and must be removed. + +InterviewCopilot collects no product analytics, behavioral events, device fingerprints, or remotely uploaded crash reports. Operational diagnostics remain local and must exclude transcripts, screenshots, audio, prompts, model responses, candidate/opportunity documents, provider credentials, and authentication tokens. Settings may provide a user-initiated diagnostic export with a preview of the redacted bundle; nothing is transmitted automatically. + +The user selects exactly one subscription provider. Start Interview snapshots that provider for the persistent conversation. InterviewCopilot never fails over, retries through, or routes work to the other provider automatically. A provider failure surfaces a clear recoverable error and leaves switching entirely under user control; a Settings change applies to the next session. + +Settings stores a separate model selection for Claude Code and Codex, including an explicit Provider default choice. Start Interview snapshots the model with the provider, and that pair remains fixed for the persistent conversation. InterviewCopilot never upgrades, downgrades, or routes between models per task. A Settings change applies to the next session, and each archived session records the provider/model pair it used. + +AI provider settings also expose a two-state **Response mode** control: + +- **Fast:** ask the selected model for lower-latency, concise reasoning using the provider's supported lower-effort control. +- **Reasoning:** allow the selected model more deliberate reasoning using the provider's supported higher-effort control. + +This is a user choice, not automatic routing. The provider-neutral driver translates the two product states into provider-specific effort options without changing the selected provider or model. Start Interview snapshots response mode together with provider and model; all three remain locked for the persistent interview conversation, and Settings changes apply to the next session. If a provider/model cannot honor a state, the UI marks that combination unavailable rather than silently substituting a model, provider, or effort level. Both states publish and stream usable content immediately when the provider makes it available; InterviewCopilot never holds a Fast response to meet a layout threshold or cuts off a Reasoning response to meet a timer. + +The persistent provider conversation must have access to the full applicable active-session record. The initial turn seeds all starting context, and later turns add finalized transcript, new question branches, screenshots, generated answers, follow-ups, constraints, and mode-state changes. Behavioral and System Design seed the full candidate dossier and active opportunity context. Coding never receives those personal documents. Raw audio is excluded unless a separate cloud-audio operation explicitly requires it. + +The active HUD includes a compact context-status indicator. Its normal settled label is **Full context** with a checkmark, meaning every applicable, submitted artifact has been accepted into the persistent provider conversation. It changes to **New context · N** while `N` locally captured artifacts are staged but not yet submitted, **Updating** while artifacts are being sent, and **Context issue** when anything is rejected, interrupted, or still pending after a retry. Provider compaction does not make the indicator an error: when the provider explicitly reports compaction, the detail view records **Provider compacted** while the main label remains **Full context** because the persistent conversation still owns the working history. The label must never imply that every original token remains verbatim after provider compaction. + +Selecting the indicator opens a restrained detail popover showing the snapshotted provider and model, interview mode, last successful update, and included source categories with counts: transcript segments, screenshots, question branches, and mode state. Behavioral and System Design also show whether candidate profile and opportunity context were included; Coding explicitly shows them as excluded by mode. Provider-reported context-window use and compaction status may appear when available. Estimated or fabricated token counts are prohibited. + +Settings → Prompts and templates opens a dedicated **Prompt Studio** with two synchronized surfaces: + +1. **Chat:** A specialized prompt agent interviews the user about desired behavior, proposes a template, explains effects, and presents a reviewable diff before saving changes. +2. **Manage:** A manual CRUD interface to create, read, duplicate, edit, rename, and delete user templates. + +Built-in mode templates are readable, duplicable, and restorable but not destructively editable. User templates may customize instructions, tone, depth, priorities, and output preferences while the underlying typed response schema and renderer contract remain protected. Chat and manual edits operate on the same stored template representation. + +At launch, every user template is a variant of Coding, System Design, or Behavioral and remains inside that core mode's template selection. Custom named modes that inherit a core schema and appear under More are deferred to a later phase. Completely arbitrary schemas and renderers are out of scope. + +Instruction conflicts are resolved dynamically by the agent rather than through a user-visible fixed precedence ladder. The agent weighs current-task relevance, specificity, recency, provenance, and mode applicability and records the effective resolution in session state. Protected response schemas and explicit product invariants—such as screenshot authority, mode locking, and the factual/synthetic Story Bank rules—remain outside dynamic resolution and cannot be overridden by a template or dossier entry. + +There is no second tutorial or permission checklist after provider setup. +Capture and microphone permissions remain contextual first-use requests, the +default mode is selected in the pre-session bar, and a sample question is not +required to finish onboarding. + +## 10. Accessibility baseline + +- All controls have visible keyboard focus. +- Required text meets WCAG AA contrast against its rendered translucent surface. +- Status never relies on color alone. +- Live transcript changes use appropriate, noninterrupting announcements. +- The waveform has a text equivalent. +- Focus is retained predictably when compact panels expand. +- Hover-only actions are prohibited. +- Zoom must not push surfaced answer controls out of reach. +- Reduced motion is supported. Quiet Signal must remain readable at the + accessibility baseline without a separate product-level high-contrast or + reduced-transparency appearance mode at launch. + +## 11. Competitive interpretation + +Research inputs: + +- [ULTRACODE](https://ultracode.ai/#features) +- [InterviewCoder](https://www.interviewcoder.co) + +Patterns worth adopting: + +- A single visually dominant live action. +- Progressive disclosure of alternative and deeper answers. +- Clear audio/capture feedback when a setup, answer, or recovery surface is intentionally visible. +- Mode-specific prompt/context management. +- Compact, progressively disclosed answer controls. + +Patterns to avoid: + +- Heavy neon glow and promotional gradients. +- Tiny low-contrast controls. +- Treating every mode as code with a different prompt. +- Long generated documents without a glanceable first answer. +- Marketing claims inside the product interface. + +## 12. Architecture implications + +Implementation should eventually introduce these concepts: + +- `InterviewMode`: mode identity, action labels, context fields, prompt policy, answer schema, renderer, and follow-up actions. +- `InterviewSession`: session type, mode, inputs, transcript, questions, responses, and retention state. +- `InputArtifact`: screenshot, transcript segment, or manual text with provenance and timestamps. +- `ResponseSection`: independently streamable typed output rather than one regex-parsed response. +- Semantic design tokens exposed through CSS variables and Tailwind mappings. +- Shared primitives for pre-session setup, temporary answer header, input tray, tabs, disclosure section, empty state, skeleton, and error recovery. + +### 12.1 Provider runtime and orchestration + +InterviewCopilot should reuse the architectural boundary proven in twarp's agent view without adopting a generic coding-chat product model: + +1. A provider-neutral `AgentDriver` owns installation and authentication checks, process lifecycle, persistent session or thread identity, structured input, normalized streaming events, graceful interruption, resume, token/context signals, compaction signals, and provider errors. +2. The Claude adapter runs one long-lived headless CLI process per interview using structured JSON input and output, a pinned session identifier, the InterviewCopilot system prompt, schema-constrained output where supported, deliberately restricted tools, and native resume. +3. The Codex adapter runs `codex app-server` over its structured protocol, starts or resumes one thread per interview, installs InterviewCopilot instructions as thread-level developer instructions, uses application-labeled additional context and per-turn output schemas, and consumes native usage and compaction events. +4. An Interview Orchestrator above both adapters owns the selected mode, protected product invariants, prompt-template composition, applicable dossier and opportunity context, transcript and screenshot provenance, question branches, requested intent, typed response schemas, retries, and synchronization state. Provider-specific JSON never reaches the renderer. +5. A session reducer converts normalized provider and capture events into the durable `InterviewSession` and independently streamable `ResponseSection` model. The compact HUD renders that typed state rather than raw assistant Markdown or terminal scrollback. +6. The encrypted local session archive remains the canonical unabridged product record. Native Claude or Codex persistence is a resumable reasoning runtime, not InterviewCopilot's History database or only source of truth. +7. Shortcut-generated answers and typed composer messages enter the same orchestrator and persistent conversation. They differ only in user intent and which new input artifacts accompany the turn; provider adapters and renderers do not maintain a separate chat agent. + +This is therefore a specialized agent host, not merely a terminal wrapper with a system prompt. The provider supplies frontier reasoning, authentication, model access, persistence, and automatic compaction; InterviewCopilot supplies interview state, context policy, mode-specific contracts, capture, privacy, and the pressure-optimized interface. + +The twarp patterns to reuse are the long-lived process per conversation, provider-neutral driver capabilities, normalized event stream, one-writer command channel, graceful Stop, native resume, defensive parsing, and explicit context usage. The generic composer, raw terminal toggle, coding tool/diff cards, unrestricted agent tools, and reliance on provider session files for product history should not become the primary InterviewCopilot experience. + +Detailed component and storage architecture will continue to tighten as the remaining product decisions are resolved. + +## 13. Decision tree + +Decisions are resolved in dependency order. A later branch may be reordered when an earlier answer removes or introduces a dependency. + +### A. Product center + +- **D-001 — Resolved:** InterviewCopilot is primarily a Live interview copilot. +- **D-002 — Resolved:** The canonical product and display name is `InterviewCopilot`. +- **D-003 — Resolved:** Optimize the initial experience for Senior and Staff+ software engineers. +- **D-004 — Resolved:** Lead with discretion and prove it through Staff-level judgment across the entire interview loop. +- **D-005a — Superseded by D-005c:** The earlier absolute invisible/undetectable positioning is replaced by a testable capture-privacy claim. +- **D-005b — Resolved:** Enforce no usage boundary, responsibility notice, or consent requirement; the user is entirely responsible for use. +- **D-005c — Resolved constraint:** Claim capture privacy only for qualified ordinary screen-sharing and recording configurations; do not implement or claim evasion of platform, proctoring, process, or device monitoring. +- **D-005d — Resolved:** Focus launch engineering and capture-privacy qualification exclusively on macOS; defer Windows and Linux. +- **D-005e — Resolved for launch:** Qualify Google Meet entire-display and specific-window sharing; defer Zoom, Teams, and other capture applications. +- **D-005f — Resolved:** Show Google Meet verification only after a guided entire-display and specific-window test on the current Mac/browser, and invalidate it after relevant version changes. +- **D-005g — Resolved:** Use the broad headline “Stay private while you share your screen,” qualified by “InterviewCopilot is designed to stay out of ordinary macOS screen shares and recordings. Coverage varies by application and capture mode; verify your setup before an interview.” Keep application-specific verification details in Privacy & Capture rather than naming Google Meet in the primary promise. +- **D-005h — Resolved:** Do not build a generic “Test My Setup” verifier at launch; expose verification only for applications and capture modes InterviewCopilot explicitly qualifies. + +### B. Session model + +- **D-006a — Resolved:** `Start Interview` explicitly starts a session; there is no separate End Interview action, and `Reset` is the only terminal lifecycle control. +- **D-006b — Resolved, refined by D-009a:** Reset archives the completed session, clears the entire active interview context, and preserves durable preferences and reusable profile data. +- **D-007 — Resolved:** Lock the selected interview mode from Start Interview until Reset. +- **D-008 — Resolved, refined by D-043a/b:** Retain complete local history and maintain the complete applicable working context in one persistent provider conversation per interview. +- **D-009a — Resolved:** Persist active-session recovery and completed searchable History locally; expose History only under Settings. +- **D-009b — Resolved:** Archive the full structured session and compressed screenshots, but never archive raw audio. +- **D-009c — Resolved:** Retain History indefinitely until the user explicitly deletes it. +- **D-009d — Resolved:** Automatically encrypt persisted session recovery and History with an application key held by the operating-system credential store. +- **D-009e — Resolved:** Provide search, open, delete one, delete all, and individual Markdown/JSON export; omit advanced library management initially. +- **D-010 — Deferred:** If Practice is introduced later, how is it kept separate from the Live experience? + +### C. Shell and navigation + +- **D-011a — Resolved:** Launch fully hidden; a global visibility shortcut reveals the compact bar; useful generated answers expand automatically into the compact answer panel. +- **D-011b — Resolved:** The global visibility shortcut toggles the entire overlay without changing active session state. +- **D-011c — Resolved, refined by D-011f:** Keep global shortcuts as first-class, remappable controls for the main live interactions while providing equivalent visible controls. +- **D-011d — Resolved:** Use `Control+Shift+C` to reveal and focus a compact agent composer attached to the current HUD. +- **D-011e — Resolved, revised:** Use `Control+Shift+Enter` as the universal Send/Submit action and ordinary `Enter` to create a composer newline. +- **D-011f — Resolved:** Add a visible HotKeys button and editable, conflict-aware shortcut panel with Reset all to defaults. +- **D-012a — Resolved, refined:** Make the main Content View pill the drag surface and use `Control+Shift+Arrow keys` to move the answer view. +- **D-012b — Resolved:** Automatically size the compact bar and answer panel; make only the expanded workspace manually resizable and persist its size per display. +- **D-012c — Resolved:** Use `Control+Option+Left/Right` for previous/next section and `Control+Option+Up/Down` to scroll vertically inside the active section. Section navigation collapses the section being left, expands the destination, and brings its header into view. +- **D-013 — Resolved:** Show Coding, System Design, and Behavioral as three visible segmented buttons in the pre-session compact bar. +- **D-014 — Resolved, refined by D-011f:** Permanently show Record, Screenshot, Chat, Submit, context status, and HotKeys in the active compact bar; place Reset under More. +- **D-015 — Resolved:** When a visible answer is dismissed, collapse it to the compact bar; the visibility shortcut can hide the bar completely. + +### D. Audio and capture + +- **D-016 — Resolved:** Transcribe locally by default and offer an explicit optional cloud fallback. +- **D-017 — Resolved, refined by D-017c:** Capture an enabled source continuously and provide Pause/Resume without ending the session; Start Interview alone does not activate audio. +- **D-017b — Resolved:** Support separate system-audio and microphone channels and let the user activate or deactivate either source independently. +- **D-017c — Resolved:** Start every new session with system audio and microphone both off. +- **D-017d — Resolved:** Make the global Record action toggle microphone and system-audio capture together while retaining independent visible source controls. +- **D-017e — Resolved:** Use `Control+Shift+R` for Record and move Reset to `Control+Shift+Backspace`. +- **D-018 — Resolved:** Highlight the detected question and wait for the user to explicitly request an answer. +- **D-019 — Resolved:** Combine source-channel labels with diarization, visibly mark uncertainty, and allow transcript-label correction. +- **D-020a — Resolved:** Support full-display screenshot capture only; omit active-window and region capture. +- **D-020b — Resolved:** Always capture the operating system's current primary display. +- **D-021 — Resolved:** Treat the screenshot as authoritative when it conflicts with the transcript. + +### E. Coding mode + +- **D-022 — Resolved:** Open with a concise approach, key trade-off, and complexity; keep full code in the adjacent tab. +- **D-023a — Resolved:** Make Python, JavaScript/TypeScript, Java, Go, C++, and C# first-class; retain Rust, Swift, Kotlin, Ruby, SQL, and R as best-effort. +- **D-023b — Resolved:** Select and persist Coding language globally in Settings; snapshot it for each session at Start Interview. +- **D-024 — Resolved:** Require an explicit Analyze, Generate Code, Debug, or Follow-up intent for every Coding request. +- **D-024b — Resolved:** Use `Control+Shift+D` to capture and diagnose the current Coding implementation without regenerating the solution. +- **D-025 — Resolved:** Use an explicit New Question action to create a clean Coding problem branch while preserving interview-level context. +- **D-026 — Resolved:** Keep generated code read-only with Copy, Regenerate, Debug, and Explain; provide no in-app editing or execution. + +### F. System Design mode + +- **D-027 — Resolved:** Generate a read-only structured architecture diagram with inspection and regeneration but no editing. +- **D-028a — Resolved:** Use a fixed Clarify → Estimate → Architecture → Data/API → Deep Dives and Trade-offs sequence. +- **D-028b — Resolved:** Show two to four material estimates with explicit assumptions and offer deeper calculations on request. +- **D-029 — Resolved:** Generate the complete design immediately, making unresolved requirements explicit assumptions rather than blockers. +- **D-030a — Resolved:** Use vendor-neutral architecture components and keep provider-specific services as secondary examples. +- **D-030b — Resolved:** Provide no standalone diagram copy or export controls. +- **D-031 — Resolved:** Let the agent dynamically determine and apply the appropriate System Design updates, then summarize what changed. + +### G. Behavioral mode + +- **D-032a — Resolved:** Build and maintain an encrypted, Markdown-based candidate dossier through an agent-guided conversation, with manual editing and resume/Markdown import. +- **D-032b — Resolved:** Permit synthetic stories only when the user enables Allow synthetic stories; save and label every generated fallback as synthetic. +- **D-033 — Resolved:** Show talking points by default and provide an optional Full Answer view using the same underlying facts. +- **D-034 — Resolved:** Use only documented claims for real stories; allow clearly synthetic plausible metrics only inside opted-in synthetic stories. +- **D-035a — Resolved:** Store optional opportunity-specific context in a separate encrypted Markdown document under Settings and preserve it across Reset. +- **D-035b — Resolved:** Store multiple named opportunity contexts with one persistent active selection. +- **D-036 — Deferred:** Define post-answer feedback only if a separate Practice experience is pursued later. + +### H. Personalization and prompts + +- **D-037 — Resolved:** Use candidate and opportunity context in Behavioral and System Design, but exclude both from Coding. +- **D-038 — Resolved:** Provide a dedicated Prompt Studio with an agent-guided chat and synchronized manual CRUD for user templates. +- **D-039a — Resolved for launch:** Allow user-created template variants only within Coding, System Design, and Behavioral. +- **D-039b — Deferred:** Later evaluate custom named modes that inherit a core mode and appear under More. +- **D-040 — Resolved:** Let the agent dynamically reconcile semantic instruction conflicts within protected product and schema invariants. + +### I. AI, privacy, and reliability + +- **D-041 — Resolved:** Require only transcription to run locally; delegate all other model intelligence dynamically to frontier subscription models. +- **D-042a — Resolved:** Support Claude Code and Codex subscription providers only; remove legacy answer-provider API-key integrations. +- **D-042b — Resolved:** Use only the provider explicitly selected by the user; provide no automatic fallback or cross-provider routing. +- **D-042c — Resolved:** Let the user select a model per subscription provider and keep it fixed until manually changed. +- **D-042d — Resolved:** Add a user-selected `Fast / Reasoning` response-mode setting, map it to the chosen provider/model's native effort controls without automatic fallback, and lock it from Start Interview until Reset. +- **D-043a — Resolved, refined by D-043b:** Make the complete applicable context available to one persistent provider conversation, seeding full starting state and sending subsequent deltas. +- **D-043b — Resolved:** Rely on the selected provider's automatic compaction within its persistent interview conversation; retain the unabridged record locally. +- **D-043c — Resolved:** Show a compact live context-status indicator with a source-level detail popover and provider-reported compaction/usage information when available. +- **D-043d — Resolved:** Keep the curated mode workspace primary and add a composer for direct conversation with the current persistent agent; do not add a generic chronological Agent View. +- **D-043e — Resolved:** Automatically preselect every newly captured, unsent transcript segment and screenshot as a removable attachment on the next agent turn. +- **D-044a — Resolved:** Stream usable answer content progressively into stable typed sections instead of waiting for the full response. Completed sections remain usable while later sections continue. +- **D-044b — Resolved for answer delivery:** Do not impose a fixed answer deadline or delay output to assemble a complete response. Instrument latency internally and publish useful content whenever the selected provider/model and response mode make it available. Local-transcription performance remains an implementation benchmark rather than an answer holdback policy. +- **D-045a — Resolved:** Cancel only the active provider turn, retain completed and partial sections, keep the persistent interview conversation alive, and offer `Continue unfinished` for interrupted or failed sections without duplicating submitted evidence. +- **D-045b — Resolved:** Always provide a best-effort answer without confidence scoring or a blocking review state. State consequential assumptions and, when useful, suggest questions the user should consider asking the interviewer; accept corrections through chat and revise affected sections. + +### J. Theme and accessibility + +- **D-046 — Resolved:** Use Quiet Signal as the core brand character: calm dark-neutral surfaces, restrained accents, minimal glow, and clear technical typography without hacker or gamer styling. +- **D-047 — Resolved:** Keep subtle mode accents—green for Coding, violet for System Design, and amber for Behavioral—while using the global signal green for primary actions in every mode. +- **D-048a — Resolved:** Offer `Compact` and `Comfortable` interface-density presets, defaulting to Compact; density changes spacing and control geometry without changing structure or behavior. +- **D-048b — Resolved:** Offer `Small`, `Default`, and `Large` content text-size presets across answers, chat, transcripts, and code, with no required text below 12px; keep this independent from interface density. +- **D-049 — Resolved:** Do not add separate high-contrast, High Legibility, or reduced-transparency appearance modes at launch; keep one readable Quiet Signal theme. Reduced-motion behavior remains supported independently. +- **D-050 — Resolved:** Keep InterviewCopilot fully silent with no UI sounds, spoken responses, or haptics; communicate all state visually. + +### K. Onboarding and commercialization + +- **D-051 — Resolved:** Use one compact provider setup checklist, require one working Claude Code or Codex subscription selection, then land directly on Start Interview. Omit a tutorial carousel and request capture permissions only on first use. +- **D-052 — Resolved:** Keep permission and provider failures inline and scoped to the affected feature; preserve the interview, provide `Open System Settings` or `Reconnect`, and retry only after explicit user action. +- **D-053 — Resolved:** Keep InterviewCopilot open source under the repository's existing AGPL-3.0-or-later model rather than turning it into a closed commercial or open-core product. +- **D-054 — Resolved:** Gate no features behind InterviewCopilot plans, credits, quotas, or entitlements; remove legacy credit and subscription-portal machinery. +- **D-055 — Resolved:** Collect no analytics and upload no crash reports automatically. Keep only content-safe local diagnostics that the user may inspect and manually export. + +## 14. Decision log + +| ID | Status | Decision | Rationale and consequences | +|---|---|---|---| +| Theme-001 / D-046 | Resolved | Use the Quiet Signal visual system described above. | It fits the transparent desktop HUD, improves glanceability, and differentiates InterviewCopilot from competitors' neon-heavy visual language without turning the interface into a hacker aesthetic. | +| D-047 | Resolved | Use green, violet, and amber as restrained identifiers for Coding, System Design, and Behavioral while keeping primary actions globally green. | Mode color improves orientation at a glance; limiting it to icons, active edges, status, and selected controls preserves one coherent Quiet Signal theme. | +| D-048a | Resolved | Provide Compact and Comfortable density presets, defaulting to Compact. | Compact minimizes screen footprint during live use; Comfortable increases spacing and hit targets without creating a different information architecture or shortcut model. | +| D-048b | Resolved | Provide Small, Default, and Large content text-size presets across answers, chat, transcripts, and code, independent of density. | Users can increase reading size without inflating every HUD control or losing the compact live layout; required information never drops below 12px. | +| D-049 | Resolved | Ship one readable Quiet Signal appearance without separate high-contrast, High Legibility, or reduced-transparency modes. | Avoid the implementation and testing cost of parallel visual systems at launch. Reduced motion remains an independent behavior setting rather than an alternate theme. | +| D-050 | Resolved | Keep the application fully silent: no UI sounds, TTS, or haptic feedback. | Visual status is discreet and cannot leak app activity into an interview or recording environment. | +| D-051 | Resolved | First run is a single provider setup checklist followed directly by Start Interview; feature permissions are requested contextually on first use. | The current app already has a provider-gated welcome path. Refining that path preserves speed while avoiding premature microphone or screen-capture prompts and a tutorial users must dismiss. | +| D-052 | Resolved | Recover from permission and provider failures inline, disable only the affected action, preserve local session state, and offer a specific repair action followed by explicit Retry. | The current implementation mostly relies on provider toasts and has no complete macOS permission-recovery path. Scoped recovery prevents a declined microphone or capture permission—or a provider disconnect—from destroying otherwise usable interview context. | +| D-053 | Resolved | Keep InterviewCopilot open source under AGPL-3.0-or-later. | This matches the repository's current license and free/open-source positioning. Users supply their own Claude Code or Codex subscription, and the product architecture does not depend on a proprietary answer backend. | +| D-054 | Resolved | Make every shipped feature available without InterviewCopilot plans, credits, quotas, or entitlements. | Users already bring a Claude Code or Codex subscription. Removing the repository's legacy credit counters and subscription portal keeps the open-source product model honest and simplifies the live UI and failure paths. | +| D-055 | Resolved | Collect no product analytics or device identifiers and perform no automatic crash upload; retain only content-safe local diagnostics with explicit manual export. | This matches the privacy-sensitive, open-source, local-first product model. Interview content, provider output, personal context, and credentials must never enter diagnostic logs. | +| Mode-001 | Proposed baseline | Start with Coding, System Design, and Behavioral. | These require genuinely different answer structures and cover the user's stated minimum. | +| Voice-001 | Proposed baseline | Treat voice as a shared input channel with visible session state; do not add spoken AI output initially. | Interviewer transcription provides more value than TTS while keeping the live UI quiet. | +| D-001 | Resolved | InterviewCopilot is primarily a Live interview copilot. | The live HUD, low latency, glanceability, and minimal interaction take priority. Practice scoring, review, and coaching are excluded from the initial product surface and cannot complicate Live. | +| D-002 | Resolved | Use `InterviewCopilot` as the canonical product and display name. | The current `Interview Coder` labels will be migrated during implementation. The `TimoCodes` repository name may remain temporarily as an internal migration detail but is not a user-facing brand. | +| D-003 | Resolved | Optimize for Senior and Staff+ software engineers. | Defaults favor judgment, trade-offs, production constraints, technical leadership, and organizational impact. Broad accessibility remains valuable, but equal optimization across all seniority levels is not a goal. | +| D-004 | Resolved | Position InterviewCopilot as “The invisible live copilot for Staff+ engineering interviews—across coding, system design, and behavioral.” | Invisibility is the immediate promise; Staff-level full-loop judgment is the product-depth differentiator. Product design and messaging must demonstrate both. | +| D-005a | Superseded by D-005c | The earlier absolute invisible/undetectable positioning is no longer the release claim. | Universal local or platform-level undetectability cannot be honestly guaranteed or safely validated. | +| D-005b | Resolved | Treat InterviewCopilot as a neutral tool and enforce no responsibility notice or consent gate. | Onboarding and session start remain frictionless. The product does not repeatedly interrupt the live workflow with usage confirmations. | +| D-005c | Resolved constraint | Limit the promise to exclusion from ordinary screen sharing and recording on explicitly qualified configurations. | Capture privacy remains release-critical and testable. The product will not hide its process, tamper with monitoring, spoof platform state, or attempt to evade anti-cheating or proctoring controls. | +| D-005d | Resolved | Make macOS the only initial engineering and capture-privacy qualification target; defer Windows and Linux. | The launch matrix stays narrow enough to test rigorously. Capture scopes and applications qualify independently; Google Meet already provides the observed entire-display and specific-window baseline recorded under D-005e. | +| D-005e | Resolved for launch | Require the release build to pass Google Meet entire-display and specific-window sharing tests on the supported macOS/browser matrix. | Both scopes already have an observed working baseline. The final test is a release gate; Zoom, Teams, browser-tab sharing, and other capture products remain unqualified until independently tested. | +| D-005f | Resolved | Provide a guided Google Meet test and show verified status only for the recorded Mac, browser, app version, and passing capture scopes. | Verification requires confirmation from the remote Meet view or a second device, becomes stale after capture-relevant app changes or major OS/browser changes, and never implies universal invisibility. The underlying `setContentProtection(true)` path is centralized and unit-guarded. | +| D-005g | Resolved | Lead with “Stay private while you share your screen,” then state that InterviewCopilot is designed to stay out of ordinary macOS screen shares and recordings and that coverage varies by application and capture mode. | The product promise should describe the general user benefit rather than a Google Meet feature. Exact verified applications, modes, versions, and dates remain visible in Privacy & Capture, while universal undetectability and anti-monitoring claims remain out of scope. | +| D-005h | Resolved | Omit an application-agnostic “Test My Setup” flow at launch. | A generic self-test creates setup cost without reliably certifying arbitrary capture implementations. Verification remains available only for explicitly qualified applications and capture modes. | +| D-006a | Resolved | Use only `Start Interview` and `Reset` as explicit session lifecycle controls. | Hiding or collapsing does not affect the session. Omitting a separate End action keeps the live control model minimal; Reset owns termination semantics. | +| D-006b | Resolved, refined by D-009a | Reset stops capture and processing, archives the completed session, clears the active working context, and returns to Start Interview. | Active transcripts, screenshots, questions, answers, and follow-ups leave the live HUD; the local History entry, preferences, provider configuration, and reusable Story Bank/profile data survive. | +| D-007 | Resolved | Select the interview mode before Start Interview and lock it until Reset. | Each session maintains one coherent prompt policy, context model, answer schema, and renderer. The active mode appears as status rather than an editable control. | +| D-008 | Resolved, refined by D-043a/b | Keep complete local session history and one persistent provider conversation per interview. | The conversation receives full starting context and later deltas; the encrypted local record remains unabridged regardless of provider compaction. | +| D-009a | Resolved | Use local storage for active crash recovery and permanent searchable session History; show History only under Settings. | Relaunch can offer Resume or Reset. Completed sessions remain retrievable without adding a history surface or visual weight to the live HUD. | +| D-009b | Resolved | Archive mode, timestamps, finalized transcript, questions, constraints, answers, code, diagrams, summaries, follow-ups, and compressed screenshots; exclude raw audio. | History remains reconstructable and searchable without retaining large, highly sensitive audio recordings. Temporary audio buffers are discarded after transcription. | +| D-009c | Resolved | Retain archived sessions indefinitely until explicit deletion. | History behaves as a durable user library. No automatic age-based expiry or pruning occurs. | +| D-009d | Resolved | Automatically encrypt persisted active-session recovery and History with an application key stored in macOS Keychain or Windows Credential Manager. | Session text, indexes, screenshots, diagrams, and caches must not remain as plaintext at rest. Explicit export is the only intentional plaintext release. | +| D-009e | Resolved | Provide History search, open, delete one, delete all, and individual Markdown/JSON export. | Users receive essential control and portability without expanding Settings into a complex library product. Tags, favorites, multi-select, and bulk export are deferred. | +| D-011a | Resolved | Launch hidden; reveal a 44px compact bar with the global visibility shortcut; automatically expand useful answers into a compact panel. | The product remains invisible until intentionally summoned, then provides stable live status and controls without opening the full workspace. | +| D-011b | Resolved | Use the global visibility shortcut to toggle the entire overlay without affecting the active session. | The user can instantly hide or restore the bar while audio capture, processing, and context continue. | +| D-011c | Resolved, refined by D-011f | Use remappable global shortcuts for the main live interactions and retain equivalent visible controls. | The user can record, capture, submit, and reveal the product without focusing the overlay, while Settings conflict detection and visible controls preserve accessibility and control. | +| D-011d | Resolved | Use `Control+Shift+C` to reveal and focus a compact composer attached to the current HUD. | A typed turn remains fast and discreet, can include pending evidence, and uses the current persistent agent without forcing the expanded workspace or introducing a generic Agent View. | +| D-011e | Resolved, revised | Use `Control+Shift+Enter` as the universal Send/Submit action and ordinary `Enter` for a composer newline. | One shortcut submits either a typed message with selected evidence or pending evidence alone, matching the existing processing muscle memory without creating a second send command. | +| D-011f | Resolved | Add a permanently discoverable HotKeys button and an anchored shortcut-management panel with inline editing, conflict detection, and Reset all to defaults. | The shortcut-first product remains learnable and controllable without duplicating a shortcut hint beside every live action. | +| D-012a | Resolved, refined | Drag from the main Content View pill, snap near screen edges, remember position per display, and move the answer view with `Control+Shift+Arrow keys`. | The dominant control surface doubles as a predictable drag handle, while global movement works without focusing or revealing extra controls. Interactive descendants never initiate dragging. | +| D-012b | Resolved | Automatically size the compact bar and compact answer; allow manual resizing only in the expanded workspace and remember that size per display. | Live states remain stable and low-effort while diagrams, code, Settings, and History can use a user-controlled workspace. | +| D-012c | Resolved | Use `Control+Option+Left/Right` to move between answer sections and `Control+Option+Up/Down` to scroll vertically within the active section. | Moving between sections collapses the section being left, expands the destination, and brings its header into view, preserving a single focused reading path while keeping all four commands spatially coherent. | +| D-013 | Resolved | Use a visible three-part segmented selector for Coding, System Design, and Behavioral before Start Interview. | The modes define the session and should remain immediately discoverable. A separate chooser is deferred until the mode count grows beyond the compact bar. | +| D-014 | Resolved, refined by D-011f | Keep Record, Screenshot, Chat, Submit, context status, and HotKeys permanently visible during an active session; put Reset under More. | The repeated capture and agent-turn controls stay immediate, shortcut management remains discoverable, and the destructive terminal action stays outside the main interaction row. | +| D-015 | Resolved | Collapse dismissed answers back to the compact bar; hide the bar only through the visibility control. | The visible session retains glanceable mode and state while still allowing a zero-pixel hidden state on demand. | +| D-016 | Resolved | Use local transcription by default with an explicit optional cloud fallback. | The product favors low latency and local processing but can recover from unsupported or underpowered devices. Remote audio processing is never enabled silently. | +| D-017 | Resolved, refined by D-017c | Once the user enables an audio source, capture it continuously; provide Pause/Resume while retaining session context. | Continuous capture preserves follow-ups and constraints without constant interaction. Starting a session alone does not activate audio. Hiding the overlay does not change enabled-source state. | +| D-017b | Resolved | Support system audio and microphone as separate channels with independent user-controlled activation. | Continuous listening captures only enabled sources. The user can change either source during a session without losing context or resetting. | +| D-017c | Resolved | Initialize system audio and microphone as off for every new session. | Audio capture always requires an explicit per-session activation and never inherits an enabled state from a prior interview. | +| D-017d | Resolved | Use one global Record action to start/resume or pause microphone and system audio together. | The shortcut is predictable and immediately captures both sides of the interview. Visible source controls still let the user disable or re-enable either channel independently. | +| D-017e | Resolved | Assign `Control+Shift+R` to the master Record toggle and move Reset to `Control+Shift+Backspace`. | Record receives the obvious mnemonic while session destruction requires a more deliberate chord. Existing screenshot, submit, and visibility shortcuts remain stable. | +| D-018 | Resolved | Surface the detected question and wait for Solve, Design, or Coach answer before generating. | The user controls timing, provider cost, and false-positive question boundaries; no detected speech silently initiates an answer request. | +| D-019 | Resolved | Default system audio to Interviewer and microphone to You; use diarization for multi-speaker channels, mark uncertainty, and allow corrections. | Source separation supplies reliable defaults while in-person/shared-channel interviews remain usable. Corrections update live context and History. | +| D-020a | Resolved | Support full-display screenshot capture only. | The capture interaction remains immediate and predictable. Active-window and region selection are intentionally excluded. | +| D-020b | Resolved | Always capture the operating system's current primary display. | Screenshot behavior is deterministic and needs no display picker. If the OS primary display changes, subsequent captures follow it. | +| D-021 | Resolved | Use the screenshot as the authoritative source when screenshot and transcript conflict. | Compatible speech can add context, but visible problem requirements win. The transcript is primary only when no screenshot is present. | +| D-022 | Resolved | Make the initial Coding answer a short approach, key trade-off, and time/space complexity; place full code in the adjacent tab. | The candidate receives something immediately speakable without scanning a full solution. Code can continue streaming independently. | +| D-023a | Resolved | Treat Python, JavaScript/TypeScript, Java, Go, C++, and C# as first-class; retain Rust, Swift, Kotlin, Ruby, SQL, and R as best-effort. | Core languages receive explicit quality fixtures and regression coverage. Additional languages remain useful without implying equal validation. | +| D-023b | Resolved | Store Coding language as a global Settings preference and snapshot it when a Coding session starts. | Language selection stays out of the compact live workflow. Mid-session Settings changes apply only to the next session, preserving answer consistency. | +| D-024 | Resolved | Require the user to choose Analyze, Generate Code, Debug, or Follow-up for every Coding request. | The system never guesses whether new evidence is a bug, changed constraint, or continuation. Each intent uses its own response schema and visible primary action. | +| D-024b | Resolved | Use `Control+Shift+D` to capture the primary display and ask the current Coding agent for a targeted fix. | The diagnostic screenshot is submitted immediately and independently of other staged evidence. The current solution is preserved, the response is a versioned Fix card, and no full-regeneration or cross-mode fallback occurs. | +| D-025 | Resolved | Add New Question to create a clean Coding problem branch within the active interview session. | Prior problem state leaves the active workspace, while complete interview-level transcript, prior branches, and History chronology remain continuous and available as full request context. | +| D-026 | Resolved | Keep code read-only with Copy, Regenerate, Debug, and Explain; omit editing, execution, terminal access, and test running. | InterviewCopilot remains a focused live copilot while the interview platform or external IDE owns code manipulation and execution. | +| D-027 | Resolved | Render System Design architecture as a read-only structured diagram. | Users can inspect, zoom, pan, and regenerate, but diagram editing and whiteboarding stay outside InterviewCopilot. | +| D-028a | Resolved | Use a consistent Clarify, Estimate, Architecture, Data/API, Deep Dives and Trade-offs sequence for every System Design session. | Stable navigation improves glanceability and prevents arbitrary model-generated document structures. | +| D-028b | Resolved | Default to two to four material capacity calculations with explicit assumptions; provide deeper estimates on request. | The live answer demonstrates quantitative judgment without crowding the interface with low-value arithmetic. | +| D-029 | Resolved | Generate all System Design sections immediately and label unresolved requirements as explicit assumptions. | The candidate receives a usable architecture without completing an interaction gate; later constraints can regenerate affected sections through Follow-up. | +| D-030a | Resolved | Use vendor-neutral component types for generated architecture diagrams. | The diagram communicates architecture and trade-offs without prematurely coupling the answer to AWS, Azure, GCP, or their icon libraries. | +| D-030b | Resolved | Provide no standalone diagram copy or export action. | Diagrams remain available within archived sessions and whole-session export, but the live Architecture tab stays focused and uncluttered. | +| D-031 | Resolved | Use agent-directed dynamic updates for System Design follow-ups. | The agent evaluates dependency impact, preserves unaffected sections, revises or regenerates what is necessary, and presents a concise What changed summary. | +| D-032a | Resolved | Use an agent-guided conversation to build and maintain a canonical Markdown candidate dossier with manual editing and resume/Markdown import. | Behavioral mode receives structured reusable context while the user retains a portable, reviewable source of truth. The document is encrypted at rest and exportable as Markdown. | +| D-032b | Resolved | Allow live synthetic stories only when the user explicitly enables the global setting; persist and label each generated fallback as `synthetic-draft`. | Verified evidence remains preferred. Synthetic material stays consistent across future answers and is never silently represented as verified dossier content. | +| D-033 | Resolved | Default Behavioral output to concise talking points with an optional Full Answer view. | The candidate gets a glanceable natural-speaking aid while retaining access to polished phrasing. Both formats must use identical underlying claims. | +| D-034 | Resolved | Real stories use only dossier-backed facts and stay qualitative when metrics are unknown; opted-in synthetic stories may use labeled plausible metrics. | Factual stories remain consistent and unsupported precision is avoided, while synthetic examples can still be complete and reusable. | +| D-035a | Resolved | Maintain company, role, level, job description, competency focus, and interview notes in a separate encrypted Markdown opportunity context under Settings. | Reset preserves opportunity context. The agent combines it with the candidate dossier without mixing short-lived target-role information into durable candidate history. | +| D-035b | Resolved | Store multiple named opportunity contexts with one active selection. | Parallel interview processes remain separate. Sessions snapshot the selected context for historical accuracy, and mid-session selection changes apply only to the next session. | +| D-037 | Resolved | Provide candidate-profile and active opportunity context to Behavioral and System Design only. | Personal evidence and target-role calibration improve those modes; Coding remains objectively grounded in the problem and selected language. | +| D-038 | Resolved | Add a Prompt Studio combining a specialized template-building chat with manual CRUD. | Conversational creation lowers the barrier while direct management gives power users control. Built-in templates and response-schema contracts remain protected. | +| D-039a | Resolved for launch | Limit user templates to variants within the three core modes. | The segmented selector and typed renderers remain stable while users can still specialize behavior. Arbitrary schemas are out of scope. | +| D-039b | Deferred | Later evaluate custom named modes that inherit a core schema and appear under More. | This preserves a clear expansion path without making the initial Prompt Studio an application builder. | +| D-040 | Resolved | Let the agent dynamically resolve semantic conflicts using relevance, specificity, recency, provenance, and mode applicability. | Behavior can adapt to context without exposing a rigid hierarchy. Protected renderer contracts and explicit product invariants remain non-overridable. | +| D-041 | Resolved | Make transcription the only locally required AI capability; use frontier models on the user's subscription for all other intelligence. | Capture, encryption, and storage remain local application mechanics, but the product does not bundle local models for diarization, detection, summarization, or answer reasoning. | +| D-042a | Resolved | Support only Claude Code and Codex subscription-authenticated providers for answer intelligence. | Onboarding and settings avoid general API-key billing and configuration. Legacy OpenAI, Anthropic, and Gemini answer-provider integrations are removed; cloud transcription remains separate. | +| D-042b | Resolved | Use only the subscription provider explicitly selected by the user. | The existing primary-provider behavior is retained. Failures surface clearly, and the user must manually choose another provider; automatic fallback and dynamic cross-provider routing are prohibited. | +| D-042c | Resolved | Store a user-controlled model selection for Claude Code and Codex and never switch it automatically. | Provider default remains an explicit selectable option. Sessions snapshot the provider/model pair for reproducibility. | +| D-042d | Resolved | Add a `Fast / Reasoning` setting, translate it into the selected provider/model's native effort controls, and snapshot it with provider/model at Start Interview. | The user explicitly chooses latency versus deliberation, while one persistent conversation keeps a consistent configuration until Reset. InterviewCopilot never silently changes or downgrades the selection; unsupported combinations are unavailable. | +| D-043a | Resolved, refined by D-043b | Seed a persistent provider conversation with complete applicable starting context and send subsequent session deltas into it. | Behavioral/System Design include candidate and opportunity documents; Coding excludes them. Raw audio remains outside general answer requests. | +| D-043b | Resolved | Use one persistent resumable provider conversation per interview and rely on provider auto-compaction. | Reset discards the provider conversation. InterviewCopilot preserves the complete encrypted local record and does not implement a second hidden compaction layer. | +| D-043c | Resolved | Show a `Full context` status indicator with `Updating` and `Context issue` states plus an inspectable source-level detail popover. | The user can verify what entered the persistent conversation without crowding the HUD. Provider-reported compaction is disclosed without falsely implying that all original tokens remain verbatim. | +| D-043d | Resolved | Keep the curated mode-specific workspace primary while allowing typed conversation with the current persistent agent. | Shortcut answers and chat messages share one provider conversation and context model. Structured responses update the curated layout; ordinary clarification can remain a compact exchange without introducing a generic terminal-style Agent View. | +| D-043e | Resolved | Preselect all newly captured, unsent transcript segments and screenshots as removable attachments for the next answer or chat submission. | The default preserves complete context without resending artifacts already held by the persistent agent. Users can exclude irrelevant evidence or send a text-only message while retaining deliberate control. | +| D-044a | Resolved | Stream usable answer content progressively into stable typed sections rather than waiting for the full response. | The first speakable or actionable result appears as soon as possible; late code, diagrams, or deep-detail sections do not block already completed content or cause the reading position to jump. | +| D-044b | Resolved for answer delivery | Publish usable answer content whenever it becomes available rather than enforcing a fixed response deadline. | Fast and Reasoning intentionally have different latency profiles. Latency remains observable for engineering, but the UI neither withholds ready content nor truncates deliberate work to hit an arbitrary timer. | +| D-045a | Resolved | Cancel only the current generation, preserve completed and partial output, retain the persistent conversation, and retry only unfinished sections. | Cancellation is a safe turn-level control rather than a session reset. Reusing the existing request and accepted context prevents duplicate evidence and unnecessary regeneration. | +| D-045b | Resolved | Always answer on a best-effort basis, state only consequential assumptions, and suggest interviewer clarifications when they could materially change the answer. | Numeric confidence and blocking review states add friction without reliable precision. The user can correct the interpretation through chat, after which the agent revises only affected sections. | +| D-036 | Deferred | Define Practice-only post-answer feedback only if a separate Practice product is pursued. | The Live-first product does not add scoring or retrospective coaching to the active interview workflow. | + +## 15. Implementation execution + +The reviewed phase order, dependency graph, acceptance gates, migration owners, +prototype disposition, and implementation/review/remediation prompts are defined +in [`docs/implementation/phase-execution-packet.md`](docs/implementation/phase-execution-packet.md), +revision P00-R1. This design remains the product source of truth; the packet is +the execution contract. Prototype evidence does not establish phase completion. diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md new file mode 100644 index 00000000..cb673466 --- /dev/null +++ b/docs/implementation/phase-execution-packet.md @@ -0,0 +1,1918 @@ +# InterviewCopilot phase-execution packet + +Packet revision: **P00-R1** + +Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` + +Canonical planning branch: `phase/P00-execution-packet` + +Product specification: [`design.md`](../../design.md) + +Launch platform: **macOS only** + +Execution phases: **12 product PRs, P01–P12** + +## 1. Authority and non-negotiable boundaries + +This packet is the implementation and independent-review contract. If it and +`design.md` differ, stop and amend both in a new planning revision before code +is merged. An implementer may add stronger tests but may not reinterpret, +rename, weaken, delete, or skip a listed gate or any pre-existing test. + +- Every phase is one standalone PR. Its branch starts from refreshed upstream + `main` containing all listed dependencies and no prototype commit. +- The inherited dirty prototype on `feat/subscription-cli-providers` is + planning evidence only. No phase may merge, cherry-pick, or claim it as + complete. Code may be reimplemented after review against the phase contract. +- Only Claude Code and Codex subscription-authenticated providers may perform + answer intelligence. The selected provider/model/response mode is fixed for + a session. There is no automatic fallback, routing, or downgrade. +- InterviewCopilot remains AGPL-3.0-or-later, has no product entitlements, + credits, quotas, analytics, device identifiers, or automatic crash upload. +- Capture privacy means documented ordinary capture behavior on explicitly + qualified configurations. It never means anti-proctoring, process hiding, + monitoring evasion, telemetry tampering, or universal undetectability. +- `setContentProtection(true)` is a release-critical invariant. It is necessary + but not sufficient; external Google Meet qualification remains mandatory. +- Windows and Linux runtime, packaging, documentation promises, and capture + qualification are deferred. Cross-platform abstractions are allowed only + when they do not enlarge the launch surface. +- Local verification is authoritative. GitHub CI may inform a review but may + not waive or replace any local gate in this packet. + +## 2. Current-state preflight evidence (not the Stage 2 baseline) + +These commands were run during P00 planning against a temporary clean worktree +at the planning base. Per controller direction, they are **preflight evidence +only**. The controller captures the formal Stage 2 baseline after packet +approval at the frozen SHA. Raw exits and counts must be recorded again then. + +| Command | Raw exit | Result/count | +|---|---:|---| +| `npm ci` | 0 | 855 packages installed; audit reported 50 vulnerabilities (9 low, 10 moderate, 27 high, 4 critical). | +| `npm test` | 0 | Placeholder only: 0 passed, 0 failed, 0 skipped, 0 tests executed. | +| `npm run lint` | 1 | 105 errors, 0 warnings. | +| `npx tsc --noEmit` | 2 | 48 TypeScript errors. | +| `npm run build` | 0 | Renderer, Electron main, and preload production bundles emitted. | +| Dirty-prototype `npm test` | 127 | `vitest: command not found`; prototype dependencies were not installed. | + +None of the red or empty results is waived. P01 owns conversion to a real, +mechanically green local gate. Until P01 is green, no dependent phase starts. + +### Formal Stage 2 capture commands + +Run from a clean checkout of the controller-frozen SHA, in this order. Record +the complete output, raw exit after each command, and test +passed/failed/skipped totals. Do not replace a nonzero result with `|| true`. + +```bash +stage2_evidence_dir=$(mktemp -d /tmp/interviewcopilot-stage2.XXXXXX) +stage2_failed=0 +run_stage2() { + stage2_label=$1 + shift + "$@" 2>&1 | tee "$stage2_evidence_dir/$stage2_label.log" + stage2_raw_exit=${PIPESTATUS[0]} + printf '%s raw_exit=%s\n' "$stage2_label" "$stage2_raw_exit" + if [ "$stage2_raw_exit" -ne 0 ]; then stage2_failed=1; fi +} +node --version +npm --version +run_stage2 install npm ci +run_stage2 test npm test +printf 'test passed=0 failed=0 skipped=0 executed=0 (upstream placeholder)\n' +run_stage2 lint npm run lint +printf 'lint summary=%s\n' "$(rg -o '[0-9]+ problems[^[:cntrl:]]*' "$stage2_evidence_dir/lint.log" | tail -1)" +run_stage2 typecheck npx tsc --noEmit +printf 'typecheck errors=%s\n' "$(rg -c 'error TS' "$stage2_evidence_dir/typecheck.log")" +run_stage2 build npm run build +printf 'aggregate_raw_exit=%s\n' "$stage2_failed" +test "$stage2_failed" -eq 0 +``` + +Expected current upstream status is evidence, not acceptance: install, the +placeholder test, and build are expected to exit 0; lint and strict type-check +are expected to reproduce their nonzero debt. The required green baseline from +P01 onward is: every command exits 0, the test runner executes at least one +test, failed = 0, skipped = 0, and the manifest check proves every inherited +and phase-owned named test ran. + +## 3. Repository architecture observed at the planning base + +- `electron/main.ts` owns the single `BrowserWindow`, global application state, + queue/solution/debug view transitions, helper construction, visibility, + position, dynamic sizing, and the direct content-protection call. +- `electron/ScreenshotHelper.ts` captures the primary display into plaintext + files below `app.getPath("userData")`; `ProcessingHelper.ts` reads those + queues and performs legacy HTTP-provider extraction, solution, and debug + calls, parsing mostly free-form output. +- `electron/ConfigHelper.ts` persists plaintext JSON containing a legacy API + key, provider/model choices, language, and opacity. `electron/store.ts` is + unused and contains a hard-coded encryption key. +- `electron/ipcHandlers.ts` and `electron/preload.ts` expose a broad, partly + legacy IPC surface including credits, subscription portal, API-key, window, + capture, update, and processing events. Renderer typings are duplicated in + `src/env.d.ts` and `src/types/electron.d.ts`. +- `src/App.tsx` gates the renderer on configuration, while `Queue`, `Solutions`, + and `Debug` are transient views. There is no durable session reducer, + persistent provider conversation, typed response-section stream, audio + pipeline, profile/context model, encrypted History, or Prompt Studio. +- Root `npm test` is a zero-test placeholder. The only tracked test is the + untouched CRA sample `renderer/src/App.test.tsx`, in an otherwise separate + legacy renderer package. It must remain and be executed by the consolidated + P01 harness. +- Root build passes while strict type-check and lint do not. The existing CI + continues past lint/type failures and is not a trustworthy acceptance gate. +- Packaging advertises macOS, Windows, and Linux, includes legacy identity, + protocol, updater, and publish metadata, and has permissive macOS entitlements + that require deliberate launch-surface reduction. + +## 4. Complete prototype disposition + +The table maps every tracked or untracked prototype path to a future owner. +“Reuse” means reconsider the idea and tests, not copy an unreviewed diff. + +| Prototype evidence | Disposition and owning phase | +|---|---| +| `package.json`, `package-lock.json`, `vitest.config.ts`, `tsconfig.electron.json` | P01 re-creates a consolidated test/lint/type gate and lockfile; the observed Vitest spike is not accepted as-is. | +| `electron/ConfigHelper.ts`, `electron/ConfigHelper.test.ts` | P02 reimplements a versioned subscription-only config migration. Legacy API-key paths in the spike are explicitly rejected. | +| `electron/ai/types.ts`, `cliProcess.ts`, `cliProcess.test.ts` | P02 reuses safety ideas (absolute executables, no shell, abort/timeout/output limits, redaction) inside the persistent driver. | +| `electron/ai/cliProviders.ts`, `cliProviders.test.ts` | P02 replaces one-shot Claude `--no-session-persistence` and Codex `--ephemeral` execution with resumable Claude sessions and Codex app-server threads. | +| `electron/ProcessingHelper.ts` | P02/P04 replace legacy provider branching and regex orchestration; no legacy API-provider branch survives P02. | +| `electron/ipcHandlers.ts`, `electron/preload.ts`, `src/env.d.ts`, `src/types/electron.d.ts` | P02 owns narrow provider/config IPC; P04 owns typed session/event IPC; P05 owns shell/window IPC. Duplicate typings become one generated/shared contract. | +| `electron/captureProtection.ts`, `captureProtection.test.ts` | P01 adopts the centralized invariant and expands lifecycle coverage; P12 owns external qualification. | +| `electron/main.ts`, `electron/ScreenshotHelper.ts` | P05 reimplements hidden launch, prior-visibility restoration, per-display geometry, click-through, and capture lifecycle without weakening protection. | +| `electron/shortcuts.ts`, `shortcuts.test.ts`, `src/utils/platform.ts` | P05 implements the final remappable shortcut map. The spike's Reset-on-`R` and inverted Up/Down behavior are rejected. | +| `src/App.tsx`, `src/_pages/Queue.tsx`, `src/_pages/SubscribedApp.tsx` | P04/P05 replace transient view state and computed-style click-through heuristics with typed session state and explicit interactive regions. | +| `src/components/Settings/SettingsDialog.tsx`, `WelcomeScreen.tsx` | P02 builds provider-only onboarding; later settings panels are added by their owning phases. The prototype is not the final Quiet Signal UI. | +| `src/components/Header/Header.tsx`, `Queue/QueueCommands.tsx`, `Solutions/SolutionCommands.tsx` | P02 removes entitlement/API debris; P05 replaces command rows and exposes visible equivalent actions. | +| `src/constants/languages.ts`, `electron/languages.test.ts`, `LanguageSelector.tsx` | P06 adopts the normalized language catalog and adds first-class language fixtures required by D-023a. | +| `src/_pages/Solutions.tsx`, `src/_pages/Debug.tsx` | P06 replaces regex-parsed views with typed Coding sections, read-only code actions, and versioned Fix cards. Copy-button ideas remain evidence only. | +| `README.md`, `CONTRIBUTING.md`, `stealth-run.sh`, `stealth-run.bat` | P12 rewrites launch docs/scripts for macOS-only qualified claims. The Windows script is retained only until P12 removes launch support through an explicit reviewed change; it is never used as evidence of support. | +| `src/_pages/SubscribedApp.tsx` sizing removal and `Queue.tsx` width change | P05 owns automatic compact sizing and expanded-only manual resize with display-clamping tests. | +| `package.json` `productName` addition | P01 owns canonical InterviewCopilot identity; P12 validates final bundle metadata. | + +No prototype path is “done.” Prototype files stay uncommitted on the planning +worktree and are excluded from the P00 commit. + +## 5. Execution graph, waves, and intended bases + +```mermaid +flowchart TD + P01["P01 Local gates and policy rails"] --> P02["P02 Subscription agent runtime"] + P01 --> P03["P03 Encrypted persistence"] + P02 --> P04["P04 Session domain and orchestrator"] + P03 --> P04 + P04 --> P05["P05 Quiet Signal live shell"] + P05 --> P06["P06 Coding mode"] + P05 --> P07["P07 System Design mode"] + P05 --> P08["P08 Profile, context, and Behavioral"] + P05 --> P09["P09 Audio and transcription"] + P06 --> P10["P10 Prompt Studio"] + P07 --> P10 + P08 --> P10 + P06 --> P11["P11 Recovery and History"] + P07 --> P11 + P08 --> P11 + P09 --> P11 + P10 --> P11 + P11 --> P12["P12 macOS release qualification"] +``` + +The graph is acyclic. Dependency-ready deterministic order is: +`P01 → P02 → P03 → P04 → P05 → P06 → P07 → P08 → P09 → P10 → P11 → P12`. +P02 and P03 may execute in parallel. P06, P07, P08, and P09 may execute in +parallel after P05; the listed order is the merge-order tie breaker. + +| Wave | Phase branches | Intended base | +|---|---|---| +| 1 | `phase/P01-local-gates` | Exact planning base plus merged P00 documentation, if available. | +| 2 | `phase/P02-subscription-runtime`, `phase/P03-encrypted-persistence` | Refreshed `main` containing P01. | +| 3 | `phase/P04-session-orchestrator` | Refreshed `main` containing P02 and P03. | +| 4 | `phase/P05-live-shell` | Refreshed `main` containing P04. | +| 5 | `phase/P06-coding`, `phase/P07-system-design`, `phase/P08-behavioral`, `phase/P09-audio` | Refreshed `main` containing P05. | +| 6 | `phase/P10-prompt-studio` | Refreshed `main` containing P06, P07, and P08. | +| 7 | `phase/P11-history-recovery` | Refreshed `main` containing P06–P10. | +| 8 | `phase/P12-macos-qualification` | Refreshed `main` containing P11 and every prior phase. | + +Parallel branches must be rebased onto the actual dependency merge before +review. A phase cannot use another open phase branch as its base. + +## 6. Immutable local-gate contract + +P01 creates and documents these scripts. From P01 onward every phase runs them +in the listed order from a clean checkout. `verify:test-manifest` fails if a +tracked test disappeared, was renamed without a packet revision, contains +`.skip`/`.todo`/`xit`/`xdescribe`, or did not execute. Test commands must print +passed, failed, and skipped totals plus their raw exit code. + +```bash +npm ci # expected exit 0 +npm run verify:policy # expected exit 0 +npm run lint # expected exit 0 +npm run typecheck # expected exit 0 +npm run test:legacy -- --reporter=verbose # expected exit 0; failed 0; skipped 0 +npm run test:unit -- --reporter=verbose # expected exit 0; failed 0; skipped 0 +npm run verify:test-manifest # expected exit 0 +npm run build # expected exit 0 +``` + +Each phase adds one domain test script and runs it between `test:unit` and the +manifest check. Exact commands and minimum named-test counts appear below. +No implementer may edit the gate script and feature behavior in the same phase +after P01; a required gate change needs a separate P00 packet revision. + +## 7. Phase contracts + +### P01 — Green local gates and policy rails + +**Objective/outcome.** Replace the zero-test/continue-on-error baseline with a +real, reproducible local quality gate and encode the license, privacy, +capture-protection, and product-identity invariants before feature work. + +**Dependencies and intended base.** No product dependency. Base directly on +the authoritative planning commit (or refreshed `main` containing only P00 +docs). Branch `phase/P01-local-gates`. + +**Scope.** Consolidate Vitest (including the unchanged tracked CRA sample), +correct ESLint parsing/ignores rather than suppressing findings, fix all current +strict TypeScript and lint failures without changing behavior, create the raw +exit/count reporter and immutable test manifest, centralize capture protection, +set canonical InterviewCopilot metadata, add policy scans, and document local +gates. **Out of scope:** new session/provider/UI behavior, deleting the legacy +renderer, dependency-vulnerability upgrades unrelated to making gates work, +and external capture claims. + +**Implementation requirements.** Use Node 20; keep lockfile deterministic; +make root tests execute `renderer/src/App.test.tsx` unchanged; permit no skip or +todo test forms; report raw exit plus passed/failed/skipped counts; fix all 105 +lint and 48 type errors rather than excluding product code; make every window +creation/reveal path call one `applyCaptureProtection` helper; add no false +content-protection path; scan dependencies/source for analytics and automatic +crash upload entry points; retain AGPL-3.0-or-later. + +**Expected files/systems.** `package*.json`, ESLint/TypeScript/Vitest configs, +`scripts/verification/**`, `tests/policy/**`, typed fixes in existing Electron +and renderer files, `electron/captureProtection.ts`, build metadata, README and +CONTRIBUTING gate sections, and `.github/workflows/ci.yml` only to mirror (not +replace) the local commands. + +**Compatibility, migration, rollback.** No persisted-data migration. Runtime +behavior must remain identical except canonical display metadata and repeated +content-protection application. Roll back the PR as one unit; never roll back +only the protection helper or test manifest. + +**Security/failure modes.** A parser ignore can hide source; a test glob can +silently execute zero tests; a reporter can mask the child exit; typed cleanup +can change behavior; capture protection can be applied after first paint. Tests +must make each failure observable and fail closed. + +**Acceptance criteria and named new tests.** All are mechanically required. + +| Criterion | Named test | +|---|---| +| P01-AC1: `npm test` executes at least one test and reports failed=0, skipped=0; the tracked CRA sample executes unchanged. | `tests/policy/gateContract.test.ts — executes the inherited CRA test and rejects a zero-test run` | +| P01-AC2: lint, strict type-check, unit tests, and build each return raw exit 0 on a clean checkout. | `tests/policy/gateContract.test.ts — propagates every child gate exit code` | +| P01-AC3: removal, rename, non-execution, `.skip`, `.todo`, `xit`, or `xdescribe` for any manifest test makes verification exit nonzero. | `tests/policy/testManifest.test.ts — rejects missing renamed skipped and unexecuted tests` | +| P01-AC4: every BrowserWindow creation and reveal path invokes `applyCaptureProtection`, which calls `setContentProtection(true)` and never false. | `electron/captureProtection.test.ts — protects creation and reveal lifecycle paths` | +| P01-AC5: package metadata and visible identity use InterviewCopilot and retain `AGPL-3.0-or-later`. | `tests/policy/productPolicy.test.ts — enforces canonical identity and AGPL metadata` | +| P01-AC6: shipped source has no analytics SDK, device fingerprint, automatic crash-upload initialization, or environment-based secret logging. | `tests/policy/productPolicy.test.ts — rejects telemetry crash upload and secret logging entry points` | +| P01-AC7: the verification reporter prints command, raw exit, and test passed/failed/skipped fields without converting nonzero to success. | `tests/policy/verificationReporter.test.ts — preserves raw failures and count fields` | + +**Clean-checkout setup.** Every command must exit 0. + +```bash +p01_verify_dir=$(mktemp -d /tmp/interviewcopilot-P01.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p01_verify_dir/repo" +git -C "$p01_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P01-local-gates +git -C "$p01_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p01_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** The phase suite must report at least 7 +P01 named tests passed, 0 failed, 0 skipped; the full suite may have more. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p01 -- --reporter=verbose +npm run verify:test-manifest +npm run build +``` + +Expected raw exit for every command is 0. **Regression suite:** all inherited +tests, capture/screenshot behavior tests, full root unit suite, strict type +check, lint, and production build. No baseline error is grandfathered. + +**Docs.** Document Node 20 clean setup, authoritative local commands, raw count +artifact format, AGPL/privacy policy, and the non-claim that unit protection +proves capture privacy. + +**Completion evidence (enumerated).** (1) commit SHA and base SHA; (2) clean +status; (3) dependency install log; (4) one raw-exit/count report per gate; +(5) manifest diff proving the inherited test remains; (6) capture lifecycle +test output; (7) build artifact list; (8) reviewer sign-off that no lint/type +rule or source glob was weakened. + +**Risk/complexity.** High risk, medium complexity: broad typed cleanup can hide +behavioral changes. Keep mechanical fixes small and independently reviewable +inside the single PR. + +**Self-contained implementation prompt.** + +> Implement P01 from P00-R1 on `phase/P01-local-gates`, based only on upstream +> `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. +> Make local lint, strict type-check, real unit tests (including the unchanged +> tracked CRA sample), manifest enforcement, and build green. Centralize and +> lifecycle-test `setContentProtection(true)`, enforce InterviewCopilot/AGPL/no- +> telemetry policy, print raw exits and test counts, add exactly the tests named +> in P01, run the commands in order, and attach every enumerated artifact. Do +> not add product features or waive existing failures. + +**Self-contained review prompt.** + +> Review P01 independently against P00-R1, not the author’s summary. From the +> clean PR checkout run every P01 command, confirm the inherited CRA test ran, +> inspect all config/glob/ignore changes for hidden coverage loss, compare typed +> cleanup for behavior changes, and prove every window lifecycle applies true +> content protection. Reject the PR for any missing raw count, skipped test, +> weakened rule, product feature, telemetry path, or nonzero local gate. + +**Remediation prompt template.** + +> Remediate P01 only. Evidence: `{failing command/raw exit/counts or review +> finding}`. Root cause: `{confirmed cause}`. Change the smallest P01-owned +> files, add/strengthen `{named regression test}`, preserve every inherited +> gate and capture invariant, rerun the complete P01 sequence from `npm ci`, +> and return new raw evidence plus the before/after commit SHAs. + +### P02 — Subscription-only persistent agent runtime + +**Objective/outcome.** Provide one hardened, provider-neutral, persistent and +resumable answer runtime for Claude Code and Codex subscriptions, with explicit +provider/model/Fast-or-Reasoning selection, provider-only onboarding, and all +legacy API/paywall paths removed. + +**Dependencies and intended base.** P01 merged. Branch +`phase/P02-subscription-runtime` from refreshed `main` containing P01. + +**Scope.** Versioned configuration migration; installation/auth diagnostics; +Claude long-lived structured session adapter; Codex app-server thread adapter; +normalized stream, usage, compaction, stop, resume, and error events; process +safety; provider settings/onboarding; removal of OpenAI/Anthropic/Gemini answer +SDK paths, API keys, Supabase, credits, plans, quotas, and subscription portal. +**Out of scope:** interview domain orchestration, mode schemas, storage +encryption, renderer answer layouts, cloud transcription, and cross-provider +fallback. + +**Implementation requirements.** Pin and validate supported CLI protocol +versions; resolve only absolute executables; use `spawn` with `shell:false`; +strip answer-provider secret overrides; cap output, timeout, abort gracefully, +then force-kill; sanitize stderr; never expose auth tokens/account identifiers; +keep one Claude session ID or Codex thread ID resumable across process/app +restart; map provider events to one discriminated union; never launch the +unselected provider after session selection; map Fast/Reasoning only to native +supported controls and mark unsupported combinations unavailable. + +**Expected files/systems.** `electron/providers/**`, shared provider event and +IPC types, `electron/config/**`, settings/onboarding UI, preload/IPC narrowing, +provider fixtures/fake executables, package dependencies, and removal of legacy +provider/entitlement modules and strings. + +**Compatibility, migration, rollback.** P02 exclusively owns migration +`M-01`: legacy `config.json` to versioned subscription config. Preserve +language/opacity; remove and never rewrite legacy API keys/models/credits; take +an owner-only backup with no key material before atomic replacement; repeated +migration is idempotent. Rollback restores the backup only after explicit user +choice because the old format contains disallowed secrets. + +**Security/failure modes.** PATH substitution, argument injection, inherited +API keys changing billing, malformed stream events, output floods, zombie +children, provider version drift, token leakage, accidental tool access, +automatic fallback, and applying settings mid-session. Fake-executable tests +cover all without a live subscription. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P02-AC1: only `claude-code` and `codex` answer-provider IDs are accepted; legacy providers/API-key/credit/entitlement IPC and dependencies are absent. | `electron/providers/providerBoundary.test.ts — rejects legacy providers and entitlement surfaces` | +| P02-AC2: two turns and an app restart resume the same Claude session and Codex thread respectively. | `electron/providers/persistence.contract.test.ts — resumes one conversation for both adapters` | +| P02-AC3: selected provider failure emits a typed recoverable error and never starts the other provider. | `electron/providers/noFallback.contract.test.ts — never invokes the unselected provider` | +| P02-AC4: provider, model, and response mode snapshot once; unsupported effort/model combinations cannot start and no silent substitution occurs. | `electron/providers/selectionSnapshot.test.ts — locks explicit provider model and effort` | +| P02-AC5: normalized streams preserve text/typed payload, usage and compaction signals, stop, completion, and sanitized provider errors. | `electron/providers/eventNormalization.contract.test.ts — normalizes streaming and compaction events` | +| P02-AC6: child processes use absolute paths, no shell, scrubbed answer-secret env, bounded output/time, and graceful-then-forceful cancellation. | `electron/providers/processSafety.test.ts — constrains provider child processes` | +| P02-AC7: M-01 preserves language/opacity, removes legacy secrets/credits, writes mode 0600 atomically, and is idempotent. | `electron/config/configMigration.test.ts — migrates legacy settings once without persisting secrets` | +| P02-AC8: first run requires exactly one installed/authenticated provider then lands on Start Interview without requesting capture/audio permission. | `src/features/onboarding/ProviderSetup.test.tsx — completes provider-only onboarding` | + +**Clean-checkout setup.** Same expected exit policy as P01. + +```bash +p02_verify_dir=$(mktemp -d /tmp/interviewcopilot-P02.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p02_verify_dir/repo" +git -C "$p02_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P02-subscription-runtime +git -C "$p02_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p02_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p02` must report at least 8 named +tests passed, 0 failed, 0 skipped; every command exits 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p02 -- --reporter=verbose +npm run verify:test-manifest +npm run build +``` + +**Regression suite.** P01 gates, capture lifecycle, screenshot queues, config +language/opacity behavior, fake provider process tests, and production build. +Live Claude/Codex smoke tests are optional evidence and never replace fakes. + +**Docs.** Supported/minimum CLI versions, install/sign-in/reconnect, provider +selection semantics, Fast/Reasoning availability, migration/rollback, process +sandbox/tool restrictions, and explicit no-fallback/no-API-key boundaries. + +**Completion evidence.** (1) SHAs/base; (2) clean gate report; (3) fake Claude +two-turn/restart transcript; (4) fake Codex two-turn/restart transcript; (5) +no-fallback process trace; (6) migration before/after with secrets redacted; +(7) dependency and IPC removal scan; (8) UI keyboard/a11y test output; +(9) supported CLI protocol fixture versions. + +**Risk/complexity.** Very high/high. CLI protocol/auth behavior is external +and evolving; pin capabilities and fail explicitly on unsupported versions. + +**Self-contained implementation prompt.** + +> Implement P02 from P00-R1 after P01, on +> `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime +> for Claude Code and Codex only, using one resumable session/thread, normalized +> streaming/usage/compaction/stop/error events, explicit provider/model/Fast- +> Reasoning snapshots, and no fallback. Migrate legacy config through M-01, +> remove every legacy answer API key/provider/credit/paywall surface, create the +> named fake-executable tests, run the exact P02 gates, and attach the evidence. +> Do not implement interview orchestration or reuse one-shot prototype code. + +**Self-contained review prompt.** + +> Review P02 against P00-R1 from a clean checkout. Trace both fake providers +> through two turns, stop, compaction, restart, and resume; force every failure +> and prove the other provider never starts. Inspect spawn/env/tool restrictions, +> IPC exposure, migration idempotence/file mode, dependency removals, model/ +> effort locking, and provider-only onboarding. Run all P02 commands and reject +> any live-credential requirement, legacy path, secret leak, silent fallback, +> ephemeral conversation, skipped test, or gate failure. + +**Remediation prompt template.** + +> Remediate P02 only for `{failed criterion/evidence}`. Reproduce with the fake +> provider fixture, state the confirmed runtime or migration cause, change the +> smallest provider/config/onboarding surface, add or strengthen `{P02 named +> test}`, prove no unselected process ran and no secret persisted, rerun all P02 +> commands from `npm ci`, and return raw exits/counts plus new SHAs. + +### P03 — Encrypted local persistence foundation + +**Objective/outcome.** Introduce a versioned, crash-safe, application-encrypted +local store for active recovery, session artifacts, and later History/profile/ +template records, with its installation key protected by macOS Keychain. + +**Dependencies and intended base.** P01 merged; may run in parallel with P02. +Branch `phase/P03-encrypted-persistence` from refreshed `main` containing P01. + +**Scope.** Key lifecycle through Electron `safeStorage`/macOS Keychain, +AES-256-GCM versioned envelopes, atomic writes, record/index interfaces, +encrypted screenshot/blob storage, in-memory search primitives, corruption and +locked-Keychain recovery, secure deletion best effort, and migration of legacy +plaintext screenshot/cache locations. **Out of scope:** session semantics, +History UI/export, dossier/templates, raw-audio retention, and provider state. + +**Implementation requirements.** Generate a random per-installation master key; +store only Keychain-protected key material; authenticate record type/version/ID +as AAD; unique nonce per write; never persist plaintext indexes, thumbnails, +screenshots, diagrams, caches, temp buffers, or keys; use owner-only +directories/files and atomic temp+rename; zero temporary buffers where +practical; make corrupted records isolated and non-destructive; store no raw +audio; expose repository interfaces without Electron objects to domain code. + +**Expected files/systems.** `electron/storage/**`, key service, encrypted record +and blob repositories, migration/repair command, storage fixtures, IPC-free +domain interfaces, and privacy/storage docs. + +**Compatibility, migration, rollback.** P03 exclusively owns `M-02` (legacy +plaintext screenshot/temp/cache files to encrypted blobs followed by verified +plaintext removal) and `M-03` (encrypted store envelope/schema v1). Both use a +journal, resume after interruption, quarantine failures, and are idempotent. +Rollback restores the pre-migration directory only while it remains in the +explicit rollback quarantine; it never writes newly created plaintext. + +**Security/failure modes.** Nonce reuse, unauthenticated metadata, plaintext +search indexes/temp files, weak permissions, Keychain locked/unavailable, +partial rename, disk full, corrupt/truncated records, symlink/path traversal, +and migration deleting the only copy. Tests use deterministic fake key storage +but production must require Keychain-backed protection. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P03-AC1: a fresh install generates one random key, stores only protected key material, and reopens records after restart. | `electron/storage/keyLifecycle.test.ts — creates protects and reopens one installation key` | +| P03-AC2: record and blob bytes contain none of fixture transcript, prompt, screenshot marker, diagram, profile text, index term, or key. | `electron/storage/plaintextLeak.test.ts — finds no sensitive fixture bytes at rest` | +| P03-AC3: AES-GCM nonces are unique and tampering with ciphertext, AAD, type, version, or ID is detected before plaintext release. | `electron/storage/envelopeCrypto.test.ts — authenticates envelope metadata and rejects tampering` | +| P03-AC4: atomic write under simulated crash/disk-full yields exactly the prior or new valid record, never a partial accepted record. | `electron/storage/atomicity.test.ts — survives interruption and disk exhaustion` | +| P03-AC5: owner-only permissions, canonical paths, and symlink rejection prevent out-of-root reads/writes. | `electron/storage/pathSafety.test.ts — confines encrypted storage and file modes` | +| P03-AC6: M-02 migrates each plaintext artifact once, verifies decryption, removes plaintext, and resumes safely after interruption. | `electron/storage/plaintextMigration.test.ts — journals verifies and resumes legacy artifact migration` | +| P03-AC7: raw audio is rejected by the persistence API and temporary audio fixtures leave no persisted bytes. | `electron/storage/retentionPolicy.test.ts — refuses raw audio persistence` | +| P03-AC8: locked/unavailable Keychain and isolated corrupt records surface typed recovery without resetting or overwriting other data. | `electron/storage/recovery.test.ts — preserves data on key and record failures` | + +**Clean-checkout setup.** Every command exits 0. + +```bash +p03_verify_dir=$(mktemp -d /tmp/interviewcopilot-P03.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p03_verify_dir/repo" +git -C "$p03_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P03-encrypted-persistence +git -C "$p03_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p03_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p03` reports at least 8 named tests +passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p03 -- --reporter=verbose +npm run verify:test-manifest +npm run build +``` + +**Regression suite.** P01 gates, capture behavior, screenshot creation/deletion, +config persistence, path safety, and build. Run storage tests on a case- +insensitive macOS filesystem in addition to temp-fixture unit tests. + +**Docs.** Threat model, Keychain/key recovery, envelope versioning, retention, +M-02/M-03 journal and rollback, corruption repair, and explicit limitations of +best-effort secure deletion on APFS/SSD snapshots. + +**Completion evidence.** (1) SHAs/base; (2) complete local-gate report; (3) +hex/string scan of encrypted fixtures; (4) file-mode listing; (5) nonce/tamper +test output; (6) interrupted migration journal before/after; (7) Keychain- +locked recovery output; (8) reviewer threat-model sign-off. + +**Risk/complexity.** Very high/high. Cryptography and destructive migration are +one-way doors; use platform primitives and reviewed authenticated encryption, +never custom cryptography. + +**Self-contained implementation prompt.** + +> Implement P03 from P00-R1 after P01 on +> `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key +> service, versioned AES-256-GCM record/blob store, atomic writes, encrypted +> in-memory-search source, typed recovery, raw-audio rejection, and journaled +> M-02/M-03 migrations exactly as specified. Add all P03 named tests and threat- +> model docs, run the exact clean gates, and attach enumerated evidence. Do not +> implement session, History, provider, profile, or template behavior. + +**Self-contained review prompt.** + +> Threat-model and review P03 independently. Run every clean gate, inspect key +> storage, nonce generation, AAD, atomicity, permissions, path canonicalization, +> temp handling, raw-audio rejection, and both migrations under interruption. +> Search fixture storage byte-for-byte for plaintext. Reject home-grown crypto, +> plaintext indexes/caches, destructive unverified deletion, broad reset on one +> corrupt record, skipped tests, or any nonzero gate. + +**Remediation prompt template.** + +> Remediate P03 only for `{crypto/storage/migration finding}`. Preserve the +> failing fixture and journal as evidence, identify the exact invariant breach, +> make the smallest storage-owned change, add or strengthen `{P03 named test}`, +> prove no plaintext/key remains and interruption is recoverable, rerun all P03 +> gates from `npm ci`, and return raw exits/counts plus new SHAs. + +### P04 — Interview session domain and orchestrator + +**Objective/outcome.** Replace queue/solution/debug global state with a durable, +typed InterviewSession reducer and one orchestrator that owns mode locking, +question branches, artifact provenance, provider context synchronization, +progressive sections, cancel/continue, Reset, and crash snapshots. + +**Dependencies and intended base.** P02 and P03 merged. Branch +`phase/P04-session-orchestrator` from refreshed `main` containing both. + +**Scope.** Domain types/reducer; typed IPC/event boundary; Start/Reset lifecycle; +provider/model/response snapshot; persistent provider-conversation binding; +input artifacts and pending-selection semantics; screenshot-over-transcript +authority; context status/detail; typed response-section streaming; request IDs, +cancellation and Continue unfinished; Coding question-branch primitive; encrypted +active-session snapshots. **Out of scope:** final shell visuals, mode renderers, +capture implementations, transcript engine, History UI/export, and templates. + +**Implementation requirements.** Reducer is deterministic and exhaustively +typed; all state changes are events; initial provider turn seeds applicable +context and later turns send deltas only; Coding excludes profile/opportunity; +submitted artifacts cannot be duplicated; excluded artifacts remain local and +pending until discard/submit; Reset cancels capture/provider work, discards the +native conversation, seals an archive-ready snapshot, clears active state, and +preserves preferences/reusable records; partial output remains after cancel; +Continue unfinished reuses request identity and only missing section IDs. + +**Expected files/systems.** `src/domain/interview/**`, +`electron/orchestrator/**`, shared IPC/event schemas, reducer/selectors, provider +driver integration, encrypted active-session repository adapter, fake clock/ID/ +provider fixtures, and replacement of global `view/problemInfo/hasDebugged`. + +**Compatibility, migration, rollback.** P04 exclusively owns `M-04`, encrypted +InterviewSession schema v1. Existing plaintext queues are imported only through +P03 M-02 as unattached artifacts; they are never silently treated as a live +session. Schema upgrades are forward-version rejected and rollback retains the +encrypted v1 record without lossy conversion. + +**Security/failure modes.** Duplicate evidence on retry, stale/out-of-order +stream events, cross-session event bleed, Coding personal-context leak, provider +compaction misreported as data loss, Reset racing with writes, cancellation +destroying native session, partial response replacing complete content, and +malformed IPC. Reducer/property tests and fake provider traces cover them. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P04-AC1: Start snapshots one mode/provider/model/response/language/context set; attempts to change them before Reset do not mutate the session. | `src/domain/interview/sessionLifecycle.test.ts — locks start snapshot until reset` | +| P04-AC2: reducer accepts only valid lifecycle transitions and ignores/rejects stale, duplicate, cross-session, and out-of-order events deterministically. | `src/domain/interview/sessionReducer.property.test.ts — preserves invariants under event permutations` | +| P04-AC3: the first turn seeds all applicable context; subsequent turns send only new deltas; Coding includes no dossier/opportunity bytes. | `electron/orchestrator/contextPolicy.test.ts — seeds once sends deltas and excludes coding personal context` | +| P04-AC4: new finalized transcript/screenshots are preselected; remove excludes without deleting; accepted artifacts are never resent; empty submission is rejected. | `electron/orchestrator/pendingArtifacts.test.ts — stages removes submits and deduplicates evidence` | +| P04-AC5: screenshot wins conflicting transcript requirements, while transcript is primary with no screenshot. | `electron/orchestrator/evidenceAuthority.test.ts — applies screenshot authority rule` | +| P04-AC6: context status transitions exactly New context → Updating → Full context or Context issue; compaction keeps Full context and appears only in detail. | `src/domain/interview/contextStatus.test.ts — derives honest synchronization and compaction state` | +| P04-AC7: stable typed sections publish progressively without reorder or completed-section replacement. | `electron/orchestrator/progressiveSections.test.ts — streams stable independently final sections` | +| P04-AC8: Cancel preserves completed/partial output and native conversation; Continue unfinished requests only incomplete IDs with the same request identity. | `electron/orchestrator/cancelContinue.test.ts — resumes unfinished sections without duplicate evidence` | +| P04-AC9: Reset cancels work, seals an encrypted archive-ready record, discards provider conversation, clears active artifacts, and preserves settings/reusable data. | `electron/orchestrator/resetSemantics.test.ts — performs the sole terminal lifecycle transition` | +| P04-AC10: restart offers Resume or Reset from the last valid encrypted snapshot and never auto-resumes capture. | `electron/orchestrator/crashRecovery.test.ts — restores session state with capture off` | + +**Clean-checkout setup.** Every command exits 0. + +```bash +p04_verify_dir=$(mktemp -d /tmp/interviewcopilot-P04.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p04_verify_dir/repo" +git -C "$p04_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P04-session-orchestrator +git -C "$p04_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p04_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p04` reports at least 10 named +tests passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p04 -- --reporter=verbose +npm run verify:test-manifest +npm run build +``` + +**Regression suite.** P01–P03 complete suites, provider fake contracts, +encrypted storage migration/recovery, capture lifecycle, screenshot queue +compatibility, and production build. + +**Docs.** State/event diagrams, schema/event catalog, context inclusion table, +request idempotency, status semantics, Reset/cancel/recovery behavior, and M-04 +version/rollback. + +**Completion evidence.** (1) SHAs/base; (2) full gates/counts; (3) reducer +property seed/corpus; (4) first-turn/delta traces for each mode; (5) explicit +Coding exclusion byte scan; (6) cancel/continue trace; (7) Reset before/after +record; (8) crash/relaunch transcript; (9) schema fixture. + +**Risk/complexity.** Very high/very high. This is the central consistency +boundary; no renderer or provider may keep a second authoritative session. + +**Self-contained implementation prompt.** + +> Implement P04 from P00-R1 after P02/P03 on +> `phase/P04-session-orchestrator`. Replace global transient state with the +> deterministic InterviewSession reducer, typed event/IPC contract, one +> persistent-conversation orchestrator, context/delta policy, pending artifacts, +> screenshot authority, progressive sections, cancel/continue, Reset, encrypted +> snapshot/recovery, and M-04 exactly as specified. Add the ten named tests, run +> all P04 gates, attach evidence, and do not build final shell/mode/audio/History +> UI or import prototype orchestration. + +**Self-contained review prompt.** + +> Review P04 as the sole session authority. Run all gates and property tests; +> trace every event, first-turn seed, delta, pending-artifact transition, +> compaction signal, cancel/continue, Reset race, and crash restart. Search a +> Coding trace for dossier/opportunity bytes. Reject duplicate state stores, +> Markdown-as-domain-state, artifact resends, section reorder, silent invalid +> transitions, capture auto-resume, skipped tests, or nonzero gates. + +**Remediation prompt template.** + +> Remediate P04 only for `{state/orchestration criterion}` using the smallest +> reducer/orchestrator/schema change. Add the exact failing event sequence to +> `{P04 named test}`, prove idempotency and no cross-session/personal-context +> leak, rerun every P04 command from `npm ci`, and return raw counts, traces, +> migration compatibility, and new SHAs. + +### P05 — Quiet Signal live shell, window, and capture controls + +**Objective/outcome.** Deliver the pressure-optimized macOS shell: hidden, +compact bar, compact answer, expanded workspace, explicit interactive regions, +input tray, remappable shortcuts, display-aware geometry, and accessible Quiet +Signal primitives while preserving capture protection. + +**Dependencies and intended base.** P04 merged. Branch `phase/P05-live-shell` +from refreshed `main` containing P04. + +**Scope.** Semantic tokens; shared HUD primitives; pre-session three-mode +selector; Start/live command rail; compact composer; answer/workspace states; +input tray; HotKeys editor/conflicts/reset; fixed shortcut map; visible action +equivalents; explicit drag/interactive/click-through regions; automatic compact +sizing, expanded-only resizing, per-display position/size/clamping/snap; +visibility and capture actions; full-primary-display screenshots; reduced +motion/density/text presets. **Out of scope:** mode content, audio implementation, +History, Prompt Studio, Meet verified status, and manual qualification. + +**Implementation requirements.** Launch zero visible pixels; hiding never +changes session; explicit `data-interactive` regions control passthrough (no +computed-color heuristic); Content View pill is the only drag root and excludes +interactive descendants; apply capture protection before display and after any +reconfiguration; screenshot hides/restores exactly prior visibility; capture +only current OS primary display; use final shortcuts from design (Record `R`, +Reset Backspace, Debug `D`); register atomically and expose conflicts before +saving; no required text under 12px; no hover-only action; system fonts only. + +**Expected files/systems.** Electron window/display/capture/shortcut services, +shell IPC, `src/features/shell/**`, design tokens/Tailwind mapping, shared HUD +components, Settings General/HotKeys, UI/window tests, and removal of old +command rows/dynamic size observers. + +**Compatibility, migration, rollback.** Version preference keys for density, +text size, shortcuts, and per-display geometry within P02 config migration +framework; P05 owns their additive `M-05a` migration. Invalid/conflicting +legacy values fall back to documented defaults without mutating active session. +Rollback ignores unknown additive keys. No session-schema migration. + +**Security/failure modes.** Transparent overlay intercepts clicks; interactive +surface becomes click-through; shortcut collision partially registers; window +lands off-screen after display change; capture reveals previously hidden app; +protection applied late; browser-tab sharing falsely inferred; drag controls +steal button input; zoom loses controls. Unit/UI/Electron integration tests +cover ordinary behavior but make no external capture claim. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P05-AC1: normal launch has no visible pixels; visibility toggles hidden↔pre-session/previous HUD without changing session or capture state. | `electron/window/windowVisibility.test.ts — launches hidden and restores exact HUD state` | +| P05-AC2: every visible window lifecycle applies content protection before show; no path sets it false. | `electron/window/captureProtection.integration.test.ts — protects before every show and reconfiguration` | +| P05-AC3: pre-session shows all three modes and Start; active bar permanently exposes Record, Screenshot, Chat, Submit, context, HotKeys and More→Reset with visible keyboard equivalents. | `src/features/shell/CommandRail.test.tsx — renders exact pre-session and active controls` | +| P05-AC4: default shortcuts and remapping match design, conflicts reject atomically, Reset all restores defaults, and every action has an accessible visible control. | `electron/shortcuts/shortcutRegistry.test.ts — registers remaps and rolls back conflicts atomically` | +| P05-AC5: transparent areas pass pointer events; explicit visible/interactive regions receive them; drag never starts on interactive descendants. | `src/features/shell/pointerRegions.test.tsx — separates passthrough drag and controls` | +| P05-AC6: compact states auto-size; only expanded state resizes; positions/sizes persist per display and clamp fully into changed work areas. | `electron/window/displayGeometry.test.ts — restores snaps and clamps each window state` | +| P05-AC7: screenshot captures only the current primary full display, stages one artifact, and restores visible or hidden prior state exactly. | `electron/capture/primaryDisplayCapture.test.ts — captures primary display and preserves visibility` | +| P05-AC8: compact composer Enter adds newline, Control+Shift+Enter submits, empty submission does not call provider, and close restores prior state/focus. | `src/features/shell/CompactComposer.test.tsx — implements universal submit and focus return` | +| P05-AC9: Quiet Signal uses the specified neutral/signal/mode tokens, global signal-green primary actions, density/text presets, focus order, AA contrast, 12px minimum, non-color status, reduced motion, no alternate appearance theme, and no sound/haptic/TTS path. | `src/features/shell/accessibility.test.tsx — enforces Quiet Signal accessibility and silence invariants` | +| P05-AC10: section arrow shortcuts collapse/expand/navigate/scroll without moving the window; window arrows move without scrolling content. | `src/features/shell/navigationShortcuts.test.tsx — separates window and answer navigation` | + +**Clean-checkout setup.** Every command exits 0. + +```bash +p05_verify_dir=$(mktemp -d /tmp/interviewcopilot-P05.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p05_verify_dir/repo" +git -C "$p05_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P05-live-shell +git -C "$p05_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p05_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p05` reports at least 10 named +tests passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p05 -- --reporter=verbose +npm run verify:test-manifest +npm run build +npm run test:electron-shell +``` + +`test:electron-shell` exits 0 on macOS and records window bounds, protection +application, screenshot-display ID, and pointer-region results. **Regression +suite:** all P01–P04 tests, provider/storage/session contracts, capture queues, +preload IPC allowlist, accessibility, and production build. + +**Docs.** Window-state and focus diagrams, shortcut reference, display recovery, +permission-repair behavior, screenshot scope, interaction-region authoring, +accessibility presets, and explicit statement that tests do not qualify Meet. + +**Completion evidence.** (1) SHAs/base; (2) all raw gates/counts; (3) Electron +shell artifact; (4) screenshots of four states at both densities/text extremes; +(5) keyboard-only recording; (6) two-display disconnect/clamp recording; +(7) hidden/visible screenshot state trace; (8) accessibility report; (9) +protection call-order trace. + +**Risk/complexity.** Very high/high. Electron transparent-window input and +display behavior is platform-sensitive and directly touches privacy regression. + +**Self-contained implementation prompt.** + +> Implement P05 from P00-R1 after P04 on `phase/P05-live-shell`. Build the +> exact Quiet Signal hidden/compact/answer/expanded shell, command rail, +> composer, input tray, explicit click-through/drag regions, final remappable +> shortcuts, display-aware geometry, primary-display screenshot behavior, +> tokens and accessibility presets. Preserve protection before every show and +> prior visibility across capture. Add the ten named tests, run all P05 gates +> including macOS Electron shell, and attach evidence. Do not add mode answers, +> audio, History, Prompt Studio, or unqualified capture claims. + +**Self-contained review prompt.** + +> Review P05 on macOS from a clean checkout. Operate every visible control and +> shortcut keyboard-only; inspect click-through/drag regions, focus restoration, +> geometry across display changes, compact sizing, screenshot scope/visibility, +> and content-protection call order. Run all P05 gates and accessibility checks. +> Reject computed-style hit testing, hidden-only actions, wrong Reset/Record +> bindings, off-screen states, capture-state mutation on hide, external privacy +> claims, skipped tests, or nonzero gates. + +**Remediation prompt template.** + +> Remediate P05 only for `{shell/window/capture criterion}`. Attach the exact +> display/window/input reproduction, fix the smallest P05-owned service or +> primitive, add/strengthen `{P05 named test}`, recheck protection and prior +> visibility, rerun every P05 command including `test:electron-shell`, and +> return raw counts, artifact paths, and new SHAs. + +### P06 — Coding mode and primary-display debugging + +**Objective/outcome.** Deliver a typed, progressively streamed Coding workspace +with explicit intent, language quality tiers, concise-first answer, read-only +code, question branches, and targeted screenshot debugging. + +**Dependencies and intended base.** P05 merged. Branch `phase/P06-coding` from +refreshed `main` containing P05. + +**Scope.** Coding schema/prompt/orchestrator policy; Answer/Plan/Code/Explain +renderer; Analyze/Generate Code/Debug/Follow-up intent; New Question branch; +`Control+Shift+D` Fix current code; versioned Fix cards; language catalog, +syntax rendering, fixtures, and first-class quality matrix; Copy/Regenerate/ +Debug/Explain. **Out of scope:** code editing/execution/terminal/test runner, +profile/opportunity context, other modes, and diagram export. + +**Implementation requirements.** A request cannot start without explicit +intent; Solve publishes 2–4 approach bullets, one trade-off, and time/space +complexity before code; stable Code section streams independently; selected +language snapshots at Start; Python means Python 3; six first-class families +receive parser/prompt/debug fixtures; Debug shortcut captures/submits only its +new primary-display screenshot, preserves staged artifacts and solution, and +never falls back; New Question clears problem-local UI while retaining +interview transcript/chronology. + +**Expected files/systems.** `src/features/coding/**`, Coding typed schemas, +orchestrator policy, language registry/highlighting, prompt fixtures, first- +class corpus, renderer/components, and screenshot debug integration. + +**Compatibility, migration, rollback.** P06 owns additive `M-05b` normalization +of legacy `python`→`python3` and `go`/`golang` aliases in global preferences; +active sessions never mutate. Rollback keeps canonical strings readable. +No session data rewrite; archived unknown Coding fields remain preserved. + +**Security/failure modes.** Personal-context leak, intent guessing, incomplete +or unsafe code fence parsing, language drift mid-session, Debug consuming staged +evidence, fabricated fix, full regeneration, code execution/tool access, branch +cross-contamination, and copy action copying prose. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P06-AC1: Analyze/Generate Code/Debug/Follow-up is required and maps to a distinct validated typed response; absent/unknown intent makes zero provider calls. | `src/features/coding/codingIntent.test.ts — requires and validates explicit intent` | +| P06-AC2: Solve first publishes 2–4 approach bullets, one trade-off, and both complexities; Code streams independently without displacing Answer. | `src/features/coding/progressiveCodingAnswer.test.tsx — renders concise answer before stable code` | +| P06-AC3: provider request and trace contain no dossier/opportunity bytes or tools capable of editing/executing code. | `electron/orchestrator/codingIsolation.test.ts — excludes personal context and execution tools` | +| P06-AC4: language snapshots once; M-05b normalizes aliases; Python 3 and all first-class/best-effort options render correctly. | `src/features/coding/languageSnapshot.test.ts — normalizes and locks the complete language catalog` | +| P06-AC5: each first-class language passes representative solve, syntax parse, and debugging schema fixtures; best-effort languages are visibly labeled. | `tests/fixtures/coding/firstClassQuality.contract.test.ts — validates six language families` | +| P06-AC6: Code is selectable/read-only and only Copy, Regenerate, Debug, Explain are exposed; no edit/run/terminal/test action exists. | `src/features/coding/CodePanel.test.tsx — exposes only approved read-only actions` | +| P06-AC7: New Question creates a clean problem branch while preserving interview transcript, prior branches, chronology, and History payload. | `electron/orchestrator/codingBranch.test.ts — isolates new question within one interview` | +| P06-AC8: Fix current code submits only the new screenshot, preserves staged artifacts/current solution, and returns a versioned targeted Fix card. | `src/features/coding/fixCurrentCode.test.ts — performs isolated targeted screenshot debug` | +| P06-AC9: when no issue is supported, Fix says so and requests better evidence; it never invents a patch or falls back/crosses mode. | `electron/orchestrator/codingDebugFailure.test.ts — fails honestly without regeneration or fallback` | + +**Clean-checkout setup.** Every command exits 0. + +```bash +p06_verify_dir=$(mktemp -d /tmp/interviewcopilot-P06.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p06_verify_dir/repo" +git -C "$p06_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P06-coding +git -C "$p06_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p06_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p06` reports at least 9 named tests +passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p06 -- --reporter=verbose +npm run verify:test-manifest +npm run test:coding-fixtures +npm run build +``` + +`test:coding-fixtures` exits 0 and reports all six first-class families passed, +0 failed, 0 skipped. **Regression suite:** P01–P05, provider/session no-fallback, +Coding personal-context exclusion, shell shortcuts/capture/protection, storage, +and production build. + +**Docs.** Coding schemas/intents, language tiers and fixture policy, question +branch semantics, Debug screenshot behavior, read-only boundary, M-05b, and +manual test matrix. + +**Completion evidence.** (1) SHAs/base; (2) raw gates/counts; (3) six-language +fixture report; (4) progressive event/UI trace; (5) request byte scan proving +personal-context absence; (6) New Question before/after state; (7) isolated +Debug request trace and Fix card; (8) keyboard/a11y capture. + +**Risk/complexity.** High/high. Structured output and multi-language quality can +regress silently; fixture contracts are merge-blocking. + +**Self-contained implementation prompt.** + +> Implement P06 from P00-R1 after P05 on `phase/P06-coding`. Add the exact +> typed Coding intents/schema/renderer, concise-first progressive answer, +> language snapshot and six-family fixtures, read-only actions, New Question, +> and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, +> tools, execution, fallback, or staged-artifact consumption. Own M-05b, add all +> nine named tests, run the exact gates/fixture matrix, and attach evidence. + +**Self-contained review prompt.** + +> Review P06 from clean checkout with fake provider fixtures. Validate every +> intent/schema, stream order, all six language families, Python 3, read-only +> surface, New Question isolation, and both successful/unsupported Fix flows. +> Inspect requests for personal data, extra artifacts, tools, and fallback. +> Run all P06 commands; reject guessed intent, language drift, code execution, +> full regeneration on Debug, skipped fixtures/tests, or nonzero gates. + +**Remediation prompt template.** + +> Remediate P06 only for `{intent/language/branch/debug criterion}`. Add the +> failing problem/language/event trace to `{P06 named test or first-class +> fixture}`, make the smallest Coding-owned change, prove isolation/no fallback, +> rerun all P06 commands and the six-family matrix, and return raw counts, +> request/response traces, and new SHAs. + +### P07 — System Design mode and structured architecture + +**Objective/outcome.** Deliver the fixed, progressively streamed System Design +workflow with material estimates, vendor-neutral structured diagrams, dynamic +follow-up impact analysis, and no editing or standalone diagram export. + +**Dependencies and intended base.** P05 merged. Branch +`phase/P07-system-design` from refreshed `main` containing P05. + +**Scope.** Typed Clarify/Estimate/Architecture/Data & APIs/Deep Dives & Trade- +offs schema and renderer; 2–4 material calculations; structured node/edge +diagram with inspect/zoom/pan/regenerate; vendor-neutral component vocabulary; +all-sections immediate generation; assumptions; agent-directed follow-up and +What changed. **Out of scope:** whiteboarding/editing, cloud-provider logo +catalogs, standalone diagram copy/export, Prompt Studio, and profile editor +(P08 later supplies context through the P04 interface). + +**Implementation requirements.** Fixed section order cannot be model-defined; +all section shells exist on submit and publish independently; Clarify questions +never gate later sections; estimates show units and assumptions; diagram data +validates IDs/edges/component types and has deterministic accessible text; +provider products may appear only as secondary examples; follow-up computes an +impact set, preserves byte-identical unaffected sections, and summarizes every +material change; no diagram serialization action appears in live UI. + +**Expected files/systems.** `src/features/system-design/**`, typed schemas and +validators, diagram layout/renderer, accessible representation, prompt/response +fixtures, orchestrator policy, update-diff engine, and mode tests. + +**Compatibility, migration, rollback.** No new persisted root schema; P04 +ResponseSection and session extension fields are additive and preserved by +unknown-field round-trip. Rollback displays archived structured diagram as +read-only JSON-unavailable placeholder rather than dropping it. + +**Security/failure modes.** Malformed graph/edge injection, unsafe labels/URLs, +layout denial-of-service, decorative calculations, silent assumption, vendor +lock-in, provider-controlled order, follow-up rewriting unaffected work, +standalone export leakage, and inaccessible canvas-only content. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P07-AC1: exactly five sections render in fixed order and publish independently without Clarify gating later sections. | `src/features/system-design/sectionContract.test.tsx — renders fixed progressive design sequence` | +| P07-AC2: Estimate contains 2–4 material unit-bearing calculations with explicit assumptions; Deepen estimates adds only requested detail. | `tests/fixtures/system-design/materialEstimates.contract.test.ts — validates bounded material calculations` | +| P07-AC3: Architecture accepts only approved vendor-neutral node types/valid edges and sanitizes labels/details. | `src/features/system-design/architectureSchema.test.ts — validates safe vendor-neutral graphs` | +| P07-AC4: diagram supports inspect, zoom, pan, regenerate and accessible text, but no move/rename/add/remove/reconnect/copy/export action. | `src/features/system-design/ArchitectureView.test.tsx — exposes only approved read-only interactions` | +| P07-AC5: unresolved requirements appear as assumptions while a complete design still generates. | `electron/orchestrator/systemDesignAssumptions.test.ts — answers best effort without clarification gate` | +| P07-AC6: follow-up changes only impacted sections, preserves unaffected bytes, and returns a complete What changed summary. | `electron/orchestrator/systemDesignFollowup.test.ts — applies dependency-scoped revisions` | +| P07-AC7: provider-specific services appear only in component detail examples, never node type/label or icon dependency. | `tests/fixtures/system-design/vendorNeutrality.contract.test.ts — keeps architecture vocabulary neutral` | +| P07-AC8: whole-session storage round-trips graph data, but the live Architecture view exposes no standalone export/copy. | `src/features/system-design/diagramRetention.test.ts — archives without live export surface` | + +**Clean-checkout setup.** Every command exits 0. + +```bash +p07_verify_dir=$(mktemp -d /tmp/interviewcopilot-P07.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p07_verify_dir/repo" +git -C "$p07_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P07-system-design +git -C "$p07_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p07_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p07` reports at least 8 named tests +passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p07 -- --reporter=verbose +npm run verify:test-manifest +npm run test:system-design-fixtures +npm run build +``` + +Fixture command exits 0 with all design/vendor/follow-up cases passed, failed 0, +skipped 0. **Regression suite:** P01–P05, provider/session/storage, shell section +navigation, accessibility, capture protection, and build. + +**Docs.** Response/graph schemas, allowed node types, estimate policy, +assumption semantics, follow-up impact algorithm, accessibility text, and live +no-export boundary. + +**Completion evidence.** (1) SHAs/base; (2) raw gates/counts; (3) progressive +five-section trace; (4) estimate fixture report; (5) graph validation corpus; +(6) before/after follow-up diff proving unaffected hashes; (7) keyboard/screen- +reader diagram recording; (8) absence-of-export DOM/API scan. + +**Risk/complexity.** High/high. Graph validation/layout and scoped regeneration +must not become a second untyped document model. + +**Self-contained implementation prompt.** + +> Implement P07 from P00-R1 after P05 on `phase/P07-system-design`. Add the +> fixed typed five-section progressive workflow, bounded material estimates, +> safe vendor-neutral structured diagram, read-only accessible interactions, +> assumption handling, dependency-scoped follow-up and What changed summary. +> Add all eight named tests/fixtures, run exact gates, attach evidence, and do +> not add diagram editing/export, vendor node types, Prompt Studio, or profile UI. + +**Self-contained review prompt.** + +> Review P07 from clean checkout using malformed and representative fixtures. +> Prove fixed order/no gate, estimate bounds/units, graph sanitization and +> accessibility, vendor neutrality, approved interactions only, archived graph +> round-trip, and hash-identical unaffected follow-up sections. Run every P07 +> gate; reject raw Markdown state, diagram export/editing, unsafe graph content, +> decorative arithmetic, skipped tests, or nonzero exits. + +**Remediation prompt template.** + +> Remediate P07 only for `{schema/estimate/diagram/follow-up criterion}`. Add the +> failing graph or event to `{P07 named fixture}`, change the smallest System +> Design-owned validator/renderer/policy, prove unaffected hashes and no export, +> rerun all P07 gates/fixtures, and return raw counts, diffs, and new SHAs. + +### P08 — Candidate profile, opportunity context, and Behavioral mode + +**Objective/outcome.** Deliver encrypted reusable candidate/opportunity context +and a factual, provenance-aware Behavioral mode with concise talking points, +STAR/Evidence/Follow-ups, optional same-facts Full Answer, and explicit synthetic +story control. + +**Dependencies and intended base.** P05 merged. Branch `phase/P08-behavioral` +from refreshed `main` containing P05. + +**Scope.** Encrypted canonical candidate Markdown dossier; guided profile chat; +manual edit and resume/Markdown import/export; multiple named opportunity +contexts with one active selection; provenance; synthetic setting/default; +Behavioral schema/renderer/story selection; context delivery to Behavioral and +System Design interface; explicit Coding exclusion. **Out of scope:** PDF/DOCX +resume parsing, custom core modes, Practice scoring/feedback, and History UI. + +**Implementation requirements.** Validate and sanitize Markdown imports; +encrypt content/indexes; retain provenance per claim/story; verified/user-edited +stories cannot gain unsupported events/technologies/scope/metrics; absent metric +stays qualitative; synthetic is off by default, opt-in only, saved immediately +as `synthetic-draft`, visibly labeled, and reused consistently; talking points +and Full Answer derive from one fact object; opportunity selection snapshots at +Start and later edits apply next session; System Design receives applicable +context while Coding receives none. + +**Expected files/systems.** `src/features/profile/**`, +`src/features/behavioral/**`, encrypted repositories/adapters, Markdown parser +and diff review, profile-agent policy, typed story/provenance schemas, settings +panels, Behavioral fixtures and renderer. + +**Compatibility, migration, rollback.** P08 exclusively owns `M-06`: encrypted +candidate dossier/opportunity schema v1 and active-selection preference. Imports +create a reviewed draft, never overwrite silently; migration is idempotent and +keeps original encrypted revision. Rollback preserves Markdown export and +unknown provenance fields. + +**Security/failure modes.** Prompt injection in resume/Markdown, path/HTML/link +injection, personal context leaking into Coding/logs, invented real-story facts +or metrics, synthetic unlabeled/promotion, cross-opportunity contamination, +Full Answer fact drift, import overwrite, and plaintext search/index/cache. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P08-AC1: dossier guided chat/manual edit/import produce a reviewable canonical Markdown draft with required sections and retained provenance. | `src/features/profile/candidateDossier.test.ts — builds reviews and edits canonical Markdown` | +| P08-AC2: dossier/opportunity content and search terms have no plaintext bytes at rest; export occurs only to an explicit destination. | `electron/storage/profileEncryption.test.ts — encrypts reusable personal context and indexes` | +| P08-AC3: multiple named opportunities persist exactly one active selection; Start snapshots it and active-session edits do not change the snapshot. | `src/features/profile/opportunitySnapshot.test.ts — isolates named opportunities across sessions` | +| P08-AC4: Behavioral request includes dossier and snapshotted opportunity, System Design gets applicable context, and Coding contains neither. | `electron/orchestrator/personalContextRouting.test.ts — routes personal context only to approved modes` | +| P08-AC5: synthetic is off by default; no matching real story returns an honest absence without provider-invented facts. | `electron/orchestrator/behavioralFactuality.test.ts — refuses unsupported real stories and metrics` | +| P08-AC6: opt-in synthetic story saves as `synthetic-draft`, visibly labels every view/metric, and later reuse has identical facts. | `src/features/behavioral/syntheticStory.test.ts — labels persists and reuses synthetic evidence` | +| P08-AC7: Answer/STAR/Evidence/Follow-ups share one typed fact object; Full Answer introduces no new fact or metric. | `src/features/behavioral/factParity.test.ts — preserves claims across concise and full formats` | +| P08-AC8: verified/user-edited stories use only dossier-backed claims and remain qualitative when metrics are absent. | `tests/fixtures/behavioral/verifiedClaims.contract.test.ts — prevents unsupported precision` | +| P08-AC9: imported Markdown sanitizes executable HTML/unsafe links/instructions and cannot override protected product/schema invariants. | `src/features/profile/markdownSafety.test.ts — treats imported content as untrusted evidence` | +| P08-AC10: no Practice score, post-answer feedback, or coaching-review surface is present. | `src/features/behavioral/liveOnlyBoundary.test.tsx — excludes deferred Practice behavior` | + +**Clean-checkout setup.** Every command exits 0. + +```bash +p08_verify_dir=$(mktemp -d /tmp/interviewcopilot-P08.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p08_verify_dir/repo" +git -C "$p08_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P08-behavioral +git -C "$p08_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p08_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p08` reports at least 10 named +tests passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p08 -- --reporter=verbose +npm run verify:test-manifest +npm run test:behavioral-fixtures +npm run build +``` + +Fixture command exits 0 with verified/synthetic/import cases passed, 0 failed, +0 skipped. **Regression suite:** P01–P06 plus P07 if already merged, storage +plaintext scans, session context policy, Coding isolation, shell/accessibility, +provider no-fallback, and build. + +**Docs.** Dossier and opportunity Markdown/schema/provenance, import threat +model, synthetic policy, context-routing matrix, M-06, export behavior, and +Practice exclusion. + +**Completion evidence.** (1) SHAs/base; (2) gates/counts; (3) encrypted byte +scan; (4) sanitized import/diff; (5) three-mode request context scans; (6) +verified and synthetic fixture report; (7) concise/full fact-object diff; +(8) multi-opportunity snapshot trace; (9) keyboard/a11y recording. + +**Risk/complexity.** Very high/high. Personal data confidentiality and factual +integrity are product trust boundaries. + +**Self-contained implementation prompt.** + +> Implement P08 from P00-R1 after P05 on `phase/P08-behavioral`. Build the +> encrypted canonical candidate dossier, guided/manual reviewed editing, +> sanitized Markdown import/export, multiple snapshotted opportunities, +> provenance, opt-in labeled persistent synthetic stories, and typed Behavioral +> views with same-facts Full Answer. Route context only to Behavioral/System +> Design, never Coding. Own M-06, add ten named tests/fixtures, run exact gates, +> attach evidence, and add no Practice or plaintext personal index. + +**Self-contained review prompt.** + +> Review P08 from clean checkout as both privacy and factuality boundary. Search +> storage/logs/Coding requests for fixture personal bytes; attack Markdown; +> compare concise/full facts; test absent metrics, synthetic off/on/reuse, +> multi-opportunity snapshotting, and System Design routing. Run all P08 gates. +> Reject unlabeled synthetic content, unsupported precision, active-session +> context mutation, plaintext indexes, Practice UI, skipped tests, or nonzero +> exits. + +**Remediation prompt template.** + +> Remediate P08 only for `{privacy/provenance/factuality/context criterion}`. +> Preserve the failing dossier/import/trace fixture, make the smallest profile +> or Behavioral-owned fix, strengthen `{P08 named test}`, repeat plaintext and +> three-mode scans, rerun every P08 command/fixture, and return raw counts, +> fact/context diffs, and new SHAs. + +### P09 — macOS audio capture, transcription, and question detection + +**Objective/outcome.** Add explicit, source-separated microphone/system-audio +capture, local-first transcription, speaker attribution/correction, provider- +assisted question detection, and typed pending transcript artifacts without +automatic answering or raw-audio retention. + +**Dependencies and intended base.** P05 merged. Branch `phase/P09-audio` from +refreshed `main` containing P05. + +**Scope.** macOS native capture helper (ScreenCaptureKit/AVAudioEngine or their +supported successor); independent sources and master Record; contextual +permissions; pause/resume; elapsed/waveform/status; bundled or checksum-pinned +`whisper.cpp` local transcription; explicit optional Apple Speech service cloud +fallback; segment finalization, source labels, multi-speaker diarization through +the selected subscription agent, uncertainty/correction, question candidate, +and session integration. **Out of scope:** Windows/Linux, automatic answer, +archived raw audio, TTS, sounds/haptics, and other cloud transcription vendors. + +**Implementation requirements.** Both sources off every session; master Record +starts/resumes or pauses both deterministically while per-source controls remain +independent; hide/collapse does nothing to capture; temporary buffers are mode +0600, bounded, deleted immediately after finalization/error/Reset, and rejected +by storage; local transcription is default/offline; Apple cloud transcription +requires explicit opt-in each configured setting, visible Remote status, and +never becomes an answer provider; permission denial disables only that source +and retries only on explicit action; source defaults Interviewer/You; uncertain +labels visible/editable; provider-assisted diarization/question detection uses +the existing session conversation with finalized transcript text only, never +raw audio or a second hidden conversation; detected question never invokes a +provider answer. + +**Expected files/systems.** macOS Swift/native audio helper and build config, +`electron/audio/**`, local transcription sidecar/model manifest/checksums, +Apple Speech adapter, audio IPC/events, Audio Settings, shell controls/waveform, +transcript/question UI, fixtures, and permission integration tests. + +**Compatibility, migration, rollback.** P09 exclusively owns `M-07`: audio +settings and typed transcript-segment schema v1. Migration defaults both sources +off and cloud fallback disabled; no prior setting can enable capture. Rollback +ignores encrypted transcripts it cannot render and never restores raw buffers. + +**Security/failure modes.** Capture without action, remote fallback without +consent, microphone/system mix-up, hidden-state pause, raw buffer leak, oversized +audio denial-of-service, model checksum/license failure, native helper crash, +permission loops, speaker hallucination, correction not reaching context, +detected question triggering answer, and audio content in logs/diagnostics. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P09-AC1: every new/resumed session starts both sources off; no device opens before explicit Record/source action. | `electron/audio/explicitActivation.test.ts — never captures before session-scoped user action` | +| P09-AC2: master Record and independent source controls follow exact deterministic pause/resume semantics; hide/collapse leaves state unchanged. | `electron/audio/sourceStateMachine.test.ts — controls two sources without session side effects` | +| P09-AC3: denial/error disables only the affected source, provides Open System Settings/Retry, and never repeats a permission prompt without action. | `electron/audio/permissionRecovery.test.ts — scopes denial and explicit retry` | +| P09-AC4: local offline fixture transcription is default; model binary/data match pinned checksum/license; no network request occurs. | `electron/audio/localTranscription.contract.test.ts — transcribes offline with pinned local engine` | +| P09-AC5: Apple Speech remote path runs only after explicit enable, visibly reports Remote, and cannot call answer APIs or silently replace local failure. | `electron/audio/cloudFallbackConsent.test.ts — requires explicit Apple transcription consent` | +| P09-AC6: temporary raw buffers are bounded, owner-only, removed on success/failure/cancel/Reset/crash cleanup, absent from encrypted archive and logs. | `electron/audio/rawAudioRetention.test.ts — leaves no retained or logged audio bytes` | +| P09-AC7: source labels default system→Interviewer/mic→You; uncertain diarization is marked and correction updates session and archive payload. | `src/features/audio/speakerAttribution.test.ts — labels marks and corrects transcript provenance` | +| P09-AC8: partial/final segment states and all eight visible audio/question/preparing/ready/error states are non-color and waveform has text equivalent. | `src/features/audio/audioStatusAccessibility.test.tsx — renders complete accessible audio state model` | +| P09-AC9: question detection produces an editable pending candidate and zero answer-provider calls until explicit Solve/Design/Coach/Submit. | `electron/audio/questionDetection.test.ts — never auto-answers detected speech` | +| P09-AC10: system-audio and microphone fixture channels remain distinct through capture, transcription, timestamps, and pending-artifact selection. | `electron/audio/channelSeparation.integration.test.ts — preserves two-channel provenance end to end` | +| P09-AC11: diarization/question detection sends finalized text only through the one selected persistent session conversation; it creates no second conversation and submits no raw audio. | `electron/audio/modelOperationRouting.test.ts — keeps audio-derived reasoning in one text-only session conversation` | + +**Clean-checkout setup.** Requires macOS; every command exits 0. + +```bash +p09_verify_dir=$(mktemp -d /tmp/interviewcopilot-P09.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p09_verify_dir/repo" +git -C "$p09_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P09-audio +git -C "$p09_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p09_verify_dir/repo" +test "$(uname -s)" = "Darwin" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p09` reports at least 11 named +tests passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p09 -- --reporter=verbose +npm run verify:test-manifest +npm run test:audio-native +npm run test:audio-retention +npm run build +``` + +Native/retention commands exit 0 and print passed/failed/skipped counts; fixture +audio contains no interview/user content. **Regression suite:** P01–P05, +provider no-fallback, session pending artifacts/Reset/recovery, encrypted storage +raw-audio rejection, shell visibility/shortcuts/accessibility, and build. + +**Docs.** Audio architecture, local model source/license/checksum/size, Apple +remote disclosure, permission matrix/repair, source/master state table, +retention/crash cleanup, attribution/correction, and no-auto-answer boundary. + +**Completion evidence.** (1) SHAs/base; (2) raw gate/count reports; (3) native +helper tests on supported macOS architectures; (4) offline network-denial trace; +(5) Apple fallback consent/network trace; (6) temp/archive/log byte scan; +(7) two-channel timestamp/provenance artifact; (8) permission-denial recording; +(9) question detection trace showing zero answer calls; (10) model SBOM/license. + +**Risk/complexity.** Very high/very high. Native audio, permissions, model +packaging, privacy, and transcription latency are launch-critical. + +**Self-contained implementation prompt.** + +> Implement P09 from P00-R1 after P05 on `phase/P09-audio`, macOS only. Build +> explicit two-source native capture, deterministic master/per-source controls, +> contextual permission recovery, pinned offline whisper.cpp transcription, +> explicit Apple Speech remote fallback, typed segments/attribution/correction, +> accessible status, pending question detection, M-07, and zero raw-audio +> retention/auto-answer. Add eleven named tests plus native/retention suites, run +> every exact gate, attach evidence, and add no other provider/platform/sound. + +**Self-contained review prompt.** + +> Review P09 on supported macOS from clean checkout with network blocked and +> permissions granted/denied. Trace device-open timing, every source/master +> transition, hide/collapse, local checksum/offline behavior, explicit Apple +> remote consent, temp/archive/log bytes, channel provenance, correction, and +> question detection provider-call count. Run all P09 gates. Reject silent +> capture/fallback, retained audio, permission loops, auto-answer, skipped tests, +> unsupported platform work, or nonzero exits. + +**Remediation prompt template.** + +> Remediate P09 only for `{capture/transcription/privacy criterion}`. Preserve +> the exact macOS/version/permission/audio fixture trace, fix the smallest +> audio-owned native/adapter/state path, strengthen `{P09 named test}`, repeat +> offline/remote-consent and byte-retention scans, rerun all P09 commands, and +> return raw counts, artifacts, and new SHAs. + +### P10 — Prompt Studio and protected template variants + +**Objective/outcome.** Add synchronized guided-chat and manual CRUD for user +template variants inside the three core modes, with protected typed schemas and +auditable dynamic instruction-conflict resolution. + +**Dependencies and intended base.** P06, P07, and P08 merged. Branch +`phase/P10-prompt-studio` from refreshed `main` containing those phases. + +**Scope.** Built-in template read/duplicate/restore; user create/read/duplicate/ +edit/rename/delete; specialized template-building chat with reviewable diff; +mode-bound selection; encrypted storage; instruction composition and recorded +conflict resolution by relevance/specificity/recency/provenance/applicability; +protected invariants/schema. **Out of scope:** arbitrary renderer/schema, +custom named mode, tool/plugin marketplace, sharing/sync, and template access to +raw credentials/personal data outside mode policy. + +**Implementation requirements.** Chat and Manage edit one representation; +built-ins immutable; deletion confirmation deterministic; template content is +untrusted data, cannot override screenshot authority, mode lock, factual/ +synthetic policy, provider selection, no fallback, tools, or response schema; +effective resolution is recorded in encrypted session state without hidden +prompt content in logs; selection snapshots at Start; Coding template cannot +request profile context; all changes show semantic diff before save. + +**Expected files/systems.** `src/features/prompts/**`, template schema/repository, +prompt-composition service, guided agent policy, diff UI, Settings selection, +mode integration, conflict fixtures, and template security tests. + +**Compatibility, migration, rollback.** P10 exclusively owns `M-08`: encrypted +template schema v1 and per-mode active-template selection. Invalid/unknown +records quarantine without changing built-ins; rollback falls back to built-in +while retaining encrypted user records for later compatible reopen. + +**Security/failure modes.** Prompt injection overriding product invariants, +template causing personal-context leak/tool enablement/fallback, hidden chat +save, built-in mutation, mode/schema mismatch, stored XSS/Markdown injection, +conflict resolution nondeterminism, and plaintext prompt indexes/logs. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P10-AC1: Chat and Manage create/edit the same encrypted typed record and require a reviewable diff before save. | `src/features/prompts/synchronizedStudio.test.tsx — synchronizes guided and manual editing through reviewed diffs` | +| P10-AC2: built-ins are readable/duplicable/restorable but cannot be edited/deleted; user templates support complete CRUD. | `src/features/prompts/templateCrud.test.ts — protects built-ins and completes user CRUD` | +| P10-AC3: every template is bound to Coding/System Design/Behavioral and validates against that mode schema; no arbitrary/custom named mode is creatable. | `src/features/prompts/modeBoundary.test.ts — limits templates to three protected core modes` | +| P10-AC4: malicious instructions cannot override protected invariants, tools, provider/model/effort, no-fallback, context routing, or response schema. | `electron/orchestrator/templateSecurity.test.ts — rejects invariant and capability escalation` | +| P10-AC5: semantic conflicts resolve by the specified factors, produce deterministic effective instructions, and record an inspectable resolution without content logs. | `electron/orchestrator/instructionResolution.test.ts — resolves and records conflicts deterministically` | +| P10-AC6: active template snapshots at Start; editing/selection changes apply only to the next session. | `src/features/prompts/templateSnapshot.test.ts — locks template revision for active session` | +| P10-AC7: M-08 encrypts records/indexes and quarantines malformed/newer versions while preserving built-ins and other templates. | `electron/storage/templateMigration.test.ts — migrates encrypts and isolates invalid templates` | +| P10-AC8: user content is safely rendered and cannot execute HTML/URLs/scripts or enter diagnostics automatically. | `src/features/prompts/templateContentSafety.test.tsx — renders untrusted instructions inertly` | + +**Clean-checkout setup.** Every command exits 0. + +```bash +p10_verify_dir=$(mktemp -d /tmp/interviewcopilot-P10.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p10_verify_dir/repo" +git -C "$p10_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P10-prompt-studio +git -C "$p10_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p10_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p10` reports at least 8 named tests +passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p10 -- --reporter=verbose +npm run verify:test-manifest +npm run test:prompt-adversarial +npm run build +``` + +Adversarial command exits 0 with every escalation fixture passed, 0 failed, 0 +skipped. **Regression suite:** P01–P08 (and P09 when merged), all mode schemas, +provider/session no-fallback and context isolation, encrypted storage, shell, +accessibility, and build. + +**Docs.** Template schema/CRUD, built-in protection, Chat/Manage diff workflow, +instruction-resolution factors/record, protected invariants, M-08, and explicit +custom-mode deferral. + +**Completion evidence.** (1) SHAs/base; (2) gates/counts; (3) Chat/Manage same- +record trace and diff; (4) CRUD/built-in matrix; (5) adversarial fixture report; +(6) three-mode schema validation; (7) active-session snapshot trace; (8) +encrypted/plaintext scan; (9) keyboard/a11y recording. + +**Risk/complexity.** High/high. User instructions are an adversarial input and +must never become a capability or schema escape hatch. + +**Self-contained implementation prompt.** + +> Implement P10 from P00-R1 after P06/P07/P08 on +> `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, +> immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, +> deterministic recorded instruction resolution, Start snapshotting, protected +> invariant/capability enforcement, and M-08. Add eight named tests and the +> adversarial suite, run all exact gates, attach evidence, and add no arbitrary +> schema/custom mode/sharing/plugin capability. + +**Self-contained review prompt.** + +> Review P10 from clean checkout as an untrusted-instruction boundary. Attack +> every invariant/provider/context/tool/schema path, verify deterministic +> conflict records, same representation/diff requirement, built-in immutability, +> CRUD, mode binding, active snapshot, encrypted bytes, and inert rendering. +> Run every P10 gate/adversarial fixture; reject any capability escalation, +> hidden save/logging, custom mode, skipped test, or nonzero exit. + +**Remediation prompt template.** + +> Remediate P10 only for `{CRUD/schema/conflict/security criterion}`. Add the +> exact malicious or state-transition input to `{P10 named/adversarial test}`, +> make the smallest Prompt Studio/composition fix, prove protected invariants +> and encrypted storage, rerun all P10 commands, and return raw counts, +> effective-instruction diff, and new SHAs. + +### P11 — Crash recovery, searchable History, export, and deletion + +**Objective/outcome.** Complete the encrypted session lifecycle with explicit +Resume/Reset after crash and Settings-only permanent History supporting search, +open, delete one/all, and individual Markdown/JSON export without raw audio. + +**Dependencies and intended base.** P06–P10 merged. Branch +`phase/P11-history-recovery` from refreshed `main` containing every dependency. + +**Scope.** Relaunch decision UI; archive projection; encrypted in-memory search +source; Settings → History list/open; delete one/all; single-session Markdown +bundle and structured JSON export; screenshot assets; provider/model/mode/ +context snapshots; deletion confirmations and recovery. **Out of scope:** tags, +favorites, multi-select, bulk export, cloud sync, automatic expiry/pruning, +archived raw audio, and live-shell History entry. + +**Implementation requirements.** Reset always archives then clears; crash +recovery never auto-starts capture/provider turn; History remains indefinitely +until explicit deletion; search indexes are encrypted or derived in memory; +open is read-only and does not resume provider; exports decrypt only selected +session to user-chosen destination, validate canonical paths, use deterministic +schema/version, and disclose plaintext; Markdown assets are bounded/sanitized; +delete is journaled and cannot affect reusable profile/opportunity/templates. + +**Expected files/systems.** `src/features/history/**`, recovery decision UI, +archive projector/repository/index, export/delete services, Settings navigation, +schema fixtures, path safety and round-trip tests. + +**Compatibility, migration, rollback.** P11 exclusively owns `M-09`: encrypted +History index/projection v1 derived from P04 session records. It is rebuildable +from encrypted records, versioned, and never authoritative. Rollback drops only +the derived encrypted index; session records remain intact. Export schemas carry +version and preserve unknown fields. + +**Security/failure modes.** Plaintext index/cache, path traversal/symlink export, +export without disclosure, delete-all hitting profiles, partial export/delete, +opening archive as live session, raw audio or secrets in export, unbounded image +decompression, search leaking terms, and retention/pruning without action. + +**Acceptance criteria and named new tests.** + +| Criterion | Named test | +|---|---| +| P11-AC1: crash relaunch offers Resume or Reset, restores last valid session with capture off, and Reset archives exactly once. | `src/features/history/crashDecision.test.tsx — offers explicit safe recovery without duplicate archive` | +| P11-AC2: Reset archive contains required mode/timestamps/transcript/questions/constraints/answers/code/diagram/follow-ups/provider snapshot/screenshots and no raw audio. | `electron/history/archiveProjection.test.ts — projects complete session and excludes audio` | +| P11-AC3: History appears only under Settings and supports search/open/delete one/delete all with indefinite retention and no auto-prune. | `src/features/history/HistorySettings.test.tsx — exposes exact Settings-only controls and retention` | +| P11-AC4: search finds required fields while fixture search terms/indexes/caches have no plaintext bytes at rest. | `electron/history/encryptedSearch.test.ts — searches in memory without plaintext index` | +| P11-AC5: Markdown bundle and JSON export round-trip one session, include bounded screenshot assets, omit secrets/raw audio, and require plaintext disclosure/destination. | `electron/history/exportRoundTrip.test.ts — exports one safe versioned session with consent` | +| P11-AC6: export rejects traversal/symlink/overwrite without confirmation and interruption leaves no partial accepted bundle. | `electron/history/exportPathSafety.test.ts — confines and atomically writes explicit exports` | +| P11-AC7: delete one/all is confirmed, journaled, resumable, and never deletes active session/preferences/profile/opportunity/templates. | `electron/history/deletionIsolation.test.ts — deletes only selected archived sessions` | +| P11-AC8: opening an archived session is read-only and creates no provider process/thread, capture, pending artifact, or active-session mutation. | `electron/history/readOnlyArchive.test.ts — inspects History without resuming live systems` | + +**Clean-checkout setup.** Every command exits 0. + +```bash +p11_verify_dir=$(mktemp -d /tmp/interviewcopilot-P11.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p11_verify_dir/repo" +git -C "$p11_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P11-history-recovery +git -C "$p11_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p11_verify_dir/repo" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p11` reports at least 8 named tests +passed, 0 failed, 0 skipped; every raw exit is 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p11 -- --reporter=verbose +npm run verify:test-manifest +npm run test:history-roundtrip +npm run test:plaintext-scan +npm run build +``` + +Round-trip/plaintext commands exit 0 with all fixtures passed, failed 0, +skipped 0. **Regression suite:** every P01–P10 test, all three modes, audio raw- +retention, provider/session recovery, storage migrations, prompt/profile data +isolation, shell/accessibility, and build. + +**Docs.** Recovery decision, archived field/retention table, search design, +Markdown/JSON schemas, plaintext export disclosure, delete semantics, M-09, +and explicit deferred library features. + +**Completion evidence.** (1) SHAs/base; (2) gates/counts; (3) crash Resume/Reset +trace; (4) archive field/no-audio report; (5) plaintext scan; (6) JSON and +Markdown round-trip hashes; (7) traversal/interruption results; (8) delete +isolation journal; (9) read-only provider/capture zero-call trace. + +**Risk/complexity.** Very high/high. History concentrates the most sensitive +content and destructive user controls. + +**Self-contained implementation prompt.** + +> Implement P11 from P00-R1 after P06–P10 on +> `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete +> encrypted archive projection, Settings-only in-memory search/open/delete one/ +> all, safe consented individual Markdown/JSON export, read-only archive open, +> indefinite retention, M-09, and strict no-audio/secret/plaintext-index rules. +> Add eight named tests/round-trip/scans, run every exact gate, and attach all +> evidence. Add no tags/favorites/bulk/cloud/pruning/live History surface. + +**Self-contained review prompt.** + +> Review P11 from clean checkout with corrupt, large, interrupted, traversal, +> and multi-session fixtures. Prove explicit recovery/capture-off, complete/no- +> audio projection, Settings-only indefinite History, no plaintext search bytes, +> safe round-trip exports/disclosure, isolated journaled deletion, and zero live +> side effects on archive open. Run every P11 gate. Reject data loss/leak, +> auto-prune, broad delete, live resume, skipped tests, or nonzero exits. + +**Remediation prompt template.** + +> Remediate P11 only for `{recovery/archive/search/export/delete criterion}`. +> Preserve the failing encrypted fixture/journal, make the smallest History- +> owned change, strengthen `{P11 named test}`, repeat round-trip/plaintext/data- +> isolation checks, rerun all P11 commands, and return raw counts, hashes, +> journals, and new SHAs. + +### P12 — macOS release hardening and Google Meet qualification + +**Objective/outcome.** Produce a macOS-only release candidate whose packaging, +permissions, diagnostics, documentation, guided verification, and exact Google +Meet entire-display/specific-window qualification support honest capture- +privacy claims and no broader evasion claim. + +**Dependencies and intended base.** P11 and every earlier phase merged. Branch +`phase/P12-macos-qualification` from refreshed `main` containing P01–P11. + +**Scope.** macOS package/identity/protocol/updater/entitlement audit; remove +Windows/Linux launch packaging/support claims; local redacted diagnostics with +preview/manual export only; end-to-end permission/provider recovery; Privacy & +Capture settings and guided Meet test; versioned verification record and stale +rules; deterministic moving marker; qualification harness/artifact validator; +final README/CONTRIBUTING/privacy/security/release docs; notarized arm64/x64 +release artifacts; final SBOM/vulnerability disposition. + +**Out of scope.** Browser-tab qualification, macOS native capture claims unless +separately passed, Zoom/Teams/Discord/other apps, Windows/Linux, generic Test My +Setup, anti-proctoring/process hiding/monitoring evasion, universal +undetectability, analytics/crash upload, and automatic result inference from a +local preview. + +**Implementation requirements.** At RC cut, freeze exact InterviewCopilot +commit/version, the latest Apple-supported stable macOS patch available on each +claimed arm64/x64 test machine, current stable Chrome, Meet version, display +mode, and architecture; qualify each supported tuple separately; +entire-display and specific-window require confirmation from remote Meet view or +second device and retained high-contrast moving-marker artifacts; one fail makes +the tuple unsupported; browser-tab remains unverified; verification state is +Not verified/Verified/Failed/Retest required and invalidates after capture- +relevant app changes or major OS/browser change; diagnostic export previews +redaction and never auto-transmits; docs use only D-005g wording and matrix. + +**Expected files/systems.** macOS build config/entitlements/icons/protocol/update +metadata, `electron/diagnostics/**`, Privacy & Capture UI, verification +repository/harness/scripts, release matrix/artifacts schema, README/ +CONTRIBUTING/SECURITY/privacy/release docs, SBOM, and removal/deferment of non- +macOS launch scripts/config. + +**Compatibility, migration, rollback.** P12 exclusively owns `M-10`: encrypted +capture-verification record v1. Older/missing record becomes Not verified; +capture-relevant version changes produce Retest required; rollback never carries +Verified forward to a different build/OS/browser tuple. No qualification record +is synced or auto-uploaded. + +**Security/failure modes.** Claim exceeds evidence; local preview false pass; +marker absent/static; stale status survives version change; unsupported tuple +shown verified; capture protection regression; overly broad entitlements; +unsafe updater/publish target; diagnostics contain user content/credentials; +generic test implies certification; signing/notarization mismatch; ordinary +qualification language drifts into evasion advice. + +**Acceptance criteria and named new tests/procedures.** + +| Criterion | Named test/procedure | +|---|---| +| P12-AC1: package config emits only macOS arm64/x64 launch artifacts with canonical identity, minimum entitlements, valid signing/notarization, AGPL metadata, and no Windows/Linux support claim. | `tests/release/macosPackagePolicy.test.ts — validates macOS-only signed package metadata` | +| P12-AC2: every BrowserWindow in the packaged app enables content protection before first visible frame and after lifecycle reconfiguration. | `tests/release/packagedCaptureProtection.test.ts — traces protection in the packaged app` | +| P12-AC3: guided Meet flow tests entire-display and specific-window separately with moving marker and requires remote/second-device confirmation; it never offers generic/browser-tab certification. | `src/features/privacy/MeetVerification.test.tsx — guides only qualified scopes with remote confirmation` | +| P12-AC4: verification record contains exact app/commit/macOS/arch/Chrome/Meet/display/scopes/date/result/artifact hashes and state invalidates by specified changes. | `electron/privacy/verificationRecord.test.ts — versions verifies fails and stales exact tuples` | +| P12-AC5: release-build Google Meet entire-display capture contains zero marker pixels while underlying control frames remain visible for every frozen tuple. | `P12-M01 — remote Google Meet entire-display moving-marker qualification` | +| P12-AC6: release-build Google Meet specific-window capture contains zero marker pixels while target-window control frames remain visible for every frozen tuple. | `P12-M02 — remote Google Meet specific-window moving-marker qualification` | +| P12-AC7: any missing/failed scope or artifact produces Failed/Not verified and makes release qualification command nonzero; local preview can never produce pass. | `scripts/qualification/meet-artifact-validator.test.ts — fails incomplete false or local-only evidence` | +| P12-AC8: diagnostics exclude transcript/audio/screenshots/prompts/responses/profile/opportunity/credentials/tokens/device IDs, preview before manual export, and perform zero network upload. | `electron/diagnostics/diagnosticPrivacy.test.ts — previews redacted local-only diagnostic export` | +| P12-AC9: provider/microphone/system-audio/screen-capture denial disables only affected action and explicit repair/retry preserves the session. | `tests/release/scopedRecovery.e2e.test.ts — preserves session through every permission/provider failure` | +| P12-AC10: shipped copy/docs contain only qualified D-005g language and no 99%, undetectable, bypass, anti-cheat, process-hiding, monitoring-evasion, or unsupported-app/platform claim. | `tests/release/claimPolicy.test.ts — rejects unqualified privacy and platform language` | +| P12-AC11: no product plan/credit/quota/entitlement, analytics/device fingerprint, or automatic crash upload exists in package/source/network trace. | `tests/release/openSourcePrivacyPolicy.test.ts — enforces free local-only product policy` | +| P12-AC12: Practice, custom named modes, browser-tab certification, generic Test My Setup, Zoom/Teams, Windows, and Linux remain absent/deferred. | `tests/release/deferredScope.test.ts — keeps deferred surfaces out of launch` | +| P12-AC13: representative Coding/System Design/Behavioral fixtures and surfaced copy prioritize Senior/Staff+ ambiguity reduction, trade-offs, production/operational judgment, leadership, and organizational impact in a Live-first flow. | `tests/release/staffLivePositioning.contract.test.ts — validates Staff plus judgment across the live loop` | +| P12-AC14: onboarding and Start contain no responsibility notice, usage-boundary acknowledgement, consent gate, or recurring confirmation. | `tests/release/noUsageGate.test.ts — preserves the neutral frictionless tool boundary` | + +**Clean-checkout setup.** Requires supported macOS, Chrome, Meet test account, +remote observer/second device, signing/notarization credentials, and both +architecture runners. Every command exits 0. + +```bash +p12_verify_dir=$(mktemp -d /tmp/interviewcopilot-P12.XXXXXX) +git clone --no-checkout https://github.com/j4wg/interview-coder-withoupaywall-opensource "$p12_verify_dir/repo" +git -C "$p12_verify_dir/repo" fetch https://github.com/timomak/interview-coder-withoupaywall-opensource phase/P12-macos-qualification +git -C "$p12_verify_dir/repo" switch --detach FETCH_HEAD +cd "$p12_verify_dir/repo" +test "$(uname -s)" = "Darwin" +test -z "$(git status --porcelain)" +node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' +``` + +**Verification commands, in order.** `test:p12` reports at least 14 named +automated/manual manifest entries passed, 0 failed, 0 skipped; all raw exits 0. + +```bash +npm ci +npm run verify:policy +npm run lint +npm run typecheck +npm run test:legacy -- --reporter=verbose +npm run test:unit -- --reporter=verbose +npm run test:p12 -- --reporter=verbose +npm run verify:test-manifest +npm run test:e2e-macos +npm run build +npm run package:mac +npm run verify:mac-package +npm run verify:diagnostics +npm run qualify:meet -- --matrix docs/qualification/macos-google-meet.json --artifacts .artifacts/qualification +npm run verify:release +``` + +`qualify:meet` exits 0 only after P12-M01 and P12-M02 records/artifacts exist for +every frozen tuple and validator finds marker pixels=0 with valid control frames. +All test scripts print passed/failed/skipped totals. **Regression suite:** the +entire P01–P11 suite, native audio, all mode fixtures, migrations, storage +plaintext scans, shell/capture integration, package smoke tests, and release +claim/deferred-scope scans. + +**Docs.** Exact supported tuple matrix/date, guided verification, stale rules, +D-005g headline/qualifier, limitations/non-security-boundary, permissions, +provider/audio/storage/privacy, diagnostics, AGPL/source offer, macOS install/ +uninstall/update, release evidence, SBOM/vulnerability disposition, and explicit +Windows/Linux/app/scope deferrals. + +**Completion evidence.** (1) SHAs/base/version; (2) every raw gate/count report; +(3) signed/notarized arm64/x64 hashes and package-policy report; (4) entitlements/ +SBOM/vulnerability disposition; (5) protection trace; (6) exact matrix; (7) +P12-M01/M02 remote recordings, control frames, marker analysis and hashes per +tuple; (8) verification-state/stale trace; (9) diagnostic preview/network-zero +trace; (10) scoped recovery E2E; (11) claim/deferred scan; (12) reviewer sign- +off that evidence supports every public claim. + +**Risk/complexity.** Release-blocking/very high. External capture behavior and +signing infrastructure cannot be inferred from unit tests. + +**Self-contained implementation prompt.** + +> Implement P12 from P00-R1 after P01–P11 on +> `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ +> architecture matrix, harden macOS-only package/entitlements/identity, add +> local-only redacted diagnostic preview/export, scoped failure recovery, +> guided remote-confirmed Meet verification and M-10, rewrite docs to qualified +> D-005g claims, and remove/defer every unsupported platform/scope/evasion claim. +> Produce signed/notarized arm64/x64 artifacts, execute P12-M01/M02 on the +> release build, run every exact gate including artifact validation, and attach +> all evidence, including the Staff+/Live-first and no-usage-gate contracts. A +> failed or incomplete tuple blocks release; never infer pass. + +**Self-contained review prompt.** + +> Independently review P12 on the exact frozen matrix. Rebuild/package from the +> clean SHA, inspect signing/notarization/entitlements/SBOM, trace protection +> before first frame, rerun all automated gates, personally verify remote Meet +> artifacts/control frames/hashes for both scopes/architectures, force stale/ +> failed records, inspect diagnostic network/content traces, and scan every +> shipped string. Reject missing tuple evidence, local-only confirmation, +> broadened claim, unsupported platform/app/scope, telemetry/entitlement, skipped +> test, vulnerability without disposition, or any nonzero gate. + +**Remediation prompt template.** + +> Remediate P12 only for `{package/qualification/privacy/release criterion}` on +> exact tuple `{app SHA/version, macOS, arch, Chrome, Meet, display, scope}`. +> Preserve failed artifacts, identify whether code/config/environment caused it, +> make the smallest P12-owned change, invalidate prior verification, strengthen +> `{P12 named test/validator}`, rebuild and rerun the complete P12 sequence and +> both remote qualifications for every affected tuple, then return raw counts, +> artifact hashes, matrix revision, and new SHAs. + +## 8. Requirement ownership matrix + +Every resolved, superseded, or deferred decision in `design.md` appears exactly +once below. “Owner” means the phase whose acceptance criteria prove the final +requirement; dependencies may provide lower-level capability but do not share +ownership. + +| Owning phase | Design requirements owned | +|---|---| +| P01 | D-002 (canonical identity); D-053 (AGPL open-source model). | +| P02 | D-042a, D-042b, D-042c, D-042d (subscription providers, no fallback, model, effort); D-051 (provider-only onboarding); D-054 (no product entitlements). | +| P03 | D-009d (Keychain-backed application encryption at rest). | +| P04 | D-006a, D-006b (Start/Reset lifecycle); D-007 (mode lock); D-008 (complete local and persistent provider context); D-021 (screenshot authority); D-043a, D-043b, D-043c, D-043d, D-043e (persistent context, compaction, status, composer, pending evidence); D-044a, D-044b (progressive/no fixed deadline); D-045a, D-045b (cancel/continue and best effort). | +| P05 | D-011a, D-011b, D-011c, D-011d, D-011e, D-011f (hidden shell/visibility/shortcuts/composer/submit/HotKeys); D-012a, D-012b, D-012c (drag/geometry/navigation); D-013, D-014, D-015 (mode selector/rail/collapse); D-020a, D-020b (full primary-display screenshot); D-046/Theme-001, D-047, D-048a, D-048b, D-049, D-050 (Quiet Signal/accessibility/silence). | +| P06 | D-022 (concise Coding first); D-023a, D-023b (language tiers/snapshot); D-024, D-024b (explicit intent/targeted Fix); D-025 (New Question); D-026 (read-only code). | +| P07 | D-027 (structured diagram); D-028a, D-028b (fixed sequence/material estimates); D-029 (complete design with assumptions); D-030a, D-030b (vendor neutral/no standalone export); D-031 (dynamic follow-up). | +| P08 | D-032a, D-032b (dossier/synthetic control); D-033 (talking points/full answer); D-034 (factual metric policy); D-035a, D-035b (opportunity contexts); D-036 (Practice feedback deferred); D-037 (personal-context routing). | +| P09 | D-016 (local transcription/explicit cloud fallback); D-017, D-017b, D-017c, D-017d, D-017e (continuous explicit two-source capture and Record binding); D-018 (detected question waits); D-019 (attribution/correction); D-041 (local capability boundary). | +| P10 | D-038 (Prompt Studio); D-039a (core-mode variants); D-039b (custom modes deferred); D-040 (dynamic conflict resolution within invariants). | +| P11 | D-009a, D-009b, D-009c, D-009e (recovery/History/archive contents/retention/search/delete/export). | +| P12 | D-001 (Live-first); D-003 (Senior/Staff+ defaults); D-004 (positioning); D-005a (superseded absolute claim); D-005b (no responsibility/consent gate); D-005c, D-005d, D-005e, D-005f, D-005g, D-005h (qualified macOS/Meet scope, guided verification, wording, no generic verifier); D-010 (Practice deferred); D-052 (scoped failure recovery); D-055 (no analytics/automatic crash upload and manual redacted diagnostics). | + +No requirement is intentionally unowned. A later design revision that adds or +changes a decision must update this matrix and the owning phase criteria before +implementation. + +## 9. Migration ownership and rollback registry + +Exactly one phase owns each persisted schema/data change. Other phases may use +the migrated interface but may not write an alternate migration. + +| Migration | Sole owner | Data change | Required rollback/recovery evidence | +|---|---|---|---| +| M-01 | P02 | Legacy API/provider/model/credit config → versioned subscription-only config. | Redacted backup, mode 0600, atomic/idempotent migration; explicit-only legacy restore. | +| M-02 | P03 | Plaintext screenshot/temp/cache artifacts → authenticated encrypted blobs. | Journal, decrypt-before-delete proof, interruption resume, quarantine. | +| M-03 | P03 | Encrypted store envelope/schema v1 and protected installation key. | Prior/new valid record atomicity, Keychain recovery, version rejection. | +| M-04 | P04 | InterviewSession/ResponseSection/active-recovery schema v1. | Encrypted fixture round-trip, forward-version rejection, no lossy downgrade. | +| M-05a | P05 | Density/text/shortcut/per-display geometry preferences. | Invalid-value defaults; old builds ignore additive keys. | +| M-05b | P06 | Language aliases (`python`→`python3`, Go aliases) to canonical preference. | Idempotent normalization; active session unchanged. | +| M-06 | P08 | Candidate dossier/opportunity/provenance/active-selection schema v1. | Reviewed draft/import, encrypted original revision, Markdown export escape hatch. | +| M-07 | P09 | Audio preferences and transcript-segment schema v1. | Both sources/cloud off by default; no raw-audio rollback. | +| M-08 | P10 | Encrypted user-template and per-mode selection schema v1. | Quarantine invalid/newer user records; built-in fallback; preserve ciphertext. | +| M-09 | P11 | Rebuildable encrypted History projection/index v1 and export schema v1. | Drop/rebuild derived index without touching session records; versioned export. | +| M-10 | P12 | Encrypted exact-tuple capture-verification record v1. | Missing/old/mismatched tuple becomes Not verified or Retest required, never carried forward. | + +## 10. Execution-time decisions, prerequisites, and genuine blockers + +No unresolved product decision blocks P00 or P01. The following values are +deliberately time-bound and must be frozen by their owner without changing the +product contract: + +1. **P02 CLI protocol versions.** Freeze the minimum tested Claude Code and + Codex app-server versions at P02 branch cut, store protocol fixtures, and + fail explicitly outside the supported capability set. This is version + selection, not permission to change provider semantics. +2. **P09 local model artifact.** Freeze a redistributable whisper.cpp binary and + model revision, license, architecture hashes, download/bundle decision, and + performance evidence before merge. Apple Speech is the sole launch remote + fallback and remains explicit/off by default. +3. **P12 qualification tuple.** At RC cut, record the exact current-stable macOS + patch, Chrome/Meet versions, display configuration, app commit/version, and + arm64/x64 hardware. Do not claim a version or architecture that was not run. +4. **External P12 prerequisites.** Apple signing/notarization credentials and a + remote Meet observer/second device are required. Their absence is not a P00 + blocker, but it is a genuine release blocker: P12 cannot pass or the product + claim ship without them. +5. **CI reliability.** CI is non-authoritative. An outage does not block a phase + whose complete local evidence passes, but required repository review policy + still applies; never falsify or bypass a required hosted check. + +There is currently no blocker to opening the P00 draft PR. Future phases must +report an unmet prerequisite instead of weakening a criterion. + +## 11. Why twelve phases is the minimum cohesive set + +P01 must precede product work because the baseline has no real tests. P02 and +P03 isolate the two highest-risk one-way doors—external agent protocols and +encrypted persistence. P04 then establishes a single session authority before +P05 builds its shell. The three answer modes and native audio are independent, +large review surfaces and therefore remain separate P06–P09 PRs. Prompt Studio +must wait for all protected mode schemas; History must wait for every archived +artifact type; release qualification must run on the final release build. +Combining any adjacent pair would mix separate security/rollback domains or +produce an unreviewably broad PR. Splitting further would create partial schema, +renderer, or migration micro-phases that cannot meet an independently useful +acceptance outcome. + +## 12. Phase admission and completion protocol + +Before implementation begins, the controller records the dependency commit +SHAs and the formal Stage 2 baseline at the frozen SHA. For each phase: + +1. Confirm all dependencies are merged into upstream `main` and record the + intended base SHA. +2. Create only the canonical phase branch/worktree; verify clean status. +3. Execute the self-contained implementation prompt without prototype commits. +4. Produce every named test and completion artifact; run commands in order. +5. Have an independent reviewer execute the self-contained review prompt from a + fresh clean checkout and challenge the solution at the owning boundary. +6. For any failure, use the phase remediation template; rerun the complete + sequence from `npm ci`, not only the failed test. +7. Merge only with all local raw exits 0, failed=0, skipped=0, manifest complete, + acceptance criteria checked, migrations/rollback evidenced, and no unresolved + actionable review feedback. + +An implementation PR description must list packet revision, phase ID, base and +head SHAs, dependencies, scope/non-goals, migration owner, command outputs/counts, +completion-artifact links/hashes, risks, and any external prerequisite. “CI +green,” a screenshot, or the author’s assurance alone is never completion +evidence. From 5b885baed4f00eda89751a646e43793aa30e1154 Mon Sep 17 00:00:00 2001 From: Timomak Date: Sun, 26 Jul 2026 17:15:36 +0200 Subject: [PATCH 2/9] docs: remediate P00 execution packet review --- design.md | 10 +- docs/implementation/phase-execution-packet.md | 901 ++++++++++++------ 2 files changed, 619 insertions(+), 292 deletions(-) diff --git a/design.md b/design.md index 94bb821c..1dbd3083 100644 --- a/design.md +++ b/design.md @@ -234,7 +234,7 @@ Reset stops audio capture, cancels in-flight processing, discards the active pro The user selects a mode before Start Interview. That mode remains locked until Reset and appears as compact status in the active bar. Changing mode therefore always begins from a clean session state. -Within the active session, InterviewCopilot retains the complete local sequence of transcript segments, screenshots, detected questions, answers, follow-ups, and explicit interviewer constraints. The selected provider owns one persistent resumable conversation for the life of that interview session. The initial provider turn receives the complete applicable starting context; subsequent turns send new inputs and changes into the same conversation, where the provider retains and automatically compacts working history as needed. Behavioral and System Design initialize with the complete candidate dossier and active opportunity context; Coding excludes both under D-037. The active session and provider conversation identifier are saved locally so a crash or accidental quit can offer Resume or Reset on relaunch. +Within the active session, InterviewCopilot retains the complete local sequence of transcript segments, screenshots, detected questions, answers, follow-ups, and explicit interviewer constraints. The selected provider owns one persistent resumable conversation for the life of that interview session. The initial provider turn receives the complete applicable starting context; subsequent turns send new inputs and changes into the same conversation, where the provider retains and automatically compacts working history as needed. Behavioral and System Design initialize with the complete candidate dossier and active opportunity context; Coding excludes both under D-037. The provider runtime accepts a caller-supplied opaque conversation identifier and may hold it only in memory; it never writes that identifier or a provider session file to plaintext application storage. The Interview Orchestrator stores the identifier only inside the P03 encrypted active-session snapshot, so a crash or accidental quit can offer Resume or Reset on relaunch without creating an unencrypted recovery path. The primary live loop is capture-first and shortcut-friendly: @@ -609,10 +609,10 @@ Implementation should eventually introduce these concepts: InterviewCopilot should reuse the architectural boundary proven in twarp's agent view without adopting a generic coding-chat product model: -1. A provider-neutral `AgentDriver` owns installation and authentication checks, process lifecycle, persistent session or thread identity, structured input, normalized streaming events, graceful interruption, resume, token/context signals, compaction signals, and provider errors. +1. A provider-neutral `AgentDriver` owns installation and authentication checks, process lifecycle, caller-supplied opaque session or thread identity, structured input, normalized streaming events, graceful interruption, resume, token/context signals, compaction signals, and provider errors. It can resume after its own child process restarts, but it keeps the opaque identity only in memory and never persists it in plaintext or provider-owned application files. 2. The Claude adapter runs one long-lived headless CLI process per interview using structured JSON input and output, a pinned session identifier, the InterviewCopilot system prompt, schema-constrained output where supported, deliberately restricted tools, and native resume. 3. The Codex adapter runs `codex app-server` over its structured protocol, starts or resumes one thread per interview, installs InterviewCopilot instructions as thread-level developer instructions, uses application-labeled additional context and per-turn output schemas, and consumes native usage and compaction events. -4. An Interview Orchestrator above both adapters owns the selected mode, protected product invariants, prompt-template composition, applicable dossier and opportunity context, transcript and screenshot provenance, question branches, requested intent, typed response schemas, retries, and synchronization state. Provider-specific JSON never reaches the renderer. +4. An Interview Orchestrator above both adapters owns the selected mode, protected product invariants, prompt-template composition, applicable dossier and opportunity context, transcript and screenshot provenance, question branches, requested intent, typed response schemas, retries, synchronization state, and encrypted persistence/recovery of the opaque provider conversation identifier through the P03 storage interface. Provider-specific JSON never reaches the renderer. 5. A session reducer converts normalized provider and capture events into the durable `InterviewSession` and independently streamable `ResponseSection` model. The compact HUD renders that typed state rather than raw assistant Markdown or terminal scrollback. 6. The encrypted local session archive remains the canonical unabridged product record. Native Claude or Codex persistence is a resumable reasoning runtime, not InterviewCopilot's History database or only source of truth. 7. Shortcut-generated answers and typed composer messages enter the same orchestrator and persistent conversation. They differ only in user intent and which new input artifacts accompany the turn; provider adapters and renderers do not maintain a separate chat agent. @@ -848,7 +848,7 @@ Decisions are resolved in dependency order. A later branch may be reordered when | D-042c | Resolved | Store a user-controlled model selection for Claude Code and Codex and never switch it automatically. | Provider default remains an explicit selectable option. Sessions snapshot the provider/model pair for reproducibility. | | D-042d | Resolved | Add a `Fast / Reasoning` setting, translate it into the selected provider/model's native effort controls, and snapshot it with provider/model at Start Interview. | The user explicitly chooses latency versus deliberation, while one persistent conversation keeps a consistent configuration until Reset. InterviewCopilot never silently changes or downgrades the selection; unsupported combinations are unavailable. | | D-043a | Resolved, refined by D-043b | Seed a persistent provider conversation with complete applicable starting context and send subsequent session deltas into it. | Behavioral/System Design include candidate and opportunity documents; Coding excludes them. Raw audio remains outside general answer requests. | -| D-043b | Resolved | Use one persistent resumable provider conversation per interview and rely on provider auto-compaction. | Reset discards the provider conversation. InterviewCopilot preserves the complete encrypted local record and does not implement a second hidden compaction layer. | +| D-043b | Resolved | Use one persistent resumable provider conversation per interview and rely on provider auto-compaction. | The driver resumes process failures from a caller-supplied opaque identifier held only in memory; the orchestrator persists that identifier solely inside the encrypted active-session record for app-restart recovery. Reset discards the provider conversation. InterviewCopilot does not implement a second hidden compaction layer. | | D-043c | Resolved | Show a `Full context` status indicator with `Updating` and `Context issue` states plus an inspectable source-level detail popover. | The user can verify what entered the persistent conversation without crowding the HUD. Provider-reported compaction is disclosed without falsely implying that all original tokens remain verbatim. | | D-043d | Resolved | Keep the curated mode-specific workspace primary while allowing typed conversation with the current persistent agent. | Shortcut answers and chat messages share one provider conversation and context model. Structured responses update the curated layout; ordinary clarification can remain a compact exchange without introducing a generic terminal-style Agent View. | | D-043e | Resolved | Preselect all newly captured, unsent transcript segments and screenshots as removable attachments for the next answer or chat submission. | The default preserves complete context without resending artifacts already held by the persistent agent. Users can exclude irrelevant evidence or send a text-only message while retaining deliberate control. | @@ -863,5 +863,5 @@ Decisions are resolved in dependency order. A later branch may be reordered when The reviewed phase order, dependency graph, acceptance gates, migration owners, prototype disposition, and implementation/review/remediation prompts are defined in [`docs/implementation/phase-execution-packet.md`](docs/implementation/phase-execution-packet.md), -revision P00-R1. This design remains the product source of truth; the packet is +revision P00-R2. This design remains the product source of truth; the packet is the execution contract. Prototype evidence does not establish phase completion. diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md index cb673466..9c9528fd 100644 --- a/docs/implementation/phase-execution-packet.md +++ b/docs/implementation/phase-execution-packet.md @@ -1,6 +1,6 @@ # InterviewCopilot phase-execution packet -Packet revision: **P00-R1** +Packet revision: **P00-R2** Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` @@ -136,17 +136,17 @@ The table maps every tracked or untracked prototype path to a future owner. |---|---| | `package.json`, `package-lock.json`, `vitest.config.ts`, `tsconfig.electron.json` | P01 re-creates a consolidated test/lint/type gate and lockfile; the observed Vitest spike is not accepted as-is. | | `electron/ConfigHelper.ts`, `electron/ConfigHelper.test.ts` | P02 reimplements a versioned subscription-only config migration. Legacy API-key paths in the spike are explicitly rejected. | -| `electron/ai/types.ts`, `cliProcess.ts`, `cliProcess.test.ts` | P02 reuses safety ideas (absolute executables, no shell, abort/timeout/output limits, redaction) inside the persistent driver. | -| `electron/ai/cliProviders.ts`, `cliProviders.test.ts` | P02 replaces one-shot Claude `--no-session-persistence` and Codex `--ephemeral` execution with resumable Claude sessions and Codex app-server threads. | +| `electron/ai/types.ts`, `electron/ai/cliProcess.ts`, `electron/ai/cliProcess.test.ts` | P02 reuses safety ideas (absolute executables, no shell, abort/timeout/output limits, redaction) inside the persistent driver. | +| `electron/ai/cliProviders.ts`, `electron/ai/cliProviders.test.ts` | P02 replaces one-shot Claude `--no-session-persistence` and Codex `--ephemeral` execution with resumable Claude sessions and Codex app-server threads. | | `electron/ProcessingHelper.ts` | P02/P04 replace legacy provider branching and regex orchestration; no legacy API-provider branch survives P02. | | `electron/ipcHandlers.ts`, `electron/preload.ts`, `src/env.d.ts`, `src/types/electron.d.ts` | P02 owns narrow provider/config IPC; P04 owns typed session/event IPC; P05 owns shell/window IPC. Duplicate typings become one generated/shared contract. | -| `electron/captureProtection.ts`, `captureProtection.test.ts` | P01 adopts the centralized invariant and expands lifecycle coverage; P12 owns external qualification. | +| `electron/captureProtection.ts`, `electron/captureProtection.test.ts` | P01 adopts the centralized invariant and expands lifecycle coverage; P12 owns external qualification. | | `electron/main.ts`, `electron/ScreenshotHelper.ts` | P05 reimplements hidden launch, prior-visibility restoration, per-display geometry, click-through, and capture lifecycle without weakening protection. | -| `electron/shortcuts.ts`, `shortcuts.test.ts`, `src/utils/platform.ts` | P05 implements the final remappable shortcut map. The spike's Reset-on-`R` and inverted Up/Down behavior are rejected. | +| `electron/shortcuts.ts`, `electron/shortcuts.test.ts`, `src/utils/platform.ts` | P05 implements the final remappable shortcut map. The spike's Reset-on-`R` and inverted Up/Down behavior are rejected. | | `src/App.tsx`, `src/_pages/Queue.tsx`, `src/_pages/SubscribedApp.tsx` | P04/P05 replace transient view state and computed-style click-through heuristics with typed session state and explicit interactive regions. | -| `src/components/Settings/SettingsDialog.tsx`, `WelcomeScreen.tsx` | P02 builds provider-only onboarding; later settings panels are added by their owning phases. The prototype is not the final Quiet Signal UI. | -| `src/components/Header/Header.tsx`, `Queue/QueueCommands.tsx`, `Solutions/SolutionCommands.tsx` | P02 removes entitlement/API debris; P05 replaces command rows and exposes visible equivalent actions. | -| `src/constants/languages.ts`, `electron/languages.test.ts`, `LanguageSelector.tsx` | P06 adopts the normalized language catalog and adds first-class language fixtures required by D-023a. | +| `src/components/Settings/SettingsDialog.tsx`, `src/components/WelcomeScreen.tsx` | P02 builds provider-only onboarding; later settings panels are added by their owning phases. The prototype is not the final Quiet Signal UI. | +| `src/components/Header/Header.tsx`, `src/components/Queue/QueueCommands.tsx`, `src/components/Solutions/SolutionCommands.tsx` | P02 removes entitlement/API debris; P05 replaces command rows and exposes visible equivalent actions. | +| `src/constants/languages.ts`, `electron/languages.test.ts`, `src/components/shared/LanguageSelector.tsx` | P06 adopts the normalized language catalog and adds first-class language fixtures required by D-023a. | | `src/_pages/Solutions.tsx`, `src/_pages/Debug.tsx` | P06 replaces regex-parsed views with typed Coding sections, read-only code actions, and versioned Fix cards. Copy-button ideas remain evidence only. | | `README.md`, `CONTRIBUTING.md`, `stealth-run.sh`, `stealth-run.bat` | P12 rewrites launch docs/scripts for macOS-only qualified claims. The Windows script is retained only until P12 removes launch support through an explicit reviewed change; it is never used as evidence of support. | | `src/_pages/SubscribedApp.tsx` sizing removal and `Queue.tsx` width change | P05 owns automatic compact sizing and expanded-only manual resize with display-clamping tests. | @@ -200,27 +200,88 @@ review. A phase cannot use another open phase branch as its base. ## 6. Immutable local-gate contract -P01 creates and documents these scripts. From P01 onward every phase runs them -in the listed order from a clean checkout. `verify:test-manifest` fails if a -tracked test disappeared, was renamed without a packet revision, contains -`.skip`/`.todo`/`xit`/`xdescribe`, or did not execute. Test commands must print -passed, failed, and skipped totals plus their raw exit code. - -```bash -npm ci # expected exit 0 -npm run verify:policy # expected exit 0 -npm run lint # expected exit 0 -npm run typecheck # expected exit 0 -npm run test:legacy -- --reporter=verbose # expected exit 0; failed 0; skipped 0 -npm run test:unit -- --reporter=verbose # expected exit 0; failed 0; skipped 0 -npm run verify:test-manifest # expected exit 0 -npm run build # expected exit 0 -``` - -Each phase adds one domain test script and runs it between `test:unit` and the -manifest check. Exact commands and minimum named-test counts appear below. -No implementer may edit the gate script and feature behavior in the same phase -after P01; a required gate change needs a separate P00 packet revision. +P01 creates and tests `scripts/verification/phase-reporter.mjs`, the package +script `verify:phase`, and immutable argv plans +`scripts/verification/plans/P01.json` through `P12.json` plus the auxiliary +`P12-observer.json`. From P01 onward a +phase invokes only that reporter for the phase gate; none of the child commands +below is run bare. The plan files contain argv arrays, test/non-test +classification, expected raw exit, and minimum test count, and the reporter +rejects shell strings, unknown labels, duplicate labels, or a plan whose hash +does not match the committed manifest. + +For every plan entry the reporter, without `shell`, prints and logs the exact +shell-escaped command, UTC start/end, duration, raw child exit or terminating +signal, and numbered stdout/stderr log path. It tees output without changing the +child result, records every raw exit, and continues after failures. For every +test-classified entry it consumes the framework's machine-readable result (or +the P01-tested adapter for native/manual suites) and prints +`passed= failed= skipped=`; missing/unparseable counts, any failure or +skip, or a count below the plan minimum is itself a recorded failure. The +reporter runs `verify:test-manifest` only after all test entries, writes one +JSON and one text aggregate report with the plan hash, and exits 0 only when +every child raw exit equals its expected value, all count requirements pass, +and the manifest proves that every inherited, phase-owned, fixture, native, +E2E, and manual procedure entry ran. Otherwise it exits 1 after the last entry. +Injected-failure tests must prove that later commands still run and that the +failed raw exit remains visible in both reports and the aggregate nonzero exit. + +Every P01–P12 plan starts with these exact argv entries, in this order; all +expect raw exit 0. The two test entries additionally require failed=0 and +skipped=0. `test:legacy` executes the preserved legacy renderer test, while +`test:unit` executes the complete inherited manifest from all merged phases; +the phase-specific `test:pNN` entry then executes the current domain criteria. +Therefore a current phase cannot replace its inherited regression suites with +only its new tests. + +| Label | Exact child command | Classification | +|---|---|---| +| `install` | `npm ci` | non-test | +| `policy` | `npm run verify:policy` | non-test | +| `lint` | `npm run lint` | non-test | +| `typecheck` | `npm run typecheck` | non-test | +| `legacy` | `npm run test:legacy -- --reporter=verbose` | test | +| `unit` | `npm run test:unit -- --reporter=verbose` | test | + +The plan then appends the exact phase entries below. Within each row, commands +run left to right. Unless the row explicitly places it later, the reporter then +runs `npm run verify:test-manifest` followed by `npm run build`, each with +expected raw exit 0. All commands beginning `test:` and `qualify:` are +test-classified and must print passed/failed/skipped counts. + +| Phase | Exact phase-plan child commands after `unit` | +|---|---| +| P01 | `npm run test:p01 -- --reporter=verbose` | +| P02 | `npm run test:p02 -- --reporter=verbose` | +| P03 | `npm run test:p03 -- --reporter=verbose` | +| P04 | `npm run test:p04 -- --reporter=verbose` | +| P05 | `npm run test:p05 -- --reporter=verbose`; `npm run test:electron-shell` | +| P06 | `npm run test:p06 -- --reporter=verbose`; `npm run test:coding-fixtures` | +| P07 | `npm run test:p07 -- --reporter=verbose`; `npm run test:system-design-fixtures` | +| P08 | `npm run test:p08 -- --reporter=verbose`; `npm run test:behavioral-fixtures` | +| P09 | `npm run test:p09 -- --reporter=verbose`; `npm run test:audio-native`; `npm run test:audio-retention` | +| P10 | `npm run test:p10 -- --reporter=verbose`; `npm run test:prompt-adversarial` | +| P11 | `npm run test:p11 -- --reporter=verbose`; `npm run test:history-roundtrip`; `npm run test:plaintext-scan` | +| P12 | `npm run test:p12 -- --reporter=verbose`; `npm run test:e2e-macos`; `npm run test:staff-live-corpus`; `npm run build`; `npm run package:mac`; `npm run verify:mac-package`; `npm run verify:diagnostics`; `npm run qualify:meet -- --matrix docs/qualification/macos-google-meet.json --artifacts .artifacts/qualification --collect-missing`; `npm run verify:test-manifest`; `npm run verify:release` | + +The P12 row is complete and therefore does not receive the default manifest or +build suffix. Package, diagnostics, Meet collection/validation, and final +release validation are child commands of the same reporter and cannot bypass +its raw-exit aggregate. `qualify:meet` launches collection when evidence is +absent as specified in P12-M01/M02; it is not an artifact-presence shortcut. +The remote device also uses the reporter, with the exact invocation +`npm run verify:phase -- --phase P12 --role meet-observer --pair + --artifacts .artifacts/qualification-observer`. +`P12-observer.json` runs `npm ci`, `npm run verify:policy`, and then +`npm run qualify:meet:observer -- --pair ` without a +shell; every child raw exit and the observer aggregate must be 0. Pair data is +an argv value, never a shell string. + +Each phase section below gives the exact reporter invocation, expected +aggregate exit, and minimum named-test count. P01 seeds all twelve phase plans +and the P12 observer plan, so no later implementer edits the reporter or a plan +alongside feature behavior. A required gate/plan change needs a new P00 packet +revision. ## 7. Phase contracts @@ -237,15 +298,18 @@ docs). Branch `phase/P01-local-gates`. **Scope.** Consolidate Vitest (including the unchanged tracked CRA sample), correct ESLint parsing/ignores rather than suppressing findings, fix all current strict TypeScript and lint failures without changing behavior, create the raw -exit/count reporter and immutable test manifest, centralize capture protection, -set canonical InterviewCopilot metadata, add policy scans, and document local -gates. **Out of scope:** new session/provider/UI behavior, deleting the legacy -renderer, dependency-vulnerability upgrades unrelated to making gates work, -and external capture claims. +exit/count reporter, all phase and P12-observer immutable argv plans, and +immutable test manifest, centralize capture protection, set canonical +InterviewCopilot metadata, add policy scans, and document local gates. **Out of +scope:** new session/provider/UI behavior, deleting the legacy renderer, +dependency-vulnerability upgrades unrelated to making gates work, and external +capture claims. **Implementation requirements.** Use Node 20; keep lockfile deterministic; make root tests execute `renderer/src/App.test.tsx` unchanged; permit no skip or -todo test forms; report raw exit plus passed/failed/skipped counts; fix all 105 +todo test forms; report exact command, raw exit, and passed/failed/skipped +counts; accumulate injected failures while preserving their raw exits and make +the final reporter aggregate nonzero; fix all 105 lint and 48 type errors rather than excluding product code; make every window creation/reveal path call one `applyCaptureProtection` helper; add no false content-protection path; scan dependencies/source for analytics and automatic @@ -277,7 +341,7 @@ must make each failure observable and fail closed. | P01-AC4: every BrowserWindow creation and reveal path invokes `applyCaptureProtection`, which calls `setContentProtection(true)` and never false. | `electron/captureProtection.test.ts — protects creation and reveal lifecycle paths` | | P01-AC5: package metadata and visible identity use InterviewCopilot and retain `AGPL-3.0-or-later`. | `tests/policy/productPolicy.test.ts — enforces canonical identity and AGPL metadata` | | P01-AC6: shipped source has no analytics SDK, device fingerprint, automatic crash-upload initialization, or environment-based secret logging. | `tests/policy/productPolicy.test.ts — rejects telemetry crash upload and secret logging entry points` | -| P01-AC7: the verification reporter prints command, raw exit, and test passed/failed/skipped fields without converting nonzero to success. | `tests/policy/verificationReporter.test.ts — preserves raw failures and count fields` | +| P01-AC7: the reporter validates immutable argv plans, logs every exact command/raw exit, prints passed/failed/skipped for every test entry, continues after an injected child failure, preserves that raw exit in JSON/text, and exits nonzero at the aggregate gate; missing counts and plan drift also fail. | `tests/policy/verificationReporter.test.ts — accumulates raw failures counts and immutable plan drift` | **Clean-checkout setup.** Every command must exit 0. @@ -295,18 +359,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) P01 named tests passed, 0 failed, 0 skipped; the full suite may have more. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p01 -- --reporter=verbose -npm run verify:test-manifest -npm run build +npm run verify:phase -- --phase P01 --artifacts .artifacts/verification/P01 ``` -Expected raw exit for every command is 0. **Regression suite:** all inherited +Expected reporter aggregate exit is 0; every logged child raw exit is 0. +**Regression suite.** all inherited tests, capture/screenshot behavior tests, full root unit suite, strict type check, lint, and production build. No baseline error is grandfathered. @@ -315,7 +372,9 @@ artifact format, AGPL/privacy policy, and the non-claim that unit protection proves capture privacy. **Completion evidence (enumerated).** (1) commit SHA and base SHA; (2) clean -status; (3) dependency install log; (4) one raw-exit/count report per gate; +status; (3) dependency install log; (4) one aggregate JSON/text report with +every child exact command/raw exit and test count plus an injected-failure +artifact proving aggregate exit 1; (5) manifest diff proving the inherited test remains; (6) capture lifecycle test output; (7) build artifact list; (8) reviewer sign-off that no lint/type rule or source glob was weakened. @@ -326,19 +385,21 @@ inside the single PR. **Self-contained implementation prompt.** -> Implement P01 from P00-R1 on `phase/P01-local-gates`, based only on upstream +> Implement P01 from P00-R2 on `phase/P01-local-gates`, based only on upstream > `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. > Make local lint, strict type-check, real unit tests (including the unchanged > tracked CRA sample), manifest enforcement, and build green. Centralize and > lifecycle-test `setContentProtection(true)`, enforce InterviewCopilot/AGPL/no- -> telemetry policy, print raw exits and test counts, add exactly the tests named -> in P01, run the commands in order, and attach every enumerated artifact. Do -> not add product features or waive existing failures. +> telemetry policy, seed/validate the exact P01–P12 and P12-observer argv plans, print raw exits +> and test counts, accumulate failures into a nonzero aggregate, add exactly the +> tests named in P01, run the P01 reporter gate, and attach every enumerated +> artifact. Do not add product features or waive existing failures. **Self-contained review prompt.** -> Review P01 independently against P00-R1, not the author’s summary. From the -> clean PR checkout run every P01 command, confirm the inherited CRA test ran, +> Review P01 independently against P00-R2, not the author’s summary. From the +> clean PR checkout run the P01 reporter invocation, confirm the inherited CRA +> test ran, > inspect all config/glob/ignore changes for hidden coverage loss, compare typed > cleanup for behavior changes, and prove every window lifecycle applies true > content protection. Reject the PR for any missing raw count, skipped test, @@ -349,8 +410,9 @@ inside the single PR. > Remediate P01 only. Evidence: `{failing command/raw exit/counts or review > finding}`. Root cause: `{confirmed cause}`. Change the smallest P01-owned > files, add/strengthen `{named regression test}`, preserve every inherited -> gate and capture invariant, rerun the complete P01 sequence from `npm ci`, -> and return new raw evidence plus the before/after commit SHAs. +> gate and capture invariant, rerun the complete P01 plan (which begins with +> `npm ci`) by invoking the reporter, and return every child raw exit/count, +> aggregate exit, and the before/after commit SHAs. ### P02 — Subscription-only persistent agent runtime @@ -368,48 +430,57 @@ normalized stream, usage, compaction, stop, resume, and error events; process safety; provider settings/onboarding; removal of OpenAI/Anthropic/Gemini answer SDK paths, API keys, Supabase, credits, plans, quotas, and subscription portal. **Out of scope:** interview domain orchestration, mode schemas, storage -encryption, renderer answer layouts, cloud transcription, and cross-provider +encryption, any on-disk provider conversation-ID persistence, app-restart +recovery, renderer answer layouts, cloud transcription, and cross-provider fallback. **Implementation requirements.** Pin and validate supported CLI protocol versions; resolve only absolute executables; use `spawn` with `shell:false`; strip answer-provider secret overrides; cap output, timeout, abort gracefully, then force-kill; sanitize stderr; never expose auth tokens/account identifiers; -keep one Claude session ID or Codex thread ID resumable across process/app -restart; map provider events to one discriminated union; never launch the -unselected provider after session selection; map Fast/Reasoning only to native -supported controls and mark unsupported combinations unavailable. +accept one caller-supplied opaque Claude session ID or Codex thread ID, retain +it only in memory/test fixtures, and resume it across driver or child-process +restart; write no provider ID/session/thread file or plaintext recovery record; +map provider events to one discriminated union; never launch the unselected +provider after session selection; map Fast/Reasoning only to native supported +controls and mark unsupported combinations unavailable. P04, after P03, owns +encrypted app-restart persistence and passes the recovered opaque ID back to +this runtime. **Expected files/systems.** `electron/providers/**`, shared provider event and IPC types, `electron/config/**`, settings/onboarding UI, preload/IPC narrowing, provider fixtures/fake executables, package dependencies, and removal of legacy -provider/entitlement modules and strings. +provider/entitlement modules and strings. Runtime tests use caller-owned opaque +IDs in memory-only fixtures; no P02 provider persistence directory is allowed. **Compatibility, migration, rollback.** P02 exclusively owns migration `M-01`: legacy `config.json` to versioned subscription config. Preserve language/opacity; remove and never rewrite legacy API keys/models/credits; take an owner-only backup with no key material before atomic replacement; repeated -migration is idempotent. Rollback restores the backup only after explicit user -choice because the old format contains disallowed secrets. +migration is idempotent. M-01 must not add a provider conversation ID or +session/thread recovery field. Rollback restores the backup only after explicit +user choice because the old format contains disallowed secrets. **Security/failure modes.** PATH substitution, argument injection, inherited API keys changing billing, malformed stream events, output floods, zombie children, provider version drift, token leakage, accidental tool access, -automatic fallback, and applying settings mid-session. Fake-executable tests -cover all without a live subscription. +automatic fallback, applying settings mid-session, and plaintext/native provider +session persistence. Fake-executable tests cover all without a live +subscription. **Acceptance criteria and named new tests.** | Criterion | Named test | |---|---| | P02-AC1: only `claude-code` and `codex` answer-provider IDs are accepted; legacy providers/API-key/credit/entitlement IPC and dependencies are absent. | `electron/providers/providerBoundary.test.ts — rejects legacy providers and entitlement surfaces` | -| P02-AC2: two turns and an app restart resume the same Claude session and Codex thread respectively. | `electron/providers/persistence.contract.test.ts — resumes one conversation for both adapters` | +| P02-AC2: two turns separated by driver and child-process restart resume the same Claude session and Codex thread when the caller supplies the same opaque ID; the runtime does not claim app-restart recovery. | `electron/providers/persistence.contract.test.ts — resumes caller-owned conversations after process restart` | | P02-AC3: selected provider failure emits a typed recoverable error and never starts the other provider. | `electron/providers/noFallback.contract.test.ts — never invokes the unselected provider` | | P02-AC4: provider, model, and response mode snapshot once; unsupported effort/model combinations cannot start and no silent substitution occurs. | `electron/providers/selectionSnapshot.test.ts — locks explicit provider model and effort` | | P02-AC5: normalized streams preserve text/typed payload, usage and compaction signals, stop, completion, and sanitized provider errors. | `electron/providers/eventNormalization.contract.test.ts — normalizes streaming and compaction events` | | P02-AC6: child processes use absolute paths, no shell, scrubbed answer-secret env, bounded output/time, and graceful-then-forceful cancellation. | `electron/providers/processSafety.test.ts — constrains provider child processes` | | P02-AC7: M-01 preserves language/opacity, removes legacy secrets/credits, writes mode 0600 atomically, and is idempotent. | `electron/config/configMigration.test.ts — migrates legacy settings once without persisting secrets` | | P02-AC8: first run requires exactly one installed/authenticated provider then lands on Start Interview without requesting capture/audio permission. | `src/features/onboarding/ProviderSetup.test.tsx — completes provider-only onboarding` | +| P02-AC9: provider IDs/session/thread state exist only in caller memory or test fixtures; config, backups, logs, provider directories, and a full test filesystem byte scan contain no opaque-ID fixture, and M-01 has no conversation field. | `electron/providers/conversationIdBoundary.test.ts — prohibits plaintext provider conversation persistence` | **Clean-checkout setup.** Same expected exit policy as P01. @@ -423,66 +494,69 @@ test -z "$(git status --porcelain)" node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' ``` -**Verification commands, in order.** `test:p02` must report at least 8 named +**Verification commands, in order.** `test:p02` must report at least 9 named tests passed, 0 failed, 0 skipped; every command exits 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p02 -- --reporter=verbose -npm run verify:test-manifest -npm run build +npm run verify:phase -- --phase P02 --artifacts .artifacts/verification/P02 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + **Regression suite.** P01 gates, capture lifecycle, screenshot queues, config -language/opacity behavior, fake provider process tests, and production build. +language/opacity behavior, fake provider process tests, conversation-ID +plaintext scans, and production build. Live Claude/Codex smoke tests are optional evidence and never replace fakes. **Docs.** Supported/minimum CLI versions, install/sign-in/reconnect, provider selection semantics, Fast/Reasoning availability, migration/rollback, process -sandbox/tool restrictions, and explicit no-fallback/no-API-key boundaries. +sandbox/tool restrictions, explicit no-fallback/no-API-key boundaries, and the +in-memory-only P02 ID boundary with encrypted app-restart ownership deferred to +P04/P03. **Completion evidence.** (1) SHAs/base; (2) clean gate report; (3) fake Claude two-turn/restart transcript; (4) fake Codex two-turn/restart transcript; (5) no-fallback process trace; (6) migration before/after with secrets redacted; (7) dependency and IPC removal scan; (8) UI keyboard/a11y test output; -(9) supported CLI protocol fixture versions. +(9) supported CLI protocol fixture versions; (10) test-filesystem/config/log +byte scan proving the opaque conversation-ID fixture was never persisted. **Risk/complexity.** Very high/high. CLI protocol/auth behavior is external and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained implementation prompt.** -> Implement P02 from P00-R1 after P01, on +> Implement P02 from P00-R2 after P01, on > `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime > for Claude Code and Codex only, using one resumable session/thread, normalized > streaming/usage/compaction/stop/error events, explicit provider/model/Fast- > Reasoning snapshots, and no fallback. Migrate legacy config through M-01, > remove every legacy answer API key/provider/credit/paywall surface, create the -> named fake-executable tests, run the exact P02 gates, and attach the evidence. -> Do not implement interview orchestration or reuse one-shot prototype code. +> named fake-executable tests, accept only caller-supplied opaque conversation +> IDs held in memory, and prove no ID/provider session persists to plaintext. +> Run the exact P02 reporter gate and attach the evidence. Do not implement app- +> restart recovery, interview orchestration, or reuse one-shot prototype code. **Self-contained review prompt.** -> Review P02 against P00-R1 from a clean checkout. Trace both fake providers -> through two turns, stop, compaction, restart, and resume; force every failure -> and prove the other provider never starts. Inspect spawn/env/tool restrictions, -> IPC exposure, migration idempotence/file mode, dependency removals, model/ -> effort locking, and provider-only onboarding. Run all P02 commands and reject -> any live-credential requirement, legacy path, secret leak, silent fallback, -> ephemeral conversation, skipped test, or gate failure. +> Review P02 against P00-R2 from a clean checkout. Trace both fake providers +> through two turns, stop, compaction, driver/child restart, and caller-ID +> resume; force every failure and prove the other provider never starts. Inspect +> spawn/env/tool restrictions, IPC exposure, migration idempotence/file mode, +> dependency removals, model/effort locking, provider-only onboarding, and a +> full filesystem scan for the opaque-ID fixture. Run the P02 reporter gate and +> reject any live-credential requirement, legacy path, plaintext provider ID, +> P02-owned app recovery, secret leak, silent fallback, ephemeral conversation, +> skipped test, or gate failure. **Remediation prompt template.** > Remediate P02 only for `{failed criterion/evidence}`. Reproduce with the fake > provider fixture, state the confirmed runtime or migration cause, change the > smallest provider/config/onboarding surface, add or strengthen `{P02 named -> test}`, prove no unselected process ran and no secret persisted, rerun all P02 -> commands from `npm ci`, and return raw exits/counts plus new SHAs. +> test}`, prove no unselected process ran and no secret or conversation ID +> persisted, rerun the complete P02 reporter plan (which begins with `npm ci`), +> and return every child raw exit/count plus the aggregate exit and new SHAs. ### P03 — Encrypted local persistence foundation @@ -554,17 +628,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p03 -- --reporter=verbose -npm run verify:test-manifest -npm run build +npm run verify:phase -- --phase P03 --artifacts .artifacts/verification/P03 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + **Regression suite.** P01 gates, capture behavior, screenshot creation/deletion, config persistence, path safety, and build. Run storage tests on a case- insensitive macOS filesystem in addition to temp-fixture unit tests. @@ -584,17 +652,17 @@ never custom cryptography. **Self-contained implementation prompt.** -> Implement P03 from P00-R1 after P01 on +> Implement P03 from P00-R2 after P01 on > `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key > service, versioned AES-256-GCM record/blob store, atomic writes, encrypted > in-memory-search source, typed recovery, raw-audio rejection, and journaled > M-02/M-03 migrations exactly as specified. Add all P03 named tests and threat- -> model docs, run the exact clean gates, and attach enumerated evidence. Do not +> model docs, run the complete P03 reporter plan, and attach enumerated evidence. Do not > implement session, History, provider, profile, or template behavior. **Self-contained review prompt.** -> Threat-model and review P03 independently. Run every clean gate, inspect key +> Threat-model and review P03 independently. Run the P03 reporter plan, inspect key > storage, nonce generation, AAD, atomicity, permissions, path canonicalization, > temp handling, raw-audio rejection, and both migrations under interruption. > Search fixture storage byte-for-byte for plaintext. Reject home-grown crypto, @@ -606,8 +674,9 @@ never custom cryptography. > Remediate P03 only for `{crypto/storage/migration finding}`. Preserve the > failing fixture and journal as evidence, identify the exact invariant breach, > make the smallest storage-owned change, add or strengthen `{P03 named test}`, -> prove no plaintext/key remains and interruption is recoverable, rerun all P03 -> gates from `npm ci`, and return raw exits/counts plus new SHAs. +> prove no plaintext/key remains and interruption is recoverable, rerun the +> complete P03 reporter plan (starting with `npm ci`), and return every child +> raw exit/count, aggregate exit, and new SHAs. ### P04 — Interview session domain and orchestrator @@ -623,8 +692,10 @@ progressive sections, cancel/continue, Reset, and crash snapshots. provider/model/response snapshot; persistent provider-conversation binding; input artifacts and pending-selection semantics; screenshot-over-transcript authority; context status/detail; typed response-section streaming; request IDs, -cancellation and Continue unfinished; Coding question-branch primitive; encrypted -active-session snapshots. **Out of scope:** final shell visuals, mode renderers, +cancellation and Continue unfinished; curated-response versus compact-chat +routing; best-effort/clarification/correction policy; Coding question-branch +primitive; encrypted active-session snapshots and encrypted provider +conversation-ID recovery. **Out of scope:** final shell visuals, mode renderers, capture implementations, transcript engine, History UI/export, and templates. **Implementation requirements.** Reducer is deterministic and exhaustively @@ -634,24 +705,36 @@ submitted artifacts cannot be duplicated; excluded artifacts remain local and pending until discard/submit; Reset cancels capture/provider work, discards the native conversation, seals an archive-ready snapshot, clears active state, and preserves preferences/reusable records; partial output remains after cancel; -Continue unfinished reuses request identity and only missing section IDs. +Continue unfinished reuses request identity and only missing section IDs; the +P02 runtime receives its opaque conversation ID from P04 and never persists it, +while P04 writes it only inside the P03 encrypted snapshot and restores it only +after explicit Resume. Structured mode-valid responses update curated sections; +ordinary clarification remains compact chat. Generation is never blocked by a +confidence threshold, and correction deltas revise only affected sections. **Expected files/systems.** `src/domain/interview/**`, `electron/orchestrator/**`, shared IPC/event schemas, reducer/selectors, provider driver integration, encrypted active-session repository adapter, fake clock/ID/ -provider fixtures, and replacement of global `view/problemInfo/hasDebugged`. +provider fixtures, response router/correction impact fixtures, and replacement +of global `view/problemInfo/hasDebugged`. **Compatibility, migration, rollback.** P04 exclusively owns `M-04`, encrypted InterviewSession schema v1. Existing plaintext queues are imported only through P03 M-02 as unattached artifacts; they are never silently treated as a live -session. Schema upgrades are forward-version rejected and rollback retains the -encrypted v1 record without lossy conversion. +session. M-04 includes the opaque provider conversation ID only inside the +authenticated encrypted envelope; no plaintext config, index, log, or provider +session file may contain it. Schema upgrades are forward-version rejected and +rollback retains the encrypted v1 record without lossy conversion. **Security/failure modes.** Duplicate evidence on retry, stale/out-of-order stream events, cross-session event bleed, Coding personal-context leak, provider compaction misreported as data loss, Reset racing with writes, cancellation destroying native session, partial response replacing complete content, and -malformed IPC. Reducer/property tests and fake provider traces cover them. +malformed IPC. Additional failures are a context popover overstating included +sources, chat opening a second conversation, ordinary clarification overwriting +curated state, confidence blocking an answer, correction rewriting unaffected +sections, and plaintext conversation-ID recovery. Reducer/property tests, +filesystem scans, and fake provider traces cover them. **Acceptance criteria and named new tests.** @@ -666,7 +749,12 @@ malformed IPC. Reducer/property tests and fake provider traces cover them. | P04-AC7: stable typed sections publish progressively without reorder or completed-section replacement. | `electron/orchestrator/progressiveSections.test.ts — streams stable independently final sections` | | P04-AC8: Cancel preserves completed/partial output and native conversation; Continue unfinished requests only incomplete IDs with the same request identity. | `electron/orchestrator/cancelContinue.test.ts — resumes unfinished sections without duplicate evidence` | | P04-AC9: Reset cancels work, seals an encrypted archive-ready record, discards provider conversation, clears active artifacts, and preserves settings/reusable data. | `electron/orchestrator/resetSemantics.test.ts — performs the sole terminal lifecycle transition` | -| P04-AC10: restart offers Resume or Reset from the last valid encrypted snapshot and never auto-resumes capture. | `electron/orchestrator/crashRecovery.test.ts — restores session state with capture off` | +| P04-AC10: app restart offers Resume or Reset from the last valid encrypted snapshot, passes the recovered opaque ID to P02 to resume the same provider conversation only after Resume, never auto-resumes capture, and leaves no ID fixture in plaintext config/index/log/provider files. | `electron/orchestrator/crashRecovery.test.ts — restores one encrypted provider conversation with capture off` | +| P04-AC11: the detail popover shows snapshotted provider/model/mode, last successful update, exact source-category counts, profile/opportunity included or Coding-excluded state, and only provider-reported usage/compaction; its main label follows AC6 and never claims original tokens remain verbatim. | `src/domain/interview/contextDetail.test.ts — renders exact honest source-level context detail` | +| P04-AC12: mode actions, typed chat, and compact clarification use the same opaque provider conversation ID and ordered context stream; no chat-only driver, process, session, or thread is created. | `electron/orchestrator/sharedConversation.test.ts — routes curated and chat turns through one conversation` | +| P04-AC13: a response satisfying the locked mode schema updates only its typed curated sections, while an ordinary non-schema clarification appears as a compact exchange and preserves the last curated answer byte-for-byte. | `electron/orchestrator/responseRouting.test.ts — separates structured updates from compact clarification` | +| P04-AC14: uncertain input still produces best-effort output with no numeric confidence field or blocking review state, states only consequential assumptions, and includes clarification suggestions exactly when a frozen impact fixture says the missing answer can materially change the result. | `electron/orchestrator/bestEffortClarification.test.ts — answers without confidence gates and suggests material clarifications` | +| P04-AC15: a correction submitted through chat is a context delta on the current branch, revises exactly the fixture-declared affected section IDs, preserves every unaffected section byte-for-byte, and returns the changed-section set. | `electron/orchestrator/correctionRevision.test.ts — applies correction-scoped revision without collateral changes` | **Clean-checkout setup.** Every command exits 0. @@ -680,64 +768,71 @@ test -z "$(git status --porcelain)" node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' ``` -**Verification commands, in order.** `test:p04` reports at least 10 named +**Verification commands, in order.** `test:p04` reports at least 15 named tests passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p04 -- --reporter=verbose -npm run verify:test-manifest -npm run build +npm run verify:phase -- --phase P04 --artifacts .artifacts/verification/P04 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + **Regression suite.** P01–P03 complete suites, provider fake contracts, encrypted storage migration/recovery, capture lifecycle, screenshot queue -compatibility, and production build. +compatibility, P02 conversation-ID plaintext boundary, and production build. **Docs.** State/event diagrams, schema/event catalog, context inclusion table, request idempotency, status semantics, Reset/cancel/recovery behavior, and M-04 -version/rollback. +version/rollback; document the context-detail fields, one-conversation +chat/curated routing table, best-effort/clarification policy, correction impact +contract, and encrypted ID ownership boundary. **Completion evidence.** (1) SHAs/base; (2) full gates/counts; (3) reducer property seed/corpus; (4) first-turn/delta traces for each mode; (5) explicit Coding exclusion byte scan; (6) cancel/continue trace; (7) Reset before/after -record; (8) crash/relaunch transcript; (9) schema fixture. +record; (8) crash/relaunch transcript plus plaintext ID scan; (9) schema +fixture; (10) context-popover snapshot; (11) shared conversation/process trace; +(12) structured-versus-compact routing trace; (13) best-effort/clarification +fixture report; (14) correction before/after section hashes. **Risk/complexity.** Very high/very high. This is the central consistency boundary; no renderer or provider may keep a second authoritative session. **Self-contained implementation prompt.** -> Implement P04 from P00-R1 after P02/P03 on +> Implement P04 from P00-R2 after P02/P03 on > `phase/P04-session-orchestrator`. Replace global transient state with the > deterministic InterviewSession reducer, typed event/IPC contract, one > persistent-conversation orchestrator, context/delta policy, pending artifacts, > screenshot authority, progressive sections, cancel/continue, Reset, encrypted -> snapshot/recovery, and M-04 exactly as specified. Add the ten named tests, run -> all P04 gates, attach evidence, and do not build final shell/mode/audio/History -> UI or import prototype orchestration. +> snapshot/recovery (including the opaque provider ID), exact context detail, +> one-conversation curated/chat routing, structured-versus-compact response +> routing, best-effort clarification, correction-scoped revision, and M-04 +> exactly as specified. Add the fifteen named tests, run the complete P04 +> reporter plan, attach all evidence, and do not build final shell/mode/audio/ +> History UI or import prototype orchestration. **Self-contained review prompt.** > Review P04 as the sole session authority. Run all gates and property tests; > trace every event, first-turn seed, delta, pending-artifact transition, -> compaction signal, cancel/continue, Reset race, and crash restart. Search a -> Coding trace for dossier/opportunity bytes. Reject duplicate state stores, -> Markdown-as-domain-state, artifact resends, section reorder, silent invalid -> transitions, capture auto-resume, skipped tests, or nonzero gates. +> compaction signal/detail field, curated/chat turn, response-routing branch, +> best-effort/clarification fixture, correction impact, cancel/continue, Reset +> race, and encrypted crash restart. Search a Coding trace for dossier/ +> opportunity bytes and all plaintext files/logs for the opaque ID fixture. +> Reject duplicate conversations/state stores, Markdown-as-domain-state, +> artifact resends, section reorder, confidence gates, collateral correction, +> silent invalid transitions, capture auto-resume, skipped tests, or nonzero +> gates. **Remediation prompt template.** > Remediate P04 only for `{state/orchestration criterion}` using the smallest > reducer/orchestrator/schema change. Add the exact failing event sequence to > `{P04 named test}`, prove idempotency and no cross-session/personal-context -> leak, rerun every P04 command from `npm ci`, and return raw counts, traces, -> migration compatibility, and new SHAs. +> or plaintext-ID leak, rerun the complete P04 reporter plan (starting with +> `npm ci`), and return every raw exit/count, aggregate exit, routing/section +> traces, migration compatibility, and new SHAs. ### P05 — Quiet Signal live shell, window, and capture controls @@ -816,21 +911,13 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) tests passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p05 -- --reporter=verbose -npm run verify:test-manifest -npm run build -npm run test:electron-shell +npm run verify:phase -- --phase P05 --artifacts .artifacts/verification/P05 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + `test:electron-shell` exits 0 on macOS and records window bounds, protection -application, screenshot-display ID, and pointer-region results. **Regression -suite:** all P01–P04 tests, provider/storage/session contracts, capture queues, +application, screenshot-display ID, and pointer-region results. **Regression suite.** all P01–P04 tests, provider/storage/session contracts, capture queues, preload IPC allowlist, accessibility, and production build. **Docs.** Window-state and focus diagrams, shortcut reference, display recovery, @@ -848,14 +935,15 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained implementation prompt.** -> Implement P05 from P00-R1 after P04 on `phase/P05-live-shell`. Build the +> Implement P05 from P00-R2 after P04 on `phase/P05-live-shell`. Build the > exact Quiet Signal hidden/compact/answer/expanded shell, command rail, > composer, input tray, explicit click-through/drag regions, final remappable > shortcuts, display-aware geometry, primary-display screenshot behavior, > tokens and accessibility presets. Preserve protection before every show and > prior visibility across capture. Add the ten named tests, run all P05 gates -> including macOS Electron shell, and attach evidence. Do not add mode answers, -> audio, History, Prompt Studio, or unqualified capture claims. +> through the P05 reporter including macOS Electron shell, and attach evidence. +> Do not add mode answers, audio, History, Prompt Studio, or unqualified capture +> claims. **Self-contained review prompt.** @@ -872,8 +960,9 @@ display behavior is platform-sensitive and directly touches privacy regression. > Remediate P05 only for `{shell/window/capture criterion}`. Attach the exact > display/window/input reproduction, fix the smallest P05-owned service or > primitive, add/strengthen `{P05 named test}`, recheck protection and prior -> visibility, rerun every P05 command including `test:electron-shell`, and -> return raw counts, artifact paths, and new SHAs. +> visibility, rerun the complete P05 reporter plan including +> `test:electron-shell`, and return every raw exit/count, aggregate exit, +> artifact paths, and new SHAs. ### P06 — Coding mode and primary-display debugging @@ -944,20 +1033,13 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p06 -- --reporter=verbose -npm run verify:test-manifest -npm run test:coding-fixtures -npm run build +npm run verify:phase -- --phase P06 --artifacts .artifacts/verification/P06 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + `test:coding-fixtures` exits 0 and reports all six first-class families passed, -0 failed, 0 skipped. **Regression suite:** P01–P05, provider/session no-fallback, +0 failed, 0 skipped. **Regression suite.** P01–P05, provider/session no-fallback, Coding personal-context exclusion, shell shortcuts/capture/protection, storage, and production build. @@ -975,12 +1057,12 @@ regress silently; fixture contracts are merge-blocking. **Self-contained implementation prompt.** -> Implement P06 from P00-R1 after P05 on `phase/P06-coding`. Add the exact +> Implement P06 from P00-R2 after P05 on `phase/P06-coding`. Add the exact > typed Coding intents/schema/renderer, concise-first progressive answer, > language snapshot and six-family fixtures, read-only actions, New Question, > and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, > tools, execution, fallback, or staged-artifact consumption. Own M-05b, add all -> nine named tests, run the exact gates/fixture matrix, and attach evidence. +> nine named tests, run the P06 reporter plan/fixture matrix, and attach evidence. **Self-contained review prompt.** @@ -996,8 +1078,8 @@ regress silently; fixture contracts are merge-blocking. > Remediate P06 only for `{intent/language/branch/debug criterion}`. Add the > failing problem/language/event trace to `{P06 named test or first-class > fixture}`, make the smallest Coding-owned change, prove isolation/no fallback, -> rerun all P06 commands and the six-family matrix, and return raw counts, -> request/response traces, and new SHAs. +> rerun the complete P06 reporter plan and six-family matrix, and return every +> raw exit/count, aggregate exit, request/response traces, and new SHAs. ### P07 — System Design mode and structured architecture @@ -1067,20 +1149,13 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p07 -- --reporter=verbose -npm run verify:test-manifest -npm run test:system-design-fixtures -npm run build +npm run verify:phase -- --phase P07 --artifacts .artifacts/verification/P07 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + Fixture command exits 0 with all design/vendor/follow-up cases passed, failed 0, -skipped 0. **Regression suite:** P01–P05, provider/session/storage, shell section +skipped 0. **Regression suite.** P01–P05, provider/session/storage, shell section navigation, accessibility, capture protection, and build. **Docs.** Response/graph schemas, allowed node types, estimate policy, @@ -1097,11 +1172,11 @@ must not become a second untyped document model. **Self-contained implementation prompt.** -> Implement P07 from P00-R1 after P05 on `phase/P07-system-design`. Add the +> Implement P07 from P00-R2 after P05 on `phase/P07-system-design`. Add the > fixed typed five-section progressive workflow, bounded material estimates, > safe vendor-neutral structured diagram, read-only accessible interactions, > assumption handling, dependency-scoped follow-up and What changed summary. -> Add all eight named tests/fixtures, run exact gates, attach evidence, and do +> Add all eight named tests/fixtures, run the P07 reporter plan, attach evidence, and do > not add diagram editing/export, vendor node types, Prompt Studio, or profile UI. **Self-contained review prompt.** @@ -1118,7 +1193,8 @@ must not become a second untyped document model. > Remediate P07 only for `{schema/estimate/diagram/follow-up criterion}`. Add the > failing graph or event to `{P07 named fixture}`, change the smallest System > Design-owned validator/renderer/policy, prove unaffected hashes and no export, -> rerun all P07 gates/fixtures, and return raw counts, diffs, and new SHAs. +> rerun the complete P07 reporter plan/fixtures, and return every raw exit/count, +> aggregate exit, diffs, and new SHAs. ### P08 — Candidate profile, opportunity context, and Behavioral mode @@ -1193,20 +1269,13 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) tests passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p08 -- --reporter=verbose -npm run verify:test-manifest -npm run test:behavioral-fixtures -npm run build +npm run verify:phase -- --phase P08 --artifacts .artifacts/verification/P08 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + Fixture command exits 0 with verified/synthetic/import cases passed, 0 failed, -0 skipped. **Regression suite:** P01–P06 plus P07 if already merged, storage +0 skipped. **Regression suite.** P01–P06 plus P07 if already merged, storage plaintext scans, session context policy, Coding isolation, shell/accessibility, provider no-fallback, and build. @@ -1224,13 +1293,14 @@ integrity are product trust boundaries. **Self-contained implementation prompt.** -> Implement P08 from P00-R1 after P05 on `phase/P08-behavioral`. Build the +> Implement P08 from P00-R2 after P05 on `phase/P08-behavioral`. Build the > encrypted canonical candidate dossier, guided/manual reviewed editing, > sanitized Markdown import/export, multiple snapshotted opportunities, > provenance, opt-in labeled persistent synthetic stories, and typed Behavioral > views with same-facts Full Answer. Route context only to Behavioral/System -> Design, never Coding. Own M-06, add ten named tests/fixtures, run exact gates, -> attach evidence, and add no Practice or plaintext personal index. +> Design, never Coding. Own M-06, add ten named tests/fixtures, run the complete +> P08 reporter plan, attach evidence, and add no Practice or plaintext personal +> index. **Self-contained review prompt.** @@ -1247,8 +1317,8 @@ integrity are product trust boundaries. > Remediate P08 only for `{privacy/provenance/factuality/context criterion}`. > Preserve the failing dossier/import/trace fixture, make the smallest profile > or Behavioral-owned fix, strengthen `{P08 named test}`, repeat plaintext and -> three-mode scans, rerun every P08 command/fixture, and return raw counts, -> fact/context diffs, and new SHAs. +> three-mode scans, rerun the complete P08 reporter plan/fixtures, and return +> every raw exit/count, aggregate exit, fact/context diffs, and new SHAs. ### P09 — macOS audio capture, transcription, and question detection @@ -1331,21 +1401,13 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) tests passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p09 -- --reporter=verbose -npm run verify:test-manifest -npm run test:audio-native -npm run test:audio-retention -npm run build +npm run verify:phase -- --phase P09 --artifacts .artifacts/verification/P09 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + Native/retention commands exit 0 and print passed/failed/skipped counts; fixture -audio contains no interview/user content. **Regression suite:** P01–P05, +audio contains no interview/user content. **Regression suite.** P01–P05, provider no-fallback, session pending artifacts/Reset/recovery, encrypted storage raw-audio rejection, shell visibility/shortcuts/accessibility, and build. @@ -1364,7 +1426,7 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained implementation prompt.** -> Implement P09 from P00-R1 after P05 on `phase/P09-audio`, macOS only. Build +> Implement P09 from P00-R2 after P05 on `phase/P09-audio`, macOS only. Build > explicit two-source native capture, deterministic master/per-source controls, > contextual permission recovery, pinned offline whisper.cpp transcription, > explicit Apple Speech remote fallback, typed segments/attribution/correction, @@ -1387,8 +1449,9 @@ packaging, privacy, and transcription latency are launch-critical. > Remediate P09 only for `{capture/transcription/privacy criterion}`. Preserve > the exact macOS/version/permission/audio fixture trace, fix the smallest > audio-owned native/adapter/state path, strengthen `{P09 named test}`, repeat -> offline/remote-consent and byte-retention scans, rerun all P09 commands, and -> return raw counts, artifacts, and new SHAs. +> offline/remote-consent and byte-retention scans, rerun the complete P09 +> reporter plan, and return every raw exit/count, aggregate exit, artifacts, +> and new SHAs. ### P10 — Prompt Studio and protected template variants @@ -1458,20 +1521,13 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p10 -- --reporter=verbose -npm run verify:test-manifest -npm run test:prompt-adversarial -npm run build +npm run verify:phase -- --phase P10 --artifacts .artifacts/verification/P10 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + Adversarial command exits 0 with every escalation fixture passed, 0 failed, 0 -skipped. **Regression suite:** P01–P08 (and P09 when merged), all mode schemas, +skipped. **Regression suite.** P01–P08 (and P09 when merged), all mode schemas, provider/session no-fallback and context isolation, encrypted storage, shell, accessibility, and build. @@ -1489,12 +1545,12 @@ must never become a capability or schema escape hatch. **Self-contained implementation prompt.** -> Implement P10 from P00-R1 after P06/P07/P08 on +> Implement P10 from P00-R2 after P06/P07/P08 on > `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, > immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, > deterministic recorded instruction resolution, Start snapshotting, protected > invariant/capability enforcement, and M-08. Add eight named tests and the -> adversarial suite, run all exact gates, attach evidence, and add no arbitrary +> adversarial suite, run the complete P10 reporter plan, attach evidence, and add no arbitrary > schema/custom mode/sharing/plugin capability. **Self-contained review prompt.** @@ -1511,8 +1567,8 @@ must never become a capability or schema escape hatch. > Remediate P10 only for `{CRUD/schema/conflict/security criterion}`. Add the > exact malicious or state-transition input to `{P10 named/adversarial test}`, > make the smallest Prompt Studio/composition fix, prove protected invariants -> and encrypted storage, rerun all P10 commands, and return raw counts, -> effective-instruction diff, and new SHAs. +> and encrypted storage, rerun the complete P10 reporter plan, and return every +> raw exit/count, aggregate exit, effective-instruction diff, and new SHAs. ### P11 — Crash recovery, searchable History, export, and deletion @@ -1582,21 +1638,13 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p11 -- --reporter=verbose -npm run verify:test-manifest -npm run test:history-roundtrip -npm run test:plaintext-scan -npm run build +npm run verify:phase -- --phase P11 --artifacts .artifacts/verification/P11 ``` +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + Round-trip/plaintext commands exit 0 with all fixtures passed, failed 0, -skipped 0. **Regression suite:** every P01–P10 test, all three modes, audio raw- +skipped 0. **Regression suite.** every P01–P10 test, all three modes, audio raw- retention, provider/session recovery, storage migrations, prompt/profile data isolation, shell/accessibility, and build. @@ -1614,12 +1662,12 @@ content and destructive user controls. **Self-contained implementation prompt.** -> Implement P11 from P00-R1 after P06–P10 on +> Implement P11 from P00-R2 after P06–P10 on > `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete > encrypted archive projection, Settings-only in-memory search/open/delete one/ > all, safe consented individual Markdown/JSON export, read-only archive open, > indefinite retention, M-09, and strict no-audio/secret/plaintext-index rules. -> Add eight named tests/round-trip/scans, run every exact gate, and attach all +> Add eight named tests/round-trip/scans, run the complete P11 reporter plan, and attach all > evidence. Add no tags/favorites/bulk/cloud/pruning/live History surface. **Self-contained review prompt.** @@ -1636,8 +1684,8 @@ content and destructive user controls. > Remediate P11 only for `{recovery/archive/search/export/delete criterion}`. > Preserve the failing encrypted fixture/journal, make the smallest History- > owned change, strengthen `{P11 named test}`, repeat round-trip/plaintext/data- -> isolation checks, rerun all P11 commands, and return raw counts, hashes, -> journals, and new SHAs. +> isolation checks, rerun the complete P11 reporter plan, and return every raw +> exit/count, aggregate exit, hashes, journals, and new SHAs. ### P12 — macOS release hardening and Google Meet qualification @@ -1666,8 +1714,16 @@ local preview. **Implementation requirements.** At RC cut, freeze exact InterviewCopilot commit/version, the latest Apple-supported stable macOS patch available on each claimed arm64/x64 test machine, current stable Chrome, Meet version, display -mode, and architecture; qualify each supported tuple separately; -entire-display and specific-window require confirmation from remote Meet view or +mode, and architecture. The shipped matrix contains full concrete values +(`ProductVersion` plus `BuildVersion`, Chrome four-part version, visible Meet +client/build identifier, app semver plus full commit SHA, architecture, display +pixel dimensions/scaling, and internal/external display type), never `latest`, +a range, or a wildcard. Those exact passing tuples—and no neighboring patch, +major version, browser, app build, architecture, or display mode—are the +supported macOS/browser/app versions until separately qualified. Qualify each +supported tuple separately. P00-R2 represents no version as supported before +that committed matrix and its evidence pass. Entire-display and specific-window +require confirmation from remote Meet view or second device and retained high-contrast moving-marker artifacts; one fail makes the tuple unsupported; browser-tab remains unverified; verification state is Not verified/Verified/Failed/Retest required and invalidates after capture- @@ -1693,11 +1749,77 @@ unsafe updater/publish target; diagnostics contain user content/credentials; generic test implies certification; signing/notarization mismatch; ordinary qualification language drifts into evasion advice. +#### P12 final macOS entitlement allowlists + +P12 replaces the planning-base configuration, which incorrectly points parent +and inherited signing at one absent file, with two committed plists. The only +allowed keys and values in `build/entitlements.mac.plist` (the parent app) are: + +| Parent entitlement | Required value | +|---|---| +| `com.apple.security.cs.allow-jit` | boolean `true` | +| `com.apple.security.cs.allow-unsigned-executable-memory` | boolean `true` | +| `com.apple.security.cs.disable-library-validation` | boolean `true` | +| `com.apple.security.device.audio-input` | boolean `true` | +| `com.apple.security.personal-information.speech-recognition` | boolean `true` | + +The only allowed keys and values in +`build/entitlements.mac.inherit.plist` (Electron helpers and other nested +executables) are the first three code-signing keys above, each boolean `true`. +Audio-input and speech-recognition entitlements are absent from the inherited +file. Both files omit App Sandbox, `get-task-allow`, camera, location, contacts, +calendar, automation, network server/client, USB, Bluetooth, iCloud, application +groups, keychain access groups, and every other entitlement. ScreenCaptureKit +and screen-recording permission are expressed through macOS usage descriptions +and TCC, not an invented signing entitlement. + +`package.json` must map `mac.entitlements` to the parent file and +`mac.entitlementsInherit` to the inherited file. The package-policy validator +parses the source plists and `codesign -d --entitlements :-` output from the +signed main executable and every signed nested executable, normalizes plist +ordering only, and rejects a missing key, extra key, wrong role, non-boolean or +false value, signing omission, or entitlement mismatch. There is no +“minimum-looking” reviewer judgment or allow-extra mode. + +#### Frozen Live-first/Staff+ corpus and assertions + +P12 commits `tests/fixtures/release/staff-live-corpus.v1.json` and its canonical +SHA-256 in the test manifest. It contains exactly these immutable cases: + +1. `SL-CODING-01`: an ambiguous multi-tenant rate-limiter change with a fixed + screenshot/transcript conflict and production-failure follow-up. +2. `SL-SYSTEM-01`: a global job scheduler with fixed scale, regional-failure, + migration, ownership, and cost constraints. +3. `SL-BEHAVIORAL-01`: influence-without-authority using a fixed verified + dossier and Staff Engineer opportunity, including a correction that changes + one claim but not the other evidence. + +Each case freezes input artifacts, provider-event fixture, expected mode, +expected affected-section IDs, forbidden Practice fields/copy, and exact +structural assertions. `SL-CODING-01` must expose ambiguity/assumptions, a key +trade-off, time and space complexity, production failure handling, and testing/ +maintainability. `SL-SYSTEM-01` must expose the five fixed sections, 2–4 +unit-bearing estimates, explicit assumptions, a vendor-neutral architecture, +regional failure, migration, operational ownership, cost, and scoped follow-up +hash preservation. `SL-BEHAVIORAL-01` must use dossier-backed claims only and +expose leadership, influence, organizational impact, qualitative handling of +unknown metrics, same-fact concise/full output, and correction-scoped hash +preservation. All three must start in the Live shell, require no Practice or +post-answer score, and include the frozen Senior/Staff+ prompt-policy snapshot. + +`npm run test:staff-live-corpus` validates the corpus hash and every assertion +deterministically against the typed fake-provider trace; any missing field, +wrong count/order, forbidden field/copy, unexpected changed-section ID, hash +drift, corpus mutation without a packet revision, failed assertion, or skipped +case exits nonzero. It prints case/assertion passed, failed, and skipped totals. +No subjective “representative fixture” or reviewer prioritization substitutes +for this gate. + **Acceptance criteria and named new tests/procedures.** | Criterion | Named test/procedure | |---|---| -| P12-AC1: package config emits only macOS arm64/x64 launch artifacts with canonical identity, minimum entitlements, valid signing/notarization, AGPL metadata, and no Windows/Linux support claim. | `tests/release/macosPackagePolicy.test.ts — validates macOS-only signed package metadata` | +| P12-AC1: package config emits only macOS arm64/x64 launch artifacts with canonical identity; the signed parent and every nested executable match their exact allowlists above with a mechanical reject-on-extra/missing/wrong-role assertion; signing/notarization and AGPL metadata are valid; no Windows/Linux support claim exists. | `tests/release/macosPackagePolicy.test.ts — rejects any macOS entitlement allowlist mismatch` | | P12-AC2: every BrowserWindow in the packaged app enables content protection before first visible frame and after lifecycle reconfiguration. | `tests/release/packagedCaptureProtection.test.ts — traces protection in the packaged app` | | P12-AC3: guided Meet flow tests entire-display and specific-window separately with moving marker and requires remote/second-device confirmation; it never offers generic/browser-tab certification. | `src/features/privacy/MeetVerification.test.tsx — guides only qualified scopes with remote confirmation` | | P12-AC4: verification record contains exact app/commit/macOS/arch/Chrome/Meet/display/scopes/date/result/artifact hashes and state invalidates by specified changes. | `electron/privacy/verificationRecord.test.ts — versions verifies fails and stales exact tuples` | @@ -1709,9 +1831,212 @@ qualification language drifts into evasion advice. | P12-AC10: shipped copy/docs contain only qualified D-005g language and no 99%, undetectable, bypass, anti-cheat, process-hiding, monitoring-evasion, or unsupported-app/platform claim. | `tests/release/claimPolicy.test.ts — rejects unqualified privacy and platform language` | | P12-AC11: no product plan/credit/quota/entitlement, analytics/device fingerprint, or automatic crash upload exists in package/source/network trace. | `tests/release/openSourcePrivacyPolicy.test.ts — enforces free local-only product policy` | | P12-AC12: Practice, custom named modes, browser-tab certification, generic Test My Setup, Zoom/Teams, Windows, and Linux remain absent/deferred. | `tests/release/deferredScope.test.ts — keeps deferred surfaces out of launch` | -| P12-AC13: representative Coding/System Design/Behavioral fixtures and surfaced copy prioritize Senior/Staff+ ambiguity reduction, trade-offs, production/operational judgment, leadership, and organizational impact in a Live-first flow. | `tests/release/staffLivePositioning.contract.test.ts — validates Staff plus judgment across the live loop` | +| P12-AC13: the SHA-pinned `staff-live-corpus.v1.json` executes all three exact cases and passes every deterministic structural/hash/forbidden-surface assertion above with failed=0 and skipped=0. | `tests/release/staffLivePositioning.contract.test.ts — enforces the frozen Live-first Staff-plus corpus` | | P12-AC14: onboarding and Start contain no responsibility notice, usage-boundary acknowledgement, consent gate, or recurring confirmation. | `tests/release/noUsageGate.test.ts — preserves the neutral frictionless tool boundary` | +#### P12-M01/M02 executable Google Meet qualification + +M01 and M02 are interactive procedures executed by `qualify:meet`; they are not +names for manually supplied files. From the clean checkout prepared below, the +P12 reporter's exact invocation launches the procedure for every incomplete +matrix tuple and scope, blocks until collection and validation finish, and +returns nonzero if a prerequisite, human step, raw artifact, count, or assertion +is absent. A pre-existing artifact directory is accepted only after complete +schema/hash validation; an empty or partial directory triggers collection or a +nonzero failure, never a presumed pass. + +**Supported version rule and release prerequisite.** Before the first run, +`docs/qualification/macos-google-meet.json` must be committed at the RC SHA with +`schemaVersion: 1`, a matrix revision, and one entry per claimed tuple. Every +entry contains concrete app semver/full SHA, signed package SHA-256, macOS +`ProductVersion`/`BuildVersion`, `arm64` or `x64`, Chrome four-part version, +visible Meet build identifier, display ID/type/pixel dimensions/scale factor, +and both scopes. Wildcards, ranges, `latest`, missing architectures, or an +uncommitted matrix make preflight exit nonzero. Only exact passing entries are +supported. The installed app must be the matrix package built from the clean RC +SHA, Developer-ID signed, hardened-runtime enabled, notarized, stapled, accepted +by `spctl`, and passing `verify:mac-package`; a development/Electron launch or +ad-hoc signature aborts collection. + +**People, accounts, devices, and network.** Each run requires: + +- a local operator on the matrix Mac and display, using the matrix Chrome and a + dedicated Google account named `IC Local Operator`; +- an independent remote observer on a second physical device and display (not + Sidecar, mirroring, remote desktop, or the local Meet preview), using a second + dedicated account named `IC Remote Observer` and the observer helper from the + same clean RC SHA; +- a new two-participant Meet with camera, microphone, captions, chat, extensions, + and background effects off, and no other participant; +- stable wired/Wi-Fi connectivity measured by preflight at at least 10 Mbit/s + up/down per endpoint, round-trip latency at most 100 ms, packet loss below 1%, + and clocks synchronized within two seconds; and +- macOS Screen Recording permission for Chrome/InterviewCopilot as required, + Accessibility permission only if the shipped app requires it, recording + permission for the observer helper, all notifications/Focus distractions + disabled, and at least 5 GiB free on both devices. + +The local operator performs share controls and may not attest the remote result. +The remote observer watches the received presentation, runs the remote recorder, +and records pass/fail notes. A single person looking at the local preview is not +an observer and cannot produce a passing record. + +**Deterministic evidence surfaces.** The collector launches the signed app's +guided Meet verification plus a packaged `Qualification Control` Chrome window. +The control window contains ordinary underlying content (fixed prose, code, +table, and image blocks), a 2 Hz UTC/frame counter, and an 8 × 8 color/checker +sequence seeded by `SHA256(matrixRevision + tupleId + scope)`. InterviewCopilot +shows a 256 × 256 marker above that ordinary content. The marker cycles exact +`#FF00FF`, `#00FFFF`, `#A6FF00`, and `#000000` quadrants at 4 Hz, embeds the +seed/frame number, moves clockwise to a new display quadrant every 15 seconds, +and records monotonic render events. Reduced motion is overridden only in this +explicit test surface. The collector fails if the control or marker seed, +cadence, size, contrast, frame sequence, position sequence, or render-event +continuity differs from the fixture. + +**Exact launch.** On the local matrix Mac, the operator runs the P12 reporter +release gate: + +```text +npm run verify:phase -- --phase P12 --artifacts .artifacts/verification/P12 +``` + +Its immutable P12 plan executes the exact `qualify:meet --collect-missing` argv +listed in section 6. That child performs package/version/network/account/ +display/permission/disk preflight, +opens the control and guided-verification surfaces, prints a one-time pairing +URL, and waits. On the remote device, from a clean checkout of the same SHA, the +observer runs the exact reporter command printed with the URL substituted: + +```text +npm run verify:phase -- --phase P12 --role meet-observer --pair --artifacts .artifacts/qualification-observer +``` + +The reporter installs/verifies the clean observer checkout and then launches the +observer helper as the exact argv child defined in `P12-observer.json`. It logs +that child raw exit and returns aggregate 0 only after the helper verifies the +SHA embedded in the pairing challenge, records only the Chrome Meet +presentation region plus recorder telemetry, and streams the original recording +and signed observer events directly into the collector's new run directory. +Pairing expires after one use. Closing either reporter, supplying a file path in +place of live pairing, or failing to upload the final record makes both +collector and observer aggregates nonzero. Thus neither command assumes a pre- +existing `.artifacts/qualification` record. + +**Shared timing and start/stop sequence.** The collector leads the following +steps and records UTC plus monotonic timestamps for each acknowledgement: + +1. Join the new Meet with the two dedicated accounts; confirm exactly two + participants, observer recording armed, presentation tile pinned remotely, + no personal content visible, and marker/control animation visibly running + locally. Record 15 seconds before sharing. +2. For M01 choose Meet **Present now → Your entire screen**, select the exact + matrix display by its recorded ID/dimensions, and choose **Share**. For M02 + choose **Present now → A window**, select only the collector-created + `Qualification Control — ` Chrome window, and choose **Share**. + Never choose **A tab** or the InterviewCopilot window. +3. Wait for the remote observer to acknowledge that the received presentation, + rather than a local preview, is pinned and the control seed/frame is readable. + That acknowledgement starts the observation interval. +4. Leave InterviewCopilot visible above the shared control content while its + marker visits all four quadrants. Do not move/cover either window, change the + display, resize, switch tabs/windows, or interact with Meet for at least 120 + continuous seconds. The remote observer records the whole interval. +5. After the collector announces 120 valid seconds, choose Meet **Stop + presenting**. The observer acknowledges presentation stopped and records 15 + more seconds. The collector then closes the test surfaces, finalizes the raw + streams, and immediately validates both scope evidence and attestations. + +M01 and M02 run separately for every tuple, in that order, with a fresh Meet +presentation and run ID. A pass in one scope never fills or waives the other. + +**Abort and fail rules.** Abort without a qualification result and rerun in a +new run directory on any version/package/display mismatch, extra participant, +account/notification/personal content, permission or update prompt, pairing or +recorder failure, app/control/marker restart, share-scope mistake, display or +window geometry change, observer disconnect, clock skew above two seconds, +network threshold breach, decoded-frame gap above 500 ms, or less than 120 +continuous observed seconds. A completed run fails (and the tuple is +unsupported) for a missing/invalid artifact or attestation; marker detected in +one or more remote shared-interval frames; marker render continuity below +99.5%; control sequence recognized in less than 99.5% of remote shared-interval +frames; any one-second interval without a valid control frame; wrong seed/scope; +local-only evidence; or hash/schema/timestamp/version inconsistency. Compression +noise is not counted as a marker: the frozen validator detects the exact +seeded color/geometry/temporal signature and reports +`marker_detected_frames=0`; its detection corpus includes positive transcodes +and must pass before real evidence is evaluated. + +**Raw and derived artifact schema.** The collector creates, never imports into, +this exact root for each run: + +```text +.artifacts/qualification///// + collection.json + raw/local-preflight.json + raw/local-marker-events.ndjson + raw/local-control-events.ndjson + raw/remote-observer.mov + raw/remote-observer-events.ndjson + attestations/local-operator.json + attestations/remote-observer.json + derived/frame-analysis.ndjson + derived/control-coverage.json + validation/report.json + hashes.sha256 +``` + +`collection.json` contains `schemaVersion`, `procedureId`, matrix revision, +tuple ID, scope, run ID, app semver/SHA/package hash, signing team/certificate/ +notarization ticket, exact OS build/arch/Chrome/Meet/display values, dedicated +pseudonymous role IDs, UTC start/share-start/share-stop/end, monotonic offsets, +duration, marker/control algorithms and seed, observer pairing challenge hash, +relative artifact paths, byte sizes, SHA-256 hashes, validator version/SHA, and +result. NDJSON records carry schema version, sequence, RFC3339 UTC, monotonic +nanoseconds, frame ID, and event payload. Attestations carry exact tuple/scope, +role, steps acknowledged, observed result, aborts/deviations, timestamps, and a +signature over `collection.json` plus `hashes.sha256`. `hashes.sha256` covers +every raw, attestation, derived, and validation file except itself. Paths must +be canonical, relative, inside the run root, non-symlinked, and mode 0600 (dirs +0700). Source video is at least 1080p, 24 fps, includes 15/120/15-second +segments, and retains original timestamps; derived frames never replace it. + +**Privacy and redaction.** Use only the dedicated names, synthetic control +content, and a disposable meeting. Do not enable audio/video/chat/captions or +show email addresses, calendars, notifications, browser profiles, interview +content, or unrelated screens. If personal data appears, abort, securely delete +the unaccepted run directory, record only the abort reason without the data, and +rerun. Accepted raw evidence is immutable and validated before any redaction; +it is never committed or publicly uploaded. A separately hashed review copy may +redact only meeting code/account chrome outside the presentation and marker/ +control analysis regions. Validation always uses raw evidence. Release storage +documents encrypted access, named independent reviewers, and retention/deletion +date; public evidence contains only hashes, tuple metadata, counts, and the +redacted copy. + +**Validation, exits, and independent reproduction.** Within `qualify:meet`, the +validator verifies schemas, canonical paths/modes, hashes, versions/signing, +two distinct signed roles, timing, frame decode/continuity, positive detector +corpus, marker absence, control visibility, and M01/M02 completeness. It prints +one line per tuple/scope plus `passed= failed= skipped=` and exits 0 +only when every matrix tuple has exactly one accepted M01 and M02 run, all +assertions pass, failed=0, and skipped=0. The P12 reporter preserves that raw +exit and makes its aggregate nonzero otherwise. + +An independent reviewer starts from a fresh clone at the exact RC SHA, obtains +the signed package and immutable raw evidence through the documented encrypted +release channel, verifies their published SHA-256 values, and runs the complete +P12 reporter command below. To reproduce collection rather than only validate, +the reviewer uses a fresh checkout with no `.artifacts/qualification`, the same +exact matrix hardware/software/display tuple, new dedicated accounts/meeting, +and the two launch commands above; absent evidence automatically launches M01 +then M02. The reviewer watches the full remote shared intervals plus pre/post +boundaries, checks at least the first/last and one frame from every 15-second +marker-position epoch against `frame-analysis.ndjson`, verifies ordinary +underlying content remains readable, and signs a separate review attestation. +Any disagreement, non-reproducible tuple, or changed version creates a new +failed/retest-required record and blocks the claim. + **Clean-checkout setup.** Requires supported macOS, Chrome, Meet test account, remote observer/second device, signing/notarization credentials, and both architecture runners. Every command exits 0. @@ -1731,26 +2056,16 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) automated/manual manifest entries passed, 0 failed, 0 skipped; all raw exits 0. ```bash -npm ci -npm run verify:policy -npm run lint -npm run typecheck -npm run test:legacy -- --reporter=verbose -npm run test:unit -- --reporter=verbose -npm run test:p12 -- --reporter=verbose -npm run verify:test-manifest -npm run test:e2e-macos -npm run build -npm run package:mac -npm run verify:mac-package -npm run verify:diagnostics -npm run qualify:meet -- --matrix docs/qualification/macos-google-meet.json --artifacts .artifacts/qualification -npm run verify:release +npm run verify:phase -- --phase P12 --artifacts .artifacts/verification/P12 ``` -`qualify:meet` exits 0 only after P12-M01 and P12-M02 records/artifacts exist for -every frozen tuple and validator finds marker pixels=0 with valid control frames. -All test scripts print passed/failed/skipped totals. **Regression suite:** the +Expected reporter aggregate exit is 0; every logged child raw exit is 0. + +`qualify:meet` launches P12-M01 and P12-M02 for absent evidence and exits 0 only +after every frozen tuple has a live-paired, complete, validated run with +`marker_detected_frames=0` and valid control coverage. `test:staff-live-corpus` +executes all three frozen cases. Every test-classified reporter entry prints +passed/failed/skipped totals. **Regression suite.** the entire P01–P11 suite, native audio, all mode fixtures, migrations, storage plaintext scans, shell/capture integration, package smoke tests, and release claim/deferred-scope scans. @@ -1759,42 +2074,52 @@ claim/deferred-scope scans. D-005g headline/qualifier, limitations/non-security-boundary, permissions, provider/audio/storage/privacy, diagnostics, AGPL/source offer, macOS install/ uninstall/update, release evidence, SBOM/vulnerability disposition, and explicit -Windows/Linux/app/scope deferrals. +Windows/Linux/app/scope deferrals. Release docs also publish the exact parent/ +inherit entitlement tables and frozen Staff-live corpus hash/assertion summary. **Completion evidence.** (1) SHAs/base/version; (2) every raw gate/count report; -(3) signed/notarized arm64/x64 hashes and package-policy report; (4) entitlements/ -SBOM/vulnerability disposition; (5) protection trace; (6) exact matrix; (7) -P12-M01/M02 remote recordings, control frames, marker analysis and hashes per -tuple; (8) verification-state/stale trace; (9) diagnostic preview/network-zero -trace; (10) scoped recovery E2E; (11) claim/deferred scan; (12) reviewer sign- -off that evidence supports every public claim. +(3) signed/notarized arm64/x64 hashes and package-policy report; (4) role-by- +role extracted entitlement plist diff, SBOM, and vulnerability disposition; +(5) protection trace; (6) exact no-wildcard matrix; (7) P12-M01/M02 raw remote +recordings, paired role attestations, control coverage, marker analysis, schema, +and hashes per tuple; (8) verification-state/stale trace; (9) diagnostic +preview/network-zero trace; (10) scoped recovery E2E; (11) claim/deferred scan; +(12) frozen Staff-live corpus hash plus all case/assertion counts; (13) +independent reviewer sign-off that evidence supports every public claim. **Risk/complexity.** Release-blocking/very high. External capture behavior and signing infrastructure cannot be inferred from unit tests. **Self-contained implementation prompt.** -> Implement P12 from P00-R1 after P01–P11 on +> Implement P12 from P00-R2 after P01–P11 on > `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ > architecture matrix, harden macOS-only package/entitlements/identity, add > local-only redacted diagnostic preview/export, scoped failure recovery, > guided remote-confirmed Meet verification and M-10, rewrite docs to qualified > D-005g claims, and remove/defer every unsupported platform/scope/evasion claim. -> Produce signed/notarized arm64/x64 artifacts, execute P12-M01/M02 on the -> release build, run every exact gate including artifact validation, and attach -> all evidence, including the Staff+/Live-first and no-usage-gate contracts. A -> failed or incomplete tuple blocks release; never infer pass. +> Enforce the exact separate parent/inherit entitlement allowlists, produce +> signed/notarized arm64/x64 artifacts, launch and execute the full live-paired +> P12-M01/M02 procedures on the release build, and run the complete P12 reporter +> plan including artifact validation and the SHA-pinned three-case Staff-live +> corpus. Attach every enumerated artifact. A failed/incomplete tuple, extra or +> missing entitlement, corpus assertion failure, or skipped case blocks release; +> never infer pass or accept pre-existing files without validation. **Self-contained review prompt.** > Independently review P12 on the exact frozen matrix. Rebuild/package from the > clean SHA, inspect signing/notarization/entitlements/SBOM, trace protection -> before first frame, rerun all automated gates, personally verify remote Meet -> artifacts/control frames/hashes for both scopes/architectures, force stale/ +> before first frame, mechanically compare every signed parent/nested executable +> with the exact role allowlist, rerun the complete reporter plan, personally +> verify remote Meet raw artifacts/control frames/hashes/role attestations for +> both scopes/architectures, and reproduce one clean live-paired tuple. Verify +> the frozen Staff-live corpus hash and every structural assertion, force stale/ > failed records, inspect diagnostic network/content traces, and scan every > shipped string. Reject missing tuple evidence, local-only confirmation, -> broadened claim, unsupported platform/app/scope, telemetry/entitlement, skipped -> test, vulnerability without disposition, or any nonzero gate. +> broadened claim, unsupported platform/app/scope, entitlement drift, telemetry, +> corpus mutation/failure, skipped test, vulnerability without disposition, or +> any nonzero child/aggregate gate. **Remediation prompt template.** @@ -1803,8 +2128,9 @@ signing infrastructure cannot be inferred from unit tests. > Preserve failed artifacts, identify whether code/config/environment caused it, > make the smallest P12-owned change, invalidate prior verification, strengthen > `{P12 named test/validator}`, rebuild and rerun the complete P12 sequence and -> both remote qualifications for every affected tuple, then return raw counts, -> artifact hashes, matrix revision, and new SHAs. +> both live-paired remote qualifications for every affected tuple, then return +> every reporter raw exit/count and aggregate exit, entitlement diff, corpus +> counts, artifact hashes, matrix revision, and new SHAs. ## 8. Requirement ownership matrix @@ -1842,7 +2168,7 @@ the migrated interface but may not write an alternate migration. | M-01 | P02 | Legacy API/provider/model/credit config → versioned subscription-only config. | Redacted backup, mode 0600, atomic/idempotent migration; explicit-only legacy restore. | | M-02 | P03 | Plaintext screenshot/temp/cache artifacts → authenticated encrypted blobs. | Journal, decrypt-before-delete proof, interruption resume, quarantine. | | M-03 | P03 | Encrypted store envelope/schema v1 and protected installation key. | Prior/new valid record atomicity, Keychain recovery, version rejection. | -| M-04 | P04 | InterviewSession/ResponseSection/active-recovery schema v1. | Encrypted fixture round-trip, forward-version rejection, no lossy downgrade. | +| M-04 | P04 | InterviewSession/ResponseSection/active-recovery schema v1, including the opaque provider conversation ID inside the authenticated encrypted envelope only. | Encrypted fixture round-trip, plaintext config/index/log/provider-directory byte scan, same-conversation Resume, forward-version rejection, no lossy downgrade. | | M-05a | P05 | Density/text/shortcut/per-display geometry preferences. | Invalid-value defaults; old builds ignore additive keys. | | M-05b | P06 | Language aliases (`python`→`python3`, Go aliases) to canonical preference. | Idempotent normalization; active session unchanged. | | M-06 | P08 | Candidate dossier/opportunity/provenance/active-selection schema v1. | Reviewed draft/import, encrypted original revision, Markdown export escape hatch. | @@ -1902,11 +2228,12 @@ SHAs and the formal Stage 2 baseline at the frozen SHA. For each phase: intended base SHA. 2. Create only the canonical phase branch/worktree; verify clean status. 3. Execute the self-contained implementation prompt without prototype commits. -4. Produce every named test and completion artifact; run commands in order. +4. Produce every named test and completion artifact; invoke the phase reporter + once and retain its exact-command/raw-exit/count/aggregate reports. 5. Have an independent reviewer execute the self-contained review prompt from a fresh clean checkout and challenge the solution at the owning boundary. 6. For any failure, use the phase remediation template; rerun the complete - sequence from `npm ci`, not only the failed test. + reporter plan, which begins with `npm ci`, not only the failed test. 7. Merge only with all local raw exits 0, failed=0, skipped=0, manifest complete, acceptance criteria checked, migrations/rollback evidenced, and no unresolved actionable review feedback. From 7733c8a9c7750e8e61e6a7e51769ceda971d6768 Mon Sep 17 00:00:00 2001 From: Timomak Date: Sun, 26 Jul 2026 18:48:22 +0200 Subject: [PATCH 3/9] docs: fix P00 qualification evidence finalization --- design.md | 2 +- docs/implementation/phase-execution-packet.md | 302 +++++++++++++----- 2 files changed, 224 insertions(+), 80 deletions(-) diff --git a/design.md b/design.md index 1dbd3083..f76ce614 100644 --- a/design.md +++ b/design.md @@ -863,5 +863,5 @@ Decisions are resolved in dependency order. A later branch may be reordered when The reviewed phase order, dependency graph, acceptance gates, migration owners, prototype disposition, and implementation/review/remediation prompts are defined in [`docs/implementation/phase-execution-packet.md`](docs/implementation/phase-execution-packet.md), -revision P00-R2. This design remains the product source of truth; the packet is +revision P00-R3. This design remains the product source of truth; the packet is the execution contract. Prototype evidence does not establish phase completion. diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md index 9c9528fd..336bfe86 100644 --- a/docs/implementation/phase-execution-packet.md +++ b/docs/implementation/phase-execution-packet.md @@ -1,6 +1,6 @@ # InterviewCopilot phase-execution packet -Packet revision: **P00-R2** +Packet revision: **P00-R3** Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` @@ -268,7 +268,8 @@ The P12 row is complete and therefore does not receive the default manifest or build suffix. Package, diagnostics, Meet collection/validation, and final release validation are child commands of the same reporter and cannot bypass its raw-exit aggregate. `qualify:meet` launches collection when evidence is -absent as specified in P12-M01/M02; it is not an artifact-presence shortcut. +absent and performs the write-once manifest/attestation/bundle finalization in +P12-M01/M02; it is not an artifact-presence shortcut. The remote device also uses the reporter, with the exact invocation `npm run verify:phase -- --phase P12 --role meet-observer --pair --artifacts .artifacts/qualification-observer`. @@ -385,7 +386,7 @@ inside the single PR. **Self-contained implementation prompt.** -> Implement P01 from P00-R2 on `phase/P01-local-gates`, based only on upstream +> Implement P01 from P00-R3 on `phase/P01-local-gates`, based only on upstream > `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. > Make local lint, strict type-check, real unit tests (including the unchanged > tracked CRA sample), manifest enforcement, and build green. Centralize and @@ -397,7 +398,7 @@ inside the single PR. **Self-contained review prompt.** -> Review P01 independently against P00-R2, not the author’s summary. From the +> Review P01 independently against P00-R3, not the author’s summary. From the > clean PR checkout run the P01 reporter invocation, confirm the inherited CRA > test ran, > inspect all config/glob/ignore changes for hidden coverage loss, compare typed @@ -526,7 +527,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained implementation prompt.** -> Implement P02 from P00-R2 after P01, on +> Implement P02 from P00-R3 after P01, on > `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime > for Claude Code and Codex only, using one resumable session/thread, normalized > streaming/usage/compaction/stop/error events, explicit provider/model/Fast- @@ -539,7 +540,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained review prompt.** -> Review P02 against P00-R2 from a clean checkout. Trace both fake providers +> Review P02 against P00-R3 from a clean checkout. Trace both fake providers > through two turns, stop, compaction, driver/child restart, and caller-ID > resume; force every failure and prove the other provider never starts. Inspect > spawn/env/tool restrictions, IPC exposure, migration idempotence/file mode, @@ -652,7 +653,7 @@ never custom cryptography. **Self-contained implementation prompt.** -> Implement P03 from P00-R2 after P01 on +> Implement P03 from P00-R3 after P01 on > `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key > service, versioned AES-256-GCM record/blob store, atomic writes, encrypted > in-memory-search source, typed recovery, raw-audio rejection, and journaled @@ -800,7 +801,7 @@ boundary; no renderer or provider may keep a second authoritative session. **Self-contained implementation prompt.** -> Implement P04 from P00-R2 after P02/P03 on +> Implement P04 from P00-R3 after P02/P03 on > `phase/P04-session-orchestrator`. Replace global transient state with the > deterministic InterviewSession reducer, typed event/IPC contract, one > persistent-conversation orchestrator, context/delta policy, pending artifacts, @@ -935,7 +936,7 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained implementation prompt.** -> Implement P05 from P00-R2 after P04 on `phase/P05-live-shell`. Build the +> Implement P05 from P00-R3 after P04 on `phase/P05-live-shell`. Build the > exact Quiet Signal hidden/compact/answer/expanded shell, command rail, > composer, input tray, explicit click-through/drag regions, final remappable > shortcuts, display-aware geometry, primary-display screenshot behavior, @@ -1057,7 +1058,7 @@ regress silently; fixture contracts are merge-blocking. **Self-contained implementation prompt.** -> Implement P06 from P00-R2 after P05 on `phase/P06-coding`. Add the exact +> Implement P06 from P00-R3 after P05 on `phase/P06-coding`. Add the exact > typed Coding intents/schema/renderer, concise-first progressive answer, > language snapshot and six-family fixtures, read-only actions, New Question, > and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, @@ -1172,7 +1173,7 @@ must not become a second untyped document model. **Self-contained implementation prompt.** -> Implement P07 from P00-R2 after P05 on `phase/P07-system-design`. Add the +> Implement P07 from P00-R3 after P05 on `phase/P07-system-design`. Add the > fixed typed five-section progressive workflow, bounded material estimates, > safe vendor-neutral structured diagram, read-only accessible interactions, > assumption handling, dependency-scoped follow-up and What changed summary. @@ -1293,7 +1294,7 @@ integrity are product trust boundaries. **Self-contained implementation prompt.** -> Implement P08 from P00-R2 after P05 on `phase/P08-behavioral`. Build the +> Implement P08 from P00-R3 after P05 on `phase/P08-behavioral`. Build the > encrypted canonical candidate dossier, guided/manual reviewed editing, > sanitized Markdown import/export, multiple snapshotted opportunities, > provenance, opt-in labeled persistent synthetic stories, and typed Behavioral @@ -1426,7 +1427,7 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained implementation prompt.** -> Implement P09 from P00-R2 after P05 on `phase/P09-audio`, macOS only. Build +> Implement P09 from P00-R3 after P05 on `phase/P09-audio`, macOS only. Build > explicit two-source native capture, deterministic master/per-source controls, > contextual permission recovery, pinned offline whisper.cpp transcription, > explicit Apple Speech remote fallback, typed segments/attribution/correction, @@ -1545,7 +1546,7 @@ must never become a capability or schema escape hatch. **Self-contained implementation prompt.** -> Implement P10 from P00-R2 after P06/P07/P08 on +> Implement P10 from P00-R3 after P06/P07/P08 on > `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, > immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, > deterministic recorded instruction resolution, Start snapshotting, protected @@ -1662,7 +1663,7 @@ content and destructive user controls. **Self-contained implementation prompt.** -> Implement P11 from P00-R2 after P06–P10 on +> Implement P11 from P00-R3 after P06–P10 on > `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete > encrypted archive projection, Settings-only in-memory search/open/delete one/ > all, safe consented individual Markdown/JSON export, read-only archive open, @@ -1721,7 +1722,7 @@ pixel dimensions/scaling, and internal/external display type), never `latest`, a range, or a wildcard. Those exact passing tuples—and no neighboring patch, major version, browser, app build, architecture, or display mode—are the supported macOS/browser/app versions until separately qualified. Qualify each -supported tuple separately. P00-R2 represents no version as supported before +supported tuple separately. P00-R3 represents no version as supported before that committed matrix and its evidence pass. Entire-display and specific-window require confirmation from remote Meet view or second device and retained high-contrast moving-marker artifacts; one fail makes @@ -1822,10 +1823,10 @@ for this gate. | P12-AC1: package config emits only macOS arm64/x64 launch artifacts with canonical identity; the signed parent and every nested executable match their exact allowlists above with a mechanical reject-on-extra/missing/wrong-role assertion; signing/notarization and AGPL metadata are valid; no Windows/Linux support claim exists. | `tests/release/macosPackagePolicy.test.ts — rejects any macOS entitlement allowlist mismatch` | | P12-AC2: every BrowserWindow in the packaged app enables content protection before first visible frame and after lifecycle reconfiguration. | `tests/release/packagedCaptureProtection.test.ts — traces protection in the packaged app` | | P12-AC3: guided Meet flow tests entire-display and specific-window separately with moving marker and requires remote/second-device confirmation; it never offers generic/browser-tab certification. | `src/features/privacy/MeetVerification.test.tsx — guides only qualified scopes with remote confirmation` | -| P12-AC4: verification record contains exact app/commit/macOS/arch/Chrome/Meet/display/scopes/date/result/artifact hashes and state invalidates by specified changes. | `electron/privacy/verificationRecord.test.ts — versions verifies fails and stales exact tuples` | -| P12-AC5: release-build Google Meet entire-display capture contains zero marker pixels while underlying control frames remain visible for every frozen tuple. | `P12-M01 — remote Google Meet entire-display moving-marker qualification` | -| P12-AC6: release-build Google Meet specific-window capture contains zero marker pixels while target-window control frames remain visible for every frozen tuple. | `P12-M02 — remote Google Meet specific-window moving-marker qualification` | -| P12-AC7: any missing/failed scope or artifact produces Failed/Not verified and makes release qualification command nonzero; local preview can never produce pass. | `scripts/qualification/meet-artifact-validator.test.ts — fails incomplete false or local-only evidence` | +| P12-AC4: verification record contains exact app/commit/macOS/arch/Chrome/Meet/display/scopes/date/result plus evidence- and bundle-manifest digests, and state invalidates by specified changes. | `electron/privacy/verificationRecord.test.ts — versions verifies fails and stales exact tuples` | +| P12-AC5: release-build Google Meet entire-display capture contains zero marker pixels while underlying control frames remain visible for every frozen tuple, with the accepted evidence bound by both independent role attestations and the final bundle digest. | `P12-M01 — remote Google Meet entire-display moving-marker qualification` | +| P12-AC6: release-build Google Meet specific-window capture contains zero marker pixels while target-window control frames remain visible for every frozen tuple, with the accepted evidence bound by both independent role attestations and the final bundle digest. | `P12-M02 — remote Google Meet specific-window moving-marker qualification` | +| P12-AC7: any missing/failed scope or artifact, noncanonical or extra manifest member, self-reference, digest/signature mismatch, or post-manifest mutation produces Failed/Not verified and makes release qualification nonzero; local preview can never produce pass. | `scripts/qualification/meet-artifact-validator.test.ts — rejects incomplete cyclic mutated or local-only evidence` | | P12-AC8: diagnostics exclude transcript/audio/screenshots/prompts/responses/profile/opportunity/credentials/tokens/device IDs, preview before manual export, and perform zero network upload. | `electron/diagnostics/diagnosticPrivacy.test.ts — previews redacted local-only diagnostic export` | | P12-AC9: provider/microphone/system-audio/screen-capture denial disables only affected action and explicit repair/retry preserves the session. | `tests/release/scopedRecovery.e2e.test.ts — preserves session through every permission/provider failure` | | P12-AC10: shipped copy/docs contain only qualified D-005g language and no 99%, undetectable, bypass, anti-cheat, process-hiding, monitoring-evasion, or unsupported-app/platform claim. | `tests/release/claimPolicy.test.ts — rejects unqualified privacy and platform language` | @@ -1842,8 +1843,8 @@ P12 reporter's exact invocation launches the procedure for every incomplete matrix tuple and scope, blocks until collection and validation finish, and returns nonzero if a prerequisite, human step, raw artifact, count, or assertion is absent. A pre-existing artifact directory is accepted only after complete -schema/hash validation; an empty or partial directory triggers collection or a -nonzero failure, never a presumed pass. +schema/canonical-byte/manifest/signature validation; an empty or partial +directory triggers collection or a nonzero failure, never a presumed pass. **Supported version rule and release prerequisite.** Before the first run, `docs/qualification/macos-google-meet.json` must be committed at the RC SHA with @@ -1945,7 +1946,8 @@ steps and records UTC plus monotonic timestamps for each acknowledgement: 5. After the collector announces 120 valid seconds, choose Meet **Stop presenting**. The observer acknowledges presentation stopped and records 15 more seconds. The collector then closes the test surfaces, finalizes the raw - streams, and immediately validates both scope evidence and attestations. + streams, executes the acyclic evidence/attestation/bundle sequence below, and + immediately validates the complete scope bundle. M01 and M02 run separately for every tuple, in that order, with a fresh Meet presentation and run ID. A pass in one scope never fills or waives the other. @@ -1961,8 +1963,9 @@ unsupported) for a missing/invalid artifact or attestation; marker detected in one or more remote shared-interval frames; marker render continuity below 99.5%; control sequence recognized in less than 99.5% of remote shared-interval frames; any one-second interval without a valid control frame; wrong seed/scope; -local-only evidence; or hash/schema/timestamp/version inconsistency. Compression -noise is not counted as a marker: the frozen validator detects the exact +local-only evidence; or manifest/signature/hash/schema/timestamp/version +inconsistency. Compression noise is not counted as a marker: the frozen +validator detects the exact seeded color/geometry/temporal signature and reports `marker_detected_frames=0`; its detection corpus includes positive transcodes and must pass before real evidence is evaluated. @@ -1978,36 +1981,147 @@ this exact root for each run: raw/local-control-events.ndjson raw/remote-observer.mov raw/remote-observer-events.ndjson - attestations/local-operator.json - attestations/remote-observer.json derived/frame-analysis.ndjson derived/control-coverage.json validation/report.json - hashes.sha256 + evidence-manifest.json + attestations/local-operator.json + attestations/remote-observer.json + bundle-metadata.json + bundle-manifest.json + bundle-manifest.sig (optional) ``` `collection.json` contains `schemaVersion`, `procedureId`, matrix revision, tuple ID, scope, run ID, app semver/SHA/package hash, signing team/certificate/ notarization ticket, exact OS build/arch/Chrome/Meet/display values, dedicated -pseudonymous role IDs, UTC start/share-start/share-stop/end, monotonic offsets, -duration, marker/control algorithms and seed, observer pairing challenge hash, -relative artifact paths, byte sizes, SHA-256 hashes, validator version/SHA, and -result. NDJSON records carry schema version, sequence, RFC3339 UTC, monotonic -nanoseconds, frame ID, and event payload. Attestations carry exact tuple/scope, -role, steps acknowledged, observed result, aborts/deviations, timestamps, and a -signature over `collection.json` plus `hashes.sha256`. `hashes.sha256` covers -every raw, attestation, derived, and validation file except itself. Paths must -be canonical, relative, inside the run root, non-symlinked, and mode 0600 (dirs -0700). Source video is at least 1080p, 24 fps, includes 15/120/15-second -segments, and retains original timestamps; derived frames never replace it. +pseudonymous role IDs and distinct pre-registered Ed25519 public-key IDs/keys, +UTC start/share-start/share-stop/end, monotonic offsets, duration, +marker/control algorithms and seed, observer pairing challenge hash, validator +version/SHA, content result, and the paths, byte sizes, and SHA-256 values of the +other eight evidence members. NDJSON records carry schema version, sequence, +RFC3339 UTC, monotonic nanoseconds, frame ID, and event payload. Source video is +at least 1080p, 24 fps, includes 15/120/15-second segments, and retains original +timestamps; derived frames never replace it. + +**Canonical bytes and exact manifest membership.** SHA-256 over exact file +bytes is the only digest algorithm; hashes are 64 lowercase hexadecimal +characters. Every JSON file is RFC 8785 JSON Canonicalization Scheme (JCS) UTF-8 +with no BOM or trailing newline, and its stored bytes must equal canonicalized +bytes. Each NDJSON line is one JCS value followed by exactly one LF, including +the last line. The video is hashed as its original bytes. Manifest entries have +exactly `path`, `bytes`, and `sha256`; entries sort by unsigned UTF-8 bytes of +their ASCII POSIX relative `path`. Duplicate, absolute, empty, dot-segment, +backslash, non-NFC, or case-colliding paths fail. + +`evidence-manifest.json` has exactly `schemaVersion: 1`, `kind: "evidence"`, +`algorithm: "sha256"`, and an `entries` array containing exactly these nine +paths, no more and no fewer: + +```text +collection.json +derived/control-coverage.json +derived/frame-analysis.ndjson +raw/local-control-events.ndjson +raw/local-marker-events.ndjson +raw/local-preflight.json +raw/remote-observer-events.ndjson +raw/remote-observer.mov +validation/report.json +``` + +It explicitly excludes itself, `attestations/**`, `bundle-metadata.json`, +`bundle-manifest.json`, `bundle-manifest.sig`, reviewer records, reporter logs, +and redacted/public copies. Its evidence digest is SHA-256 of its own canonical +bytes; no member refers to that digest. `validation/report.json` is the frozen +content-analysis result and does not claim to validate a manifest or +attestation that does not yet exist. + +Each role attestation is a JCS object containing exactly `payload` and +`signature`. The payload contains schema version, procedure/matrix/tuple/scope/ +run identity, role and pseudonymous role ID, every required acknowledgement, +observed result, deviations/aborts, RFC3339 timestamp, and the exact lowercase +`evidenceManifestSha256`. The signature contains exactly `algorithm: +"Ed25519"`, the matching pre-registered `keyId`, and an unpadded base64url +value. The role signs the ASCII domain separator +`InterviewCopilot qualification attestation v1\n` followed by the JCS bytes of +`payload`; Ed25519's deterministic signature and the pinned public key make the +payload and stored attestation bytes independently verifiable. Local and remote +roles, IDs, keys, and signatures must differ. + +`bundle-metadata.json` is JCS and contains exactly `schemaVersion`, +`procedureId`, `matrixRevision`, `tupleId`, `scope`, `runId`, +`evidenceManifestSha256`, `localAttestationSha256`, +`remoteAttestationSha256`, `finalizedAt`, `retentionDeleteAt`, and +`encryptedStoreId`. It cannot contain a bundle digest or signature. +`bundle-manifest.json` has the same four manifest fields as the evidence +manifest except `kind: "bundle"`, and its exact ordered membership is: + +```text +attestations/local-operator.json +attestations/remote-observer.json +bundle-metadata.json +evidence-manifest.json +``` + +The final bundle digest is SHA-256 of canonical `bundle-manifest.json` bytes. +The manifest explicitly excludes itself, all nine evidence files already +committed through the evidence manifest, and `bundle-manifest.sig`. If the +optional detached JCS signature exists, it contains exactly `schemaVersion`, +`algorithm: "Ed25519"`, release `keyId`, `bundleManifestSha256`, and unpadded +base64url `signature`. The release key signs +`InterviewCopilot qualification bundle v1\n` followed by the lowercase bundle +digest. The signature file's own bytes are never in that digest. No other file +is allowed in an accepted run root. + +**Acyclic finalization and overwrite rules.** The collector uses a newly and +exclusively created sibling `.partial` directory; it never imports or +reuses a supplied run. It performs this sole legal order: + +1. Create and close the five raw files; fsync them and prohibit overwrite. +2. Create and freeze the two derived files and content-only validation report, + then create and freeze `collection.json` from those already immutable bytes. +3. Hash the exact nine-member allowlist, create `evidence-manifest.json`, rehash + every member, and freeze both the members and manifest. +4. Send only the evidence-manifest canonical bytes/digest to both roles. Create + each independently signed attestation once; verify its payload, pinned key, + canonical bytes, signature, and evidence digest before freezing it. +5. Create and freeze `bundle-metadata.json`; hash exactly it, the evidence + manifest, and both frozen attestations into `bundle-manifest.json`; then + compute and freeze the final bundle digest. +6. Optionally create the detached final-bundle signature, validate the entire + graph without writing inside it, set files to 0400 and directories to 0500, + fsync, and atomically rename the staging directory to ``. + +Creation is exclusive and write-once. A collision, changed size/hash/mtime, +second write, regenerated manifest or attestation, file with link count other +than one, symlink, non-regular file, unexpected path, or failure after any +freeze point rejects and retains the run as failed, except the privacy-deletion +rule below; retry uses a new run ID. Neither collector nor validator repairs, +normalizes, deletes, or overwrites an accepted or retained failed run. This gives +the only dependency graph: + +```text +raw -> derived/content-validation -> collection -> evidence-manifest +evidence-manifest -> local-attestation +evidence-manifest -> remote-attestation +evidence-manifest + both-attestations -> bundle-metadata +evidence-manifest + both-attestations + bundle-metadata -> bundle-manifest +bundle-manifest-digest -> optional-detached-signature +``` + +Every edge points from an already frozen node to a newly created node; no node +hashes itself or any descendant. **Privacy and redaction.** Use only the dedicated names, synthetic control content, and a disposable meeting. Do not enable audio/video/chat/captions or show email addresses, calendars, notifications, browser profiles, interview -content, or unrelated screens. If personal data appears, abort, securely delete -the unaccepted run directory, record only the abort reason without the data, and -rerun. Accepted raw evidence is immutable and validated before any redaction; -it is never committed or publicly uploaded. A separately hashed review copy may +content, or unrelated screens. If personal data appears, abort before creating +either manifest, securely delete the unaccepted staging directory, record only +the abort reason outside it without the data, and rerun. This is the sole +failed-run retention exception. Accepted raw evidence is immutable and validated +before any redaction; it is never committed or publicly uploaded. A separately +hashed review copy may redact only meeting code/account chrome outside the presentation and marker/ control analysis regions. Validation always uses raw evidence. Release storage documents encrypted access, named independent reviewers, and retention/deletion @@ -2015,26 +2129,42 @@ date; public evidence contains only hashes, tuple metadata, counts, and the redacted copy. **Validation, exits, and independent reproduction.** Within `qualify:meet`, the -validator verifies schemas, canonical paths/modes, hashes, versions/signing, -two distinct signed roles, timing, frame decode/continuity, positive detector -corpus, marker absence, control visibility, and M01/M02 completeness. It prints -one line per tuple/scope plus `passed= failed= skipped=` and exits 0 -only when every matrix tuple has exactly one accepted M01 and M02 run, all -assertions pass, failed=0, and skipped=0. The P12 reporter preserves that raw -exit and makes its aggregate nonzero otherwise. +validator is read-only. Before content assertions it rejects any noncanonical +serialization/path/order/mode, missing or extra file/entry, forbidden manifest +member, self-reference, size/hash mismatch, evidence or bundle digest mismatch, +unpinned/same-role/invalid attestation signature, identity/digest disagreement, +invalid optional detached signature, post-freeze mutation, `.partial` root, or +non-regular/linked file. It then verifies versions/signing, timing, frame +decode/continuity, positive detector corpus, marker absence, control visibility, +and M01/M02 completeness. The validator writes only to the reporter's separate +log directory. Its tests construct the valid graph, reproduce identical +manifest and signature bytes from canonical inputs, topologically prove the +edge list above, and mutate every member class plus each include/exclude rule to +prove a nonzero result. + +It prints one line per tuple/scope plus `passed= failed= skipped=` and +exits 0 only when every matrix tuple has exactly one accepted M01 and M02 bundle, +the exact graph and all assertions pass, failed=0, and skipped=0. Missing raw +evidence, either attestation, either manifest, or the bundle metadata is a +failure, never a skip. The P12 reporter preserves that raw exit and makes its +aggregate nonzero otherwise. An independent reviewer starts from a fresh clone at the exact RC SHA, obtains -the signed package and immutable raw evidence through the documented encrypted -release channel, verifies their published SHA-256 values, and runs the complete -P12 reporter command below. To reproduce collection rather than only validate, -the reviewer uses a fresh checkout with no `.artifacts/qualification`, the same -exact matrix hardware/software/display tuple, new dedicated accounts/meeting, -and the two launch commands above; absent evidence automatically launches M01 -then M02. The reviewer watches the full remote shared intervals plus pre/post -boundaries, checks at least the first/last and one frame from every 15-second -marker-position epoch against `frame-analysis.ndjson`, verifies ordinary -underlying content remains readable, and signs a separate review attestation. -Any disagreement, non-reproducible tuple, or changed version creates a new +the signed package and complete immutable bundle through the documented +encrypted release channel, recomputes both manifest digests from canonical +bytes, walks every allowlist edge, verifies both role signatures against the +keys pinned in `collection.json`, and runs the complete P12 reporter command +below. To reproduce collection rather than only validate, the reviewer uses a +fresh checkout with no `.artifacts/qualification`, the same exact matrix +hardware/software/display tuple, new dedicated accounts/meeting, and the two +launch commands above; absent evidence automatically launches M01 then M02. +The reviewer watches the full remote shared intervals plus pre/post boundaries, +checks at least the first/last and one frame from every 15-second marker-position +epoch against `frame-analysis.ndjson`, and verifies ordinary underlying content +remains readable. The review attestation signs the final bundle digest and is +stored as a detached review record outside the accepted run root, so review +cannot mutate or become a dependency of the bundle it reviews. Any disagreement, +non-reproducible tuple, graph/byte mismatch, or changed version creates a new failed/retest-required record and blocks the claim. **Clean-checkout setup.** Requires supported macOS, Chrome, Meet test account, @@ -2062,8 +2192,9 @@ npm run verify:phase -- --phase P12 --artifacts .artifacts/verification/P12 Expected reporter aggregate exit is 0; every logged child raw exit is 0. `qualify:meet` launches P12-M01 and P12-M02 for absent evidence and exits 0 only -after every frozen tuple has a live-paired, complete, validated run with -`marker_detected_frames=0` and valid control coverage. `test:staff-live-corpus` +after every frozen tuple has a live-paired, complete, read-only validated bundle +with `marker_detected_frames=0`, valid control coverage, the exact acyclic +manifest graph, and two valid role attestations. `test:staff-live-corpus` executes all three frozen cases. Every test-classified reporter entry prints passed/failed/skipped totals. **Regression suite.** the entire P01–P11 suite, native audio, all mode fixtures, migrations, storage @@ -2075,24 +2206,29 @@ D-005g headline/qualifier, limitations/non-security-boundary, permissions, provider/audio/storage/privacy, diagnostics, AGPL/source offer, macOS install/ uninstall/update, release evidence, SBOM/vulnerability disposition, and explicit Windows/Linux/app/scope deferrals. Release docs also publish the exact parent/ -inherit entitlement tables and frozen Staff-live corpus hash/assertion summary. +inherit entitlement tables, frozen Staff-live corpus hash/assertion summary, +both manifest schemas/memberships/digests, signature verification result, and +detached independent-review record. **Completion evidence.** (1) SHAs/base/version; (2) every raw gate/count report; (3) signed/notarized arm64/x64 hashes and package-policy report; (4) role-by- role extracted entitlement plist diff, SBOM, and vulnerability disposition; -(5) protection trace; (6) exact no-wildcard matrix; (7) P12-M01/M02 raw remote -recordings, paired role attestations, control coverage, marker analysis, schema, -and hashes per tuple; (8) verification-state/stale trace; (9) diagnostic -preview/network-zero trace; (10) scoped recovery E2E; (11) claim/deferred scan; -(12) frozen Staff-live corpus hash plus all case/assertion counts; (13) -independent reviewer sign-off that evidence supports every public claim. +(5) protection trace; (6) exact no-wildcard matrix; (7) per-tuple P12-M01/M02 +raw recording/content analysis, exact evidence-manifest membership/digest, both +canonical signed role attestations, bundle metadata, final bundle-manifest +membership/digest, and optional detached signature; (8) validator proof of the +acyclic graph plus mutation/include/exclude failure fixtures; (9) verification- +state/stale trace; (10) diagnostic preview/network-zero trace; (11) scoped +recovery E2E; (12) claim/deferred scan; (13) frozen Staff-live corpus hash plus +all case/assertion counts; (14) detached independent-review sign-off over the +final bundle digest that supports every public claim. **Risk/complexity.** Release-blocking/very high. External capture behavior and signing infrastructure cannot be inferred from unit tests. **Self-contained implementation prompt.** -> Implement P12 from P00-R2 after P01–P11 on +> Implement P12 from P00-R3 after P01–P11 on > `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ > architecture matrix, harden macOS-only package/entitlements/identity, add > local-only redacted diagnostic preview/export, scoped failure recovery, @@ -2102,9 +2238,13 @@ signing infrastructure cannot be inferred from unit tests. > signed/notarized arm64/x64 artifacts, launch and execute the full live-paired > P12-M01/M02 procedures on the release build, and run the complete P12 reporter > plan including artifact validation and the SHA-pinned three-case Staff-live -> corpus. Attach every enumerated artifact. A failed/incomplete tuple, extra or -> missing entitlement, corpus assertion failure, or skipped case blocks release; -> never infer pass or accept pre-existing files without validation. +> corpus. Implement the exact write-once evidence-manifest → two independent +> role attestations → final bundle-manifest/digest sequence, canonical bytes, +> memberships, exclusions, detached-signature rule, and read-only validator. +> Attach every enumerated artifact. A failed/incomplete tuple, cyclic/extra/ +> missing/mutated bundle member, invalid signature, extra or missing entitlement, +> corpus assertion failure, or skipped case blocks release; never infer pass or +> accept pre-existing files without complete read-only validation. **Self-contained review prompt.** @@ -2112,14 +2252,17 @@ signing infrastructure cannot be inferred from unit tests. > clean SHA, inspect signing/notarization/entitlements/SBOM, trace protection > before first frame, mechanically compare every signed parent/nested executable > with the exact role allowlist, rerun the complete reporter plan, personally -> verify remote Meet raw artifacts/control frames/hashes/role attestations for -> both scopes/architectures, and reproduce one clean live-paired tuple. Verify +> verify remote Meet raw artifacts/control frames, canonical evidence manifest, +> independently signed role attestations, bundle metadata/final digest, exact +> include/exclude rules, and acyclic dependency graph for both scopes/ +> architectures, and reproduce one clean live-paired tuple. Verify > the frozen Staff-live corpus hash and every structural assertion, force stale/ > failed records, inspect diagnostic network/content traces, and scan every > shipped string. Reject missing tuple evidence, local-only confirmation, > broadened claim, unsupported platform/app/scope, entitlement drift, telemetry, -> corpus mutation/failure, skipped test, vulnerability without disposition, or -> any nonzero child/aggregate gate. +> corpus mutation/failure, self-reference, post-signing mutation, invalid role or +> bundle signature, skipped test, vulnerability without disposition, or any +> nonzero child/aggregate gate. Store review sign-off outside the immutable run. **Remediation prompt template.** @@ -2130,7 +2273,8 @@ signing infrastructure cannot be inferred from unit tests. > `{P12 named test/validator}`, rebuild and rerun the complete P12 sequence and > both live-paired remote qualifications for every affected tuple, then return > every reporter raw exit/count and aggregate exit, entitlement diff, corpus -> counts, artifact hashes, matrix revision, and new SHAs. +> counts, both manifest memberships/digests, role/detached-signature results, +> matrix revision, and new SHAs. ## 8. Requirement ownership matrix From 66b5b14c00cc8b6573fb675f965b6109e0f730a1 Mon Sep 17 00:00:00 2001 From: Timomak Date: Sun, 26 Jul 2026 19:56:21 +0200 Subject: [PATCH 4/9] docs: close P00 qualification trust protocol --- design.md | 2 +- docs/implementation/phase-execution-packet.md | 520 ++++++++++++++---- 2 files changed, 408 insertions(+), 114 deletions(-) diff --git a/design.md b/design.md index f76ce614..5ef913f3 100644 --- a/design.md +++ b/design.md @@ -863,5 +863,5 @@ Decisions are resolved in dependency order. A later branch may be reordered when The reviewed phase order, dependency graph, acceptance gates, migration owners, prototype disposition, and implementation/review/remediation prompts are defined in [`docs/implementation/phase-execution-packet.md`](docs/implementation/phase-execution-packet.md), -revision P00-R3. This design remains the product source of truth; the packet is +revision P00-R4. This design remains the product source of truth; the packet is the execution contract. Prototype evidence does not establish phase completion. diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md index 336bfe86..6832eefa 100644 --- a/docs/implementation/phase-execution-packet.md +++ b/docs/implementation/phase-execution-packet.md @@ -1,6 +1,6 @@ # InterviewCopilot phase-execution packet -Packet revision: **P00-R3** +Packet revision: **P00-R4** Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` @@ -386,7 +386,7 @@ inside the single PR. **Self-contained implementation prompt.** -> Implement P01 from P00-R3 on `phase/P01-local-gates`, based only on upstream +> Implement P01 from P00-R4 on `phase/P01-local-gates`, based only on upstream > `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. > Make local lint, strict type-check, real unit tests (including the unchanged > tracked CRA sample), manifest enforcement, and build green. Centralize and @@ -398,7 +398,7 @@ inside the single PR. **Self-contained review prompt.** -> Review P01 independently against P00-R3, not the author’s summary. From the +> Review P01 independently against P00-R4, not the author’s summary. From the > clean PR checkout run the P01 reporter invocation, confirm the inherited CRA > test ran, > inspect all config/glob/ignore changes for hidden coverage loss, compare typed @@ -527,7 +527,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained implementation prompt.** -> Implement P02 from P00-R3 after P01, on +> Implement P02 from P00-R4 after P01, on > `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime > for Claude Code and Codex only, using one resumable session/thread, normalized > streaming/usage/compaction/stop/error events, explicit provider/model/Fast- @@ -540,7 +540,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained review prompt.** -> Review P02 against P00-R3 from a clean checkout. Trace both fake providers +> Review P02 against P00-R4 from a clean checkout. Trace both fake providers > through two turns, stop, compaction, driver/child restart, and caller-ID > resume; force every failure and prove the other provider never starts. Inspect > spawn/env/tool restrictions, IPC exposure, migration idempotence/file mode, @@ -653,7 +653,7 @@ never custom cryptography. **Self-contained implementation prompt.** -> Implement P03 from P00-R3 after P01 on +> Implement P03 from P00-R4 after P01 on > `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key > service, versioned AES-256-GCM record/blob store, atomic writes, encrypted > in-memory-search source, typed recovery, raw-audio rejection, and journaled @@ -801,7 +801,7 @@ boundary; no renderer or provider may keep a second authoritative session. **Self-contained implementation prompt.** -> Implement P04 from P00-R3 after P02/P03 on +> Implement P04 from P00-R4 after P02/P03 on > `phase/P04-session-orchestrator`. Replace global transient state with the > deterministic InterviewSession reducer, typed event/IPC contract, one > persistent-conversation orchestrator, context/delta policy, pending artifacts, @@ -936,7 +936,7 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained implementation prompt.** -> Implement P05 from P00-R3 after P04 on `phase/P05-live-shell`. Build the +> Implement P05 from P00-R4 after P04 on `phase/P05-live-shell`. Build the > exact Quiet Signal hidden/compact/answer/expanded shell, command rail, > composer, input tray, explicit click-through/drag regions, final remappable > shortcuts, display-aware geometry, primary-display screenshot behavior, @@ -1058,7 +1058,7 @@ regress silently; fixture contracts are merge-blocking. **Self-contained implementation prompt.** -> Implement P06 from P00-R3 after P05 on `phase/P06-coding`. Add the exact +> Implement P06 from P00-R4 after P05 on `phase/P06-coding`. Add the exact > typed Coding intents/schema/renderer, concise-first progressive answer, > language snapshot and six-family fixtures, read-only actions, New Question, > and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, @@ -1173,7 +1173,7 @@ must not become a second untyped document model. **Self-contained implementation prompt.** -> Implement P07 from P00-R3 after P05 on `phase/P07-system-design`. Add the +> Implement P07 from P00-R4 after P05 on `phase/P07-system-design`. Add the > fixed typed five-section progressive workflow, bounded material estimates, > safe vendor-neutral structured diagram, read-only accessible interactions, > assumption handling, dependency-scoped follow-up and What changed summary. @@ -1294,7 +1294,7 @@ integrity are product trust boundaries. **Self-contained implementation prompt.** -> Implement P08 from P00-R3 after P05 on `phase/P08-behavioral`. Build the +> Implement P08 from P00-R4 after P05 on `phase/P08-behavioral`. Build the > encrypted canonical candidate dossier, guided/manual reviewed editing, > sanitized Markdown import/export, multiple snapshotted opportunities, > provenance, opt-in labeled persistent synthetic stories, and typed Behavioral @@ -1427,7 +1427,7 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained implementation prompt.** -> Implement P09 from P00-R3 after P05 on `phase/P09-audio`, macOS only. Build +> Implement P09 from P00-R4 after P05 on `phase/P09-audio`, macOS only. Build > explicit two-source native capture, deterministic master/per-source controls, > contextual permission recovery, pinned offline whisper.cpp transcription, > explicit Apple Speech remote fallback, typed segments/attribution/correction, @@ -1546,7 +1546,7 @@ must never become a capability or schema escape hatch. **Self-contained implementation prompt.** -> Implement P10 from P00-R3 after P06/P07/P08 on +> Implement P10 from P00-R4 after P06/P07/P08 on > `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, > immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, > deterministic recorded instruction resolution, Start snapshotting, protected @@ -1663,7 +1663,7 @@ content and destructive user controls. **Self-contained implementation prompt.** -> Implement P11 from P00-R3 after P06–P10 on +> Implement P11 from P00-R4 after P06–P10 on > `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete > encrypted archive projection, Settings-only in-memory search/open/delete one/ > all, safe consented individual Markdown/JSON export, read-only archive open, @@ -1722,7 +1722,7 @@ pixel dimensions/scaling, and internal/external display type), never `latest`, a range, or a wildcard. Those exact passing tuples—and no neighboring patch, major version, browser, app build, architecture, or display mode—are the supported macOS/browser/app versions until separately qualified. Qualify each -supported tuple separately. P00-R3 represents no version as supported before +supported tuple separately. P00-R4 represents no version as supported before that committed matrix and its evidence pass. Entire-display and specific-window require confirmation from remote Meet view or second device and retained high-contrast moving-marker artifacts; one fail makes @@ -1826,7 +1826,7 @@ for this gate. | P12-AC4: verification record contains exact app/commit/macOS/arch/Chrome/Meet/display/scopes/date/result plus evidence- and bundle-manifest digests, and state invalidates by specified changes. | `electron/privacy/verificationRecord.test.ts — versions verifies fails and stales exact tuples` | | P12-AC5: release-build Google Meet entire-display capture contains zero marker pixels while underlying control frames remain visible for every frozen tuple, with the accepted evidence bound by both independent role attestations and the final bundle digest. | `P12-M01 — remote Google Meet entire-display moving-marker qualification` | | P12-AC6: release-build Google Meet specific-window capture contains zero marker pixels while target-window control frames remain visible for every frozen tuple, with the accepted evidence bound by both independent role attestations and the final bundle digest. | `P12-M02 — remote Google Meet specific-window moving-marker qualification` | -| P12-AC7: any missing/failed scope or artifact, noncanonical or extra manifest member, self-reference, digest/signature mismatch, or post-manifest mutation produces Failed/Not verified and makes release qualification nonzero; local preview can never produce pass. | `scripts/qualification/meet-artifact-validator.test.ts — rejects incomplete cyclic mutated or local-only evidence` | +| P12-AC7: any missing/failed scope or artifact, noncanonical or extra manifest member, self-reference, final-byte size/hash mismatch, schema/identity/trust/signature failure, or required detached-review failure produces Failed/Not verified and makes release qualification nonzero; local preview can never produce pass. Historical second writes or mutate-and-restore are collector-runtime concerns and are not inferred from an identical accepted final state. | `scripts/qualification/meet-artifact-validator.test.ts — rejects incomplete cyclic final-byte-mutated untrusted or local-only evidence` | | P12-AC8: diagnostics exclude transcript/audio/screenshots/prompts/responses/profile/opportunity/credentials/tokens/device IDs, preview before manual export, and perform zero network upload. | `electron/diagnostics/diagnosticPrivacy.test.ts — previews redacted local-only diagnostic export` | | P12-AC9: provider/microphone/system-audio/screen-capture denial disables only affected action and explicit repair/retry preserves the session. | `tests/release/scopedRecovery.e2e.test.ts — preserves session through every permission/provider failure` | | P12-AC10: shipped copy/docs contain only qualified D-005g language and no 99%, undetectable, bypass, anti-cheat, process-hiding, monitoring-evasion, or unsupported-app/platform claim. | `tests/release/claimPolicy.test.ts — rejects unqualified privacy and platform language` | @@ -1992,27 +1992,175 @@ this exact root for each run: bundle-manifest.sig (optional) ``` -`collection.json` contains `schemaVersion`, `procedureId`, matrix revision, -tuple ID, scope, run ID, app semver/SHA/package hash, signing team/certificate/ -notarization ticket, exact OS build/arch/Chrome/Meet/display values, dedicated -pseudonymous role IDs and distinct pre-registered Ed25519 public-key IDs/keys, -UTC start/share-start/share-stop/end, monotonic offsets, duration, -marker/control algorithms and seed, observer pairing challenge hash, validator -version/SHA, content result, and the paths, byte sizes, and SHA-256 values of the -other eight evidence members. NDJSON records carry schema version, sequence, -RFC3339 UTC, monotonic nanoseconds, frame ID, and event payload. Source video is -at least 1080p, 24 fps, includes 15/120/15-second segments, and retains original +**Closed schema vocabulary and canonical bytes.** The following rules are +normative for the matrix and every qualification protocol object. A listed key +is required, key names are case-sensitive, and every object at every depth has +`additionalProperties: false`; an absent listed key, a duplicate JSON key, or +an outer or nested extra key is a schema failure. Arrays are ordered as stated, +have no holes, and reject duplicate values unless a rule explicitly permits +them. Strings must be valid Unicode scalar values in NFC with no NUL or control +character. The protocol uses these exact lexical primitives: + +| Name | Exact representation | +|---|---| +| `Sha256` | string matching `^[0-9a-f]{64}$` | +| `RcSha` | string matching `^[0-9a-f]{40}$`; it equals the checked-out RC commit | +| `Token` | string matching `^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$` | +| `RoleId` | string matching `^[a-z0-9][a-z0-9-]{15,63}$` | +| `RunId` | string matching `^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$` | +| `SemVer` | string matching `^(0\|[1-9][0-9]*)\.(0\|[1-9][0-9]*)\.(0\|[1-9][0-9]*)(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`, with no leading zero in a numeric prerelease identifier | +| `Uint64String` | string matching `^(0\|[1-9][0-9]{0,19})$` whose mathematical value is at most `18446744073709551615` | +| `UtcMillis` | a real Gregorian instant matching `^20[0-9]{2}-(0[1-9]\|1[0-2])-([0-2][0-9]\|3[01])T([01][0-9]\|2[0-3]):[0-5][0-9]:[0-5][0-9]\.[0-9]{3}Z$`; UTC `Z`, exactly milliseconds, and no leap second | +| `Base64Url32` | string matching `^[A-Za-z0-9_-]{43}$` that decodes to exactly 32 bytes and re-encodes byte-for-byte | +| `Base64Url64` | string matching `^[A-Za-z0-9_-]{86}$` that decodes to exactly 64 bytes and re-encodes byte-for-byte | + +No timestamp offset, omitted or extra fractional digit, numeric epoch, local +time, or lower-case `z` is accepted. Nanoseconds, byte sizes, frame/sequence +counters, and durations use `Uint64String`, never a JSON number, so no value can +cross the IEEE-754 safe-integer boundary ambiguously. `schemaVersion` is the +JSON integer `1`; no other protocol field is a JSON number unless its range is +explicitly given below. + +SHA-256 over exact file bytes is the only digest algorithm. Every JSON protocol +file is RFC 8785 JCS UTF-8 with no BOM or trailing newline, and stored bytes must +equal JCS serialization of the already schema-valid value. JCS does not repair +input: duplicate keys, non-NFC strings, alternate timestamp/counter spellings, +unknown fields, and values outside the closed schema fail before +canonicalization. Each NDJSON line is one independently schema-valid JCS value +followed by exactly one LF, including the last line. The video is hashed as its +original bytes. Two separately maintained conforming serializers—one Node +implementation and one non-JavaScript implementation—must serialize every +committed positive fixture to identical bytes and SHA-256. Negative fixtures +cover key reordering stored without JCS, whitespace, `1.0`/exponent spellings, +duplicate keys, Unicode variants, timestamp variants, numeric large counters, +wrong array order, and every outer/nested extra field; semantic equivalence is +not an acceptance rule. + +**RC-pinned matrix and trust registry.** The already required committed +`docs/qualification/macos-google-meet.json` is the sole trust root; this adds no +artifact or phase. Its top-level object contains exactly `schemaVersion: 1`, +`matrixRevision: Token`, `rcSha: RcSha`, `trustRegistry`, and `entries`. +`entries` is a nonempty array sorted by `tupleId`; each entry contains exactly +`tupleId: Token`, `appSemver: SemVer` (without leading `v`), +`appCommitSha: RcSha`, `packageSha256: Sha256`, `macOSProductVersion` (three +dot-separated decimal components without leading zeroes), +`macOSBuildVersion: Token`, `architecture` (`"arm64"` or `"x64"`), +`chromeVersion` (four dot-separated decimal components without leading zeroes), +`meetBuildId: Token`, `display`, and `scopes`. `display` contains exactly +`displayId: Token`, `type` (`"internal"` or `"external"`), `pixelWidth` and +`pixelHeight` (JSON integers 1–32768), and `scaleFactor` (string matching +`^[1-4](\.[0-9]{1,3})?$`). `scopes` is exactly +`["entire-display","specific-window"]`. Every `appCommitSha` and trust entry +`rcSha` equals the top-level `rcSha`; tuple IDs are unique. + +`trustRegistry` is an array of 3–64 objects sorted by unsigned UTF-8 bytes of +`keyId`. Each object contains exactly `keyId` (string matching +`^[a-z0-9][a-z0-9._-]{15,63}$`), `publicKeyBase64Url: Base64Url32`, `purpose`, +`role`, `status` (`"active"` or `"revoked"`), and `rcSha: RcSha`. The only legal +purpose/role pairs are: + +| `purpose` | `role` | +|---|---| +| `"qualification-role-attestation"` | `"local-operator"` | +| `"qualification-role-attestation"` | `"remote-observer"` | +| `"qualification-independent-review"` | `"independent-reviewer"` | +| `"qualification-release-bundle"` | `"release-bundle"` | + +There is at least one active key for each of the first three rows. A release- +bundle key is optional, but every such key and every key referenced anywhere +must occur exactly once in this registry at the exact RC SHA. `keyId` values and +decoded public-key bytes are globally unique across the registry. A key cannot +be reused for another role or purpose; local operator, remote observer, +independent reviewer, and release signer must all be different keys. Unknown, +revoked, wrong-purpose, wrong-role, duplicate-ID, reused-role, same-public-key, +RC-mismatched, or malformed entries block acceptance. `collection.json` and +signature files reference trusted `keyId` values; they never carry or override +public-key bytes. Verification always loads the matrix from a clean checkout at +its exact `rcSha`, closing the self-pinning dependency. + +**Exact `collection.json` schema.** The top-level object contains exactly these +required keys and values: + +| Key | Type and constraint | +|---|---| +| `schemaVersion` | integer constant `1` | +| `kind` | string constant `"qualification-collection"` | +| `rcSha` | `RcSha` | +| `procedureId` | `"P12-M01"` for entire-display or `"P12-M02"` for specific-window | +| `matrixRevision`, `tupleId` | `Token`; exact matrix values | +| `scope` | `"entire-display"` or `"specific-window"`; agrees with `procedureId` | +| `runId` | `RunId` | +| `app` | closed object defined below | +| `environment` | closed object defined below | +| `roles` | closed object defined below | +| `timestamps` | closed object defined below | +| `monotonicNs` | closed object defined below | +| `marker` | closed object defined below | +| `control` | closed object defined below | +| `pairingChallengeSha256` | `Sha256` | +| `validator` | closed object defined below | +| `contentResult` | closed object defined below | +| `evidenceMembers` | exact ordered eight-entry array defined below | + +`app` contains exactly `semver: SemVer`, `commitSha: RcSha`, +`packageSha256: Sha256`, `signingTeamId` (string matching +`^[A-Z0-9]{10}$`), `signingCertificateSha256: Sha256`, and +`notarizationTicketId: Token`. `environment` contains exactly +`macOSProductVersion`, `macOSBuildVersion`, `architecture`, `chromeVersion`, +`meetBuildId`, and `display`, with values and nested display schema identical to +the selected matrix entry. `roles` contains exactly `localOperator` and +`remoteObserver`; each contains exactly `roleId: RoleId` and `keyId` matching an +active trust-registry entry for that exact role. The two role IDs, key IDs, and +public keys are pairwise different. + +`timestamps` contains exactly `startedAt`, `shareStartedAt`, `shareStoppedAt`, +and `endedAt`, all `UtcMillis` and strictly increasing. `monotonicNs` contains +the same four key names, all `Uint64String`, strictly increasing by mathematical +value; `shareStoppedAt - shareStartedAt` is at least 120 seconds in both UTC and +monotonic time. `marker` contains exactly `algorithm: +"ic-marker-quadrants-v1"`, `seed: Sha256`, `cadenceHz: "4"`, and +`sizePixels: "256"`. `control` contains exactly `algorithm: +"ic-control-checker-v1"`, the same `seed`, `cadenceHz: "2"`, and +`gridSize: "8"`. These small counters are strings intentionally; alternative +numeric spellings fail. + +`validator` contains exactly `version` (canonical SemVer) and `commitSha: +RcSha`, which equals the RC SHA. `contentResult` contains exactly `result: +"pass"`, `markerDetectedFrames: "0"`, `markerContinuityPpm`, +`controlRecognizedPpm`, and `validSharedIntervalFrames`, with the last three +values as `Uint64String`; both ppm values are 995000–1000000 and the frame count +is nonzero. An accepted bundle cannot encode a failure or abort. + +Each `evidenceMembers` element contains exactly `path`, `bytes: +Uint64String`, and `sha256: Sha256`; `bytes` is mathematically nonzero. The array +is exactly the following ASCII path order and never includes `collection.json`, +which cannot describe its own bytes: + +```text +derived/control-coverage.json +derived/frame-analysis.ndjson +raw/local-control-events.ndjson +raw/local-marker-events.ndjson +raw/local-preflight.json +raw/remote-observer-events.ndjson +raw/remote-observer.mov +validation/report.json +``` + +NDJSON event records contain exactly `schemaVersion: 1`, `sequence: +Uint64String`, `at: UtcMillis`, `monotonicNs: Uint64String`, `frameId: +Uint64String`, `eventType`, and a closed event-type-specific `payload` from the +committed schema inventory. Sequences start at `"0"`, increase by exactly one, +and monotonic values strictly increase per file. Source video is at least +1080p, 24 fps, includes the 15/120/15-second segments, and retains original timestamps; derived frames never replace it. -**Canonical bytes and exact manifest membership.** SHA-256 over exact file -bytes is the only digest algorithm; hashes are 64 lowercase hexadecimal -characters. Every JSON file is RFC 8785 JSON Canonicalization Scheme (JCS) UTF-8 -with no BOM or trailing newline, and its stored bytes must equal canonicalized -bytes. Each NDJSON line is one JCS value followed by exactly one LF, including -the last line. The video is hashed as its original bytes. Manifest entries have -exactly `path`, `bytes`, and `sha256`; entries sort by unsigned UTF-8 bytes of -their ASCII POSIX relative `path`. Duplicate, absolute, empty, dot-segment, -backslash, non-NFC, or case-colliding paths fail. +**Exact manifest schemas and membership.** A manifest object contains exactly +`schemaVersion: 1`, `kind`, `algorithm: "sha256"`, and `entries`. Every entry +contains exactly `path`, `bytes: Uint64String`, and `sha256: Sha256`; byte size +is nonzero. Entries sort by unsigned UTF-8 bytes of their ASCII POSIX relative +`path`. Duplicate, absolute, empty, dot-segment, backslash, non-NFC, or case- +colliding paths fail. `evidence-manifest.json` has exactly `schemaVersion: 1`, `kind: "evidence"`, `algorithm: "sha256"`, and an `entries` array containing exactly these nine @@ -2037,23 +2185,54 @@ bytes; no member refers to that digest. `validation/report.json` is the frozen content-analysis result and does not claim to validate a manifest or attestation that does not yet exist. -Each role attestation is a JCS object containing exactly `payload` and -`signature`. The payload contains schema version, procedure/matrix/tuple/scope/ -run identity, role and pseudonymous role ID, every required acknowledgement, -observed result, deviations/aborts, RFC3339 timestamp, and the exact lowercase -`evidenceManifestSha256`. The signature contains exactly `algorithm: -"Ed25519"`, the matching pre-registered `keyId`, and an unpadded base64url -value. The role signs the ASCII domain separator -`InterviewCopilot qualification attestation v1\n` followed by the JCS bytes of -`payload`; Ed25519's deterministic signature and the pinned public key make the -payload and stored attestation bytes independently verifiable. Local and remote -roles, IDs, keys, and signatures must differ. - -`bundle-metadata.json` is JCS and contains exactly `schemaVersion`, +**Closed role attestations and acknowledgements.** Each role-attestation file +is a JCS signature envelope containing exactly `payload` and `signature`. +`signature` contains exactly `algorithm: "Ed25519"`, `keyId`, and `value: +Base64Url64`. The payload contains exactly `schemaVersion: 1`, `kind: +"qualification-role-attestation"`, `rcSha: RcSha`, `procedureId`, +`matrixRevision`, `tupleId`, `scope`, `runId`, `role` (`"local-operator"` or +`"remote-observer"`), `roleId: RoleId`, `keyId`, `acknowledgements`, +`observedResult: "pass"`, `deviations: []`, `aborts: []`, `attestedAt: +UtcMillis`, and `evidenceManifestSha256: Sha256`. Identity fields exactly match +`collection.json`; both payload and signature `keyId` values are equal and +resolve to the active matrix key for the payload role. `attestedAt` is after +that role's final acknowledgement and no later than collection `endedAt`. + +Every acknowledgement is a closed object containing exactly +`acknowledgementId`, `role`, `scope`, `result: "acknowledged"`, `at: +UtcMillis`, and `monotonicNs: Uint64String`. Its role/scope match the payload; +times are strictly increasing within each array. The arrays have exactly these +IDs in exactly this order (the slash selects the value for M01/M02): + +| Role/scope | Exact ordered `acknowledgementId` values | +|---|---| +| local operator / M01 entire-display | `preflight-ready`; `meet-two-party-confirmed`; `personal-content-absent`; `entire-display-share-selected`; `remote-observation-start-received`; `continuous-interval-complete`; `presentation-stop-commanded`; `raw-streams-finalized` | +| local operator / M02 specific-window | `preflight-ready`; `meet-two-party-confirmed`; `personal-content-absent`; `specific-window-share-selected`; `remote-observation-start-received`; `continuous-interval-complete`; `presentation-stop-commanded`; `raw-streams-finalized` | +| remote observer / M01 entire-display | `recorder-armed`; `meet-two-party-confirmed`; `entire-display-presentation-received`; `presentation-pinned`; `control-seed-readable`; `observation-start-acknowledged`; `continuous-interval-complete`; `presentation-stopped`; `raw-upload-complete` | +| remote observer / M02 specific-window | `recorder-armed`; `meet-two-party-confirmed`; `specific-window-presentation-received`; `presentation-pinned`; `control-seed-readable`; `observation-start-acknowledged`; `continuous-interval-complete`; `presentation-stopped`; `raw-upload-complete` | + +The remote `observation-start-acknowledged.at` equals collection +`shareStartedAt`; `presentation-stopped.at` equals collection `shareStoppedAt`. +The local `raw-streams-finalized.at` is no later than collection `endedAt`. +Acknowledgement order, role, scope, constant, timestamp representation, and +monotonic progression are schema assertions, not free-form notes. + +The exact signed bytes are the UTF-8/ASCII bytes of +`InterviewCopilot qualification role attestation v1\n` (one LF, no NUL), +immediately followed by the JCS UTF-8 bytes of `payload`, with no trailing byte. +Ed25519 signs those bytes directly, not their hexadecimal display or an extra +hash. Local and remote roles, IDs, keys, payload bytes, and signatures differ. + +**Closed bundle metadata.** `bundle-metadata.json` contains exactly +`schemaVersion: 1`, `kind: "qualification-bundle-metadata"`, `rcSha: RcSha`, `procedureId`, `matrixRevision`, `tupleId`, `scope`, `runId`, -`evidenceManifestSha256`, `localAttestationSha256`, -`remoteAttestationSha256`, `finalizedAt`, `retentionDeleteAt`, and -`encryptedStoreId`. It cannot contain a bundle digest or signature. +`evidenceManifestSha256: Sha256`, `localAttestationSha256: Sha256`, +`remoteAttestationSha256: Sha256`, `finalizedAt: UtcMillis`, +`retentionDeleteAt: UtcMillis`, and `encryptedStoreId` (string matching +`^[a-z0-9][a-z0-9._-]{15,127}$`). Identity fields match the collection and +attestations; the three hashes equal exact canonical file bytes; +`retentionDeleteAt` is later than `finalizedAt`. It cannot contain a bundle +digest, signature, public key, acknowledgement, or additional field. `bundle-manifest.json` has the same four manifest fields as the evidence manifest except `kind: "bundle"`, and its exact ordered membership is: @@ -2066,13 +2245,22 @@ evidence-manifest.json The final bundle digest is SHA-256 of canonical `bundle-manifest.json` bytes. The manifest explicitly excludes itself, all nine evidence files already -committed through the evidence manifest, and `bundle-manifest.sig`. If the -optional detached JCS signature exists, it contains exactly `schemaVersion`, -`algorithm: "Ed25519"`, release `keyId`, `bundleManifestSha256`, and unpadded -base64url `signature`. The release key signs -`InterviewCopilot qualification bundle v1\n` followed by the lowercase bundle -digest. The signature file's own bytes are never in that digest. No other file -is allowed in an accepted run root. +committed through the evidence manifest, and `bundle-manifest.sig`. + +If `bundle-manifest.sig` is present, it is a closed JCS envelope with exactly +`payload` and `signature`. Its payload contains exactly `schemaVersion: 1`, +`kind: "qualification-release-bundle"`, `rcSha: RcSha`, `keyId`, +`bundleManifestSha256: Sha256`, and `signedAt: UtcMillis`; its signature uses +the exact common `{algorithm,keyId,value}` schema. Both key IDs are equal and +resolve to an active `qualification-release-bundle`/`release-bundle` matrix +entry. The signed bytes are exactly the ASCII/UTF-8 domain separator +`InterviewCopilot qualification release bundle v1\n` followed immediately by +JCS payload bytes, with no trailing byte. If the file is absent, no release +signature is inferred or required and required role/reviewer checks still +apply. If it is present, every schema, RC/key-purpose, digest, timestamp, and +Ed25519 check is mandatory; any failure blocks acceptance. The signature file's +own bytes are never in the digest. No other file is allowed in an accepted run +root. **Acyclic finalization and overwrite rules.** The collector uses a newly and exclusively created sibling `.partial` directory; it never imports or @@ -2084,8 +2272,9 @@ reuses a supplied run. It performs this sole legal order: 3. Hash the exact nine-member allowlist, create `evidence-manifest.json`, rehash every member, and freeze both the members and manifest. 4. Send only the evidence-manifest canonical bytes/digest to both roles. Create - each independently signed attestation once; verify its payload, pinned key, - canonical bytes, signature, and evidence digest before freezing it. + each independently signed attestation once; verify its payload, matrix- + trusted role key, canonical bytes, signature, acknowledgements, and evidence + digest before freezing it. 5. Create and freeze `bundle-metadata.json`; hash exactly it, the evidence manifest, and both frozen attestations into `bundle-manifest.json`; then compute and freeze the final bundle digest. @@ -2093,13 +2282,17 @@ reuses a supplied run. It performs this sole legal order: graph without writing inside it, set files to 0400 and directories to 0500, fsync, and atomically rename the staging directory to ``. -Creation is exclusive and write-once. A collision, changed size/hash/mtime, -second write, regenerated manifest or attestation, file with link count other -than one, symlink, non-regular file, unexpected path, or failure after any -freeze point rejects and retains the run as failed, except the privacy-deletion -rule below; retry uses a new run ID. Neither collector nor validator repairs, -normalizes, deletes, or overwrites an accepted or retained failed run. This gives -the only dependency graph: +Creation is exclusive and write-once. The live collector owns open file +descriptors and an in-memory creation ledger; exclusive-create collisions, +close-then-write attempts, a second create/write/rename for any path, changed +size/hash/mtime while the collector is running, regenerated manifests or +attestations, link count other than one, links/non-regular files, unexpected +paths, or failure after a freeze point reject and retain the run as failed, +except the privacy-deletion rule below. Retry uses a new run ID. Collector tests +exercise first-touch, second-write, regeneration, and mutate-then-restore before +finalization while the ledger and handles can observe that history. Neither +collector nor validator repairs, normalizes, deletes, or overwrites an accepted +or retained failed run. This gives the only dependency graph: ```text raw -> derived/content-validation -> collection -> evidence-manifest @@ -2107,12 +2300,25 @@ evidence-manifest -> local-attestation evidence-manifest -> remote-attestation evidence-manifest + both-attestations -> bundle-metadata evidence-manifest + both-attestations + bundle-metadata -> bundle-manifest -bundle-manifest-digest -> optional-detached-signature +bundle-manifest-digest -> optional-release-signature ``` Every edge points from an already frozen node to a newly created node; no node hashes itself or any descendant. +The expanded commitment inventory has exactly 16 nodes: the nine evidence +members, evidence manifest, two role attestations, bundle metadata, bundle +manifest, optional bundle signature, and detached independent-review record. +It has exactly 28 directed edges: the eight non-collection evidence members to +collection; all nine evidence members to evidence manifest; evidence manifest +to each role attestation; evidence manifest plus both attestations to bundle +metadata; the four exact bundle members to bundle manifest; bundle manifest to +the optional signature; and bundle manifest to detached review. The matrix +trust registry and externally hashed reviewer work products are RC-pinned trust +inputs, not accepted-run members or additional finalization nodes. A +topological-sort fixture proves all 16 nodes are visited with 28 edges and zero +cycle. + **Privacy and redaction.** Use only the dedicated names, synthetic control content, and a disposable meeting. Do not enable audio/video/chat/captions or show email addresses, calendars, notifications, browser profiles, interview @@ -2128,19 +2334,49 @@ documents encrypted access, named independent reviewers, and retention/deletion date; public evidence contains only hashes, tuple metadata, counts, and the redacted copy. -**Validation, exits, and independent reproduction.** Within `qualify:meet`, the -validator is read-only. Before content assertions it rejects any noncanonical -serialization/path/order/mode, missing or extra file/entry, forbidden manifest -member, self-reference, size/hash mismatch, evidence or bundle digest mismatch, -unpinned/same-role/invalid attestation signature, identity/digest disagreement, -invalid optional detached signature, post-freeze mutation, `.partial` root, or -non-regular/linked file. It then verifies versions/signing, timing, frame -decode/continuity, positive detector corpus, marker absence, control visibility, -and M01/M02 completeness. The validator writes only to the reporter's separate -log directory. Its tests construct the valid graph, reproduce identical -manifest and signature bytes from canonical inputs, topologically prove the -edge list above, and mutate every member class plus each include/exclude rule to -prove a nonzero result. +**Offline acceptance boundary.** Within `qualify:meet`, the final-state +validator is read-only. Its acceptance proof is deliberately limited to the +bytes and filesystem state it can observe: exact canonical bytes, closed +schemas, byte sizes and hashes, path/order/membership, regular-file status, +link-count-one/no-link constraints, final 0400/0500 modes, identities, matrix/RC +trust lookup, key purpose/role/status/distinctness, and signatures. It then +verifies versions/signing, timing expressed in the records, frame decode/ +continuity, the positive detector corpus, marker absence, control visibility, +and M01/M02 completeness. It rejects `.partial` roots and writes only to the +reporter's separate log directory. + +The offline validator does not claim to observe filesystem history. It cannot +prove first touch, historical mtime changes, a prior second write, +regeneration, or mutate-and-restore when the restored final bytes and observable +metadata are identical. Those remain exclusive/write-once/freeze collector +runtime rules and runtime tests. A changed final byte, size, hash, mode, path, +link status, schema, identity, trust binding, or signature fails; an +identical restored final state does not disclose how it was produced. No audit +store is invented. + +The validator test suite constructs the valid graph, reproduces identical +manifest/envelope bytes from canonical inputs, topologically proves the exact +16-node/28-edge inventory, and applies final-state mutations to every member +class plus every include/exclude, schema, identity, trust, key-purpose, domain- +separator, and optional-signature rule. Mutation fixtures claim only observable +final-state rejection; separate collector-runtime fixtures make the historical +write assertions. + +`scripts/qualification/schema-inventory.test.ts` inventories the committed +closed schemas for the matrix, each of the four NDJSON event payload families, +local preflight, control coverage, frame analysis, content-validation report, +collection, manifest/entry, acknowledgement, role attestation, bundle metadata, +optional bundle signature, and detached review. It recursively fails any +object schema missing `additionalProperties: false`, any unconstrained array, +unknown union arm, unsafe integer counter, non-exact time format, or missing +positive/negative fixture. `scripts/qualification/canonical-bytes.test.ts` +runs the two independent serializer fixture sets and checks identical JCS bytes, +digests, exact domain separators, and rejection of noncanonical semantic +variants. `scripts/qualification/trust-registry.test.ts` probes unknown, +revoked, wrong-purpose, wrong-role, reused-role, duplicate-ID, same-public-key, +RC-mismatched, malformed, and collection-supplied-key cases. The artifact- +validator suite covers optional bundle signature absent, valid-present, and +invalid-present; only the first two pass. It prints one line per tuple/scope plus `passed= failed= skipped=` and exits 0 only when every matrix tuple has exactly one accepted M01 and M02 bundle, @@ -2149,23 +2385,67 @@ evidence, either attestation, either manifest, or the bundle metadata is a failure, never a skip. The P12 reporter preserves that raw exit and makes its aggregate nonzero otherwise. -An independent reviewer starts from a fresh clone at the exact RC SHA, obtains -the signed package and complete immutable bundle through the documented -encrypted release channel, recomputes both manifest digests from canonical -bytes, walks every allowlist edge, verifies both role signatures against the -keys pinned in `collection.json`, and runs the complete P12 reporter command -below. To reproduce collection rather than only validate, the reviewer uses a -fresh checkout with no `.artifacts/qualification`, the same exact matrix -hardware/software/display tuple, new dedicated accounts/meeting, and the two -launch commands above; absent evidence automatically launches M01 then M02. +**Detached independent review.** An independent reviewer starts from a fresh +clone at the exact RC SHA, obtains the signed package and complete immutable +bundle through the documented encrypted release channel, recomputes both +manifest digests from canonical bytes, walks every allowlist edge, verifies both +role signatures against the RC matrix registry, and runs the complete P12 +reporter command below. To reproduce collection rather than only validate, the +reviewer uses a fresh checkout with no `.artifacts/qualification`, the exact +matrix hardware/software/display tuple, new dedicated accounts/meeting, and the +two launch commands above; absent evidence automatically launches M01 then M02. The reviewer watches the full remote shared intervals plus pre/post boundaries, checks at least the first/last and one frame from every 15-second marker-position epoch against `frame-analysis.ndjson`, and verifies ordinary underlying content -remains readable. The review attestation signs the final bundle digest and is -stored as a detached review record outside the accepted run root, so review -cannot mutate or become a dependency of the bundle it reviews. Any disagreement, -non-reproducible tuple, graph/byte mismatch, or changed version creates a new -failed/retest-required record and blocks the claim. +remains readable. + +For each accepted run the record is stored at exactly +`.artifacts/qualification-reviews/////independent-review.json`. +Every variable path segment must pass its schema lexical rule and exact identity +match. This path is outside the run root, evidence manifest, bundle manifest, +and optional bundle signature; it is never copied into accepted membership. + +The record is a closed JCS `{payload,signature}` envelope using the common +signature schema. Its payload contains exactly `schemaVersion: 1`, `kind: +"qualification-independent-review"`, `rcSha: RcSha`, `matrixRevision`, +`tupleId`, `scope`, `runId`, `bundleManifestSha256: Sha256`, `reviewerId: +RoleId`, `keyId`, `result: "pass"`, `reviewedAt: UtcMillis`, `reports`, and +`observations`. `reports` contains exactly `artifactValidatorReportSha256`, +`packagePolicyReportSha256`, `frameSamplingReportSha256`, and +`claimScanReportSha256`, all `Sha256` of retained reviewer outputs outside the +accepted run. `observations` contains exactly the following keys and pass +values: `canonicalBytesReproduced: true`, `manifestGraphAcyclic: true`, +`roleSignaturesValid: true`, `trustRegistryValid: true`, +`remoteIntervalsWatched: true`, `firstAndLastFramesChecked: true`, +`eachFifteenSecondEpochChecked: true`, `underlyingContentReadable: true`, +`livePairingReproduced` (boolean), `sampledFrames: Uint64String` with +mathematical value at least 10, and `reproductionRunId` (`RunId` when that +boolean is true, otherwise JSON `null`). At least one accepted review record per +matrix revision has `livePairingReproduced: true`, preserving the required one +clean live-paired reproduction without pretending every retained run was +recollected. Identity and bundle digest match the reviewed bundle. Both key IDs +are equal and resolve only to an active +`qualification-independent-review`/`independent-reviewer` key at the RC SHA, +distinct from both role keys and any release-bundle key. + +The exact signed bytes are the ASCII/UTF-8 domain separator +`InterviewCopilot qualification independent review v1\n` followed immediately +by JCS payload bytes, with no trailing byte. Missing record, wrong external +path, failed/unknown result, missing report hash or observation, identity/RC/ +digest disagreement, unknown/wrong-purpose/reused key, noncanonical bytes, or +bad signature blocks `verify:release` and the P12 aggregate. + +No reporter plan entry or ad-hoc shell command is added. The existing +`qualify:meet --collect-missing` child validates bundles and, when run by the +configured independent reviewer after the required prompts/checks, writes and +immediately verifies this detached record outside the run root. The already- +planned final `verify:release` child requires and revalidates the exact record +for every accepted M01/M02 run. An initial collector run may therefore finish +collection but cannot make the release aggregate green until independent +review exists; the final unchanged P12 reporter rerun must have all raw exits +zero. Any disagreement, non-reproducible tuple, graph/byte mismatch, or changed +version leaves external reporter failure evidence, produces no qualifying +`result: "pass"` review envelope, and blocks the claim. **Clean-checkout setup.** Requires supported macOS, Chrome, Meet test account, remote observer/second device, signing/notarization credentials, and both @@ -2199,7 +2479,9 @@ executes all three frozen cases. Every test-classified reporter entry prints passed/failed/skipped totals. **Regression suite.** the entire P01–P11 suite, native audio, all mode fixtures, migrations, storage plaintext scans, shell/capture integration, package smoke tests, and release -claim/deferred-scope scans. +claim/deferred-scope scans. The later existing `verify:release` entry makes the +unchanged reporter aggregate nonzero unless every accepted run also has its +valid external independent-review envelope. **Docs.** Exact supported tuple matrix/date, guided verification, stale rules, D-005g headline/qualifier, limitations/non-security-boundary, permissions, @@ -2207,8 +2489,9 @@ provider/audio/storage/privacy, diagnostics, AGPL/source offer, macOS install/ uninstall/update, release evidence, SBOM/vulnerability disposition, and explicit Windows/Linux/app/scope deferrals. Release docs also publish the exact parent/ inherit entitlement tables, frozen Staff-live corpus hash/assertion summary, -both manifest schemas/memberships/digests, signature verification result, and -detached independent-review record. +closed schema inventory, RC-pinned trust registry, both manifest schemas/ +memberships/digests, signature verification result, and detached independent- +review record. **Completion evidence.** (1) SHAs/base/version; (2) every raw gate/count report; (3) signed/notarized arm64/x64 hashes and package-policy report; (4) role-by- @@ -2216,11 +2499,14 @@ role extracted entitlement plist diff, SBOM, and vulnerability disposition; (5) protection trace; (6) exact no-wildcard matrix; (7) per-tuple P12-M01/M02 raw recording/content analysis, exact evidence-manifest membership/digest, both canonical signed role attestations, bundle metadata, final bundle-manifest -membership/digest, and optional detached signature; (8) validator proof of the -acyclic graph plus mutation/include/exclude failure fixtures; (9) verification- +membership/digest, and optional release signature absence/presence result; (8) +validator proof of the 16-node/28-edge acyclic graph plus final-state mutation/ +include/exclude, recursive-schema, canonical-byte, trust/key-purpose, and exact- +domain failure fixtures, alongside separate collector write-history tests; (9) verification- state/stale trace; (10) diagnostic preview/network-zero trace; (11) scoped recovery E2E; (12) claim/deferred scan; (13) frozen Staff-live corpus hash plus -all case/assertion counts; (14) detached independent-review sign-off over the +all case/assertion counts; (14) mandatory detached independent-review envelope, +external path, report hashes, observations, key lookup, and signature over the final bundle digest that supports every public claim. **Risk/complexity.** Release-blocking/very high. External capture behavior and @@ -2228,7 +2514,7 @@ signing infrastructure cannot be inferred from unit tests. **Self-contained implementation prompt.** -> Implement P12 from P00-R3 after P01–P11 on +> Implement P12 from P00-R4 after P01–P11 on > `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ > architecture matrix, harden macOS-only package/entitlements/identity, add > local-only redacted diagnostic preview/export, scoped failure recovery, @@ -2240,11 +2526,15 @@ signing infrastructure cannot be inferred from unit tests. > plan including artifact validation and the SHA-pinned three-case Staff-live > corpus. Implement the exact write-once evidence-manifest → two independent > role attestations → final bundle-manifest/digest sequence, canonical bytes, -> memberships, exclusions, detached-signature rule, and read-only validator. -> Attach every enumerated artifact. A failed/incomplete tuple, cyclic/extra/ -> missing/mutated bundle member, invalid signature, extra or missing entitlement, -> corpus assertion failure, or skipped case blocks release; never infer pass or -> accept pre-existing files without complete read-only validation. +> recursively closed schemas, matrix-pinned role/reviewer/release trust, +> memberships, exclusions, exact signature domains, optional release-signature +> absence/presence rules, mandatory external review, and read-only validator. +> Enforce first-touch/write-once/freeze in the live collector while limiting +> offline claims to observable final state. Attach every enumerated artifact. A +> failed/incomplete tuple, cyclic/extra/missing member, observable final-byte or +> trust/signature mismatch, missing review, extra or missing entitlement, corpus +> assertion failure, or skipped case blocks release; never infer pass or accept +> pre-existing files without complete read-only validation. **Self-contained review prompt.** @@ -2255,14 +2545,18 @@ signing infrastructure cannot be inferred from unit tests. > verify remote Meet raw artifacts/control frames, canonical evidence manifest, > independently signed role attestations, bundle metadata/final digest, exact > include/exclude rules, and acyclic dependency graph for both scopes/ -> architectures, and reproduce one clean live-paired tuple. Verify +> architectures, recursively closed schemas, RC-pinned key purposes, exact +> signature domains, optional release-signature semantics, and reproduce one +> clean live-paired tuple. Verify > the frozen Staff-live corpus hash and every structural assertion, force stale/ > failed records, inspect diagnostic network/content traces, and scan every > shipped string. Reject missing tuple evidence, local-only confirmation, > broadened claim, unsupported platform/app/scope, entitlement drift, telemetry, -> corpus mutation/failure, self-reference, post-signing mutation, invalid role or -> bundle signature, skipped test, vulnerability without disposition, or any -> nonzero child/aggregate gate. Store review sign-off outside the immutable run. +> corpus mutation/failure, self-reference, observable final-byte mismatch, +> invalid role/reviewer/release signature or trust binding, skipped test, +> vulnerability without disposition, or any nonzero child/aggregate gate. Sign +> the closed review envelope at its exact external path; do not claim the offline +> validator proves write history. **Remediation prompt template.** @@ -2273,8 +2567,8 @@ signing infrastructure cannot be inferred from unit tests. > `{P12 named test/validator}`, rebuild and rerun the complete P12 sequence and > both live-paired remote qualifications for every affected tuple, then return > every reporter raw exit/count and aggregate exit, entitlement diff, corpus -> counts, both manifest memberships/digests, role/detached-signature results, -> matrix revision, and new SHAs. +> counts, both manifest memberships/digests, schema/canonical/trust probes, +> role/release/reviewer signature results, matrix revision, and new SHAs. ## 8. Requirement ownership matrix From 8820b6c848d96162bb63315c329a52b328d415e5 Mon Sep 17 00:00:00 2001 From: Timomak Date: Sun, 26 Jul 2026 20:33:57 +0200 Subject: [PATCH 5/9] docs: make P00 release qualification constructible --- design.md | 6 +- docs/implementation/phase-execution-packet.md | 465 ++++++++++++------ 2 files changed, 325 insertions(+), 146 deletions(-) diff --git a/design.md b/design.md index 5ef913f3..99bc6117 100644 --- a/design.md +++ b/design.md @@ -316,7 +316,7 @@ Capture privacy is a tested platform capability, not a UI setting or an inferred - macOS is the only launch engineering and capture-privacy qualification target. Windows and Linux application support and capture qualification are deferred to a later phase. - The existing macOS build has already passed real entire-display and specific-window screen-sharing tests and both behaviors must be preserved as launch regression baselines. Electron's documented ScreenCaptureKit limitation means these results cannot be generalized to every application or version without testing. - Entire-display, specific-window, and browser-tab sharing remain separate macOS qualification paths. The first two have an observed working baseline; browser-tab sharing and every named launch application still require explicit verification. -- Google Meet is the only conferencing product in the initial launch qualification matrix. A final test of the release build on the supported macOS and browser versions is a mandatory release gate. Zoom, Microsoft Teams, and other sharing or recording products are deferred and must not inherit the Google Meet claim without their own tests. +- Google Meet is the only conferencing product in the initial launch qualification matrix. That committed matrix freezes only the exact pre-release environment/scope policy and purpose-separated verification keys. A final test of the externally selected release commit's signed/notarized build on those macOS and browser versions is a mandatory release gate, and a required detached post-build release statement binds that commit, the matrix bytes, and the package identity without creating a Git self-reference. Zoom, Microsoft Teams, and other sharing or recording products are deferred and must not inherit the Google Meet claim without their own tests. - Do not add an application-agnostic “Test My Setup” flow at launch. Arbitrary capture software cannot be meaningfully certified by a generic self-test, and the extra setup would add disproportionate complexity. Keep verification limited to explicitly qualified integrations. - The implementation safeguard is centralized in `electron/captureProtection.ts`. Every InterviewCopilot `BrowserWindow` must call `applyCaptureProtection` immediately after creation and whenever a lifecycle path can recreate or materially reconfigure the window. A unit guard ensures that helper always invokes `setContentProtection(true)`. Removing, bypassing, or weakening this helper is a release-blocking change and still requires the external Google Meet regression test because unit coverage cannot inspect captured frames. - Settings → Privacy & Capture includes a guided Google Meet verification. It walks the user through entire-display and specific-window sharing with a conspicuous animated test marker and requires confirmation from Meet's remote presentation view or a second participant/device for each scope. The app never infers a pass from the local preview alone. @@ -781,7 +781,7 @@ Decisions are resolved in dependency order. A later branch may be reordered when | D-005b | Resolved | Treat InterviewCopilot as a neutral tool and enforce no responsibility notice or consent gate. | Onboarding and session start remain frictionless. The product does not repeatedly interrupt the live workflow with usage confirmations. | | D-005c | Resolved constraint | Limit the promise to exclusion from ordinary screen sharing and recording on explicitly qualified configurations. | Capture privacy remains release-critical and testable. The product will not hide its process, tamper with monitoring, spoof platform state, or attempt to evade anti-cheating or proctoring controls. | | D-005d | Resolved | Make macOS the only initial engineering and capture-privacy qualification target; defer Windows and Linux. | The launch matrix stays narrow enough to test rigorously. Capture scopes and applications qualify independently; Google Meet already provides the observed entire-display and specific-window baseline recorded under D-005e. | -| D-005e | Resolved for launch | Require the release build to pass Google Meet entire-display and specific-window sharing tests on the supported macOS/browser matrix. | Both scopes already have an observed working baseline. The final test is a release gate; Zoom, Teams, browser-tab sharing, and other capture products remain unqualified until independently tested. | +| D-005e | Resolved for launch | Require the externally selected release commit's signed/notarized build to pass Google Meet entire-display and specific-window sharing tests on the committed supported macOS/browser matrix. | Both scopes already have an observed working baseline. The immutable checkout supplies the expected commit and matrix/key policy; a mandatory detached post-build statement supplies the package identity. The final test is a release gate; Zoom, Teams, browser-tab sharing, and other capture products remain unqualified until independently tested. | | D-005f | Resolved | Provide a guided Google Meet test and show verified status only for the recorded Mac, browser, app version, and passing capture scopes. | Verification requires confirmation from the remote Meet view or a second device, becomes stale after capture-relevant app changes or major OS/browser changes, and never implies universal invisibility. The underlying `setContentProtection(true)` path is centralized and unit-guarded. | | D-005g | Resolved | Lead with “Stay private while you share your screen,” then state that InterviewCopilot is designed to stay out of ordinary macOS screen shares and recordings and that coverage varies by application and capture mode. | The product promise should describe the general user benefit rather than a Google Meet feature. Exact verified applications, modes, versions, and dates remain visible in Privacy & Capture, while universal undetectability and anti-monitoring claims remain out of scope. | | D-005h | Resolved | Omit an application-agnostic “Test My Setup” flow at launch. | A generic self-test creates setup cost without reliably certifying arbitrary capture implementations. Verification remains available only for explicitly qualified applications and capture modes. | @@ -863,5 +863,5 @@ Decisions are resolved in dependency order. A later branch may be reordered when The reviewed phase order, dependency graph, acceptance gates, migration owners, prototype disposition, and implementation/review/remediation prompts are defined in [`docs/implementation/phase-execution-packet.md`](docs/implementation/phase-execution-packet.md), -revision P00-R4. This design remains the product source of truth; the packet is +revision P00-R5. This design remains the product source of truth; the packet is the execution contract. Prototype evidence does not establish phase completion. diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md index 6832eefa..19938da1 100644 --- a/docs/implementation/phase-execution-packet.md +++ b/docs/implementation/phase-execution-packet.md @@ -1,6 +1,6 @@ # InterviewCopilot phase-execution packet -Packet revision: **P00-R4** +Packet revision: **P00-R5** Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` @@ -267,9 +267,13 @@ test-classified and must print passed/failed/skipped counts. The P12 row is complete and therefore does not receive the default manifest or build suffix. Package, diagnostics, Meet collection/validation, and final release validation are child commands of the same reporter and cannot bypass -its raw-exit aggregate. `qualify:meet` launches collection when evidence is -absent and performs the write-once manifest/attestation/bundle finalization in -P12-M01/M02; it is not an artifact-presence shortcut. +its raw-exit aggregate. `package:mac` invokes the controller-owned writer for +the mandatory external release statement only after signing/notarization/ +stapling; `verify:mac-package`, +`qualify:meet`, and `verify:release` require and validate but never synthesize +it. `qualify:meet` launches collection when evidence is absent and performs the +write-once manifest/attestation/bundle finalization in P12-M01/M02; it is not an +artifact-presence shortcut. The remote device also uses the reporter, with the exact invocation `npm run verify:phase -- --phase P12 --role meet-observer --pair --artifacts .artifacts/qualification-observer`. @@ -386,7 +390,7 @@ inside the single PR. **Self-contained implementation prompt.** -> Implement P01 from P00-R4 on `phase/P01-local-gates`, based only on upstream +> Implement P01 from P00-R5 on `phase/P01-local-gates`, based only on upstream > `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. > Make local lint, strict type-check, real unit tests (including the unchanged > tracked CRA sample), manifest enforcement, and build green. Centralize and @@ -398,7 +402,7 @@ inside the single PR. **Self-contained review prompt.** -> Review P01 independently against P00-R4, not the author’s summary. From the +> Review P01 independently against P00-R5, not the author’s summary. From the > clean PR checkout run the P01 reporter invocation, confirm the inherited CRA > test ran, > inspect all config/glob/ignore changes for hidden coverage loss, compare typed @@ -527,7 +531,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained implementation prompt.** -> Implement P02 from P00-R4 after P01, on +> Implement P02 from P00-R5 after P01, on > `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime > for Claude Code and Codex only, using one resumable session/thread, normalized > streaming/usage/compaction/stop/error events, explicit provider/model/Fast- @@ -540,7 +544,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained review prompt.** -> Review P02 against P00-R4 from a clean checkout. Trace both fake providers +> Review P02 against P00-R5 from a clean checkout. Trace both fake providers > through two turns, stop, compaction, driver/child restart, and caller-ID > resume; force every failure and prove the other provider never starts. Inspect > spawn/env/tool restrictions, IPC exposure, migration idempotence/file mode, @@ -653,7 +657,7 @@ never custom cryptography. **Self-contained implementation prompt.** -> Implement P03 from P00-R4 after P01 on +> Implement P03 from P00-R5 after P01 on > `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key > service, versioned AES-256-GCM record/blob store, atomic writes, encrypted > in-memory-search source, typed recovery, raw-audio rejection, and journaled @@ -801,7 +805,7 @@ boundary; no renderer or provider may keep a second authoritative session. **Self-contained implementation prompt.** -> Implement P04 from P00-R4 after P02/P03 on +> Implement P04 from P00-R5 after P02/P03 on > `phase/P04-session-orchestrator`. Replace global transient state with the > deterministic InterviewSession reducer, typed event/IPC contract, one > persistent-conversation orchestrator, context/delta policy, pending artifacts, @@ -936,7 +940,7 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained implementation prompt.** -> Implement P05 from P00-R4 after P04 on `phase/P05-live-shell`. Build the +> Implement P05 from P00-R5 after P04 on `phase/P05-live-shell`. Build the > exact Quiet Signal hidden/compact/answer/expanded shell, command rail, > composer, input tray, explicit click-through/drag regions, final remappable > shortcuts, display-aware geometry, primary-display screenshot behavior, @@ -1058,7 +1062,7 @@ regress silently; fixture contracts are merge-blocking. **Self-contained implementation prompt.** -> Implement P06 from P00-R4 after P05 on `phase/P06-coding`. Add the exact +> Implement P06 from P00-R5 after P05 on `phase/P06-coding`. Add the exact > typed Coding intents/schema/renderer, concise-first progressive answer, > language snapshot and six-family fixtures, read-only actions, New Question, > and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, @@ -1173,7 +1177,7 @@ must not become a second untyped document model. **Self-contained implementation prompt.** -> Implement P07 from P00-R4 after P05 on `phase/P07-system-design`. Add the +> Implement P07 from P00-R5 after P05 on `phase/P07-system-design`. Add the > fixed typed five-section progressive workflow, bounded material estimates, > safe vendor-neutral structured diagram, read-only accessible interactions, > assumption handling, dependency-scoped follow-up and What changed summary. @@ -1294,7 +1298,7 @@ integrity are product trust boundaries. **Self-contained implementation prompt.** -> Implement P08 from P00-R4 after P05 on `phase/P08-behavioral`. Build the +> Implement P08 from P00-R5 after P05 on `phase/P08-behavioral`. Build the > encrypted canonical candidate dossier, guided/manual reviewed editing, > sanitized Markdown import/export, multiple snapshotted opportunities, > provenance, opt-in labeled persistent synthetic stories, and typed Behavioral @@ -1427,7 +1431,7 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained implementation prompt.** -> Implement P09 from P00-R4 after P05 on `phase/P09-audio`, macOS only. Build +> Implement P09 from P00-R5 after P05 on `phase/P09-audio`, macOS only. Build > explicit two-source native capture, deterministic master/per-source controls, > contextual permission recovery, pinned offline whisper.cpp transcription, > explicit Apple Speech remote fallback, typed segments/attribution/correction, @@ -1546,7 +1550,7 @@ must never become a capability or schema escape hatch. **Self-contained implementation prompt.** -> Implement P10 from P00-R4 after P06/P07/P08 on +> Implement P10 from P00-R5 after P06/P07/P08 on > `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, > immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, > deterministic recorded instruction resolution, Start snapshotting, protected @@ -1663,7 +1667,7 @@ content and destructive user controls. **Self-contained implementation prompt.** -> Implement P11 from P00-R4 after P06–P10 on +> Implement P11 from P00-R5 after P06–P10 on > `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete > encrypted archive projection, Settings-only in-memory search/open/delete one/ > all, safe consented individual Markdown/JSON export, read-only archive open, @@ -1712,18 +1716,20 @@ Setup, anti-proctoring/process hiding/monitoring evasion, universal undetectability, analytics/crash upload, and automatic result inference from a local preview. -**Implementation requirements.** At RC cut, freeze exact InterviewCopilot -commit/version, the latest Apple-supported stable macOS patch available on each -claimed arm64/x64 test machine, current stable Chrome, Meet version, display -mode, and architecture. The shipped matrix contains full concrete values +**Implementation requirements.** Before RC cut, freeze the latest Apple- +supported stable macOS patch available on each claimed arm64/x64 test machine, +current stable Chrome, Meet version, display mode, and architecture. The +committed matrix contains only those full concrete pre-commit policy values (`ProductVersion` plus `BuildVersion`, Chrome four-part version, visible Meet -client/build identifier, app semver plus full commit SHA, architecture, display -pixel dimensions/scaling, and internal/external display type), never `latest`, -a range, or a wildcard. Those exact passing tuples—and no neighboring patch, -major version, browser, app build, architecture, or display mode—are the -supported macOS/browser/app versions until separately qualified. Qualify each -supported tuple separately. P00-R4 represents no version as supported before -that committed matrix and its evidence pass. Entire-display and specific-window +client/build identifier, architecture, display pixel dimensions/scaling, and +internal/external display type), never `latest`, a range, or a wildcard. The +external controller later pins the exact clean-checkout commit; the mandatory +detached statement binds its app semver and post-build package identity. Those +exact passing tuples—and no neighboring patch, major version, browser, app +build, architecture, or display mode—are the supported macOS/browser/app +versions until separately qualified. Qualify each supported tuple separately. +P00-R5 represents no version as supported before the committed matrix, detached +release statement, and evidence pass. Entire-display and specific-window require confirmation from remote Meet view or second device and retained high-contrast moving-marker artifacts; one fail makes the tuple unsupported; browser-tab remains unverified; verification state is @@ -1826,7 +1832,7 @@ for this gate. | P12-AC4: verification record contains exact app/commit/macOS/arch/Chrome/Meet/display/scopes/date/result plus evidence- and bundle-manifest digests, and state invalidates by specified changes. | `electron/privacy/verificationRecord.test.ts — versions verifies fails and stales exact tuples` | | P12-AC5: release-build Google Meet entire-display capture contains zero marker pixels while underlying control frames remain visible for every frozen tuple, with the accepted evidence bound by both independent role attestations and the final bundle digest. | `P12-M01 — remote Google Meet entire-display moving-marker qualification` | | P12-AC6: release-build Google Meet specific-window capture contains zero marker pixels while target-window control frames remain visible for every frozen tuple, with the accepted evidence bound by both independent role attestations and the final bundle digest. | `P12-M02 — remote Google Meet specific-window moving-marker qualification` | -| P12-AC7: any missing/failed scope or artifact, noncanonical or extra manifest member, self-reference, final-byte size/hash mismatch, schema/identity/trust/signature failure, or required detached-review failure produces Failed/Not verified and makes release qualification nonzero; local preview can never produce pass. Historical second writes or mutate-and-restore are collector-runtime concerns and are not inferred from an identical accepted final state. | `scripts/qualification/meet-artifact-validator.test.ts — rejects incomplete cyclic final-byte-mutated untrusted or local-only evidence` | +| P12-AC7: any missing/failed scope or artifact, missing/mismatched/invalid detached release statement, noncanonical or extra manifest member, self-reference, final-byte size/hash mismatch, schema/identity/trust/signature failure, or required detached-review failure produces Failed/Not verified and makes release qualification nonzero; local preview can never produce pass. Historical second writes or mutate-and-restore are collector-runtime concerns and are not inferred from an identical accepted final state. | `scripts/qualification/meet-artifact-validator.test.ts — rejects incomplete cyclic final-byte-mutated untrusted or local-only evidence` | | P12-AC8: diagnostics exclude transcript/audio/screenshots/prompts/responses/profile/opportunity/credentials/tokens/device IDs, preview before manual export, and perform zero network upload. | `electron/diagnostics/diagnosticPrivacy.test.ts — previews redacted local-only diagnostic export` | | P12-AC9: provider/microphone/system-audio/screen-capture denial disables only affected action and explicit repair/retry preserves the session. | `tests/release/scopedRecovery.e2e.test.ts — preserves session through every permission/provider failure` | | P12-AC10: shipped copy/docs contain only qualified D-005g language and no 99%, undetectable, bypass, anti-cheat, process-hiding, monitoring-evasion, or unsupported-app/platform claim. | `tests/release/claimPolicy.test.ts — rejects unqualified privacy and platform language` | @@ -1846,18 +1852,29 @@ is absent. A pre-existing artifact directory is accepted only after complete schema/canonical-byte/manifest/signature validation; an empty or partial directory triggers collection or a nonzero failure, never a presumed pass. -**Supported version rule and release prerequisite.** Before the first run, -`docs/qualification/macos-google-meet.json` must be committed at the RC SHA with -`schemaVersion: 1`, a matrix revision, and one entry per claimed tuple. Every -entry contains concrete app semver/full SHA, signed package SHA-256, macOS -`ProductVersion`/`BuildVersion`, `arm64` or `x64`, Chrome four-part version, -visible Meet build identifier, display ID/type/pixel dimensions/scale factor, -and both scopes. Wildcards, ranges, `latest`, missing architectures, or an -uncommitted matrix make preflight exit nonzero. Only exact passing entries are -supported. The installed app must be the matrix package built from the clean RC -SHA, Developer-ID signed, hardened-runtime enabled, notarized, stapled, accepted -by `spctl`, and passing `verify:mac-package`; a development/Electron launch or -ad-hoc signature aborts collection. +**Supported version rule and release prerequisite.** Before the RC is selected, +`docs/qualification/macos-google-meet.json` must be committed with +`schemaVersion: 1`, a matrix revision, and one pre-commit policy entry per +claimed tuple. Every entry contains the exact macOS `ProductVersion`/ +`BuildVersion`, `arm64` or `x64`, Chrome four-part version, visible Meet build +identifier, display ID/type/pixel dimensions/scale factor, and both scopes. +Wildcards, ranges, `latest`, missing architectures, or an uncommitted matrix +make preflight exit nonzero. The matrix deliberately contains no containing +commit SHA, app/package hash, notarization or staple output, build timestamp, +or detached-statement digest. + +The release controller externally selects the reviewed PR/release commit, +checks it out detached, proves the checkout is clean, and pins `git rev-parse +HEAD` in memory as `expectedRcSha` before reading any artifact. Both +`qualify:meet` and `verify:release` repeat that derivation independently and +accept no artifact field, CLI artifact value, environment value, pairing +message, or detached statement as a checkout selector or override. They freeze +and hash the exact committed matrix bytes as `matrixBlobSha256`. After the RC +exists and the signed/notarized packages are built, the release controller +creates the mandatory detached release statement defined below. Only a package +bound by that valid statement, Developer-ID signed, hardened-runtime enabled, +notarized, stapled, accepted by `spctl`, and passing `verify:mac-package` may be +collected; a development/Electron launch or ad-hoc signature aborts collection. **People, accounts, devices, and network.** Each run requires: @@ -1916,7 +1933,8 @@ npm run verify:phase -- --phase P12 --role meet-observer --pair :docs/qualification/macos-google-meet.json`, requires it to be +byte-for-byte identical to the clean worktree path, validates and hashes it +once, retains those exact bytes and the parsed registry in memory, and rechecks +HEAD, cleanliness, and that digest before exit. Its top-level object contains +exactly `schemaVersion: 1`, `matrixRevision: Token`, `trustRegistry`, and +`entries`. It contains only pre-commit-constructible policy and contains no +`rcSha`, app commit/version, package hash, signing result, notarization/staple +output, build timestamp, or detached-statement digest at any depth. + +`entries` is a nonempty array sorted by unsigned UTF-8 bytes of `tupleId`; each +entry contains exactly `tupleId: Token`, `macOSProductVersion` (three dot- +separated decimal components without leading zeroes), `macOSBuildVersion: +Token`, `architecture` (`"arm64"` or `"x64"`), `chromeVersion` (four dot- +separated decimal components without leading zeroes), `meetBuildId: Token`, +`display`, and `scopes`. `display` contains exactly `displayId: Token`, `type` +(`"internal"` or `"external"`), `pixelWidth` and `pixelHeight` (JSON integers +1–32768), and `scaleFactor` (string matching `^[1-4](\.[0-9]{1,3})?$`). +`scopes` is exactly `["entire-display","specific-window"]`; tuple IDs are +unique. + +`trustRegistry` is an array of 4–64 objects sorted by unsigned UTF-8 bytes of `keyId`. Each object contains exactly `keyId` (string matching `^[a-z0-9][a-z0-9._-]{15,63}$`), `publicKeyBase64Url: Base64Url32`, `purpose`, -`role`, `status` (`"active"` or `"revoked"`), and `rcSha: RcSha`. The only legal -purpose/role pairs are: +`role`, and `status` (`"active"` or `"revoked"`). The only legal purpose/role +pairs are: | `purpose` | `role` | |---|---| @@ -2065,18 +2091,89 @@ purpose/role pairs are: | `"qualification-role-attestation"` | `"remote-observer"` | | `"qualification-independent-review"` | `"independent-reviewer"` | | `"qualification-release-bundle"` | `"release-bundle"` | +| `"qualification-release-statement"` | `"release-statement"` | -There is at least one active key for each of the first three rows. A release- -bundle key is optional, but every such key and every key referenced anywhere -must occur exactly once in this registry at the exact RC SHA. `keyId` values and -decoded public-key bytes are globally unique across the registry. A key cannot +There is at least one active key for each row except the optional release-bundle +row. Every key referenced anywhere must occur exactly once in this registry. +`keyId` values and decoded public-key bytes are globally unique. A key cannot be reused for another role or purpose; local operator, remote observer, -independent reviewer, and release signer must all be different keys. Unknown, -revoked, wrong-purpose, wrong-role, duplicate-ID, reused-role, same-public-key, -RC-mismatched, or malformed entries block acceptance. `collection.json` and -signature files reference trusted `keyId` values; they never carry or override -public-key bytes. Verification always loads the matrix from a clean checkout at -its exact `rcSha`, closing the self-pinning dependency. +independent reviewer, optional bundle signer, and mandatory release-statement +signer are all different keys. Unknown, revoked, wrong-purpose, wrong-role, +duplicate-ID, reused-role, same-public-key, or malformed entries block +acceptance. Collection, bundle, review, and release-statement envelopes carry +only `keyId`; they never carry or override public-key bytes. Verification loads +the public key only from the matrix in the already externally selected checkout. +No artifact selects a checkout, expected SHA, matrix, registry, key, or purpose. + +**Mandatory detached post-RC release statement.** After the RC commit exists +and each signed/notarized package is built, `package:mac` invokes the release +controller's writer to create one statement at exactly +`/Users/Shared/InterviewCopilot/qualification-release-statements//release-statement.json`. +The resolved statement path and every +ancestor below `/Users/Shared` must be regular directories with no symlink, and +must be outside every Git worktree, per-run bundle, and +`.artifacts/qualification-reviews` root. The statement is never added to Git, +copied into a run/review root, or committed back into the RC. Creating, +replacing, or resigning it cannot change `expectedRcSha` or the frozen matrix +bytes/digest. The statement itself is a link-count-one regular file with mode +0400; links, alternate paths, or a writable accepted file fail validation. + +The existing `package:mac` child is the only producer. As its final step after +signing, notarization, stapling, and `spctl` assessment, it invokes the release- +controller-owned external writer/signing operation with those frozen post-build +results; that operation creates the statement once with exclusive-create +semantics at the external path. `package:mac` returns nonzero if the operation +fails. `verify:mac-package`, `qualify:meet`, and `verify:release` only validate +the result; none creates, repairs, replaces, or infers a missing statement. This +adds no reporter-plan entry or per-run artifact. + +The statement is a closed JCS envelope containing exactly `payload` and +`signature`; `signature` contains exactly `algorithm: "Ed25519"`, `keyId`, and +`value: Base64Url64`. The payload contains exactly `schemaVersion: 1`, `kind: +"qualification-release-statement"`, `expectedRcSha: RcSha`, `matrixPath: +"docs/qualification/macos-google-meet.json"`, `matrixBlobSha256: Sha256`, +`matrixRevision: Token`, `appSemver: SemVer`, `packages`, `releaseKeyId`, and +`issuedAt: UtcMillis`. `expectedRcSha` equals the verifier's already-pinned +checkout HEAD; the matrix path, digest, and revision equal the already-validated +committed matrix. The statement never contains its own digest. + +`packages` is a nonempty array sorted by unsigned UTF-8 bytes of `architecture` +and contains exactly one object for every distinct architecture in the matrix, +with no other architecture. Each object contains exactly `architecture` +(`"arm64"` or `"x64"`), `packageSha256: Sha256`, `signingTeamId` (string +matching `^[A-Z0-9]{10}$`), `signingCertificateSha256: Sha256`, +`hardenedRuntime: true`, `notarizationTicketId: Token`, +`notarizationStatus: "Accepted"`, `notarizationLogSha256: Sha256`, +`stapleStatus: "valid"`, `staplerStdoutSha256: Sha256`, +`staplerStderrSha256: Sha256`, `spctlStatus: "accepted"`, +`spctlStdoutSha256: Sha256`, `spctlStderrSha256: Sha256`, `builtAt: UtcMillis`, +`notarizedAt: UtcMillis`, and `stapledAt: UtcMillis`. Its three timestamps are +strictly increasing. +`issuedAt` is no earlier than every `stapledAt`. These fields are the complete +post-build package/signing/notarization/staple identity used by qualification. +`notarizationTicketId` is the accepted submission/ticket identifier emitted by +`xcrun notarytool`; collection uses that same identifier. The log digest hashes +the exact raw bytes returned by `xcrun notarytool log `. +The four stdout/stderr digests hash the exact, unnormalized byte streams from +`xcrun stapler validate -v ` and `spctl --assess --type execute +--verbose=4 `, respectively; empty streams hash as empty bytes and +no stream is concatenated with another. The three status constants and the +tools' raw exit 0 are independently required by `package:mac` and +`verify:mac-package`; a digest alone cannot turn a failed result into success. + +`releaseKeyId`, the signature `keyId`, and the looked-up registry `keyId` are +equal and resolve only to an active `qualification-release-statement`/ +`release-statement` entry. The exact signed bytes are the UTF-8/ASCII bytes of +`InterviewCopilot qualification release statement v1\n` (one LF, no NUL), +immediately followed by the JCS UTF-8 payload bytes, with no trailing byte. +This fourth domain is distinct from the three existing role-attestation, +optional release-bundle, and independent-review domains. A missing statement, +wrong external path, extra/missing/wrong-type field, non-JCS object-key order, +wrong package order, bad timestamp/order, expected-RC or matrix disagreement, +package hash mismatch, unknown/revoked/wrong-purpose/reused key, noncanonical +bytes, wrong domain, or +bad signature makes `qualify:meet`, `verify:release`, and the P12 aggregate +nonzero. **Exact `collection.json` schema.** The top-level object contains exactly these required keys and values: @@ -2102,10 +2199,17 @@ required keys and values: | `contentResult` | closed object defined below | | `evidenceMembers` | exact ordered eight-entry array defined below | +The top-level `rcSha` equals the externally pinned `expectedRcSha`; no +collection value can supply or change that expectation. + `app` contains exactly `semver: SemVer`, `commitSha: RcSha`, `packageSha256: Sha256`, `signingTeamId` (string matching `^[A-Z0-9]{10}$`), `signingCertificateSha256: Sha256`, and -`notarizationTicketId: Token`. `environment` contains exactly +`notarizationTicketId: Token`. `commitSha` equals the externally pinned +`expectedRcSha`; every other app field equals the already-validated detached +release statement and the selected architecture's package object (with +`notarizationTicketId` equal to its same-named field). `environment` +contains exactly `macOSProductVersion`, `macOSBuildVersion`, `architecture`, `chromeVersion`, `meetBuildId`, and `display`, with values and nested display schema identical to the selected matrix entry. `roles` contains exactly `localOperator` and @@ -2125,7 +2229,8 @@ monotonic time. `marker` contains exactly `algorithm: numeric spellings fail. `validator` contains exactly `version` (canonical SemVer) and `commitSha: -RcSha`, which equals the RC SHA. `contentResult` contains exactly `result: +RcSha`, which equals the externally pinned `expectedRcSha`. `contentResult` +contains exactly `result: "pass"`, `markerDetectedFrames: "0"`, `markerContinuityPpm`, `controlRecognizedPpm`, and `validSharedIntervalFrames`, with the last three values as `Uint64String`; both ppm values are 995000–1000000 and the frame count @@ -2253,12 +2358,14 @@ If `bundle-manifest.sig` is present, it is a closed JCS envelope with exactly `bundleManifestSha256: Sha256`, and `signedAt: UtcMillis`; its signature uses the exact common `{algorithm,keyId,value}` schema. Both key IDs are equal and resolve to an active `qualification-release-bundle`/`release-bundle` matrix -entry. The signed bytes are exactly the ASCII/UTF-8 domain separator +entry distinct from the mandatory release-statement key. The signed bytes are +exactly the ASCII/UTF-8 domain separator `InterviewCopilot qualification release bundle v1\n` followed immediately by JCS payload bytes, with no trailing byte. If the file is absent, no release -signature is inferred or required and required role/reviewer checks still +signature is inferred or required and required statement/role/reviewer checks still apply. If it is present, every schema, RC/key-purpose, digest, timestamp, and -Ed25519 check is mandatory; any failure blocks acceptance. The signature file's +Ed25519 check is mandatory, and its `rcSha` equals the externally pinned +`expectedRcSha`; any failure blocks acceptance. The signature file's own bytes are never in the digest. No other file is allowed in an accepted run root. @@ -2313,9 +2420,10 @@ It has exactly 28 directed edges: the eight non-collection evidence members to collection; all nine evidence members to evidence manifest; evidence manifest to each role attestation; evidence manifest plus both attestations to bundle metadata; the four exact bundle members to bundle manifest; bundle manifest to -the optional signature; and bundle manifest to detached review. The matrix -trust registry and externally hashed reviewer work products are RC-pinned trust -inputs, not accepted-run members or additional finalization nodes. A +the optional signature; and bundle manifest to detached review. The committed +matrix, mandatory detached release statement, and externally hashed reviewer +work products are validation inputs, not accepted-run members or additional +finalization nodes. Neither detached input adds an edge to this per-run graph. A topological-sort fixture proves all 16 nodes are visited with 28 edges and zero cycle. @@ -2335,12 +2443,17 @@ date; public evidence contains only hashes, tuple metadata, counts, and the redacted copy. **Offline acceptance boundary.** Within `qualify:meet`, the final-state -validator is read-only. Its acceptance proof is deliberately limited to the -bytes and filesystem state it can observe: exact canonical bytes, closed -schemas, byte sizes and hashes, path/order/membership, regular-file status, -link-count-one/no-link constraints, final 0400/0500 modes, identities, matrix/RC -trust lookup, key purpose/role/status/distinctness, and signatures. It then -verifies versions/signing, timing expressed in the records, frame decode/ +validator is read-only. Before it opens any per-run artifact, it pins the clean +checkout HEAD, validates and freezes the committed matrix bytes/closed schema/ +registry, computes `matrixBlobSha256`, and validates the mandatory external +release statement's path, closed schema, expected RC, matrix binding, package +identity, purpose-separated key, domain, and signature. Its later per-run proof +is deliberately limited to the bytes and filesystem state it can observe: +exact canonical bytes, closed schemas, byte sizes and hashes, path/order/ +membership, regular-file status, link-count-one/no-link constraints, final +0400/0500 modes, identities, expected-RC/matrix/statement trust lookup, key +purpose/role/status/distinctness, and signatures. It then verifies versions/ +signing against the statement, timing expressed in the records, frame decode/ continuity, the positive detector corpus, marker absence, control visibility, and M01/M02 completeness. It rejects `.partial` roots and writes only to the reporter's separate log directory. @@ -2362,38 +2475,66 @@ separator, and optional-signature rule. Mutation fixtures claim only observable final-state rejection; separate collector-runtime fixtures make the historical write assertions. +`scripts/qualification/release-statement-constructibility.test.ts` runs a real +toy-Git probe in a temporary directory: it commits a canonical matrix containing +only the policy/registry schema above, records HEAD/tree/matrix blob bytes and +`matrixBlobSha256`, builds a toy package, creates a purpose-separated Ed25519 +statement at the external sibling path, and verifies its HEAD/matrix/package/ +signature bindings. It then replaces the statement with another validly signed +post-build statement and proves HEAD, tree, matrix blob, and matrix digest are +unchanged; placing, updating, or deleting the external statement never changes +Git identity. A statement bound to a second toy commit fails against the first +already-selected checkout without causing a fetch, checkout, reset, or switch. +The companion fixed-point scan rejects any matrix field or normative prose that +requires the matrix to contain its own RC SHA, app/package hash, signing/ +notarization/staple output, build timestamp, or release-statement digest. + `scripts/qualification/schema-inventory.test.ts` inventories the committed -closed schemas for the matrix, each of the four NDJSON event payload families, +closed schemas for the matrix and release-envelope family (mandatory detached +statement plus optional bundle signature), each of the four NDJSON event payload +families, local preflight, control coverage, frame analysis, content-validation report, collection, manifest/entry, acknowledgement, role attestation, bundle metadata, -optional bundle signature, and detached review. It recursively fails any +and detached review. The inventory remains the same 13 schema families while +adding the release-statement arm to the existing release-envelope family. It +recursively fails any object schema missing `additionalProperties: false`, any unconstrained array, unknown union arm, unsafe integer counter, non-exact time format, or missing positive/negative fixture. `scripts/qualification/canonical-bytes.test.ts` runs the two independent serializer fixture sets and checks identical JCS bytes, -digests, exact domain separators, and rejection of noncanonical semantic +digests, all four exact domain separators, and rejection of noncanonical semantic variants. `scripts/qualification/trust-registry.test.ts` probes unknown, revoked, wrong-purpose, wrong-role, reused-role, duplicate-ID, same-public-key, -RC-mismatched, malformed, and collection-supplied-key cases. The artifact- -validator suite covers optional bundle signature absent, valid-present, and -invalid-present; only the first two pass. +expected-RC-mismatched, malformed, and collection-supplied-key cases. The +release-statement suite tampers `expectedRcSha`, matrix digest, package hash, +release key/purpose/signature, each outer/nested extra field, each field type, +package order, and every timestamp/order variant; all mutations fail. It also +proves that no artifact-derived value is consumed before checkout/matrix pinning +or can select a checkout. The artifact-validator suite covers optional bundle +signature absent, valid-present, and invalid-present; only the first two pass. It prints one line per tuple/scope plus `passed= failed= skipped=` and -exits 0 only when every matrix tuple has exactly one accepted M01 and M02 bundle, -the exact graph and all assertions pass, failed=0, and skipped=0. Missing raw -evidence, either attestation, either manifest, or the bundle metadata is a +exits 0 only when the mandatory release statement is valid, every matrix tuple +has exactly one accepted M01 and M02 bundle, the exact graph and all assertions +pass, failed=0, and skipped=0. A missing/mismatched/invalid release statement, +raw evidence, either attestation, either manifest, or bundle metadata is a failure, never a skip. The P12 reporter preserves that raw exit and makes its aggregate nonzero otherwise. -**Detached independent review.** An independent reviewer starts from a fresh -clone at the exact RC SHA, obtains the signed package and complete immutable -bundle through the documented encrypted release channel, recomputes both -manifest digests from canonical bytes, walks every allowlist edge, verifies both -role signatures against the RC matrix registry, and runs the complete P12 -reporter command below. To reproduce collection rather than only validate, the -reviewer uses a fresh checkout with no `.artifacts/qualification`, the exact -matrix hardware/software/display tuple, new dedicated accounts/meeting, and the -two launch commands above; absent evidence automatically launches M01 then M02. +**Detached independent review.** An independent reviewer externally selects +and checks out the reviewed RC before obtaining any artifact, independently +pins clean `HEAD` as `expectedRcSha`, validates/freezes/hashes the committed +matrix, and then obtains the signed package, mandatory detached release +statement, and complete immutable bundle through the documented encrypted +release channel. In that order the reviewer validates the statement against the +already-pinned SHA, matrix digest/revision, package, and matrix-only release key; +recomputes both manifest digests from canonical bytes; walks every allowlist +edge; verifies both role signatures against the committed registry; and runs +the complete P12 reporter command below. To reproduce collection rather than +only validate, the reviewer uses a fresh checkout with no +`.artifacts/qualification`, the exact matrix hardware/software/display tuple, +new dedicated accounts/meeting, and the two launch commands above; absent +evidence automatically launches M01 then M02. The reviewer watches the full remote shared intervals plus pre/post boundaries, checks at least the first/last and one frame from every 15-second marker-position epoch against `frame-analysis.ndjson`, and verifies ordinary underlying content @@ -2424,9 +2565,9 @@ boolean is true, otherwise JSON `null`). At least one accepted review record per matrix revision has `livePairingReproduced: true`, preserving the required one clean live-paired reproduction without pretending every retained run was recollected. Identity and bundle digest match the reviewed bundle. Both key IDs -are equal and resolve only to an active -`qualification-independent-review`/`independent-reviewer` key at the RC SHA, -distinct from both role keys and any release-bundle key. +are equal and resolve only to an active `qualification-independent-review`/ +`independent-reviewer` matrix key, distinct from both role keys and either +release-purpose key. Its `rcSha` equals the externally pinned `expectedRcSha`. The exact signed bytes are the ASCII/UTF-8 domain separator `InterviewCopilot qualification independent review v1\n` followed immediately @@ -2436,14 +2577,16 @@ digest disagreement, unknown/wrong-purpose/reused key, noncanonical bytes, or bad signature blocks `verify:release` and the P12 aggregate. No reporter plan entry or ad-hoc shell command is added. The existing -`qualify:meet --collect-missing` child validates bundles and, when run by the -configured independent reviewer after the required prompts/checks, writes and -immediately verifies this detached record outside the run root. The already- -planned final `verify:release` child requires and revalidates the exact record -for every accepted M01/M02 run. An initial collector run may therefore finish -collection but cannot make the release aggregate green until independent -review exists; the final unchanged P12 reporter rerun must have all raw exits -zero. Any disagreement, non-reproducible tuple, graph/byte mismatch, or changed +`qualify:meet --collect-missing` child first requires the valid detached release +statement, then validates bundles and, when run by the configured independent +reviewer after the required prompts/checks, writes and immediately verifies +this detached record outside the run root. The already-planned final +`verify:release` child independently repins clean `HEAD`, matrix bytes, and the +statement, then requires and revalidates the exact review record for every +accepted M01/M02 run. An initial collector run may therefore finish collection +but cannot make the release aggregate green until independent review exists; +the final unchanged P12 reporter rerun must have all raw exits zero. Any +statement disagreement, non-reproducible tuple, graph/byte mismatch, or changed version leaves external reporter failure evidence, produces no qualifying `result: "pass"` review envelope, and blocks the claim. @@ -2459,11 +2602,27 @@ git -C "$p12_verify_dir/repo" switch --detach FETCH_HEAD cd "$p12_verify_dir/repo" test "$(uname -s)" = "Darwin" test -z "$(git status --porcelain)" +expected_rc_sha=$(git rev-parse HEAD) +test "$expected_rc_sha" = "$(git rev-parse HEAD)" node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1)' ``` -**Verification commands, in order.** `test:p12` reports at least 14 named -automated/manual manifest entries passed, 0 failed, 0 skipped; all raw exits 0. +**Verification commands and non-circular order.** The external controller, not +an artifact, chooses the commit used by `switch --detach`. Each verifier then +executes this strict order: (1) require clean checkout and pin HEAD as +`expectedRcSha`; (2) load the matrix blob from that commit, compare the +worktree bytes, validate its closed schema/JCS/registry, and freeze/hash it; +(3) validate the external statement's fixed path, closed schema/JCS, +`expectedRcSha`, matrix binding, package identity, purpose-separated key, +domain, and signature; (4) validate or collect per-run evidence and detached +reviewer records; and (5) run `verify:release`. A bundle, statement, review, +pairing challenge, or other artifact is never read to fetch, switch, reset, or +select a checkout, matrix, registry, or expected SHA. The observer independently +pins its already selected clean checkout and only compares the pairing SHA to +that value. + +`test:p12` reports at least 14 named automated/manual manifest entries passed, +0 failed, 0 skipped; all raw exits 0. ```bash npm run verify:phase -- --phase P12 --artifacts .artifacts/verification/P12 @@ -2472,16 +2631,18 @@ npm run verify:phase -- --phase P12 --artifacts .artifacts/verification/P12 Expected reporter aggregate exit is 0; every logged child raw exit is 0. `qualify:meet` launches P12-M01 and P12-M02 for absent evidence and exits 0 only -after every frozen tuple has a live-paired, complete, read-only validated bundle -with `marker_detected_frames=0`, valid control coverage, the exact acyclic -manifest graph, and two valid role attestations. `test:staff-live-corpus` +after the detached release statement is valid and every frozen tuple has a live- +paired, complete, read-only validated bundle with `marker_detected_frames=0`, +valid control coverage, the exact acyclic manifest graph, and two valid role +attestations. `test:staff-live-corpus` executes all three frozen cases. Every test-classified reporter entry prints passed/failed/skipped totals. **Regression suite.** the entire P01–P11 suite, native audio, all mode fixtures, migrations, storage plaintext scans, shell/capture integration, package smoke tests, and release claim/deferred-scope scans. The later existing `verify:release` entry makes the -unchanged reporter aggregate nonzero unless every accepted run also has its -valid external independent-review envelope. +unchanged reporter aggregate nonzero unless the mandatory statement remains +valid and every accepted run also has its valid external independent-review +envelope. **Docs.** Exact supported tuple matrix/date, guided verification, stale rules, D-005g headline/qualifier, limitations/non-security-boundary, permissions, @@ -2489,12 +2650,17 @@ provider/audio/storage/privacy, diagnostics, AGPL/source offer, macOS install/ uninstall/update, release evidence, SBOM/vulnerability disposition, and explicit Windows/Linux/app/scope deferrals. Release docs also publish the exact parent/ inherit entitlement tables, frozen Staff-live corpus hash/assertion summary, -closed schema inventory, RC-pinned trust registry, both manifest schemas/ -memberships/digests, signature verification result, and detached independent- -review record. - -**Completion evidence.** (1) SHAs/base/version; (2) every raw gate/count report; -(3) signed/notarized arm64/x64 hashes and package-policy report; (4) role-by- +closed schema inventory, externally selected RC/matrix trust boundary, frozen +matrix digest and purpose-separated registry, detached release-statement path/ +schema/signature result, both manifest schemas/memberships/digests, signature +verification result, and detached independent-review record. + +**Completion evidence.** (1) externally selected SHAs/base/version and proof +that no artifact selected them; (2) every raw gate/count report; (3) exact +committed matrix bytes/digest plus the mandatory detached release statement's +external path, closed payload, arm64/x64 package/signing/notarization/staple +identities, matrix-only release key lookup, domain, and signature, together with +the package-policy report; (4) role-by- role extracted entitlement plist diff, SBOM, and vulnerability disposition; (5) protection trace; (6) exact no-wildcard matrix; (7) per-tuple P12-M01/M02 raw recording/content analysis, exact evidence-manifest membership/digest, both @@ -2514,7 +2680,7 @@ signing infrastructure cannot be inferred from unit tests. **Self-contained implementation prompt.** -> Implement P12 from P00-R4 after P01–P11 on +> Implement P12 from P00-R5 after P01–P11 on > `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ > architecture matrix, harden macOS-only package/entitlements/identity, add > local-only redacted diagnostic preview/export, scoped failure recovery, @@ -2524,36 +2690,45 @@ signing infrastructure cannot be inferred from unit tests. > signed/notarized arm64/x64 artifacts, launch and execute the full live-paired > P12-M01/M02 procedures on the release build, and run the complete P12 reporter > plan including artifact validation and the SHA-pinned three-case Staff-live -> corpus. Implement the exact write-once evidence-manifest → two independent +> corpus. Externally select and pin clean checkout HEAD before artifacts, +> validate/freeze/hash the pre-commit-only committed matrix, produce the +> mandatory signed detached post-RC release statement outside Git and all +> bundle/review roots, and fail qualification/release on any checkout, matrix, +> package, key-purpose, domain, or signature disagreement. Implement the exact +> write-once evidence-manifest → two independent > role attestations → final bundle-manifest/digest sequence, canonical bytes, -> recursively closed schemas, matrix-pinned role/reviewer/release trust, +> recursively closed schemas, committed-matrix role/reviewer/release trust, > memberships, exclusions, exact signature domains, optional release-signature > absence/presence rules, mandatory external review, and read-only validator. > Enforce first-touch/write-once/freeze in the live collector while limiting > offline claims to observable final state. Attach every enumerated artifact. A -> failed/incomplete tuple, cyclic/extra/missing member, observable final-byte or -> trust/signature mismatch, missing review, extra or missing entitlement, corpus +> failed/incomplete tuple, missing/invalid release statement, cyclic/extra/ +> missing member, observable final-byte or trust/signature mismatch, missing +> review, extra or missing entitlement, corpus > assertion failure, or skipped case blocks release; never infer pass or accept > pre-existing files without complete read-only validation. **Self-contained review prompt.** -> Independently review P12 on the exact frozen matrix. Rebuild/package from the -> clean SHA, inspect signing/notarization/entitlements/SBOM, trace protection +> Independently review P12 by externally selecting the clean SHA, freezing and +> hashing its exact committed matrix before reading artifacts, then validate the +> required external release statement and rebuild/package identity. Inspect +> signing/notarization/entitlements/SBOM, trace protection > before first frame, mechanically compare every signed parent/nested executable > with the exact role allowlist, rerun the complete reporter plan, personally > verify remote Meet raw artifacts/control frames, canonical evidence manifest, > independently signed role attestations, bundle metadata/final digest, exact > include/exclude rules, and acyclic dependency graph for both scopes/ -> architectures, recursively closed schemas, RC-pinned key purposes, exact -> signature domains, optional release-signature semantics, and reproduce one +> architectures, recursively closed schemas, matrix-only key purposes, all four +> exact signature domains, optional bundle-signature semantics, and reproduce one > clean live-paired tuple. Verify > the frozen Staff-live corpus hash and every structural assertion, force stale/ > failed records, inspect diagnostic network/content traces, and scan every > shipped string. Reject missing tuple evidence, local-only confirmation, > broadened claim, unsupported platform/app/scope, entitlement drift, telemetry, -> corpus mutation/failure, self-reference, observable final-byte mismatch, -> invalid role/reviewer/release signature or trust binding, skipped test, +> corpus mutation/failure, self-reference, artifact-derived checkout selection, +> observable final-byte mismatch, missing/invalid statement, invalid role/ +> reviewer/release signature or trust binding, skipped test, > vulnerability without disposition, or any nonzero child/aggregate gate. Sign > the closed review envelope at its exact external path; do not claim the offline > validator proves write history. @@ -2568,7 +2743,8 @@ signing infrastructure cannot be inferred from unit tests. > both live-paired remote qualifications for every affected tuple, then return > every reporter raw exit/count and aggregate exit, entitlement diff, corpus > counts, both manifest memberships/digests, schema/canonical/trust probes, -> role/release/reviewer signature results, matrix revision, and new SHAs. +> detached-statement/role/optional-bundle/reviewer signature results, frozen +> matrix revision/digest, externally pinned expected RC, and new SHAs. ## 8. Requirement ownership matrix @@ -2630,8 +2806,11 @@ product contract: performance evidence before merge. Apple Speech is the sole launch remote fallback and remains explicit/off by default. 3. **P12 qualification tuple.** At RC cut, record the exact current-stable macOS - patch, Chrome/Meet versions, display configuration, app commit/version, and - arm64/x64 hardware. Do not claim a version or architecture that was not run. + patch, Chrome/Meet versions, display configuration, and arm64/x64 hardware in + the pre-commit matrix; externally pin the selected app commit from clean + checkout HEAD and bind app version/package identities only in the later + detached release statement. Do not claim a version or architecture that was + not run. 4. **External P12 prerequisites.** Apple signing/notarization credentials and a remote Meet observer/second device are required. Their absence is not a P00 blocker, but it is a genuine release blocker: P12 cannot pass or the product From 42925fb617a61a1149bdf1e027cf21c975b0f13a Mon Sep 17 00:00:00 2001 From: Timomak Date: Sun, 26 Jul 2026 22:16:46 +0200 Subject: [PATCH 6/9] docs: make P00 package reruns constructible --- design.md | 4 +- docs/implementation/phase-execution-packet.md | 357 ++++++++++++++---- 2 files changed, 296 insertions(+), 65 deletions(-) diff --git a/design.md b/design.md index 99bc6117..ece46e3a 100644 --- a/design.md +++ b/design.md @@ -781,7 +781,7 @@ Decisions are resolved in dependency order. A later branch may be reordered when | D-005b | Resolved | Treat InterviewCopilot as a neutral tool and enforce no responsibility notice or consent gate. | Onboarding and session start remain frictionless. The product does not repeatedly interrupt the live workflow with usage confirmations. | | D-005c | Resolved constraint | Limit the promise to exclusion from ordinary screen sharing and recording on explicitly qualified configurations. | Capture privacy remains release-critical and testable. The product will not hide its process, tamper with monitoring, spoof platform state, or attempt to evade anti-cheating or proctoring controls. | | D-005d | Resolved | Make macOS the only initial engineering and capture-privacy qualification target; defer Windows and Linux. | The launch matrix stays narrow enough to test rigorously. Capture scopes and applications qualify independently; Google Meet already provides the observed entire-display and specific-window baseline recorded under D-005e. | -| D-005e | Resolved for launch | Require the externally selected release commit's signed/notarized build to pass Google Meet entire-display and specific-window sharing tests on the committed supported macOS/browser matrix. | Both scopes already have an observed working baseline. The immutable checkout supplies the expected commit and matrix/key policy; a mandatory detached post-build statement supplies the package identity. The final test is a release gate; Zoom, Teams, browser-tab sharing, and other capture products remain unqualified until independently tested. | +| D-005e | Resolved for launch | Require the externally selected release commit's signed/notarized build to pass Google Meet entire-display and specific-window sharing tests on the committed supported macOS/browser matrix. | Both scopes already have an observed working baseline. The immutable checkout supplies the expected commit and matrix/key policy; a mandatory detached post-build statement binds an immutable RC-scoped package set that later unchanged release reporters validate without rebuilding. The final test is a release gate; Zoom, Teams, browser-tab sharing, and other capture products remain unqualified until independently tested. | | D-005f | Resolved | Provide a guided Google Meet test and show verified status only for the recorded Mac, browser, app version, and passing capture scopes. | Verification requires confirmation from the remote Meet view or a second device, becomes stale after capture-relevant app changes or major OS/browser changes, and never implies universal invisibility. The underlying `setContentProtection(true)` path is centralized and unit-guarded. | | D-005g | Resolved | Lead with “Stay private while you share your screen,” then state that InterviewCopilot is designed to stay out of ordinary macOS screen shares and recordings and that coverage varies by application and capture mode. | The product promise should describe the general user benefit rather than a Google Meet feature. Exact verified applications, modes, versions, and dates remain visible in Privacy & Capture, while universal undetectability and anti-monitoring claims remain out of scope. | | D-005h | Resolved | Omit an application-agnostic “Test My Setup” flow at launch. | A generic self-test creates setup cost without reliably certifying arbitrary capture implementations. Verification remains available only for explicitly qualified applications and capture modes. | @@ -863,5 +863,5 @@ Decisions are resolved in dependency order. A later branch may be reordered when The reviewed phase order, dependency graph, acceptance gates, migration owners, prototype disposition, and implementation/review/remediation prompts are defined in [`docs/implementation/phase-execution-packet.md`](docs/implementation/phase-execution-packet.md), -revision P00-R5. This design remains the product source of truth; the packet is +revision P00-R6. This design remains the product source of truth; the packet is the execution contract. Prototype evidence does not establish phase completion. diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md index 19938da1..6898ed01 100644 --- a/docs/implementation/phase-execution-packet.md +++ b/docs/implementation/phase-execution-packet.md @@ -1,6 +1,6 @@ # InterviewCopilot phase-execution packet -Packet revision: **P00-R5** +Packet revision: **P00-R6** Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` @@ -267,9 +267,10 @@ test-classified and must print passed/failed/skipped counts. The P12 row is complete and therefore does not receive the default manifest or build suffix. Package, diagnostics, Meet collection/validation, and final release validation are child commands of the same reporter and cannot bypass -its raw-exit aggregate. `package:mac` invokes the controller-owned writer for -the mandatory external release statement only after signing/notarization/ -stapling; `verify:mac-package`, +its raw-exit aggregate. In CREATE, `package:mac` invokes the controller-owned +writer for the mandatory external release statement only after signing/ +notarization/stapling; in REUSE it validates that exact statement and sealed +package set without invoking any producer. `verify:mac-package`, `qualify:meet`, and `verify:release` require and validate but never synthesize it. `qualify:meet` launches collection when evidence is absent and performs the write-once manifest/attestation/bundle finalization in P12-M01/M02; it is not an @@ -390,7 +391,7 @@ inside the single PR. **Self-contained implementation prompt.** -> Implement P01 from P00-R5 on `phase/P01-local-gates`, based only on upstream +> Implement P01 from P00-R6 on `phase/P01-local-gates`, based only on upstream > `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. > Make local lint, strict type-check, real unit tests (including the unchanged > tracked CRA sample), manifest enforcement, and build green. Centralize and @@ -402,7 +403,7 @@ inside the single PR. **Self-contained review prompt.** -> Review P01 independently against P00-R5, not the author’s summary. From the +> Review P01 independently against P00-R6, not the author’s summary. From the > clean PR checkout run the P01 reporter invocation, confirm the inherited CRA > test ran, > inspect all config/glob/ignore changes for hidden coverage loss, compare typed @@ -531,7 +532,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained implementation prompt.** -> Implement P02 from P00-R5 after P01, on +> Implement P02 from P00-R6 after P01, on > `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime > for Claude Code and Codex only, using one resumable session/thread, normalized > streaming/usage/compaction/stop/error events, explicit provider/model/Fast- @@ -544,7 +545,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained review prompt.** -> Review P02 against P00-R5 from a clean checkout. Trace both fake providers +> Review P02 against P00-R6 from a clean checkout. Trace both fake providers > through two turns, stop, compaction, driver/child restart, and caller-ID > resume; force every failure and prove the other provider never starts. Inspect > spawn/env/tool restrictions, IPC exposure, migration idempotence/file mode, @@ -657,7 +658,7 @@ never custom cryptography. **Self-contained implementation prompt.** -> Implement P03 from P00-R5 after P01 on +> Implement P03 from P00-R6 after P01 on > `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key > service, versioned AES-256-GCM record/blob store, atomic writes, encrypted > in-memory-search source, typed recovery, raw-audio rejection, and journaled @@ -805,7 +806,7 @@ boundary; no renderer or provider may keep a second authoritative session. **Self-contained implementation prompt.** -> Implement P04 from P00-R5 after P02/P03 on +> Implement P04 from P00-R6 after P02/P03 on > `phase/P04-session-orchestrator`. Replace global transient state with the > deterministic InterviewSession reducer, typed event/IPC contract, one > persistent-conversation orchestrator, context/delta policy, pending artifacts, @@ -940,7 +941,7 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained implementation prompt.** -> Implement P05 from P00-R5 after P04 on `phase/P05-live-shell`. Build the +> Implement P05 from P00-R6 after P04 on `phase/P05-live-shell`. Build the > exact Quiet Signal hidden/compact/answer/expanded shell, command rail, > composer, input tray, explicit click-through/drag regions, final remappable > shortcuts, display-aware geometry, primary-display screenshot behavior, @@ -1062,7 +1063,7 @@ regress silently; fixture contracts are merge-blocking. **Self-contained implementation prompt.** -> Implement P06 from P00-R5 after P05 on `phase/P06-coding`. Add the exact +> Implement P06 from P00-R6 after P05 on `phase/P06-coding`. Add the exact > typed Coding intents/schema/renderer, concise-first progressive answer, > language snapshot and six-family fixtures, read-only actions, New Question, > and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, @@ -1177,7 +1178,7 @@ must not become a second untyped document model. **Self-contained implementation prompt.** -> Implement P07 from P00-R5 after P05 on `phase/P07-system-design`. Add the +> Implement P07 from P00-R6 after P05 on `phase/P07-system-design`. Add the > fixed typed five-section progressive workflow, bounded material estimates, > safe vendor-neutral structured diagram, read-only accessible interactions, > assumption handling, dependency-scoped follow-up and What changed summary. @@ -1298,7 +1299,7 @@ integrity are product trust boundaries. **Self-contained implementation prompt.** -> Implement P08 from P00-R5 after P05 on `phase/P08-behavioral`. Build the +> Implement P08 from P00-R6 after P05 on `phase/P08-behavioral`. Build the > encrypted canonical candidate dossier, guided/manual reviewed editing, > sanitized Markdown import/export, multiple snapshotted opportunities, > provenance, opt-in labeled persistent synthetic stories, and typed Behavioral @@ -1431,7 +1432,7 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained implementation prompt.** -> Implement P09 from P00-R5 after P05 on `phase/P09-audio`, macOS only. Build +> Implement P09 from P00-R6 after P05 on `phase/P09-audio`, macOS only. Build > explicit two-source native capture, deterministic master/per-source controls, > contextual permission recovery, pinned offline whisper.cpp transcription, > explicit Apple Speech remote fallback, typed segments/attribution/correction, @@ -1550,7 +1551,7 @@ must never become a capability or schema escape hatch. **Self-contained implementation prompt.** -> Implement P10 from P00-R5 after P06/P07/P08 on +> Implement P10 from P00-R6 after P06/P07/P08 on > `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, > immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, > deterministic recorded instruction resolution, Start snapshotting, protected @@ -1667,7 +1668,7 @@ content and destructive user controls. **Self-contained implementation prompt.** -> Implement P11 from P00-R5 after P06–P10 on +> Implement P11 from P00-R6 after P06–P10 on > `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete > encrypted archive projection, Settings-only in-memory search/open/delete one/ > all, safe consented individual Markdown/JSON export, read-only archive open, @@ -1728,7 +1729,7 @@ detached statement binds its app semver and post-build package identity. Those exact passing tuples—and no neighboring patch, major version, browser, app build, architecture, or display mode—are the supported macOS/browser/app versions until separately qualified. Qualify each supported tuple separately. -P00-R5 represents no version as supported before the committed matrix, detached +P00-R6 represents no version as supported before the committed matrix, detached release statement, and evidence pass. Entire-display and specific-window require confirmation from remote Meet view or second device and retained high-contrast moving-marker artifacts; one fail makes @@ -2105,37 +2106,227 @@ only `keyId`; they never carry or override public-key bytes. Verification loads the public key only from the matrix in the already externally selected checkout. No artifact selects a checkout, expected SHA, matrix, registry, key, or purpose. -**Mandatory detached post-RC release statement.** After the RC commit exists -and each signed/notarized package is built, `package:mac` invokes the release -controller's writer to create one statement at exactly -`/Users/Shared/InterviewCopilot/qualification-release-statements//release-statement.json`. -The resolved statement path and every -ancestor below `/Users/Shared` must be regular directories with no symlink, and -must be outside every Git worktree, per-run bundle, and -`.artifacts/qualification-reviews` root. The statement is never added to Git, -copied into a run/review root, or committed back into the RC. Creating, -replacing, or resigning it cannot change `expectedRcSha` or the frozen matrix -bytes/digest. The statement itself is a link-count-one regular file with mode -0400; links, alternate paths, or a writable accepted file fail validation. - -The existing `package:mac` child is the only producer. As its final step after -signing, notarization, stapling, and `spctl` assessment, it invokes the release- -controller-owned external writer/signing operation with those frozen post-build -results; that operation creates the statement once with exclusive-create -semantics at the external path. `package:mac` returns nonzero if the operation -fails. `verify:mac-package`, `qualify:meet`, and `verify:release` only validate -the result; none creates, repairs, replaces, or infers a missing statement. This -adds no reporter-plan entry or per-run artifact. - -The statement is a closed JCS envelope containing exactly `payload` and -`signature`; `signature` contains exactly `algorithm: "Ed25519"`, `keyId`, and -`value: Base64Url64`. The payload contains exactly `schemaVersion: 1`, `kind: -"qualification-release-statement"`, `expectedRcSha: RcSha`, `matrixPath: +**Mandatory detached post-RC release statement and sealed package set.** The +existing `package:mac` child remains the only producer, but it is a three-state +command: CREATE when no accepted statement exists, REUSE when the exact +statement exists, and REJECT for every other state. Its canonical RC root is +exactly +`/Users/Shared/InterviewCopilot/qualification-release-statements//`. +The statement remains exactly `release-statement.json`. The same RC root holds +the producer's immutable package set at `sealed-package-set/`, with this exact +closed layout and no other directory entry: + +```text +sealed-package-set/ + producer-record.json + arm64/InterviewCopilot--arm64.dmg + arm64/notarytool.log + arm64/stapler.stdout + arm64/stapler.stderr + arm64/spctl.stdout + arm64/spctl.stderr + x64/InterviewCopilot--x64.dmg + x64/notarytool.log + x64/stapler.stdout + x64/stapler.stderr + x64/spctl.stdout + x64/spctl.stderr +``` + +Only architecture directories required by the committed matrix exist. Thus a +one-architecture matrix has only its one listed directory. The package names +are derived from the commit-object app semver and architecture, never from a +build-output filename or artifact field. `producer-record.json` is exactly the +JCS payload later embedded in the statement. It is immutable recovery input, +not an accepted statement, qualification artifact, evidence member, review, +reporter child, or alternative trust root. The statement is the sole commit +record that makes the package set acceptable. + +The release-controller service identity exclusively owns +`/Users/Shared/InterviewCopilot`. Its installer pre-provisions a regular +link-count-one lock file outside every RC root. Every canonical directory below +`/Users/Shared` is opened component-by-component from an already opened +`/Users/Shared` descriptor with `openat` plus `O_DIRECTORY|O_NOFOLLOW`; it is +owned by the controller service, has no ACL, mount transition, or group/other +write bit, and has mode 0555 once installed. Accepted package and raw-result +files are link-count-one regular files with mode 0444; `producer-record.json` +and `release-statement.json` are link-count-one regular files with mode 0400. +Accepted files have no file flags set. Their controller ownership, absence of +owner/group/other write bits, and nonwritable installed directories make both +file bytes and closed entry sets immutable to the invoking user without a +post-rename flag operation or crash window. The privileged controller is the +only process allowed to install a new name into those nonwritable directories. +Root/controller credential compromise is outside the threat model; symlinks, +aliases, hard links, clone-selected +alternate roots, writable ancestors, unexpected ownership/mode/flags, and +paths supplied through argv, environment, artifacts, pairing, or statements +are in scope and fail. + +**PIN FIRST.** Before opening the canonical RC root, the command requires a +detached, clean checkout; pins `git rev-parse HEAD` as `expectedRcSha`; resolves +that object as a commit; reads the matrix with `git cat-file` from +`:docs/qualification/macos-google-meet.json`; and retains those +exact bytes, their SHA-256 as `matrixBlobSha256`, the parsed closed matrix/key +registry, its blob object ID, and the commit-object app semver in memory. It +then requires the worktree matrix bytes to equal those commit-object bytes. +Tracked/index differences, non-ignored untracked paths, a symbolic branch HEAD, +an invalid matrix, or a moving/unresolvable commit fails before any artifact is +read. Artifacts, the external package root, environment, and CLI values can +never select a commit, move/switch/fetch a checkout, choose matrix bytes, or +override any pin. + +After PIN FIRST, `package:mac` opens and takes the pre-provisioned lock without +creating it, then repeats the complete HEAD/cleanliness/commit-object/matrix +check before state selection. The privileged controller creates an absent +canonical `` directory once with `mkdirat`, mode 0555, and an +immediate parent fsync; `EEXIST` requires the same anchored directory +validation. An empty canonical RC directory is a safe no-statement/no-seal +CREATE state, not accepted identity. The command repeats PIN FIRST again before +any exclusive install and before returning. Every validator independently +performs the same pin and final recheck. A checkout-selection attempt or change +at any checkpoint is REJECT without repair or checkout movement. + +**CREATE.** With the lock held, absence means an `openat` of the canonical +statement name returns `ENOENT`, not merely that a prior pathname probe did. +There are only two safe no-statement substates: + +1. If both the statement and `sealed-package-set` are absent, `package:mac` + builds, Developer-ID signs with hardened runtime, notarizes, staples, and + runs `xcrun stapler validate -v` and `spctl --assess --type execute + --verbose=4` exactly once per required architecture. It does so in a fresh + controller-created 0700 nonce directory below + `/Users/Shared/InterviewCopilot/qualification-release-staging//` + on the same APFS volume. This is the package producer build, distinct from + the preceding repository `npm run build` child. +2. If the statement is absent but a complete installed `sealed-package-set` + exists, CREATE is a crash-resume commit step. The command runs the entire + REUSE package-set validation below and, only on exact agreement, invokes the + statement writer. It never rebuilds, resigns, renotarizes, restaples, reruns + a producer, or edits the installed set. + +The staging directory contains exactly the closed layout above. Before install, +the controller independently derives every architecture from the pinned +matrix, hashes the exact package and raw output bytes, validates the signature, +hardened-runtime entitlement, certificate/team identity, accepted +notarization ticket and exact raw log, valid staple, and accepted `spctl` raw +exit/status, and creates the exact canonical `producer-record.json`. It rejects +extra packages, architectures, app bundles, metadata, or output files. It +fsyncs every file after its final bytes and mode, fsyncs each directory +bottom-up, requires zero file flags and applies the final read-only modes, and +fsyncs the staging parent. It then atomically installs the whole directory with macOS +`renameatx_np(..., RENAME_EXCL)` to the canonical +`sealed-package-set` name and fsyncs both source and destination parents. No +copy, ordinary rename-over, unlink, repair, or replacement is allowed. + +An install `EEXIST` is a race, never success by existence. The contender closes +all staging descriptors, securely reopens the canonical installed set from the +anchored RC descriptor, and performs the complete validation below. It may +continue only if the installed bytes and every identity field exactly equal +the locally derived candidate; otherwise it returns nonzero without changing +either set. Cooperating `package:mac` processes serialize on the lock, so the +second ordinarily reaches REUSE before running any producer; the `EEXIST` path +is still mandatory for a noncooperating or injected race. + +Only after the installed set passes that validation does `package:mac` invoke +the controller-owned exclusive statement writer, exactly once and as its final +producer step. The writer signs the already sealed `producer-record.json` +payload, constructs the closed statement envelope, writes it to a fresh 0600 +nonce file in the same-volume staging root with `O_CREAT|O_EXCL|O_NOFOLLOW`, +fsyncs its complete canonical bytes, changes it to mode 0400, requires zero file +flags, fsyncs it again and fsyncs the staging directory, then atomically +installs it +at `release-statement.json` using +`renameatx_np(..., RENAME_EXCL)`. It fsyncs the canonical RC directory, securely +reopens the installed name, fully validates it and the sealed set, repeats the +PIN check, and only then returns 0. The final pathname therefore exposes either +no file or one complete canonical file, never a partially written statement. + +Writer `EEXIST` has the same exact race rule: close the uninstalled nonce file; +open the canonical name from the anchored RC descriptor with `O_NOFOLLOW`; +require the final file and all ancestors, the sealed package set, canonical +bytes, payload, signature/purpose, and every pinned and post-build identity to +pass the complete REUSE validation; and return 0 only if that exact pre-existing +identity equals the writer input byte-for-byte. It never unlinks, renames over, +replaces, resigns, repairs, or trusts the file merely because it exists. + +**REUSE.** If the exact statement name opens successfully after the second pin, +`package:mac` becomes validation-only before consulting any worktree build +output. It must not run a build/package producer, sign, submit/query a new +notarization, staple, invoke the writer, create an accepted artifact or +evidence file, mutate staging or sealed paths, repair permissions/flags, replace +or resign the statement, or remove anything. It returns 0 only after all of +these checks succeed: + +- securely reopen the canonical root, statement, closed package-set tree, every + package, raw-result file, and producer record through anchored descriptors; + reject alternate/symlink roots and require the exact types, ownership, modes, + flags, names, architecture set, link counts, and absence of extra entries; +- capture `(device,inode,size,mode,uid,gid,flags,linkCount,mtime,ctime)` from + each open descriptor, stream and hash exact bytes from that descriptor, then + `fstat` it again and reopen its canonical name to require the same device and + inode and unchanged metadata, preventing path-swap and read/verify TOCTOU; +- require package hashes and architectures to equal the statement and matrix; + mount each sealed DMG read-only/no-browse, require its single expected signed + app identity, and use read-only `codesign --verify --deep --strict`, + `xcrun stapler validate -v`, and `spctl --assess --type execute --verbose=4` + to revalidate the exact Team ID, certificate digest, hardened runtime, + embedded accepted ticket, valid staple, and accepted Gatekeeper identity; +- hash the sealed original notary log and stapler/spctl stdout/stderr byte + streams and require their statement digests and recorded raw-zero/status + constants. Fresh verification-tool diagnostic text is not compared to those + producer streams because Apple tool output is not a reproducible package + identity; no package is resubmitted, restapled, or rewritten; +- require `producer-record.json` to be canonical JCS and byte-for-byte equal to + the statement payload, then validate the statement's canonical envelope, + signature domain, active purpose-specific key, matrix/app/HEAD bindings, + status constants, time order, and all closed-schema rules; and +- repeat every descriptor/path/metadata check after tool validation, unmount + read-only mounts, and repeat PIN FIRST's HEAD, cleanliness, commit-object + matrix bytes/object ID/digest, and app-semver checks before returning. + +The read-only controller-owned files, nonwritable controller-owned directories, +held controller lock, descriptor-before/after comparison, and final path reopen +are the ordinary local race boundary. Any observed difference fails; +validation never changes accepted state. `verify:mac-package`, `qualify:meet`, and +`verify:release` use the same validation routine and only validate. None +creates, repairs, replaces, resigns, or infers a missing statement or package +set. This adds no reporter-plan entry, per-run artifact, evidence member, or +bundle member. + +**REJECT and crash safety.** A statement that exists but is invalid, +noncanonical, writable, linked, replaced, or mismatched is never treated as +absence. A missing/partial/replaced/writable/linked package set; wrong +package/signing/notary/staple/`spctl` identity or status; bad HEAD/matrix/app +binding; unexpected file, architecture, path, root, mount, owner, mode, flag, +link, or inode change; alternate or symlink root; unsafe `EEXIST`; attempted +replacement; producer invocation after REUSE selection; or any ambiguous +partial state returns nonzero without mutation, repair, evidence creation, or +checkout movement. + +A crash before the package-set rename leaves only an unaccepted nonce staging +directory, which state selection never reads and a separate privileged +maintenance job may later remove. A crash after that atomic rename but before +statement install leaves the one explicitly resumable state: a complete, +immutable sealed set with no statement. A retry validates it and runs only the +writer. A crash during statement staging leaves only an unaccepted nonce file. +A crash at statement rename yields, after filesystem recovery, either ENOENT +and the safe sealed-set resume or the complete immutable statement; the latter +must pass full REUSE before zero. Staging paths are never accepted, promoted by +discovery, or allowed to select identity. Thus there is no accepted half-state +and no permanently ambiguous canonical state; the sole producer either resumes +its final commit from the exact seal or rejects. + +**Statement schema and identity.** The statement is a closed JCS envelope +containing exactly `payload` and `signature`; `signature` contains exactly +`algorithm: "Ed25519"`, `keyId`, and `value: Base64Url64`. The payload contains +exactly `schemaVersion: 1`, `kind: "qualification-release-statement"`, +`expectedRcSha: RcSha`, `matrixPath: "docs/qualification/macos-google-meet.json"`, `matrixBlobSha256: Sha256`, `matrixRevision: Token`, `appSemver: SemVer`, `packages`, `releaseKeyId`, and `issuedAt: UtcMillis`. `expectedRcSha` equals the verifier's already-pinned -checkout HEAD; the matrix path, digest, and revision equal the already-validated -committed matrix. The statement never contains its own digest. +checkout HEAD; the matrix path, digest, revision, and app semver equal the +already pinned commit-object values. The statement never contains its own +digest. `packages` is a nonempty array sorted by unsigned UTF-8 bytes of `architecture` and contains exactly one object for every distinct architecture in the matrix, @@ -2146,20 +2337,25 @@ matching `^[A-Z0-9]{10}$`), `signingCertificateSha256: Sha256`, `notarizationStatus: "Accepted"`, `notarizationLogSha256: Sha256`, `stapleStatus: "valid"`, `staplerStdoutSha256: Sha256`, `staplerStderrSha256: Sha256`, `spctlStatus: "accepted"`, -`spctlStdoutSha256: Sha256`, `spctlStderrSha256: Sha256`, `builtAt: UtcMillis`, -`notarizedAt: UtcMillis`, and `stapledAt: UtcMillis`. Its three timestamps are -strictly increasing. -`issuedAt` is no earlier than every `stapledAt`. These fields are the complete +`spctlStdoutSha256: Sha256`, `spctlStderrSha256: Sha256`, +`notarytoolSubmitRawExit: 0`, `notarytoolLogRawExit: 0`, +`staplerRawExit: 0`, `spctlRawExit: 0`, `builtAt: UtcMillis`, +`notarizedAt: UtcMillis`, and `stapledAt: UtcMillis`. The four raw exits are +JSON integer constants. Its three timestamps are strictly increasing. +`issuedAt` is no earlier than every `stapledAt`. These fields, the deterministic +external paths, and the required filesystem metadata are the complete post-build package/signing/notarization/staple identity used by qualification. + `notarizationTicketId` is the accepted submission/ticket identifier emitted by `xcrun notarytool`; collection uses that same identifier. The log digest hashes the exact raw bytes returned by `xcrun notarytool log `. The four stdout/stderr digests hash the exact, unnormalized byte streams from -`xcrun stapler validate -v ` and `spctl --assess --type execute ---verbose=4 `, respectively; empty streams hash as empty bytes and -no stream is concatenated with another. The three status constants and the -tools' raw exit 0 are independently required by `package:mac` and -`verify:mac-package`; a digest alone cannot turn a failed result into success. +the producer's `xcrun stapler validate -v ` and +`spctl --assess --type execute --verbose=4 `, respectively; empty +streams hash as empty bytes and no stream is concatenated with another. The +three status constants, four recorded raw-zero fields, and current read-only +verification exits are independently required by CREATE and REUSE; a digest +alone cannot turn a failed result into success. `releaseKeyId`, the signature `keyId`, and the looked-up registry `keyId` are equal and resolve only to an active `qualification-release-statement`/ @@ -2171,9 +2367,34 @@ optional release-bundle, and independent-review domains. A missing statement, wrong external path, extra/missing/wrong-type field, non-JCS object-key order, wrong package order, bad timestamp/order, expected-RC or matrix disagreement, package hash mismatch, unknown/revoked/wrong-purpose/reused key, noncanonical -bytes, wrong domain, or -bad signature makes `qualify:meet`, `verify:release`, and the P12 aggregate -nonzero. +bytes, wrong domain, bad signature, or any filesystem validation failure makes +`qualify:meet`, `verify:release`, and the P12 aggregate nonzero. + +**Unchanged reporter lifecycle proof.** The P12 command row in section 6 is +byte-for-byte unchanged. Its preceding `npm run build` still executes on every +reporter run and may replace only ignored build outputs inside the pinned +worktree. The canonical sealed root is external, selected only from the pinned +HEAD, controller-owned/nonwritable, and never a build output or packaging input +in REUSE; therefore that ordinary build cannot mutate or reselect sealed +packages. `package:mac` is still the only package producer while later +invocations are validators: + +| Exact reporter run | Required state and raw outcomes | Producer and identity proof | +|---|---|---| +| Run 1, no independent review yet | CREATE: `package:mac=0`; every collection/validation child through `qualify:meet --collect-missing=0`; `verify:release!=0` solely for missing independent review; reporter aggregate nonzero by raw-exit aggregation. | Package-producer build/sign/notary/staple counts and statement-writer invocation/successful-install count are exactly one. Snapshot statement and package paths, bytes, device/inodes, sizes, hashes, modes, flags, and link counts after the run. | +| Add one valid independent review, then exact unchanged run 2 | REUSE: `package:mac=0`; pre-existing collection is fully validated; every child including `verify:release=0`; aggregate 0. | All snapshotted statement/package values are identical before and after; no producer or writer runs, so all producer counts remain one. | +| Exact unchanged run 3 | REUSE again; every child and aggregate are 0. | The same snapshots are identical and producer/writer counts remain one. | + +The lifecycle model and mutation suite must instrument every producer and the +writer, attempt statement/package/binding/status/path/root/mode/flag/link/ +canonicalization/signature changes, force checkout-selection attempts, crash at +every fsync and atomic-install boundary, inject unsafe partial states, request a +producer after REUSE selection, and race both exclusive installs. Every case +fails without accepted mutation except a valid no-statement sealed-set resume +or valid `EEXIST` convergence; either may return 0 only after full anchored +identity validation. The model must also prove the three runs above, including +unchanged bytes/inodes/hashes/modes/paths/link counts and one total package- +producer/writer execution. **Exact `collection.json` schema.** The top-level object contains exactly these required keys and values: @@ -2660,7 +2881,8 @@ that no artifact selected them; (2) every raw gate/count report; (3) exact committed matrix bytes/digest plus the mandatory detached release statement's external path, closed payload, arm64/x64 package/signing/notarization/staple identities, matrix-only release key lookup, domain, and signature, together with -the package-policy report; (4) role-by- +the deterministic sealed-package paths/metadata and CREATE/REUSE/REJECT +three-run/crash/race proof; (4) role-by- role extracted entitlement plist diff, SBOM, and vulnerability disposition; (5) protection trace; (6) exact no-wildcard matrix; (7) per-tuple P12-M01/M02 raw recording/content analysis, exact evidence-manifest membership/digest, both @@ -2680,7 +2902,7 @@ signing infrastructure cannot be inferred from unit tests. **Self-contained implementation prompt.** -> Implement P12 from P00-R5 after P01–P11 on +> Implement P12 from P00-R6 after P01–P11 on > `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ > architecture matrix, harden macOS-only package/entitlements/identity, add > local-only redacted diagnostic preview/export, scoped failure recovery, @@ -2693,8 +2915,13 @@ signing infrastructure cannot be inferred from unit tests. > corpus. Externally select and pin clean checkout HEAD before artifacts, > validate/freeze/hash the pre-commit-only committed matrix, produce the > mandatory signed detached post-RC release statement outside Git and all -> bundle/review roots, and fail qualification/release on any checkout, matrix, -> package, key-purpose, domain, or signature disagreement. Implement the exact +> bundle/review roots through the exact CREATE/REUSE/REJECT package state +> machine, and fail qualification/release on any checkout, matrix, sealed-path, +> package, key-purpose, domain, or signature disagreement. Prove the unchanged +> reporter's first run creates once, its second and third runs validate without +> any package producer or writer, every crash boundary is safely resumable or +> rejected, and every exclusive-install `EEXIST` is fully identity-validated. +> Implement the exact > write-once evidence-manifest → two independent > role attestations → final bundle-manifest/digest sequence, canonical bytes, > recursively closed schemas, committed-matrix role/reviewer/release trust, @@ -2712,7 +2939,11 @@ signing infrastructure cannot be inferred from unit tests. > Independently review P12 by externally selecting the clean SHA, freezing and > hashing its exact committed matrix before reading artifacts, then validate the -> required external release statement and rebuild/package identity. Inspect +> required external release statement and sealed-package identity without +> rebuilding, resigning, renotarizing, or restapling in REUSE. Challenge PIN +> FIRST, CREATE/REUSE/REJECT state selection, descriptor/path TOCTOU defenses, +> every crash/fsync/atomic-install boundary, exact `EEXIST` convergence, and the +> unchanged reporter's three-run producer counts and inode/byte stability. Inspect > signing/notarization/entitlements/SBOM, trace protection > before first frame, mechanically compare every signed parent/nested executable > with the exact role allowlist, rerun the complete reporter plan, personally From 494e518f62d636e6af4e455ba615596d95b4d06b Mon Sep 17 00:00:00 2001 From: Timomak Date: Mon, 27 Jul 2026 07:50:46 +0200 Subject: [PATCH 7/9] docs: close P00 release qualification gaps --- design.md | 2 +- docs/implementation/phase-execution-packet.md | 417 ++++++++++++------ 2 files changed, 290 insertions(+), 129 deletions(-) diff --git a/design.md b/design.md index ece46e3a..8976c78c 100644 --- a/design.md +++ b/design.md @@ -863,5 +863,5 @@ Decisions are resolved in dependency order. A later branch may be reordered when The reviewed phase order, dependency graph, acceptance gates, migration owners, prototype disposition, and implementation/review/remediation prompts are defined in [`docs/implementation/phase-execution-packet.md`](docs/implementation/phase-execution-packet.md), -revision P00-R6. This design remains the product source of truth; the packet is +revision P00-R7. This design remains the product source of truth; the packet is the execution contract. Prototype evidence does not establish phase completion. diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md index 6898ed01..c8d93e33 100644 --- a/docs/implementation/phase-execution-packet.md +++ b/docs/implementation/phase-execution-packet.md @@ -1,6 +1,6 @@ # InterviewCopilot phase-execution packet -Packet revision: **P00-R6** +Packet revision: **P00-R7** Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` @@ -391,7 +391,7 @@ inside the single PR. **Self-contained implementation prompt.** -> Implement P01 from P00-R6 on `phase/P01-local-gates`, based only on upstream +> Implement P01 from P00-R7 on `phase/P01-local-gates`, based only on upstream > `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. > Make local lint, strict type-check, real unit tests (including the unchanged > tracked CRA sample), manifest enforcement, and build green. Centralize and @@ -403,7 +403,7 @@ inside the single PR. **Self-contained review prompt.** -> Review P01 independently against P00-R6, not the author’s summary. From the +> Review P01 independently against P00-R7, not the author’s summary. From the > clean PR checkout run the P01 reporter invocation, confirm the inherited CRA > test ran, > inspect all config/glob/ignore changes for hidden coverage loss, compare typed @@ -532,7 +532,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained implementation prompt.** -> Implement P02 from P00-R6 after P01, on +> Implement P02 from P00-R7 after P01, on > `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime > for Claude Code and Codex only, using one resumable session/thread, normalized > streaming/usage/compaction/stop/error events, explicit provider/model/Fast- @@ -545,7 +545,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained review prompt.** -> Review P02 against P00-R6 from a clean checkout. Trace both fake providers +> Review P02 against P00-R7 from a clean checkout. Trace both fake providers > through two turns, stop, compaction, driver/child restart, and caller-ID > resume; force every failure and prove the other provider never starts. Inspect > spawn/env/tool restrictions, IPC exposure, migration idempotence/file mode, @@ -658,7 +658,7 @@ never custom cryptography. **Self-contained implementation prompt.** -> Implement P03 from P00-R6 after P01 on +> Implement P03 from P00-R7 after P01 on > `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key > service, versioned AES-256-GCM record/blob store, atomic writes, encrypted > in-memory-search source, typed recovery, raw-audio rejection, and journaled @@ -806,7 +806,7 @@ boundary; no renderer or provider may keep a second authoritative session. **Self-contained implementation prompt.** -> Implement P04 from P00-R6 after P02/P03 on +> Implement P04 from P00-R7 after P02/P03 on > `phase/P04-session-orchestrator`. Replace global transient state with the > deterministic InterviewSession reducer, typed event/IPC contract, one > persistent-conversation orchestrator, context/delta policy, pending artifacts, @@ -941,7 +941,7 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained implementation prompt.** -> Implement P05 from P00-R6 after P04 on `phase/P05-live-shell`. Build the +> Implement P05 from P00-R7 after P04 on `phase/P05-live-shell`. Build the > exact Quiet Signal hidden/compact/answer/expanded shell, command rail, > composer, input tray, explicit click-through/drag regions, final remappable > shortcuts, display-aware geometry, primary-display screenshot behavior, @@ -1063,7 +1063,7 @@ regress silently; fixture contracts are merge-blocking. **Self-contained implementation prompt.** -> Implement P06 from P00-R6 after P05 on `phase/P06-coding`. Add the exact +> Implement P06 from P00-R7 after P05 on `phase/P06-coding`. Add the exact > typed Coding intents/schema/renderer, concise-first progressive answer, > language snapshot and six-family fixtures, read-only actions, New Question, > and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, @@ -1178,7 +1178,7 @@ must not become a second untyped document model. **Self-contained implementation prompt.** -> Implement P07 from P00-R6 after P05 on `phase/P07-system-design`. Add the +> Implement P07 from P00-R7 after P05 on `phase/P07-system-design`. Add the > fixed typed five-section progressive workflow, bounded material estimates, > safe vendor-neutral structured diagram, read-only accessible interactions, > assumption handling, dependency-scoped follow-up and What changed summary. @@ -1299,7 +1299,7 @@ integrity are product trust boundaries. **Self-contained implementation prompt.** -> Implement P08 from P00-R6 after P05 on `phase/P08-behavioral`. Build the +> Implement P08 from P00-R7 after P05 on `phase/P08-behavioral`. Build the > encrypted canonical candidate dossier, guided/manual reviewed editing, > sanitized Markdown import/export, multiple snapshotted opportunities, > provenance, opt-in labeled persistent synthetic stories, and typed Behavioral @@ -1432,7 +1432,7 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained implementation prompt.** -> Implement P09 from P00-R6 after P05 on `phase/P09-audio`, macOS only. Build +> Implement P09 from P00-R7 after P05 on `phase/P09-audio`, macOS only. Build > explicit two-source native capture, deterministic master/per-source controls, > contextual permission recovery, pinned offline whisper.cpp transcription, > explicit Apple Speech remote fallback, typed segments/attribution/correction, @@ -1551,7 +1551,7 @@ must never become a capability or schema escape hatch. **Self-contained implementation prompt.** -> Implement P10 from P00-R6 after P06/P07/P08 on +> Implement P10 from P00-R7 after P06/P07/P08 on > `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, > immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, > deterministic recorded instruction resolution, Start snapshotting, protected @@ -1668,7 +1668,7 @@ content and destructive user controls. **Self-contained implementation prompt.** -> Implement P11 from P00-R6 after P06–P10 on +> Implement P11 from P00-R7 after P06–P10 on > `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete > encrypted archive projection, Settings-only in-memory search/open/delete one/ > all, safe consented individual Markdown/JSON export, read-only archive open, @@ -1729,7 +1729,7 @@ detached statement binds its app semver and post-build package identity. Those exact passing tuples—and no neighboring patch, major version, browser, app build, architecture, or display mode—are the supported macOS/browser/app versions until separately qualified. Qualify each supported tuple separately. -P00-R6 represents no version as supported before the committed matrix, detached +P00-R7 represents no version as supported before the committed matrix, detached release statement, and evidence pass. Entire-display and specific-window require confirmation from remote Meet view or second device and retained high-contrast moving-marker artifacts; one fail makes @@ -2144,23 +2144,62 @@ record that makes the package set acceptable. The release-controller service identity exclusively owns `/Users/Shared/InterviewCopilot`. Its installer pre-provisions a regular -link-count-one lock file outside every RC root. Every canonical directory below -`/Users/Shared` is opened component-by-component from an already opened -`/Users/Shared` descriptor with `openat` plus `O_DIRECTORY|O_NOFOLLOW`; it is -owned by the controller service, has no ACL, mount transition, or group/other -write bit, and has mode 0555 once installed. Accepted package and raw-result -files are link-count-one regular files with mode 0444; `producer-record.json` -and `release-statement.json` are link-count-one regular files with mode 0400. +link-count-one lock file outside every RC root. The fixed filesystem-root +descriptor, `/Users`, `/Users/Shared`, and every canonical or staging +descendant are opened component-by-component with `openat` plus +`O_DIRECTORY|O_NOFOLLOW`. Every ancestor descriptor, the pre-provisioned lock, +controller root, release-statement root, canonical RC root, staging root, +staging RC root, every nonce/sealed/architecture directory, and every staged or +accepted file have no extended ACL entry. Every +controller-owned directory also has no mount transition or group/other write +bit and has mode 0555 once installed. Accepted package and raw-result files are +link-count-one regular files with mode 0444; `producer-record.json` and +`release-statement.json` are link-count-one regular files with mode 0400. Accepted files have no file flags set. Their controller ownership, absence of -owner/group/other write bits, and nonwritable installed directories make both -file bytes and closed entry sets immutable to the invoking user without a -post-rename flag operation or crash window. The privileged controller is the -only process allowed to install a new name into those nonwritable directories. -Root/controller credential compromise is outside the threat model; symlinks, -aliases, hard links, clone-selected -alternate roots, writable ancestors, unexpected ownership/mode/flags, and -paths supplied through argv, environment, artifacts, pairing, or statements -are in scope and fail. +owner/group/other write bits and extended ACLs, and nonwritable installed +directories make both file bytes and closed entry sets immutable to the +invoking user without a post-rename flag operation or crash window. The +privileged controller is the only process allowed to install a new name into +those nonwritable directories. Root/controller credential compromise is +outside the threat model; symlinks, aliases, hard links, clone-selected +alternate roots, writable or ACL-bearing ancestors, unexpected +ownership/mode/flags/ACLs, and paths supplied through argv, environment, +artifacts, pairing, or statements are in scope and fail. + +**Descriptor ACL authority.** Extended-ACL state is determined only from each +already anchored descriptor. On the matrix-pinned macOS product/build and APFS +volume, the native fixture must compile against the current macOS SDK and prove +the one canonical `NO_EXTENDED_ACL` result for both a directory and regular +file: set `errno=0`; call +`acl_get_fd_np(fd, ACL_TYPE_EXTENDED)`; require `(acl_t)NULL` with +`errno==ENOENT`. This `ENOENT` is an ACL-library sentinel observed only after +the object descriptor is open; it never means the filesystem object or +accepted identity is absent. The P00-R7 isolated authoring probe established +this result on macOS 26.5.1 build 25F80, APFS, with SDK 26.5; P12 must reproduce +it on each exact matrix-pinned macOS product/build before qualification and +fail constructibility if it differs. The fixture must also prove that direct +and inherited allow/deny write/append entries instead return an ACL object for +which `acl_get_entry(acl, ACL_FIRST_ENTRY, &entry)==0`. + +The runtime uses that exact routine. A returned ACL object is never success: +it clears errno, calls `acl_get_entry` with `ACL_FIRST_ENTRY`, records its return +and errno, calls `acl_free` on every returned object on every path, records that +return, and rejects an entry. It +also rejects a returned object with no readable first entry, any +`acl_get_entry` result other than the fixture-proved entry result, any +`acl_free` failure, a null result with errno other than `ENOENT`, an +unsupported filesystem, or any other retrieval ambiguity. Thus a nonnull empty +ACL object is unexpected and fail-closed rather than an alternative no-ACL +sentinel. Mode bits, ctime, pathname xattr probes, and `ls` output are never ACL +authority. + +Every in-memory descriptor before/after snapshot therefore contains exactly +`(device,inode,size,mode,uid,gid,flags,linkCount,mtime,ctime,aclState)`, where +`aclState` is the live descriptor-proved canonical `NO_EXTENDED_ACL` result; +this adds no persisted schema field. Every final canonical-name reopen repeats +the ACL call on the reopened descriptor before identity comparison. Allow, +deny, write, append, inherited, and mixed ACLs all reject regardless of whether +POSIX mode, size, ctime, or any other snapshot field appears canonical. **PIN FIRST.** Before opening the canonical RC root, the command requires a detached, clean checkout; pins `git rev-parse HEAD` as `expectedRcSha`; resolves @@ -2177,14 +2216,19 @@ override any pin. After PIN FIRST, `package:mac` opens and takes the pre-provisioned lock without creating it, then repeats the complete HEAD/cleanliness/commit-object/matrix -check before state selection. The privileged controller creates an absent -canonical `` directory once with `mkdirat`, mode 0555, and an -immediate parent fsync; `EEXIST` requires the same anchored directory -validation. An empty canonical RC directory is a safe no-statement/no-seal -CREATE state, not accepted identity. The command repeats PIN FIRST again before -any exclusive install and before returning. Every validator independently -performs the same pin and final recheck. A checkout-selection attempt or change -at any checkpoint is REJECT without repair or checkout movement. +check before state selection. The lock descriptor, filesystem root, `/Users`, +`/Users/Shared`, and every canonical and staging ancestor descriptor must first +pass ACL-free validation. The privileged controller creates an absent canonical +`` directory once with `mkdirat`, mode 0555, validates its +descriptor including ACL state before any child creation and after its final +mode, and immediately fsyncs the parent; `EEXIST` requires the same anchored +directory validation. An ACL-bearing existing object is REJECT, never absence, +success by existence, or repairable state. An empty canonical RC directory is +a safe no-statement/no-seal CREATE state, not accepted identity. The command +repeats PIN FIRST again before any exclusive install and before returning. +Every validator independently performs the same pin and final recheck. A +checkout-selection attempt or change at any checkpoint is REJECT without +repair or checkout movement. **CREATE.** With the lock held, absence means an `openat` of the canonical statement name returns `ENOENT`, not merely that a prior pathname probe did. @@ -2199,55 +2243,102 @@ There are only two safe no-statement substates: on the same APFS volume. This is the package producer build, distinct from the preceding repository `npm run build` child. 2. If the statement is absent but a complete installed `sealed-package-set` - exists, CREATE is a crash-resume commit step. The command runs the entire - REUSE package-set validation below and, only on exact agreement, invokes the - statement writer. It never rebuilds, resigns, renotarizes, restaples, reruns - a producer, or edits the installed set. - -The staging directory contains exactly the closed layout above. Before install, -the controller independently derives every architecture from the pinned -matrix, hashes the exact package and raw output bytes, validates the signature, -hardened-runtime entitlement, certificate/team identity, accepted -notarization ticket and exact raw log, valid staple, and accepted `spctl` raw -exit/status, and creates the exact canonical `producer-record.json`. It rejects -extra packages, architectures, app bundles, metadata, or output files. It -fsyncs every file after its final bytes and mode, fsyncs each directory -bottom-up, requires zero file flags and applies the final read-only modes, and -fsyncs the staging parent. It then atomically installs the whole directory with macOS + exists, CREATE is a crash-resume commit step. It does not enter REUSE, + because REUSE requires a statement. It parses the canonical + `producer-record.json` as the local candidate payload, runs the anchored + statement-independent sealed-set validator below with the pinned context and + that candidate, and only on exact agreement invokes the statement writer. + It never rebuilds, resigns, renotarizes, restaples, reruns a producer, or + edits the installed set. + +**Anchored sealed-set validation.** The single reusable routine is +`validateSealedSet(pinnedContext, candidatePayload)`. It never opens or requires +a release statement. From anchored descriptors it validates the exact closed +directory tree; all ownership, type, mode, flag, link, name, mount, before/ +after/final-reopen ACL, and identity properties; every package and raw +notary/stapler/`spctl` byte stream and digest; every current read-only +signature, hardened-runtime, certificate/team, notarization-ticket, staple, +Gatekeeper status, and raw-zero requirement; and every closed, canonical, +pinned package/status/timestamp field in `producer-record.json`. The producer +record must be canonical JCS and byte-for-byte equal to `candidatePayload`; +neither one selects the pinned context. After read-only tools and PIN recheck, +the routine repeats every canonical-name reopen and descriptor/ACL snapshot as +its last fallible operation immediately before any zero return. The same rule +applies to every writer, command, and validator zero return. + +Fresh CREATE supplies the independently derived in-memory producer payload and +runs this routine on the staged set before install and the canonical set after +install. Package-set `RENAME_EXCL EEXIST` convergence supplies that same locally +retained payload and additionally requires the installed set to equal the +contender's complete candidate identity. Crash resume has no retained producer +process: it accepts the canonical producer record only as a candidate, derives +and cross-checks every one of its fields against the pinned context, sealed +packages, raw streams, and read-only tool results, and invokes the writer only +after the routine succeeds. Full REUSE remains statement-dependent: it first +validates the canonical statement and signature, then calls this routine with +the exact statement payload and requires the producer record to equal it. +Partial, ambiguous, ACL-bearing, or mismatched state fails without repair at +every crash boundary and both package-set install outcomes. + +The staging directory contains exactly the closed layout above. Before CREATE +produces any identity, the controller validates the controller-owned staging +ancestors, staging RC directory, and fresh nonce root as ACL-free. It +exclusively creates each expected directory and file, validates the new +descriptor as ACL-free before producing child names or file content, and +validates it again after its final mode. It never strips, replaces, normalizes, +or repairs an ACL or other noncanonical metadata. The controller independently +derives every architecture from the pinned matrix, hashes the exact package and +raw output bytes, validates the signature, hardened-runtime entitlement, +certificate/team identity, accepted notarization ticket and exact raw log, +valid staple, and accepted `spctl` raw exit/status, and creates the exact +canonical `producer-record.json`. It rejects extra packages, architectures, app +bundles, metadata, output files, or any direct/inherited ACL. It fsyncs every +file after its final bytes and mode, fsyncs each directory bottom-up, requires +zero file flags and ACL-free final descriptors, applies the final read-only +modes, and fsyncs the staging parent. It then atomically installs the whole +directory with macOS `renameatx_np(..., RENAME_EXCL)` to the canonical `sealed-package-set` name and fsyncs both source and destination parents. No -copy, ordinary rename-over, unlink, repair, or replacement is allowed. +copy, ordinary rename-over, unlink, ACL sanitization, repair, or replacement is +allowed. An install `EEXIST` is a race, never success by existence. The contender closes all staging descriptors, securely reopens the canonical installed set from the -anchored RC descriptor, and performs the complete validation below. It may -continue only if the installed bytes and every identity field exactly equal -the locally derived candidate; otherwise it returns nonzero without changing -either set. Cooperating `package:mac` processes serialize on the lock, so the -second ordinarily reaches REUSE before running any producer; the `EEXIST` path -is still mandatory for a noncooperating or injected race. +anchored RC descriptor, and calls +`validateSealedSet(pinnedContext, locallyDerivedCandidatePayload)`, including +all ACL checks. It may continue only if the installed bytes and every identity +field exactly equal the locally derived candidate; otherwise it returns +nonzero without changing either set. Cooperating `package:mac` processes +serialize on the lock, so the second ordinarily reaches REUSE before running +any producer; the `EEXIST` path is still mandatory for a noncooperating or +injected race. Only after the installed set passes that validation does `package:mac` invoke the controller-owned exclusive statement writer, exactly once and as its final producer step. The writer signs the already sealed `producer-record.json` -payload, constructs the closed statement envelope, writes it to a fresh 0600 -nonce file in the same-volume staging root with `O_CREAT|O_EXCL|O_NOFOLLOW`, -fsyncs its complete canonical bytes, changes it to mode 0400, requires zero file -flags, fsyncs it again and fsyncs the staging directory, then atomically -installs it +payload, constructs the closed statement envelope, and opens a fresh 0600 nonce +file in the already ACL-free same-volume staging root with +`O_CREAT|O_EXCL|O_NOFOLLOW`. It validates the new descriptor as ACL-free before +writing, fsyncs its complete canonical bytes, changes it to mode 0400, requires +zero file flags and an ACL-free descriptor again, fsyncs it again and fsyncs +the staging directory, then atomically installs it at `release-statement.json` using `renameatx_np(..., RENAME_EXCL)`. It fsyncs the canonical RC directory, securely reopens the installed name, fully validates it and the sealed set, repeats the -PIN check, and only then returns 0. The final pathname therefore exposes either -no file or one complete canonical file, never a partially written statement. +PIN check, repeats the final descriptor/ACL snapshots immediately before the +zero return, and only then returns 0. The final pathname therefore exposes +either no file or one complete canonical file, never a partially written +statement. Writer `EEXIST` has the same exact race rule: close the uninstalled nonce file; open the canonical name from the anchored RC descriptor with `O_NOFOLLOW`; require the final file and all ancestors, the sealed package set, canonical -bytes, payload, signature/purpose, and every pinned and post-build identity to -pass the complete REUSE validation; and return 0 only if that exact pre-existing -identity equals the writer input byte-for-byte. It never unlinks, renames over, -replaces, resigns, repairs, or trusts the file merely because it exists. +bytes, payload, signature/purpose, ACL state, and every pinned and post-build +identity to pass the complete statement-dependent REUSE validation; repeat the +final descriptor/ACL snapshots immediately before zero; and return 0 only if +that exact pre-existing identity equals the writer input byte-for-byte. It +never unlinks, renames over, replaces, resigns, strips ACLs, repairs, or trusts +the file merely because it exists. **REUSE.** If the exact statement name opens successfully after the second pin, `package:mac` becomes validation-only before consulting any worktree build @@ -2257,14 +2348,22 @@ evidence file, mutate staging or sealed paths, repair permissions/flags, replace or resign the statement, or remove anything. It returns 0 only after all of these checks succeed: +- validate the statement's canonical envelope, signature domain, active + purpose-specific key, matrix/app/HEAD bindings, status constants, time order, + and all closed-schema rules, then pass its exact payload to + `validateSealedSet`; a sealed set without a statement can never enter this + statement-dependent path; - securely reopen the canonical root, statement, closed package-set tree, every package, raw-result file, and producer record through anchored descriptors; reject alternate/symlink roots and require the exact types, ownership, modes, - flags, names, architecture set, link counts, and absence of extra entries; -- capture `(device,inode,size,mode,uid,gid,flags,linkCount,mtime,ctime)` from - each open descriptor, stream and hash exact bytes from that descriptor, then - `fstat` it again and reopen its canonical name to require the same device and - inode and unchanged metadata, preventing path-swap and read/verify TOCTOU; + flags, ACL-free state, names, architecture set, link counts, and absence of + extra entries; +- capture + `(device,inode,size,mode,uid,gid,flags,linkCount,mtime,ctime,aclState)` from + each open directory and file descriptor, stream and hash exact bytes from + the file descriptor, then `fstat` and inspect its ACL again and reopen its + canonical name to require the same device, inode, metadata, and ACL-free + state, preventing path-swap and read/verify/ACL TOCTOU; - require package hashes and architectures to equal the statement and matrix; mount each sealed DMG read-only/no-browse, require its single expected signed app identity, and use read-only `codesign --verify --deep --strict`, @@ -2277,44 +2376,57 @@ these checks succeed: producer streams because Apple tool output is not a reproducible package identity; no package is resubmitted, restapled, or rewritten; - require `producer-record.json` to be canonical JCS and byte-for-byte equal to - the statement payload, then validate the statement's canonical envelope, - signature domain, active purpose-specific key, matrix/app/HEAD bindings, - status constants, time order, and all closed-schema rules; and -- repeat every descriptor/path/metadata check after tool validation, unmount - read-only mounts, and repeat PIN FIRST's HEAD, cleanliness, commit-object - matrix bytes/object ID/digest, and app-semver checks before returning. + the already validated statement payload; and +- repeat every descriptor/path/metadata/ACL check after every read-only tool + validation, unmount read-only mounts, repeat PIN FIRST's HEAD, cleanliness, + commit-object matrix bytes/object ID/digest, and app-semver checks, then + perform a final canonical-name reopen and unchanged descriptor/ACL snapshot + on every object immediately before returning 0. No tool, pathname probe, + cleanup, PIN operation, or other fallible work intervenes between that final + ACL pass and the zero return. The read-only controller-owned files, nonwritable controller-owned directories, -held controller lock, descriptor-before/after comparison, and final path reopen -are the ordinary local race boundary. Any observed difference fails; -validation never changes accepted state. `verify:mac-package`, `qualify:meet`, and -`verify:release` use the same validation routine and only validate. None -creates, repairs, replaces, resigns, or infers a missing statement or package -set. This adds no reporter-plan entry, per-run artifact, evidence member, or -bundle member. +held ACL-free controller lock, descriptor-before/after ACL comparison, final +path reopen, and immediate pre-zero ACL pass are the ordinary local race +boundary. Any observed difference fails; validation never changes accepted +state. Initial CREATE, statement-independent sealed-set crash resume, exact +REUSE runs 2 and 3, package-set `RENAME_EXCL EEXIST`, statement +`RENAME_EXCL EEXIST`, `verify:mac-package`, `qualify:meet`, `verify:release`, +and every other validator all use the same descriptor ACL authority at every +checkpoint. Validators use statement-dependent REUSE and only validate. None +creates, repairs, replaces, resigns, strips ACLs, or infers a missing statement +or package set. This adds no reporter-plan entry, per-run artifact, evidence +member, or bundle member. **REJECT and crash safety.** A statement that exists but is invalid, -noncanonical, writable, linked, replaced, or mismatched is never treated as -absence. A missing/partial/replaced/writable/linked package set; wrong +noncanonical, writable, ACL-bearing, linked, replaced, or mismatched is never +treated as absence. A missing/partial/replaced/writable/ACL-bearing/linked +package set; an ACL-bearing lock, ancestor, staged object, or accepted object; +an unexpected ACL API/errno/free result; wrong package/signing/notary/staple/`spctl` identity or status; bad HEAD/matrix/app binding; unexpected file, architecture, path, root, mount, owner, mode, flag, -link, or inode change; alternate or symlink root; unsafe `EEXIST`; attempted -replacement; producer invocation after REUSE selection; or any ambiguous -partial state returns nonzero without mutation, repair, evidence creation, or -checkout movement. +ACL, link, or inode change; alternate or symlink root; unsafe `EEXIST`; +attempted replacement; producer invocation after REUSE selection; or any +ambiguous partial state returns nonzero without mutation, ACL sanitization, +repair, evidence creation, or checkout movement. A crash before the package-set rename leaves only an unaccepted nonce staging -directory, which state selection never reads and a separate privileged -maintenance job may later remove. A crash after that atomic rename but before -statement install leaves the one explicitly resumable state: a complete, -immutable sealed set with no statement. A retry validates it and runs only the -writer. A crash during statement staging leaves only an unaccepted nonce file. -A crash at statement rename yields, after filesystem recovery, either ENOENT -and the safe sealed-set resume or the complete immutable statement; the latter -must pass full REUSE before zero. Staging paths are never accepted, promoted by -discovery, or allowed to select identity. Thus there is no accepted half-state -and no permanently ambiguous canonical state; the sole producer either resumes -its final commit from the exact seal or rejects. +directory, which state selection never reads. A separate privileged +maintenance job may remove an explicitly unaccepted staging path, but it never +discovers or selects accepted identity, invokes either validator or writer, +promotes a staged path, strips an ACL, sanitizes metadata, or repairs a path. +A crash after the atomic package-set rename but before statement install leaves +the one explicitly resumable state: a complete immutable sealed set with no +statement. A retry runs only +`validateSealedSet(pinnedContext, resumeCandidatePayload)` and, after exact +success, the writer. A crash during statement staging leaves only an +unaccepted nonce file. A crash at statement rename yields, after filesystem +recovery, either object-level `ENOENT` and the safe sealed-set resume or the +complete immutable statement; the latter must pass full statement-dependent +REUSE and the immediate pre-zero ACL pass. Staging paths are never accepted, +promoted by discovery, or allowed to select identity. Thus there is no accepted +half-state and no permanently ambiguous canonical state; the sole producer +either resumes its final commit from the exact validated seal or rejects. **Statement schema and identity.** The statement is a closed JCS envelope containing exactly `payload` and `signature`; `signature` contains exactly @@ -2381,20 +2493,24 @@ invocations are validators: | Exact reporter run | Required state and raw outcomes | Producer and identity proof | |---|---|---| -| Run 1, no independent review yet | CREATE: `package:mac=0`; every collection/validation child through `qualify:meet --collect-missing=0`; `verify:release!=0` solely for missing independent review; reporter aggregate nonzero by raw-exit aggregation. | Package-producer build/sign/notary/staple counts and statement-writer invocation/successful-install count are exactly one. Snapshot statement and package paths, bytes, device/inodes, sizes, hashes, modes, flags, and link counts after the run. | -| Add one valid independent review, then exact unchanged run 2 | REUSE: `package:mac=0`; pre-existing collection is fully validated; every child including `verify:release=0`; aggregate 0. | All snapshotted statement/package values are identical before and after; no producer or writer runs, so all producer counts remain one. | -| Exact unchanged run 3 | REUSE again; every child and aggregate are 0. | The same snapshots are identical and producer/writer counts remain one. | +| Run 1, no independent review yet | CREATE: `package:mac=0`; every collection/qualification child through `qualify:meet --collect-missing=0`; `verify:release=1` solely for missing independent review; reporter aggregate `=1` by raw-exit aggregation. No other nonzero value is accepted. | Package-producer build/sign/notary/staple counts and statement-writer invocation/successful-install count are exactly one. Snapshot statement and package paths, bytes, device/inodes, sizes, hashes, modes, flags, ACL states, and link counts after the run. | +| Add one valid independent review, then exact unchanged run 2 | REUSE: `package:mac=0`; pre-existing collection is fully validated; every child raw exit including `verify:release=0`; aggregate `=0`. | All snapshotted statement/package values, including ACL-free state, are identical before and after; no producer or writer runs, so all producer counts remain one. | +| Exact unchanged run 3 | REUSE again; every child raw exit and the aggregate are exactly `0`. | The same snapshots, including ACL-free state, are identical and producer/writer counts remain one. | The lifecycle model and mutation suite must instrument every producer and the -writer, attempt statement/package/binding/status/path/root/mode/flag/link/ -canonicalization/signature changes, force checkout-selection attempts, crash at -every fsync and atomic-install boundary, inject unsafe partial states, request a -producer after REUSE selection, and race both exclusive installs. Every case -fails without accepted mutation except a valid no-statement sealed-set resume -or valid `EEXIST` convergence; either may return 0 only after full anchored -identity validation. The model must also prove the three runs above, including -unchanged bytes/inodes/hashes/modes/paths/link counts and one total package- -producer/writer execution. +writer, attempt statement/package/binding/status/path/root/mode/flag/ACL/link/ +canonicalization/signature changes, force checkout-selection attempts, crash +at every fsync and atomic-install boundary, inject unsafe partial states, +request a producer after REUSE selection, and race both exclusive installs. +It separately exercises the statement-independent sealed-set validator at +every safe package-install/crash-resume boundary and the statement-dependent +REUSE validator only when the statement exists. Every case fails without +accepted mutation except a valid no-statement sealed-set resume or valid +`EEXIST` convergence; either may return 0 only after the applicable full +anchored identity/ACL validation. The model must also prove the three runs +above, including exact child and aggregate exits, unchanged bytes/inodes/hashes/ +modes/paths/ACL states/link counts, and one total package-producer/writer +execution. **Exact `collection.json` schema.** The top-level object contains exactly these required keys and values: @@ -2710,6 +2826,37 @@ The companion fixed-point scan rejects any matrix field or normative prose that requires the matrix to contain its own RC SHA, app/package hash, signing/ notarization/staple output, build timestamp, or release-statement digest. +That existing contract also contains the named case +`rejects inherited and direct write-or-append ACLs on every staged and accepted lifecycle path`. +It compiles a native current-SDK descriptor helper and fixture-proves the +matrix-pinned macOS/APFS no-ACL sentinel before exercising the pre-provisioned +lock; filesystem root, `/Users`, `/Users/Shared`, canonical, and staging +ancestors; nonce, sealed, and architecture directories; package, +`producer-record.json`, every raw +notary/stapler/`spctl` stream, statement nonce, and accepted statement. It +injects allow, deny, write, append, inherited, and mixed ACEs at CREATE before +content/child creation and after final mode, sealed-set crash resume, exact +REUSE runs 2 and 3, package-set and statement `RENAME_EXCL EEXIST`, every +descriptor before/after pass, final canonical-name reopen, every validator, and +the immediate pre-zero pass. It proves modes remain unchanged and a same-size +post-check overwrite would succeed under an injected write ACE, while every +such case is REJECT once descriptor ACL validation is present. It injects +unexpected null errno, returned-empty-object, entry-iteration, ACL-free +unsupported-filesystem, and `acl_free` failures and requires fail-closed cleanup +of every returned ACL object. + +The same existing constructibility contract separately exercises +`validateSealedSet(pinnedContext, candidatePayload)` with a complete canonical +seal and no statement after every safe fsync/install crash boundary, and after +package-set `EEXIST`; only exact validation may invoke the exclusive writer. +Partial, ambiguous, ACL-bearing, and candidate/record/package/raw/status +mismatches reject without repair. It also proves that full REUSE rejects an +absent statement, that writer `EEXIST` requires full statement-dependent +validation, and that the three reporter runs have exact raw-exit vectors: +run 1 has only `verify:release=1` and aggregate `1`, while every child and +aggregate on runs 2 and 3 is `0`. These are additions to the existing P12 test +aggregate, not a new reporter child, acceptance criterion, artifact, or schema. + `scripts/qualification/schema-inventory.test.ts` inventories the committed closed schemas for the matrix and release-envelope family (mandatory detached statement plus optional bundle signature), each of the four NDJSON event payload @@ -2882,7 +3029,9 @@ committed matrix bytes/digest plus the mandatory detached release statement's external path, closed payload, arm64/x64 package/signing/notarization/staple identities, matrix-only release key lookup, domain, and signature, together with the deterministic sealed-package paths/metadata and CREATE/REUSE/REJECT -three-run/crash/race proof; (4) role-by- +three-run/crash/race proof, exact first/second/third-run exits, separate sealed- +set-resume/full-REUSE validator proof, and native descriptor ACL sentinel/ +mutation proof; (4) role-by- role extracted entitlement plist diff, SBOM, and vulnerability disposition; (5) protection trace; (6) exact no-wildcard matrix; (7) per-tuple P12-M01/M02 raw recording/content analysis, exact evidence-manifest membership/digest, both @@ -2902,7 +3051,7 @@ signing infrastructure cannot be inferred from unit tests. **Self-contained implementation prompt.** -> Implement P12 from P00-R6 after P01–P11 on +> Implement P12 from P00-R7 after P01–P11 on > `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ > architecture matrix, harden macOS-only package/entitlements/identity, add > local-only redacted diagnostic preview/export, scoped failure recovery, @@ -2917,10 +3066,18 @@ signing infrastructure cannot be inferred from unit tests. > mandatory signed detached post-RC release statement outside Git and all > bundle/review roots through the exact CREATE/REUSE/REJECT package state > machine, and fail qualification/release on any checkout, matrix, sealed-path, -> package, key-purpose, domain, or signature disagreement. Prove the unchanged -> reporter's first run creates once, its second and third runs validate without -> any package producer or writer, every crash boundary is safely resumable or -> rejected, and every exclusive-install `EEXIST` is fully identity-validated. +> package, filesystem ACL, key-purpose, domain, or signature disagreement. Use +> descriptor-only current-SDK extended-ACL inspection, enforce the pinned +> no-ACL sentinel on the lock and every canonical/staged/accepted ancestor, +> directory, and file before/after/final-reopen/immediate-pre-zero, and reject +> rather than sanitize inherited or direct ACLs. Implement the separate +> statement-independent anchored sealed-set validator for complete-seal/no- +> statement crash resume; keep full REUSE statement-dependent. Prove the +> unchanged reporter's first run creates once with only `verify:release=1` and +> aggregate `1`, its second and third runs have exact all-zero child/aggregate +> exits without any package producer or writer, every crash boundary is safely +> resumable or rejected, and every exclusive-install `EEXIST` is fully +> identity- and ACL-validated. > Implement the exact > write-once evidence-manifest → two independent > role attestations → final bundle-manifest/digest sequence, canonical bytes, @@ -2941,9 +3098,13 @@ signing infrastructure cannot be inferred from unit tests. > hashing its exact committed matrix before reading artifacts, then validate the > required external release statement and sealed-package identity without > rebuilding, resigning, renotarizing, or restapling in REUSE. Challenge PIN -> FIRST, CREATE/REUSE/REJECT state selection, descriptor/path TOCTOU defenses, -> every crash/fsync/atomic-install boundary, exact `EEXIST` convergence, and the -> unchanged reporter's three-run producer counts and inode/byte stability. Inspect +> FIRST, CREATE/REUSE/REJECT state selection, the distinct sealed-set-resume and +> statement-dependent REUSE validators, descriptor/path/ACL TOCTOU defenses, +> ACL inheritance and changes at every checkpoint, ACL-object cleanup and +> unsupported-filesystem/error behavior, accepted versus unaccepted cleanup, +> every crash/fsync/atomic-install boundary, both exact `EEXIST` convergence +> paths, immediate-pre-zero timing, and the unchanged reporter's exact three-run +> raw exits, producer counts, and inode/byte/ACL stability. Inspect > signing/notarization/entitlements/SBOM, trace protection > before first frame, mechanically compare every signed parent/nested executable > with the exact role allowlist, rerun the complete reporter plan, personally From ce5e6ae533b65cde6d7996ec572c6d35315b5bde Mon Sep 17 00:00:00 2001 From: Timomak Date: Mon, 27 Jul 2026 15:43:38 +0200 Subject: [PATCH 8/9] docs: add P00 verification controller contract --- design.md | 2 +- docs/implementation/phase-execution-packet.md | 636 +++++++++++++----- 2 files changed, 467 insertions(+), 171 deletions(-) diff --git a/design.md b/design.md index 8976c78c..0edab452 100644 --- a/design.md +++ b/design.md @@ -863,5 +863,5 @@ Decisions are resolved in dependency order. A later branch may be reordered when The reviewed phase order, dependency graph, acceptance gates, migration owners, prototype disposition, and implementation/review/remediation prompts are defined in [`docs/implementation/phase-execution-packet.md`](docs/implementation/phase-execution-packet.md), -revision P00-R7. This design remains the product source of truth; the packet is +revision P00-R8. This design remains the product source of truth; the packet is the execution contract. Prototype evidence does not establish phase completion. diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md index c8d93e33..579a5f23 100644 --- a/docs/implementation/phase-execution-packet.md +++ b/docs/implementation/phase-execution-packet.md @@ -1,6 +1,6 @@ # InterviewCopilot phase-execution packet -Packet revision: **P00-R7** +Packet revision: **P00-R8** Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` @@ -39,6 +39,15 @@ rename, weaken, delete, or skip a listed gate or any pre-existing test. when they do not enlarge the launch surface. - Local verification is authoritative. GitHub CI may inform a review but may not waive or replace any local gate in this packet. +- From P01 onward the acceptance trust root is the fixed, controller-owned + verification entrypoint defined in section 6. Its first instruction executes + before npm lifecycle dispatch; a package script, candidate checkout, + candidate-supplied path, artifact, environment value, or author report can + neither select the accepted candidate nor produce authoritative gate + evidence. Root/controller credential compromise remains outside the existing + threat model. Candidate, invoking-user, lifecycle, same-user filesystem, + runner/hash, result-channel, and race/restore mutation remain in scope and + fail closed. ## 2. Current-state preflight evidence (not the Stage 2 baseline) @@ -200,31 +209,213 @@ review. A phase cannot use another open phase branch as its base. ## 6. Immutable local-gate contract -P01 creates and tests `scripts/verification/phase-reporter.mjs`, the package -script `verify:phase`, and immutable argv plans +P01 creates and tests `scripts/verification/phase-bootstrap.mjs`, +`scripts/verification/phase-reporter.mjs`, and immutable argv plans `scripts/verification/plans/P01.json` through `P12.json` plus the auxiliary -`P12-observer.json`. From P01 onward a -phase invokes only that reporter for the phase gate; none of the child commands -below is run bare. The plan files contain argv arrays, test/non-test -classification, expected raw exit, and minimum test count, and the reporter -rejects shell strings, unknown labels, duplicate labels, or a plan whose hash -does not match the committed manifest. - -For every plan entry the reporter, without `shell`, prints and logs the exact -shell-escaped command, UTC start/end, duration, raw child exit or terminating -signal, and numbered stdout/stderr log path. It tees output without changing the -child result, records every raw exit, and continues after failures. For every -test-classified entry it consumes the framework's machine-readable result (or -the P01-tested adapter for native/manual suites) and prints +`P12-observer.json`. A package script named `verify:phase` is not an acceptance +entrypoint: P01 removes it or makes every direct invocation return nonzero +without spawning a gate, and documentation never instructs an author or +reviewer to use it. From P01 onward the fixed controller command below directly +loads the anchored bootstrap/reporter; none of the child commands below is run +bare. The plan files contain argv arrays, test/non-test classification, +expected raw exit, and minimum test count, and the reporter rejects shell +strings, unknown labels, duplicate labels, or a plan whose hash does not match +the externally anchored manifest. + +**Controller installation and first instruction.** The verification-controller +service identity exclusively owns +`/Users/Shared/InterviewCopilot/verification-controller`. Its privileged +installer creates the versioned `v1/bin/arm-phase` and `v1/bin/verify-phase` +executables, controller Git-object store, active-anchor registry, sealed run +roots, and authoritative evidence roots. The fixed filesystem-root descriptor, +`/Users`, `/Users/Shared`, `/Users/Shared/InterviewCopilot`, and every +controller descendant are opened component-by-component with `openat` plus +`O_DIRECTORY|O_NOFOLLOW`; none is a symlink, alternate root, or mount +transition. Every opened ancestor has its installer-pinned root/controller +identity, mode/flags—including the required sticky semantics for the ordinary +shared root—and no extended ACL. Every controller-owned descendant has no +group/other write bit and is mode 0555 once installed. Executables and anchors +are link-count-one regular files with no write bit or extended ACL and with +installer-recorded SHA-256 identities. Any ownership, mode, link, ACL, mount, +path, executable-hash, or ancestor disagreement is a preflight failure. +Root/controller credential compromise is outside the existing threat model; +candidate and invoking-user mutation is not. The first instruction of the +absolute `verify-phase` executable is therefore the first trusted verification +instruction and runs before npm or candidate code. + +**PIN FIRST and active anchor.** A controller administrator, never the phase +author or a candidate process, arms one phase from the independently observed +PR head with exact command +`/Users/Shared/InterviewCopilot/verification-controller/v1/bin/arm-phase +--phase --pr --expected-head + --approved-packet `. + +The privileged command independently resolves the live PR head, requires exact +agreement with `expected-head`, fetches that commit into the controller-owned +object store, proves it is a commit, and atomically installs a closed canonical +active anchor at the fixed phase/role slot. The anchor binds the canonical +remote and PR, candidate commit and tree, phase/role, approved packet +SHA/revision, complete committed-tree identity, and explicit identities for +`package.json`, the lockfile and project npm configuration; package scripts and +closed lifecycle map; bootstrap, reporter, result adapters, test manifest, all +thirteen plans and their manifest; every gate configuration/source, test, +fixture, runner, and colocated expected-hash table; exact Node/npm executable +realpaths and SHA-256 values; macOS build/architecture and the closed sanitized +environment; dependency integrity and canonical post-install closure; allowed +writable roots; and result/evidence schemas. It also records the controller +entrypoint identity. The entire tree anchor prevents a jointly changed gate and +expected hash from becoming self-authoritative, while the explicit identities +make drift attributable. + +The anchor is JCS-canonical JSON with no unknown or duplicate key and exactly +these top-level fields: `schemaVersion`, `controllerVersion`, +`controllerSha256`, `approvedPacketSha`, `packetRevision`, `canonicalRemote`, +`prNumber`, `candidateCommitSha`, `candidateTreeSha`, `phase`, `role`, +`inputs`, `packageScripts`, `lifecycleMap`, `plans`, `toolchain`, +`environment`, `dependencyClosure`, `writableRoots`, `resultSchemas`, +`armedAt`, and `prHeadObservedAt`. `inputs`, `plans`, and `resultSchemas` are +closed path/name maps whose values carry Git mode where applicable, byte +length, and SHA-256. `toolchain` carries OS/build/architecture plus Node/npm +realpath, version, and SHA-256. `environment` is a closed allowlist with the +fixed npm lifecycle-suppression and shell values. `writableRoots` is a closed +list derived by the controller, never a candidate path. The controller stores +the canonical anchor bytes as `anchor.json` and its lowercase-hex digest as +`anchor.sha256` under the fixed `anchors/active//local/` slot. Arming +P12 atomically installs the same candidate/input identity with role +`meet-observer` under `anchors/active/P12/meet-observer/`; no other role slot is +valid. The local and observer anchors differ only in role-bound plan/result +fields. Any schema, canonical-byte, field, or digest disagreement rejects. + +The active anchor, not cwd or an artifact, selects the accepted candidate. +Candidate argv, environment, worktree, package data, plan, manifest, pairing, +output, report, or author-provided SHA cannot select or override the remote, +checkout, commit, tree, packet, toolchain, phase plan, or evidence root. The +controller rejects a changed live PR head before execution and repeats that +comparison before zero. It never fetches, checks out, resets, switches, repairs, +or re-arms from candidate output. + +**Sealed materialization and lifecycle containment.** `verify-phase` +materializes the active commit from the controller object store into a fresh +controller-owned run root with no inode shared with an invoking-user worktree. +It rejects unapproved symlinks or gitlinks, hard links, case-colliding names, +alternate roots, writable/ACL-bearing ancestry, and mount changes. Candidate +and verification inputs are controller-owned and nonwritable to the dedicated +unprivileged execution identity. The closed writable set is only per-run +scratch/cache, `node_modules` while the install child is active, declared +build/package outputs, and phase-owned product/qualification artifacts; none +can replace an anchored input or controller evidence. + +The exact `npm ci` plan child starts only after the controller is trusted. +Install lifecycle is limited to the anchor's exact package/dependency map and +the closed writable set. The controller records it, waits for and terminates +the complete child process group, rejects any surviving or detached descendant, +validates the exact post-install dependency closure, and makes `node_modules` +nonwritable before another entry starts. For every later plan child beginning +with `npm run`, the controller preserves the plan argv byte-for-byte while +supplying a controller-owned effective configuration with +`npm_config_ignore_scripts=true`, a pinned `script-shell`, isolated npm config, +sanitized `PATH`, and no candidate `NODE_OPTIONS`. The explicitly requested +target still runs, but no matching pre/post companion does. A committed +pre/post companion for any planned target, unexpected root/install lifecycle, +or effective-config disagreement is itself anchor/policy failure. + +**Controller spawn and result authority.** The controller opens the anchored +bootstrap, reporter, plan, and manifest through held no-follow descriptors and +directly invokes the bootstrap with the pinned Node executable; no npm +lifecycle dispatch can precede it. The reporter requests each next immutable +plan entry through a private controller broker. The broker requires the exact +next index and argv, resolves the pinned executable, spawns without `shell`, +and independently records the planned argv, resolved executable realpath/hash, +actual spawn argv, UTC start/end, duration, OS raw exit or terminating signal, +and numbered stdout/stderr log identity. It owns the process group and does not +accept a reporter-supplied executable or path. + +For every plan entry the reporter prints and logs the exact shell-escaped +command, UTC start/end, duration, raw child exit or terminating signal, and +numbered stdout/stderr log identity. It tees output without changing the child +result, records every raw exit, and continues after ordinary child failures. +For every test-classified entry it consumes the framework's machine-readable +result (or the P01-tested adapter for native/manual suites) and prints `passed= failed= skipped=`; missing/unparseable counts, any failure or skip, or a count below the plan minimum is itself a recorded failure. The -reporter runs `verify:test-manifest` only after all test entries, writes one -JSON and one text aggregate report with the plan hash, and exits 0 only when -every child raw exit equals its expected value, all count requirements pass, -and the manifest proves that every inherited, phase-owned, fixture, native, -E2E, and manual procedure entry ran. Otherwise it exits 1 after the last entry. -Injected-failure tests must prove that later commands still run and that the -failed raw exit remains visible in both reports and the aggregate nonzero exit. +reporter runs `verify:test-manifest` only after all test entries and emits one +JSON and one text aggregate through framed controller-provided descriptors. +Plan children inherit neither those descriptors nor a controller evidence path. +Candidate stdout, environment, artifact paths, duplicate/replayed records, and +unframed structured output are never result authority. + +The authoritative run root is exactly +`/Users/Shared/InterviewCopilot/verification-controller/runs////`, +where `runId` is a controller-generated 128-bit random lowercase-hex value. Its +closed controller-owned layout is `anchor.json`, `input-inventory.json`, +`controller-transcript.json`, `reporter-aggregate.json`, +`reporter-aggregate.txt`, `output-inventory.json`, numbered stdout/stderr logs, +and either `success.json` or `failure.json`, never both. These controller files +are external gate evidence, not additions to the nine-member P12 qualification +evidence set or four-member release bundle. Each transcript entry contains +exactly `index`, `label`, `plannedArgv`, `resolvedExecutable`, +`resolvedExecutableSha256`, `actualSpawnArgv`, `startedAt`, `endedAt`, +`durationMs`, `rawExit`, `signal`, `stdoutLog`, `stdoutSha256`, `stderrLog`, +`stderrSha256`, optional `counts`, and `reporterRecordSha256`. The terminal +record binds the anchor/run/transcript/aggregate/inventory hashes, +`reporterStarted`, `candidateProcessesSpawned`, controller and reporter +aggregate exits, integrity-failure class if any, final-reopen result, survivor +count, and UTC completion. Unknown, missing, duplicate, unframed, reordered, or +hash-disagreeing data rejects. + +The reporter exits 0 only when every child raw exit equals its expected value, +all count requirements pass, and the manifest proves that every inherited, +phase-owned, fixture, native, E2E, and manual procedure entry ran. Otherwise it +exits 1 after the last ordinary entry. The controller independently correlates +the reporter records with its broker transcript and is the sole acceptance +authority. Immediately before zero it requires exact candidate/PR/anchor +identity, reopens every protected canonical name and compares its descriptor +identity/bytes/metadata, validates closed writable-root inventories and both +aggregate formats, and proves that no descendant remains. Any mismatch returns +nonzero; reporter zero can never override it. + +**Failure classes and negative controls.** Candidate/PR/packet, controller, +anchor, ownership, lifecycle, package/bootstrap/plan/manifest/gate, +runner/hash, executable/environment, result-channel, descriptor, process-group, +or TOCTOU disagreement before reporter start returns 1 with +`reporterStarted=false` and `candidateProcessesSpawned=0`. An integrity or +result-authority loss after start terminates the complete process group, stops +further entries, preserves the external controller failure record, and returns +1 without repair, restoration, unlink, retry, or aggregate-zero output. +Ordinary child failures retain the existing continue-and-aggregate behavior. +Injected-failure tests must prove exact children with raw exits 7 then 0 both +spawn, the later result remains visible, the 7 remains exact in JSON/text and +the broker transcript, and the aggregate returns 1. + +P01-AC7 extends its existing named +`tests/policy/verificationReporter.test.ts` suite, without adding an acceptance +criterion or reporter plan, with these mandatory named cases: + +- `rejects archived preverify self-removal and gate mutation before reporter start`; +- `rejects committed preverify and postverify companions during anchor admission`; +- `suppresses companion hooks while preserving the requested npm target argv`; +- `rejects joint package bootstrap plan manifest and gate mutation`; +- `rejects runner plus colocated current-hash forgery`; +- `rejects PATH node npm npmrc NODE_OPTIONS and script-shell substitution`; +- `rejects detached-restorer and lifecycle-time mutate-restore`; +- `rejects same-size overwrite rename symlink hardlink and case-collision TOCTOU`; +- `rejects result-path environment stdout duplicate replay and structured-record forgery`; +- `records planned argv resolved executable actual argv raw exit and signal exactly`; +- `continues exact injected exits seven then zero and aggregates one`; +- `preserves every P01-R1-B01 through P01-R1-B06 hostile probe`; and +- `rejects any surviving child or detached descendant before zero`. + +Independent P01 review reuses the exact P01-CV-B01 hostile lifecycle fixture +with SHA-256 +`8a081c023a044b50298d6ad1917a3fbe5ab8de349738d1457e113c39730398bc`. +The archived false-zero aggregate JSON/text identities are respectively +`c2528633014d271b2501c85b1d4884694b556f10f1b16abbc1e1b95e85ce2bb3` +and `9da4a97de56809959aa7c9d102e410fe93cca305993d1bebdc0ac9d08f52e5c1`. +A benign replay of that exact archived candidate retains observed test counts +legacy=1, unit=30, and P01=21; the hostile replay must fail before its hook or +detached restorer executes and can never accept those fabricated counts. +Future candidates still report their exact observed counts rather than +normalizing them to these archived values. Every P01–P12 plan starts with these exact argv entries, in this order; all expect raw exit 0. The two test entries additionally require failed=0 and @@ -275,19 +466,21 @@ package set without invoking any producer. `verify:mac-package`, it. `qualify:meet` launches collection when evidence is absent and performs the write-once manifest/attestation/bundle finalization in P12-M01/M02; it is not an artifact-presence shortcut. -The remote device also uses the reporter, with the exact invocation -`npm run verify:phase -- --phase P12 --role meet-observer --pair - --artifacts .artifacts/qualification-observer`. +The remote device also uses the controller-owned entrypoint, with the exact +invocation +`/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase +--phase P12 --role meet-observer --pair `. `P12-observer.json` runs `npm ci`, `npm run verify:policy`, and then `npm run qualify:meet:observer -- --pair ` without a shell; every child raw exit and the observer aggregate must be 0. Pair data is -an argv value, never a shell string. +an argv value, never a shell string, and cannot select an anchor, checkout, +plan, evidence root, or accepted SHA. -Each phase section below gives the exact reporter invocation, expected +Each phase section below gives the exact controller invocation, expected aggregate exit, and minimum named-test count. P01 seeds all twelve phase plans and the P12 observer plan, so no later implementer edits the reporter or a plan -alongside feature behavior. A required gate/plan change needs a new P00 packet -revision. +alongside feature behavior. A required gate/plan/controller-contract change +needs a new P00 packet revision. ## 7. Phase contracts @@ -304,22 +497,28 @@ docs). Branch `phase/P01-local-gates`. **Scope.** Consolidate Vitest (including the unchanged tracked CRA sample), correct ESLint parsing/ignores rather than suppressing findings, fix all current strict TypeScript and lint failures without changing behavior, create the raw -exit/count reporter, all phase and P12-observer immutable argv plans, and -immutable test manifest, centralize capture protection, set canonical -InterviewCopilot metadata, add policy scans, and document local gates. **Out of -scope:** new session/provider/UI behavior, deleting the legacy renderer, -dependency-vulnerability upgrades unrelated to making gates work, and external -capture claims. +exit/count reporter and controller-broker protocol, all phase and P12-observer +immutable argv plans, and immutable test manifest; prohibit a package-owned +acceptance entrypoint; centralize capture protection; set canonical +InterviewCopilot metadata; add policy scans; and document controller-owned +local gates. **Out of scope:** implementing or installing the privileged +controller inside the candidate repository, new session/provider/UI behavior, +deleting the legacy renderer, dependency-vulnerability upgrades unrelated to +making gates work, and external capture claims. **Implementation requirements.** Use Node 20; keep lockfile deterministic; make root tests execute `renderer/src/App.test.tsx` unchanged; permit no skip or todo test forms; report exact command, raw exit, and passed/failed/skipped -counts; accumulate injected failures while preserving their raw exits and make -the final reporter aggregate nonzero; fix all 105 -lint and 48 type errors rather than excluding product code; make every window -creation/reveal path call one `applyCaptureProtection` helper; add no false -content-protection path; scan dependencies/source for analytics and automatic -crash upload entry points; retain AGPL-3.0-or-later. +counts; accept plan-entry execution and authoritative raw exits only through the +controller broker; emit framed result records without exposing the controller +evidence path or descriptor to children; accumulate injected failures while +preserving their raw exits and make the final reporter aggregate nonzero; +reject package/bootstrap/plan/manifest/gate, runner/hash, lifecycle, +environment, result-channel, survivor-process, and mutate/restore drift; fix all +105 lint and 48 type errors rather than excluding product code; make every +window creation/reveal path call one `applyCaptureProtection` helper; add no +false content-protection path; scan dependencies/source for analytics and +automatic crash upload entry points; retain AGPL-3.0-or-later. **Expected files/systems.** `package*.json`, ESLint/TypeScript/Vitest configs, `scripts/verification/**`, `tests/policy/**`, typed fixes in existing Electron @@ -333,9 +532,15 @@ content-protection application. Roll back the PR as one unit; never roll back only the protection helper or test manifest. **Security/failure modes.** A parser ignore can hide source; a test glob can -silently execute zero tests; a reporter can mask the child exit; typed cleanup -can change behavior; capture protection can be applied after first paint. Tests -must make each failure observable and fail closed. +silently execute zero tests; a package pre/post lifecycle can run before a +candidate bootstrap; a mutable package/bootstrap/plan/manifest/gate or +runner/hash pair can manufacture acceptance; PATH/npm config/`NODE_OPTIONS` can +substitute execution; a reporter or child can forge a writable result channel; +a detached restorer can erase tracked drift after aggregate zero; typed cleanup +can change behavior; capture protection can be applied after first paint. The +controller boundary and tests must make each failure observable and fail +closed. Ordinary gate failures continue for complete raw-exit evidence; +integrity or result-authority loss terminates the run immediately. **Acceptance criteria and named new tests.** All are mechanically required. @@ -347,7 +552,7 @@ must make each failure observable and fail closed. | P01-AC4: every BrowserWindow creation and reveal path invokes `applyCaptureProtection`, which calls `setContentProtection(true)` and never false. | `electron/captureProtection.test.ts — protects creation and reveal lifecycle paths` | | P01-AC5: package metadata and visible identity use InterviewCopilot and retain `AGPL-3.0-or-later`. | `tests/policy/productPolicy.test.ts — enforces canonical identity and AGPL metadata` | | P01-AC6: shipped source has no analytics SDK, device fingerprint, automatic crash-upload initialization, or environment-based secret logging. | `tests/policy/productPolicy.test.ts — rejects telemetry crash upload and secret logging entry points` | -| P01-AC7: the reporter validates immutable argv plans, logs every exact command/raw exit, prints passed/failed/skipped for every test entry, continues after an injected child failure, preserves that raw exit in JSON/text, and exits nonzero at the aggregate gate; missing counts and plan drift also fail. | `tests/policy/verificationReporter.test.ts — accumulates raw failures counts and immutable plan drift` | +| P01-AC7: the controller-owned first instruction anchors the exact candidate/toolchain/verification closure before npm, directly invokes the bootstrap/reporter without package pre/post dispatch, brokers and logs every exact planned/resolved/actual argv and OS raw exit/signal, suppresses planned-target companion hooks without changing child argv, prints passed/failed/skipped for every test entry, gives children no authoritative result path/descriptor, rejects lifecycle, package/bootstrap/plan/manifest/gate, runner/hash, environment, result-channel, survivor-process, and TOCTOU/mutate-restore drift before any zero, and preserves ordinary injected exits 7 then 0 in JSON/text/controller evidence with aggregate 1; missing counts, plan drift, or controller/reporter disagreement also fail. | `tests/policy/verificationReporter.test.ts — accumulates raw failures counts and immutable plan drift` | **Clean-checkout setup.** Every command must exit 0. @@ -365,17 +570,20 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) P01 named tests passed, 0 failed, 0 skipped; the full suite may have more. ```bash -npm run verify:phase -- --phase P01 --artifacts .artifacts/verification/P01 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P01 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. **Regression suite.** all inherited tests, capture/screenshot behavior tests, full root unit suite, strict type check, lint, and production build. No baseline error is grandfathered. **Docs.** Document Node 20 clean setup, authoritative local commands, raw count artifact format, AGPL/privacy policy, and the non-claim that unit protection -proves capture privacy. +proves capture privacy. State explicitly that direct `npm run verify:phase`, +candidate-selected SHAs/checkouts, and candidate evidence paths are +non-authoritative. **Completion evidence (enumerated).** (1) commit SHA and base SHA; (2) clean status; (3) dependency install log; (4) one aggregate JSON/text report with @@ -383,7 +591,11 @@ every child exact command/raw exit and test count plus an injected-failure artifact proving aggregate exit 1; (5) manifest diff proving the inherited test remains; (6) capture lifecycle test output; (7) build artifact list; (8) reviewer sign-off that no lint/type -rule or source glob was weakened. +rule or source glob was weakened; (9) controller executable/ancestor +ownership-mode-ACL/hash evidence, active-anchor bytes/hash, sealed-root +inventory, broker transcript, and final reopen/process-group proof; (10) the +archived lifecycle exploit plus the complete joint-mutation/result-channel/ +TOCTOU matrix and exact exits-7-then-0 negative control. **Risk/complexity.** High risk, medium complexity: broad typed cleanup can hide behavioral changes. Keep mechanical fixes small and independently reviewable @@ -391,25 +603,34 @@ inside the single PR. **Self-contained implementation prompt.** -> Implement P01 from P00-R7 on `phase/P01-local-gates`, based only on upstream +> Implement P01 from P00-R8 on `phase/P01-local-gates`, based only on upstream > `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. > Make local lint, strict type-check, real unit tests (including the unchanged > tracked CRA sample), manifest enforcement, and build green. Centralize and > lifecycle-test `setContentProtection(true)`, enforce InterviewCopilot/AGPL/no- -> telemetry policy, seed/validate the exact P01–P12 and P12-observer argv plans, print raw exits -> and test counts, accumulate failures into a nonzero aggregate, add exactly the -> tests named in P01, run the P01 reporter gate, and attach every enumerated -> artifact. Do not add product features or waive existing failures. +> telemetry policy, seed/validate the exact P01–P12 and P12-observer argv plans, +> integrate the reporter only with the section-6 controller broker, print exact +> argv/raw exits and test counts, keep ordinary failure aggregation, fail fast +> on trust mutation, extend the existing P01-AC7 named suite with every +> lifecycle/joint-mutation/result-channel/TOCTOU and exits-7-then-0 case, run the +> P01 controller gate, and attach every enumerated artifact. Do not add product +> features, a package-owned acceptance path, or waived failures. **Self-contained review prompt.** -> Review P01 independently against P00-R7, not the author’s summary. From the -> clean PR checkout run the P01 reporter invocation, confirm the inherited CRA +> Review P01 independently against P00-R8, not the author’s summary. Select and +> arm the exact live PR head independently, then run the fixed P01 controller +> invocation from a clean checkout and sealed root. Confirm the inherited CRA > test ran, > inspect all config/glob/ignore changes for hidden coverage loss, compare typed > cleanup for behavior changes, and prove every window lifecycle applies true -> content protection. Reject the PR for any missing raw count, skipped test, -> weakened rule, product feature, telemetry path, or nonzero local gate. +> content protection. Reproduce the archived self-removing preverify bypass, +> every joint package/bootstrap/plan/manifest/gate and runner/hash mutation, +> executable/environment substitution, result-channel forgery, detached +> restore/TOCTOU case, and the exact exits-7-then-0 control. Reject the PR for +> candidate-selected identity/evidence, a package-owned accepted invocation, +> any mutation admitted before zero, missing raw count, skipped test, weakened +> rule, product feature, telemetry path, or nonzero local gate. **Remediation prompt template.** @@ -417,8 +638,10 @@ inside the single PR. > finding}`. Root cause: `{confirmed cause}`. Change the smallest P01-owned > files, add/strengthen `{named regression test}`, preserve every inherited > gate and capture invariant, rerun the complete P01 plan (which begins with -> `npm ci`) by invoking the reporter, and return every child raw exit/count, -> aggregate exit, and the before/after commit SHAs. +> `npm ci`) through a freshly armed fixed controller entrypoint, and return the +> active-anchor/controller identities, every child planned/resolved/actual +> argv/raw exit/count, controller and reporter aggregate exits, mutation-matrix +> results, and the before/after commit SHAs. ### P02 — Subscription-only persistent agent runtime @@ -504,10 +727,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) tests passed, 0 failed, 0 skipped; every command exits 0. ```bash -npm run verify:phase -- --phase P02 --artifacts .artifacts/verification/P02 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P02 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. **Regression suite.** P01 gates, capture lifecycle, screenshot queues, config language/opacity behavior, fake provider process tests, conversation-ID @@ -532,7 +756,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained implementation prompt.** -> Implement P02 from P00-R7 after P01, on +> Implement P02 from P00-R8 after P01, on > `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime > for Claude Code and Codex only, using one resumable session/thread, normalized > streaming/usage/compaction/stop/error events, explicit provider/model/Fast- @@ -540,17 +764,20 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. > remove every legacy answer API key/provider/credit/paywall surface, create the > named fake-executable tests, accept only caller-supplied opaque conversation > IDs held in memory, and prove no ID/provider session persists to plaintext. -> Run the exact P02 reporter gate and attach the evidence. Do not implement app- +> Run the exact P02 reporter gate through the fixed controller entrypoint and +> attach the evidence. Do not implement app- > restart recovery, interview orchestration, or reuse one-shot prototype code. **Self-contained review prompt.** -> Review P02 against P00-R7 from a clean checkout. Trace both fake providers +> Review P02 against P00-R8 from a clean checkout and a controller-selected, +> sealed exact PR head. Trace both fake providers > through two turns, stop, compaction, driver/child restart, and caller-ID > resume; force every failure and prove the other provider never starts. Inspect > spawn/env/tool restrictions, IPC exposure, migration idempotence/file mode, > dependency removals, model/effort locking, provider-only onboarding, and a -> full filesystem scan for the opaque-ID fixture. Run the P02 reporter gate and +> full filesystem scan for the opaque-ID fixture. Run the P02 reporter gate +> through the fixed controller entrypoint and > reject any live-credential requirement, legacy path, plaintext provider ID, > P02-owned app recovery, secret leak, silent fallback, ephemeral conversation, > skipped test, or gate failure. @@ -561,7 +788,8 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. > provider fixture, state the confirmed runtime or migration cause, change the > smallest provider/config/onboarding surface, add or strengthen `{P02 named > test}`, prove no unselected process ran and no secret or conversation ID -> persisted, rerun the complete P02 reporter plan (which begins with `npm ci`), +> persisted, re-arm the exact head and rerun the complete P02 reporter plan +> through the fixed controller entrypoint (which begins with `npm ci`), > and return every child raw exit/count plus the aggregate exit and new SHAs. ### P03 — Encrypted local persistence foundation @@ -634,10 +862,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P03 --artifacts .artifacts/verification/P03 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P03 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. **Regression suite.** P01 gates, capture behavior, screenshot creation/deletion, config persistence, path safety, and build. Run storage tests on a case- @@ -658,18 +887,21 @@ never custom cryptography. **Self-contained implementation prompt.** -> Implement P03 from P00-R7 after P01 on +> Implement P03 from P00-R8 after P01 on > `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key > service, versioned AES-256-GCM record/blob store, atomic writes, encrypted > in-memory-search source, typed recovery, raw-audio rejection, and journaled > M-02/M-03 migrations exactly as specified. Add all P03 named tests and threat- -> model docs, run the complete P03 reporter plan, and attach enumerated evidence. Do not +> model docs, run the complete P03 reporter plan through the fixed controller +> entrypoint, and attach enumerated evidence. Do not > implement session, History, provider, profile, or template behavior. **Self-contained review prompt.** -> Threat-model and review P03 independently. Run the P03 reporter plan, inspect key -> storage, nonce generation, AAD, atomicity, permissions, path canonicalization, +> Threat-model and review P03 from an independently armed, controller-selected, +> sealed exact PR head. Run the P03 reporter plan only through the fixed +> controller entrypoint; inspect key storage, nonce generation, AAD, atomicity, +> permissions, path canonicalization, > temp handling, raw-audio rejection, and both migrations under interruption. > Search fixture storage byte-for-byte for plaintext. Reject home-grown crypto, > plaintext indexes/caches, destructive unverified deletion, broad reset on one @@ -778,10 +1010,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) tests passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P04 --artifacts .artifacts/verification/P04 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P04 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. **Regression suite.** P01–P03 complete suites, provider fake contracts, encrypted storage migration/recovery, capture lifecycle, screenshot queue @@ -806,7 +1039,7 @@ boundary; no renderer or provider may keep a second authoritative session. **Self-contained implementation prompt.** -> Implement P04 from P00-R7 after P02/P03 on +> Implement P04 from P00-R8 after P02/P03 on > `phase/P04-session-orchestrator`. Replace global transient state with the > deterministic InterviewSession reducer, typed event/IPC contract, one > persistent-conversation orchestrator, context/delta policy, pending artifacts, @@ -820,7 +1053,9 @@ boundary; no renderer or provider may keep a second authoritative session. **Self-contained review prompt.** -> Review P04 as the sole session authority. Run all gates and property tests; +> Review P04 from an independently armed, controller-selected, sealed exact PR +> head as the sole session authority. Run all gates and property tests only +> through the fixed controller entrypoint; > trace every event, first-turn seed, delta, pending-artifact transition, > compaction signal/detail field, curated/chat turn, response-routing branch, > best-effort/clarification fixture, correction impact, cancel/continue, Reset @@ -836,7 +1071,8 @@ boundary; no renderer or provider may keep a second authoritative session. > Remediate P04 only for `{state/orchestration criterion}` using the smallest > reducer/orchestrator/schema change. Add the exact failing event sequence to > `{P04 named test}`, prove idempotency and no cross-session/personal-context -> or plaintext-ID leak, rerun the complete P04 reporter plan (starting with +> or plaintext-ID leak, re-arm the exact head and rerun the complete P04 +> reporter plan through the fixed controller entrypoint (starting with > `npm ci`), and return every raw exit/count, aggregate exit, routing/section > traces, migration compatibility, and new SHAs. @@ -917,10 +1153,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) tests passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P05 --artifacts .artifacts/verification/P05 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P05 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. `test:electron-shell` exits 0 on macOS and records window bounds, protection application, screenshot-display ID, and pointer-region results. **Regression suite.** all P01–P04 tests, provider/storage/session contracts, capture queues, @@ -941,7 +1178,7 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained implementation prompt.** -> Implement P05 from P00-R7 after P04 on `phase/P05-live-shell`. Build the +> Implement P05 from P00-R8 after P04 on `phase/P05-live-shell`. Build the > exact Quiet Signal hidden/compact/answer/expanded shell, command rail, > composer, input tray, explicit click-through/drag regions, final remappable > shortcuts, display-aware geometry, primary-display screenshot behavior, @@ -953,7 +1190,8 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained review prompt.** -> Review P05 on macOS from a clean checkout. Operate every visible control and +> Review P05 on macOS from an independently armed, controller-selected, sealed +> exact PR head. Operate every visible control and > shortcut keyboard-only; inspect click-through/drag regions, focus restoration, > geometry across display changes, compact sizing, screenshot scope/visibility, > and content-protection call order. Run all P05 gates and accessibility checks. @@ -966,7 +1204,8 @@ display behavior is platform-sensitive and directly touches privacy regression. > Remediate P05 only for `{shell/window/capture criterion}`. Attach the exact > display/window/input reproduction, fix the smallest P05-owned service or > primitive, add/strengthen `{P05 named test}`, recheck protection and prior -> visibility, rerun the complete P05 reporter plan including +> visibility, re-arm the exact head and rerun the complete P05 reporter plan +> through the fixed controller entrypoint including > `test:electron-shell`, and return every raw exit/count, aggregate exit, > artifact paths, and new SHAs. @@ -1039,10 +1278,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P06 --artifacts .artifacts/verification/P06 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P06 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. `test:coding-fixtures` exits 0 and reports all six first-class families passed, 0 failed, 0 skipped. **Regression suite.** P01–P05, provider/session no-fallback, @@ -1063,16 +1303,18 @@ regress silently; fixture contracts are merge-blocking. **Self-contained implementation prompt.** -> Implement P06 from P00-R7 after P05 on `phase/P06-coding`. Add the exact +> Implement P06 from P00-R8 after P05 on `phase/P06-coding`. Add the exact > typed Coding intents/schema/renderer, concise-first progressive answer, > language snapshot and six-family fixtures, read-only actions, New Question, > and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, > tools, execution, fallback, or staged-artifact consumption. Own M-05b, add all -> nine named tests, run the P06 reporter plan/fixture matrix, and attach evidence. +> nine named tests, run the P06 reporter plan/fixture matrix through the fixed +> controller entrypoint, and attach evidence. **Self-contained review prompt.** -> Review P06 from clean checkout with fake provider fixtures. Validate every +> Review P06 from an independently armed, controller-selected, sealed exact PR +> head with fake provider fixtures. Validate every > intent/schema, stream order, all six language families, Python 3, read-only > surface, New Question isolation, and both successful/unsupported Fix flows. > Inspect requests for personal data, extra artifacts, tools, and fallback. @@ -1084,7 +1326,8 @@ regress silently; fixture contracts are merge-blocking. > Remediate P06 only for `{intent/language/branch/debug criterion}`. Add the > failing problem/language/event trace to `{P06 named test or first-class > fixture}`, make the smallest Coding-owned change, prove isolation/no fallback, -> rerun the complete P06 reporter plan and six-family matrix, and return every +> re-arm the exact head and rerun the complete P06 reporter plan through the +> fixed controller entrypoint and the six-family matrix, and return every > raw exit/count, aggregate exit, request/response traces, and new SHAs. ### P07 — System Design mode and structured architecture @@ -1155,10 +1398,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P07 --artifacts .artifacts/verification/P07 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P07 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. Fixture command exits 0 with all design/vendor/follow-up cases passed, failed 0, skipped 0. **Regression suite.** P01–P05, provider/session/storage, shell section @@ -1178,16 +1422,18 @@ must not become a second untyped document model. **Self-contained implementation prompt.** -> Implement P07 from P00-R7 after P05 on `phase/P07-system-design`. Add the +> Implement P07 from P00-R8 after P05 on `phase/P07-system-design`. Add the > fixed typed five-section progressive workflow, bounded material estimates, > safe vendor-neutral structured diagram, read-only accessible interactions, > assumption handling, dependency-scoped follow-up and What changed summary. -> Add all eight named tests/fixtures, run the P07 reporter plan, attach evidence, and do +> Add all eight named tests/fixtures, run the P07 reporter plan through the +> fixed controller entrypoint, attach evidence, and do > not add diagram editing/export, vendor node types, Prompt Studio, or profile UI. **Self-contained review prompt.** -> Review P07 from clean checkout using malformed and representative fixtures. +> Review P07 from an independently armed, controller-selected, sealed exact PR +> head using malformed and representative fixtures. > Prove fixed order/no gate, estimate bounds/units, graph sanitization and > accessibility, vendor neutrality, approved interactions only, archived graph > round-trip, and hash-identical unaffected follow-up sections. Run every P07 @@ -1199,7 +1445,8 @@ must not become a second untyped document model. > Remediate P07 only for `{schema/estimate/diagram/follow-up criterion}`. Add the > failing graph or event to `{P07 named fixture}`, change the smallest System > Design-owned validator/renderer/policy, prove unaffected hashes and no export, -> rerun the complete P07 reporter plan/fixtures, and return every raw exit/count, +> re-arm the exact head and rerun the complete P07 reporter plan/fixtures +> through the fixed controller entrypoint, and return every raw exit/count, > aggregate exit, diffs, and new SHAs. ### P08 — Candidate profile, opportunity context, and Behavioral mode @@ -1275,10 +1522,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) tests passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P08 --artifacts .artifacts/verification/P08 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P08 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. Fixture command exits 0 with verified/synthetic/import cases passed, 0 failed, 0 skipped. **Regression suite.** P01–P06 plus P07 if already merged, storage @@ -1299,7 +1547,7 @@ integrity are product trust boundaries. **Self-contained implementation prompt.** -> Implement P08 from P00-R7 after P05 on `phase/P08-behavioral`. Build the +> Implement P08 from P00-R8 after P05 on `phase/P08-behavioral`. Build the > encrypted canonical candidate dossier, guided/manual reviewed editing, > sanitized Markdown import/export, multiple snapshotted opportunities, > provenance, opt-in labeled persistent synthetic stories, and typed Behavioral @@ -1310,7 +1558,8 @@ integrity are product trust boundaries. **Self-contained review prompt.** -> Review P08 from clean checkout as both privacy and factuality boundary. Search +> Review P08 from an independently armed, controller-selected, sealed exact PR +> head as both privacy and factuality boundary. Search > storage/logs/Coding requests for fixture personal bytes; attack Markdown; > compare concise/full facts; test absent metrics, synthetic off/on/reuse, > multi-opportunity snapshotting, and System Design routing. Run all P08 gates. @@ -1323,7 +1572,8 @@ integrity are product trust boundaries. > Remediate P08 only for `{privacy/provenance/factuality/context criterion}`. > Preserve the failing dossier/import/trace fixture, make the smallest profile > or Behavioral-owned fix, strengthen `{P08 named test}`, repeat plaintext and -> three-mode scans, rerun the complete P08 reporter plan/fixtures, and return +> three-mode scans, re-arm the exact head and rerun the complete P08 reporter +> plan/fixtures through the fixed controller entrypoint, and return > every raw exit/count, aggregate exit, fact/context diffs, and new SHAs. ### P09 — macOS audio capture, transcription, and question detection @@ -1407,10 +1657,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) tests passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P09 --artifacts .artifacts/verification/P09 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P09 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. Native/retention commands exit 0 and print passed/failed/skipped counts; fixture audio contains no interview/user content. **Regression suite.** P01–P05, @@ -1432,7 +1683,7 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained implementation prompt.** -> Implement P09 from P00-R7 after P05 on `phase/P09-audio`, macOS only. Build +> Implement P09 from P00-R8 after P05 on `phase/P09-audio`, macOS only. Build > explicit two-source native capture, deterministic master/per-source controls, > contextual permission recovery, pinned offline whisper.cpp transcription, > explicit Apple Speech remote fallback, typed segments/attribution/correction, @@ -1442,7 +1693,8 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained review prompt.** -> Review P09 on supported macOS from clean checkout with network blocked and +> Review P09 on supported macOS from an independently armed, +> controller-selected, sealed exact PR head with network blocked and > permissions granted/denied. Trace device-open timing, every source/master > transition, hide/collapse, local checksum/offline behavior, explicit Apple > remote consent, temp/archive/log bytes, channel provenance, correction, and @@ -1527,10 +1779,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P10 --artifacts .artifacts/verification/P10 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P10 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. Adversarial command exits 0 with every escalation fixture passed, 0 failed, 0 skipped. **Regression suite.** P01–P08 (and P09 when merged), all mode schemas, @@ -1551,17 +1804,19 @@ must never become a capability or schema escape hatch. **Self-contained implementation prompt.** -> Implement P10 from P00-R7 after P06/P07/P08 on +> Implement P10 from P00-R8 after P06/P07/P08 on > `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, > immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, > deterministic recorded instruction resolution, Start snapshotting, protected > invariant/capability enforcement, and M-08. Add eight named tests and the -> adversarial suite, run the complete P10 reporter plan, attach evidence, and add no arbitrary +> adversarial suite, run the complete P10 reporter plan through the fixed +> controller entrypoint, attach evidence, and add no arbitrary > schema/custom mode/sharing/plugin capability. **Self-contained review prompt.** -> Review P10 from clean checkout as an untrusted-instruction boundary. Attack +> Review P10 from an independently armed, controller-selected, sealed exact PR +> head as an untrusted-instruction boundary. Attack > every invariant/provider/context/tool/schema path, verify deterministic > conflict records, same representation/diff requirement, built-in immutability, > CRUD, mode binding, active snapshot, encrypted bytes, and inert rendering. @@ -1573,7 +1828,8 @@ must never become a capability or schema escape hatch. > Remediate P10 only for `{CRUD/schema/conflict/security criterion}`. Add the > exact malicious or state-transition input to `{P10 named/adversarial test}`, > make the smallest Prompt Studio/composition fix, prove protected invariants -> and encrypted storage, rerun the complete P10 reporter plan, and return every +> and encrypted storage, re-arm the exact head and rerun the complete P10 +> reporter plan through the fixed controller entrypoint, and return every > raw exit/count, aggregate exit, effective-instruction diff, and new SHAs. ### P11 — Crash recovery, searchable History, export, and deletion @@ -1644,10 +1900,11 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) passed, 0 failed, 0 skipped; every raw exit is 0. ```bash -npm run verify:phase -- --phase P11 --artifacts .artifacts/verification/P11 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P11 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. Round-trip/plaintext commands exit 0 with all fixtures passed, failed 0, skipped 0. **Regression suite.** every P01–P10 test, all three modes, audio raw- @@ -1668,17 +1925,19 @@ content and destructive user controls. **Self-contained implementation prompt.** -> Implement P11 from P00-R7 after P06–P10 on +> Implement P11 from P00-R8 after P06–P10 on > `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete > encrypted archive projection, Settings-only in-memory search/open/delete one/ > all, safe consented individual Markdown/JSON export, read-only archive open, > indefinite retention, M-09, and strict no-audio/secret/plaintext-index rules. -> Add eight named tests/round-trip/scans, run the complete P11 reporter plan, and attach all +> Add eight named tests/round-trip/scans, run the complete P11 reporter plan +> through the fixed controller entrypoint, and attach all > evidence. Add no tags/favorites/bulk/cloud/pruning/live History surface. **Self-contained review prompt.** -> Review P11 from clean checkout with corrupt, large, interrupted, traversal, +> Review P11 from an independently armed, controller-selected, sealed exact PR +> head with corrupt, large, interrupted, traversal, > and multi-session fixtures. Prove explicit recovery/capture-off, complete/no- > audio projection, Settings-only indefinite History, no plaintext search bytes, > safe round-trip exports/disclosure, isolated journaled deletion, and zero live @@ -1690,7 +1949,8 @@ content and destructive user controls. > Remediate P11 only for `{recovery/archive/search/export/delete criterion}`. > Preserve the failing encrypted fixture/journal, make the smallest History- > owned change, strengthen `{P11 named test}`, repeat round-trip/plaintext/data- -> isolation checks, rerun the complete P11 reporter plan, and return every raw +> isolation checks, re-arm the exact head and rerun the complete P11 reporter +> plan through the fixed controller entrypoint, and return every raw > exit/count, aggregate exit, hashes, journals, and new SHAs. ### P12 — macOS release hardening and Google Meet qualification @@ -1729,7 +1989,7 @@ detached statement binds its app semver and post-build package identity. Those exact passing tuples—and no neighboring patch, major version, browser, app build, architecture, or display mode—are the supported macOS/browser/app versions until separately qualified. Qualify each supported tuple separately. -P00-R7 represents no version as supported before the committed matrix, detached +P00-R8 represents no version as supported before the committed matrix, detached release statement, and evidence pass. Entire-display and specific-window require confirmation from remote Meet view or second device and retained high-contrast moving-marker artifacts; one fail makes @@ -1913,11 +2173,12 @@ explicit test surface. The collector fails if the control or marker seed, cadence, size, contrast, frame sequence, position sequence, or render-event continuity differs from the fixture. -**Exact launch.** On the local matrix Mac, the operator runs the P12 reporter -release gate: +**Exact launch.** After a controller administrator independently arms the exact +P12 PR/RC head, the operator runs the fixed controller gate on the local matrix +Mac: ```text -npm run verify:phase -- --phase P12 --artifacts .artifacts/verification/P12 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P12 ``` Its immutable P12 plan executes the exact `qualify:meet --collect-missing` argv @@ -1925,23 +2186,25 @@ listed in section 6. That child performs package/version/network/account/ display/permission/disk preflight, opens the control and guided-verification surfaces, prints a one-time pairing URL, and waits. On the remote device, from a clean checkout of the same SHA, the -observer runs the exact reporter command printed with the URL substituted: +independent controller materializes the same active SHA and the observer runs +the exact controller command printed with the URL substituted: ```text -npm run verify:phase -- --phase P12 --role meet-observer --pair --artifacts .artifacts/qualification-observer +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P12 --role meet-observer --pair ``` -The reporter installs/verifies the clean observer checkout and then launches the -observer helper as the exact argv child defined in `P12-observer.json`. It logs -that child raw exit and returns aggregate 0 only after the helper verifies the -SHA embedded in the pairing challenge equals the observer's independently -pinned checkout HEAD, without fetching or switching from it, records only the Chrome Meet -presentation region plus recorder telemetry, and streams the original recording -and signed observer events directly into the collector's new run directory. -Pairing expires after one use. Closing either reporter, supplying a file path in -place of live pairing, or failing to upload the final record makes both -collector and observer aggregates nonzero. Thus neither command assumes a pre- -existing `.artifacts/qualification` record. +The controller runs the observer plan from its sealed materialization and +launches the observer helper as the exact argv child defined in +`P12-observer.json`. It logs that child raw exit and returns aggregate 0 only +after the helper verifies the SHA embedded in the pairing challenge equals the +observer controller's independently active candidate SHA, without fetching, +switching, or re-arming from pairing data; records only the Chrome Meet +presentation region plus recorder telemetry; and streams the original +recording and signed observer events directly into the collector's new run +directory. Pairing expires after one use. Closing either controller, supplying +a file path in place of live pairing, or failing to upload the final record +makes both collector and observer aggregates nonzero. Thus neither command +assumes a pre-existing `.artifacts/qualification` record. **Shared timing and start/stop sequence.** The collector leads the following steps and records UTC plus monotonic timestamps for each acknowledgement: @@ -2976,27 +3239,30 @@ node -e 'if (Number(process.versions.node.split(".")[0]) !== 20) process.exit(1) ``` **Verification commands and non-circular order.** The external controller, not -an artifact, chooses the commit used by `switch --detach`. Each verifier then -executes this strict order: (1) require clean checkout and pin HEAD as -`expectedRcSha`; (2) load the matrix blob from that commit, compare the -worktree bytes, validate its closed schema/JCS/registry, and freeze/hash it; -(3) validate the external statement's fixed path, closed schema/JCS, -`expectedRcSha`, matrix binding, package identity, purpose-separated key, -domain, and signature; (4) validate or collect per-run evidence and detached -reviewer records; and (5) run `verify:release`. A bundle, statement, review, -pairing challenge, or other artifact is never read to fetch, switch, reset, or -select a checkout, matrix, registry, or expected SHA. The observer independently -pins its already selected clean checkout and only compares the pairing SHA to -that value. +an artifact, independently selects the commit, installs the active anchor, and +materializes the sealed detached checkout. Each verifier then executes this +strict order: (1) require the active anchor/live PR-head agreement and pin the +materialized HEAD as `expectedRcSha`; (2) load the matrix blob from that commit, +compare the sealed worktree bytes, validate its closed schema/JCS/registry, and +freeze/hash it; (3) validate the external statement's fixed path, closed +schema/JCS, `expectedRcSha`, matrix binding, package identity, +purpose-separated key, domain, and signature; (4) validate or collect per-run +evidence and detached reviewer records; and (5) run `verify:release`. A bundle, +statement, review, pairing challenge, candidate path, or other artifact is +never read to fetch, switch, reset, re-arm, or select a checkout, matrix, +registry, expected SHA, toolchain, or controller evidence root. The observer +independently uses its controller-selected active anchor and only compares the +pairing SHA to that value. `test:p12` reports at least 14 named automated/manual manifest entries passed, 0 failed, 0 skipped; all raw exits 0. ```bash -npm run verify:phase -- --phase P12 --artifacts .artifacts/verification/P12 +/Users/Shared/InterviewCopilot/verification-controller/v1/bin/verify-phase --phase P12 ``` -Expected reporter aggregate exit is 0; every logged child raw exit is 0. +Expected controller and reporter aggregate exits are 0; every logged child raw +exit is 0. `qualify:meet` launches P12-M01 and P12-M02 for absent evidence and exits 0 only after the detached release statement is valid and every frozen tuple has a live- @@ -3051,7 +3317,7 @@ signing infrastructure cannot be inferred from unit tests. **Self-contained implementation prompt.** -> Implement P12 from P00-R7 after P01–P11 on +> Implement P12 from P00-R8 after P01–P11 on > `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ > architecture matrix, harden macOS-only package/entitlements/identity, add > local-only redacted diagnostic preview/export, scoped failure recovery, @@ -3060,8 +3326,9 @@ signing infrastructure cannot be inferred from unit tests. > Enforce the exact separate parent/inherit entitlement allowlists, produce > signed/notarized arm64/x64 artifacts, launch and execute the full live-paired > P12-M01/M02 procedures on the release build, and run the complete P12 reporter -> plan including artifact validation and the SHA-pinned three-case Staff-live -> corpus. Externally select and pin clean checkout HEAD before artifacts, +> plan through the fixed controller entrypoint, including artifact validation +> and the SHA-pinned three-case Staff-live corpus. Independently arm the exact +> clean PR/RC head before artifacts, > validate/freeze/hash the pre-commit-only committed matrix, produce the > mandatory signed detached post-RC release statement outside Git and all > bundle/review roots through the exact CREATE/REUSE/REJECT package state @@ -3094,8 +3361,9 @@ signing infrastructure cannot be inferred from unit tests. **Self-contained review prompt.** -> Independently review P12 by externally selecting the clean SHA, freezing and -> hashing its exact committed matrix before reading artifacts, then validate the +> Independently review P12 by arming the externally selected exact clean PR/RC +> SHA through the fixed controller, freezing and hashing its exact committed +> matrix before reading artifacts, then validate the > required external release statement and sealed-package identity without > rebuilding, resigning, renotarizing, or restapling in REUSE. Challenge PIN > FIRST, CREATE/REUSE/REJECT state selection, the distinct sealed-set-resume and @@ -3107,7 +3375,8 @@ signing infrastructure cannot be inferred from unit tests. > raw exits, producer counts, and inode/byte/ACL stability. Inspect > signing/notarization/entitlements/SBOM, trace protection > before first frame, mechanically compare every signed parent/nested executable -> with the exact role allowlist, rerun the complete reporter plan, personally +> with the exact role allowlist, rerun the complete reporter plan through the +> freshly armed fixed controller entrypoint, personally > verify remote Meet raw artifacts/control frames, canonical evidence manifest, > independently signed role attestations, bundle metadata/final digest, exact > include/exclude rules, and acyclic dependency graph for both scopes/ @@ -3210,9 +3479,20 @@ product contract: 5. **CI reliability.** CI is non-authoritative. An outage does not block a phase whose complete local evidence passes, but required repository review policy still applies; never falsify or bypass a required hosted check. - -There is currently no blocker to opening the P00 draft PR. Future phases must -report an unmet prerequisite instead of weakening a criterion. +6. **Verification-controller installation and active candidate.** Before P01 + remediation resumes, the controller owner installs and independently proves + the fixed section-6 service identities, executables, object/anchor/run/ + evidence roots, ownership/mode/ACL/link/mount invariants, and hostile-probe + behavior. At each phase/review branch cut the controller freezes the exact + entrypoint hash, approved packet SHA, live PR head, Node/npm/macOS identities, + dependency closure, and run ID in the active anchor. These are time-bound + execution values, not permission to move the trust root into the candidate + repository or alter the controller contract. + +There is no unresolved material decision and no blocker to the P00-R8 planning +PR. Controller installation plus fresh P00/review-8 executable proof is a hard +P01 admission prerequisite. Future phases must report an unmet prerequisite +instead of weakening a criterion. ## 11. Why twelve phases is the minimum cohesive set @@ -3231,24 +3511,40 @@ acceptance outcome. ## 12. Phase admission and completion protocol Before implementation begins, the controller records the dependency commit -SHAs and the formal Stage 2 baseline at the frozen SHA. For each phase: +SHAs and the formal Stage 2 baseline at the frozen SHA. Before P01 resumes it +also installs and proves the fixed section-6 verification controller. For each +phase: 1. Confirm all dependencies are merged into upstream `main` and record the intended base SHA. 2. Create only the canonical phase branch/worktree; verify clean status. 3. Execute the self-contained implementation prompt without prototype commits. -4. Produce every named test and completion artifact; invoke the phase reporter - once and retain its exact-command/raw-exit/count/aggregate reports. -5. Have an independent reviewer execute the self-contained review prompt from a - fresh clean checkout and challenge the solution at the owning boundary. -6. For any failure, use the phase remediation template; rerun the complete - reporter plan, which begins with `npm ci`, not only the failed test. -7. Merge only with all local raw exits 0, failed=0, skipped=0, manifest complete, - acceptance criteria checked, migrations/rollback evidenced, and no unresolved - actionable review feedback. +4. Commit and push the candidate to its standalone draft PR. A controller + administrator independently resolves that live PR head, arms the phase, and + records the immutable anchor/entrypoint identities; author cwd, SHA, + artifacts, or reports are never selection authority. +5. Produce every named test and completion artifact only through the fixed + controller invocation. Retain its anchor, sealed-root inventory, broker + exact-command/raw-exit/count/process transcript, reporter JSON/text + aggregates, mutation-matrix results, and final-reopen evidence. +6. Have an independent reviewer re-resolve and freshly arm the exact live PR + head, execute the self-contained review prompt from a fresh sealed + materialization, reproduce the required hostile/negative controls, and + challenge the solution at the owning boundary without treating author + evidence as review evidence. +7. For any failure, use the phase remediation template; after the new commit is + pushed, re-arm that exact PR head and rerun the complete reporter plan, which + begins with `npm ci`, not only the failed test. +8. Merge only with controller and reporter aggregate exits 0, every local raw + exit 0, failed=0, skipped=0, manifest complete, acceptance criteria checked, + migrations/rollback evidenced, required hosted checks green, required + approvals on the most recent push, and no unresolved actionable review + feedback. An implementation PR description must list packet revision, phase ID, base and -head SHAs, dependencies, scope/non-goals, migration owner, command outputs/counts, -completion-artifact links/hashes, risks, and any external prerequisite. “CI -green,” a screenshot, or the author’s assurance alone is never completion +head SHAs, dependencies, scope/non-goals, migration owner, controller +entrypoint/anchor/run identities, planned/resolved/actual command outputs and +counts, completion-artifact links/hashes, mutation-matrix evidence, risks, and +any external prerequisite. “CI green,” a screenshot, a package-owned gate, a +candidate evidence path, or the author’s assurance alone is never completion evidence. From 02ee6ddec78d6e4ea9e2de3c0303ffd6bc9f45bf Mon Sep 17 00:00:00 2001 From: Timomak Date: Mon, 27 Jul 2026 16:22:59 +0200 Subject: [PATCH 9/9] docs: add P00 per-run verification binding --- docs/implementation/phase-execution-packet.md | 201 +++++++++++++----- 1 file changed, 149 insertions(+), 52 deletions(-) diff --git a/docs/implementation/phase-execution-packet.md b/docs/implementation/phase-execution-packet.md index 579a5f23..be39390d 100644 --- a/docs/implementation/phase-execution-packet.md +++ b/docs/implementation/phase-execution-packet.md @@ -1,6 +1,10 @@ # InterviewCopilot phase-execution packet -Packet revision: **P00-R8** +Packet revision: **P00-R9** + +P00-R9 is a packet-only correction to P00-R8's execution protocol. It changes +no product decision, phase inventory, or requirement owner, so `design.md` +remains byte-for-byte unchanged. Planning base: `main@9dcb4b2d39607273a8528a24657cdb4f5bfc3412` @@ -248,7 +252,7 @@ author or a candidate process, arms one phase from the independently observed PR head with exact command `/Users/Shared/InterviewCopilot/verification-controller/v1/bin/arm-phase --phase --pr --expected-head - --approved-packet `. + --approved-packet `. The privileged command independently resolves the live PR head, requires exact agreement with `expected-head`, fetches that commit into the controller-owned @@ -278,10 +282,18 @@ closed path/name maps whose values carry Git mode where applicable, byte length, and SHA-256. `toolchain` carries OS/build/architecture plus Node/npm realpath, version, and SHA-256. `environment` is a closed allowlist with the fixed npm lifecycle-suppression and shell values. `writableRoots` is a closed -list derived by the controller, never a candidate path. The controller stores -the canonical anchor bytes as `anchor.json` and its lowercase-hex digest as -`anchor.sha256` under the fixed `anchors/active//local/` slot. Arming -P12 atomically installs the same candidate/input identity with role +list derived by the controller, never a candidate path. The closed active +anchor has no `runId` or other current-run value; a result/evidence schema may +describe such a later field but cannot supply its value. Only `arm-phase` may +atomically install an active anchor. After `verify-phase` selects and opens one, +that invocation treats its canonical bytes and digest as immutable and never +rewrites, augments, repairs, replaces, or re-arms it. It holds the +controller-owned phase/role anchor-slot lock through terminal finalization and +return; `arm-phase` requires the exclusive lock and returns nonzero without +installing when a run holds it. The controller stores the canonical anchor bytes +as `anchor.json` and its lowercase-hex digest as `anchor.sha256` under the fixed +`anchors/active//local/` slot. Arming P12 atomically installs the same +candidate/input identity with role `meet-observer` under `anchors/active/P12/meet-observer/`; no other role slot is valid. The local and observer anchors differ only in role-bound plan/result fields. Any schema, canonical-byte, field, or digest disagreement rejects. @@ -294,6 +306,43 @@ controller rejects a changed live PR head before execution and repeats that comparison before zero. It never fetches, checks out, resets, switches, repairs, or re-arms from candidate output. +**Per-run binding and run-root creation.** Only after the controller has opened, +schema-validated, digest-validated, and selected the immutable active anchor and +confirmed the live PR head does it generate a `ControllerRunId`: exactly 16 +bytes from the controller CSPRNG encoded as 32 lowercase hexadecimal characters +matching `^[0-9a-f]{32}$`. The controller derives, without a candidate value, +the exact run path +`/Users/Shared/InterviewCopilot/verification-controller/runs////` +from the selected anchor's commit and phase plus that generated ID. It creates +the final run directory exclusively beneath descriptor-opened controller-owned +ancestors. `EEXIST`, CSPRNG failure, unsafe ancestry, or any ownership, mode, +ACL, link, flag, mount, or descriptor disagreement is an integrity failure; the +controller never adopts an existing root or retries the same ID. + +Before materialization or any candidate process, the controller exclusively +creates a byte-identical `anchor.json` snapshot from its held active-anchor +descriptor and a separate JCS-canonical `run-binding.json`. The snapshot is not +the active anchor and also has no run ID. The binding rejects duplicate or +unknown keys and contains exactly `schemaVersion` (JSON integer `1`), `kind` +(`"verification-run-binding"`), `runId: ControllerRunId`, `anchorSha256` +(lowercase SHA-256 of the selected canonical active-anchor bytes), +`candidateCommitSha` (the anchor's exact 40-lowercase-hex commit), `phase` +(`"P01"` through `"P12"`), `role` (`"local"` or `"meet-observer"`), and +`createdAt` (a real UTC timestamp with exactly milliseconds and terminal `Z`, +created after anchor selection and before the first spawn). Every repeated +identity exactly equals the held anchor. The binding is evidence and never a +checkout, plan, role, toolchain, writable-root, or evidence-root selector; its +SHA-256 is computed over its canonical bytes and is not stored inside itself. + +The service identity creates both files with exclusive no-follow operations, +fsyncs their complete bytes, freezes `run-binding.json` as a controller-owned +mode-0400 regular link-count-one file with no write bit, ACL entry, or file +flag, fsyncs the run directory, reopens both canonical names by descriptor, and +compares bytes, digests, ownership, device/inode, mode, flags, ACL state, size, +and link count. It retains the descriptors for the entire invocation. Candidate +processes inherit neither descriptor nor controller evidence path. Only after +these steps succeed may sealed materialization begin. + **Sealed materialization and lifecycle containment.** `verify-phase` materializes the active commit from the controller object store into a fresh controller-owned run root with no inode shared with an invoking-user worktree. @@ -344,23 +393,27 @@ Plan children inherit neither those descriptors nor a controller evidence path. Candidate stdout, environment, artifact paths, duplicate/replayed records, and unframed structured output are never result authority. -The authoritative run root is exactly -`/Users/Shared/InterviewCopilot/verification-controller/runs////`, -where `runId` is a controller-generated 128-bit random lowercase-hex value. Its -closed controller-owned layout is `anchor.json`, `input-inventory.json`, +The authoritative run root created above has the closed controller-owned layout +`anchor.json`, `run-binding.json`, `input-inventory.json`, `controller-transcript.json`, `reporter-aggregate.json`, `reporter-aggregate.txt`, `output-inventory.json`, numbered stdout/stderr logs, and either `success.json` or `failure.json`, never both. These controller files are external gate evidence, not additions to the nine-member P12 qualification -evidence set or four-member release bundle. Each transcript entry contains +evidence set, four-member release bundle, or 16-node/28-edge qualification +graph. Each transcript entry contains exactly `index`, `label`, `plannedArgv`, `resolvedExecutable`, `resolvedExecutableSha256`, `actualSpawnArgv`, `startedAt`, `endedAt`, `durationMs`, `rawExit`, `signal`, `stdoutLog`, `stdoutSha256`, `stderrLog`, -`stderrSha256`, optional `counts`, and `reporterRecordSha256`. The terminal -record binds the anchor/run/transcript/aggregate/inventory hashes, +`stderrSha256`, optional `counts`, and `reporterRecordSha256`. Both closed +terminal-record variants require `runId`, `runBindingSha256`, and +`anchorSha256` to match the binding and held active anchor, and bind the +unchanged transcript/aggregate/inventory hashes, `reporterStarted`, `candidateProcessesSpawned`, controller and reporter aggregate exits, integrity-failure class if any, final-reopen result, survivor -count, and UTC completion. Unknown, missing, duplicate, unframed, reordered, or +count, and UTC completion. `success.json` requires matching identities, complete +hashes, both zero aggregates, zero survivors, and a passing final reopen; +`failure.json` records unavailable later hashes/exits as null and can never be +interpreted as success. Unknown, missing, duplicate, unframed, reordered, or hash-disagreeing data rejects. The reporter exits 0 only when every child raw exit equals its expected value, @@ -369,19 +422,35 @@ phase-owned, fixture, native, E2E, and manual procedure entry ran. Otherwise it exits 1 after the last ordinary entry. The controller independently correlates the reporter records with its broker transcript and is the sole acceptance authority. Immediately before zero it requires exact candidate/PR/anchor -identity, reopens every protected canonical name and compares its descriptor -identity/bytes/metadata, validates closed writable-root inventories and both -aggregate formats, and proves that no descendant remains. Any mismatch returns -nonzero; reporter zero can never override it. +identity, reopens the fixed active-anchor slot and digest, run-root anchor +snapshot, `run-binding.json`, and every other protected canonical name, and +compares their descriptor identity/bytes/metadata. It validates closed +writable-root inventories and both aggregate formats and proves that no +descendant remains. Any forced anchor-slot replacement or live-head change +during the invocation is therefore a final-reopen failure. Only after those +checks may it exclusively create, fsync, and reopen `success.json`; it then +rechecks the held anchor and binding immediately before returning zero and +releases the anchor-slot lock only after the return result is fixed. Any +mismatch returns nonzero; reporter zero can never override it. **Failure classes and negative controls.** Candidate/PR/packet, controller, -anchor, ownership, lifecycle, package/bootstrap/plan/manifest/gate, +anchor, run-root/binding creation, ownership, lifecycle, +package/bootstrap/plan/manifest/gate, runner/hash, executable/environment, result-channel, descriptor, process-group, or TOCTOU disagreement before reporter start returns 1 with `reporterStarted=false` and `candidateProcessesSpawned=0`. An integrity or result-authority loss after start terminates the complete process group, stops further entries, preserves the external controller failure record, and returns 1 without repair, restoration, unlink, retry, or aggregate-zero output. +Failure before a complete binding is frozen preserves the incomplete root as +non-acceptable audit state and uses the existing external preflight-failure +record; the root is never resumed, repaired, removed, or reused. After binding +freeze, every orderly exit has exactly one closed terminal record. A controller +crash may leave no terminal record; that root remains non-accepting and is never +resumed or reused. Any missing, partial, or mismatched terminal record is +non-accepting. The controller +descriptor-validates the binding before the first candidate spawn and after +each broker-owned process group is fully reaped. Ordinary child failures retain the existing continue-and-aggregate behavior. Injected-failure tests must prove exact children with raw exits 7 then 0 both spawn, the later result remains visible, the 7 remains exact in JSON/text and @@ -405,6 +474,17 @@ criterion or reporter plan, with these mandatory named cases: - `preserves every P01-R1-B01 through P01-R1-B06 hostile probe`; and - `rejects any surviving child or detached descendant before zero`. +Without adding a fourteenth case, reporter child, criterion, or plan, this same +thirteen-case suite also proves that a valid active anchor rejects an injected +`runId`; two invocations under byte-identical anchor bytes receive distinct +controller IDs, roots, bindings, and terminal records; root collision or a +partial binding fails before candidate spawn; binding byte/metadata replacement +fails at creation, post-child validation, and final reopen; concurrent re-arm +is rejected without changing the slot and any forced slot replacement fails the +old run's final reopen; candidate argv/environment/output/pairing cannot select +a binding; and P12's three reporter invocations use three fresh controller +bindings without changing its qualification-run identities. + Independent P01 review reuses the exact P01-CV-B01 hostile lifecycle fixture with SHA-256 `8a081c023a044b50298d6ad1917a3fbe5ab8de349738d1457e113c39730398bc`. @@ -552,7 +632,7 @@ integrity or result-authority loss terminates the run immediately. | P01-AC4: every BrowserWindow creation and reveal path invokes `applyCaptureProtection`, which calls `setContentProtection(true)` and never false. | `electron/captureProtection.test.ts — protects creation and reveal lifecycle paths` | | P01-AC5: package metadata and visible identity use InterviewCopilot and retain `AGPL-3.0-or-later`. | `tests/policy/productPolicy.test.ts — enforces canonical identity and AGPL metadata` | | P01-AC6: shipped source has no analytics SDK, device fingerprint, automatic crash-upload initialization, or environment-based secret logging. | `tests/policy/productPolicy.test.ts — rejects telemetry crash upload and secret logging entry points` | -| P01-AC7: the controller-owned first instruction anchors the exact candidate/toolchain/verification closure before npm, directly invokes the bootstrap/reporter without package pre/post dispatch, brokers and logs every exact planned/resolved/actual argv and OS raw exit/signal, suppresses planned-target companion hooks without changing child argv, prints passed/failed/skipped for every test entry, gives children no authoritative result path/descriptor, rejects lifecycle, package/bootstrap/plan/manifest/gate, runner/hash, environment, result-channel, survivor-process, and TOCTOU/mutate-restore drift before any zero, and preserves ordinary injected exits 7 then 0 in JSON/text/controller evidence with aggregate 1; missing counts, plan drift, or controller/reporter disagreement also fail. | `tests/policy/verificationReporter.test.ts — accumulates raw failures counts and immutable plan drift` | +| P01-AC7: the controller-owned first instruction anchors the exact candidate/toolchain/verification closure before npm, selects an immutable active anchor with no per-run value, exclusively creates and descriptor-validates the closed non-selecting per-run binding, directly invokes the bootstrap/reporter without package pre/post dispatch, brokers and logs every exact planned/resolved/actual argv and OS raw exit/signal, suppresses planned-target companion hooks without changing child argv, prints passed/failed/skipped for every test entry, gives children no authoritative result path/descriptor, rejects lifecycle, package/bootstrap/plan/manifest/gate, runner/hash, environment, result-channel, binding, survivor-process, and TOCTOU/mutate-restore drift before any zero, and preserves ordinary injected exits 7 then 0 in JSON/text/controller evidence with aggregate 1; missing counts, plan drift, or controller/reporter/binding disagreement also fail. | `tests/policy/verificationReporter.test.ts — accumulates raw failures counts and immutable plan drift` | **Clean-checkout setup.** Every command must exit 0. @@ -592,8 +672,9 @@ artifact proving aggregate exit 1; (5) manifest diff proving the inherited test remains; (6) capture lifecycle test output; (7) build artifact list; (8) reviewer sign-off that no lint/type rule or source glob was weakened; (9) controller executable/ancestor -ownership-mode-ACL/hash evidence, active-anchor bytes/hash, sealed-root -inventory, broker transcript, and final reopen/process-group proof; (10) the +ownership-mode-ACL/hash evidence, active-anchor bytes/hash, per-run binding +bytes/hash, sealed-root inventory, broker transcript, and final reopen/process- +group proof; (10) the archived lifecycle exploit plus the complete joint-mutation/result-channel/ TOCTOU matrix and exact exits-7-then-0 negative control. @@ -603,7 +684,7 @@ inside the single PR. **Self-contained implementation prompt.** -> Implement P01 from P00-R8 on `phase/P01-local-gates`, based only on upstream +> Implement P01 from P00-R9 on `phase/P01-local-gates`, based only on upstream > `main@9dcb4b2d…` plus merged planning docs. Do not import the dirty prototype. > Make local lint, strict type-check, real unit tests (including the unchanged > tracked CRA sample), manifest enforcement, and build green. Centralize and @@ -618,7 +699,7 @@ inside the single PR. **Self-contained review prompt.** -> Review P01 independently against P00-R8, not the author’s summary. Select and +> Review P01 independently against P00-R9, not the author’s summary. Select and > arm the exact live PR head independently, then run the fixed P01 controller > invocation from a clean checkout and sealed root. Confirm the inherited CRA > test ran, @@ -639,7 +720,7 @@ inside the single PR. > files, add/strengthen `{named regression test}`, preserve every inherited > gate and capture invariant, rerun the complete P01 plan (which begins with > `npm ci`) through a freshly armed fixed controller entrypoint, and return the -> active-anchor/controller identities, every child planned/resolved/actual +> active-anchor/per-run-binding/controller identities, every child planned/resolved/actual > argv/raw exit/count, controller and reporter aggregate exits, mutation-matrix > results, and the before/after commit SHAs. @@ -756,7 +837,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained implementation prompt.** -> Implement P02 from P00-R8 after P01, on +> Implement P02 from P00-R9 after P01, on > `phase/P02-subscription-runtime`. Build a provider-neutral persistent runtime > for Claude Code and Codex only, using one resumable session/thread, normalized > streaming/usage/compaction/stop/error events, explicit provider/model/Fast- @@ -770,7 +851,7 @@ and evolving; pin capabilities and fail explicitly on unsupported versions. **Self-contained review prompt.** -> Review P02 against P00-R8 from a clean checkout and a controller-selected, +> Review P02 against P00-R9 from a clean checkout and a controller-selected, > sealed exact PR head. Trace both fake providers > through two turns, stop, compaction, driver/child restart, and caller-ID > resume; force every failure and prove the other provider never starts. Inspect @@ -887,7 +968,7 @@ never custom cryptography. **Self-contained implementation prompt.** -> Implement P03 from P00-R8 after P01 on +> Implement P03 from P00-R9 after P01 on > `phase/P03-encrypted-persistence`. Build the Keychain-backed installation-key > service, versioned AES-256-GCM record/blob store, atomic writes, encrypted > in-memory-search source, typed recovery, raw-audio rejection, and journaled @@ -1039,7 +1120,7 @@ boundary; no renderer or provider may keep a second authoritative session. **Self-contained implementation prompt.** -> Implement P04 from P00-R8 after P02/P03 on +> Implement P04 from P00-R9 after P02/P03 on > `phase/P04-session-orchestrator`. Replace global transient state with the > deterministic InterviewSession reducer, typed event/IPC contract, one > persistent-conversation orchestrator, context/delta policy, pending artifacts, @@ -1178,7 +1259,7 @@ display behavior is platform-sensitive and directly touches privacy regression. **Self-contained implementation prompt.** -> Implement P05 from P00-R8 after P04 on `phase/P05-live-shell`. Build the +> Implement P05 from P00-R9 after P04 on `phase/P05-live-shell`. Build the > exact Quiet Signal hidden/compact/answer/expanded shell, command rail, > composer, input tray, explicit click-through/drag regions, final remappable > shortcuts, display-aware geometry, primary-display screenshot behavior, @@ -1303,7 +1384,7 @@ regress silently; fixture contracts are merge-blocking. **Self-contained implementation prompt.** -> Implement P06 from P00-R8 after P05 on `phase/P06-coding`. Add the exact +> Implement P06 from P00-R9 after P05 on `phase/P06-coding`. Add the exact > typed Coding intents/schema/renderer, concise-first progressive answer, > language snapshot and six-family fixtures, read-only actions, New Question, > and isolated `Control+Shift+D` versioned Fix flow. Enforce no personal context, @@ -1422,7 +1503,7 @@ must not become a second untyped document model. **Self-contained implementation prompt.** -> Implement P07 from P00-R8 after P05 on `phase/P07-system-design`. Add the +> Implement P07 from P00-R9 after P05 on `phase/P07-system-design`. Add the > fixed typed five-section progressive workflow, bounded material estimates, > safe vendor-neutral structured diagram, read-only accessible interactions, > assumption handling, dependency-scoped follow-up and What changed summary. @@ -1547,7 +1628,7 @@ integrity are product trust boundaries. **Self-contained implementation prompt.** -> Implement P08 from P00-R8 after P05 on `phase/P08-behavioral`. Build the +> Implement P08 from P00-R9 after P05 on `phase/P08-behavioral`. Build the > encrypted canonical candidate dossier, guided/manual reviewed editing, > sanitized Markdown import/export, multiple snapshotted opportunities, > provenance, opt-in labeled persistent synthetic stories, and typed Behavioral @@ -1683,7 +1764,7 @@ packaging, privacy, and transcription latency are launch-critical. **Self-contained implementation prompt.** -> Implement P09 from P00-R8 after P05 on `phase/P09-audio`, macOS only. Build +> Implement P09 from P00-R9 after P05 on `phase/P09-audio`, macOS only. Build > explicit two-source native capture, deterministic master/per-source controls, > contextual permission recovery, pinned offline whisper.cpp transcription, > explicit Apple Speech remote fallback, typed segments/attribution/correction, @@ -1804,7 +1885,7 @@ must never become a capability or schema escape hatch. **Self-contained implementation prompt.** -> Implement P10 from P00-R8 after P06/P07/P08 on +> Implement P10 from P00-R9 after P06/P07/P08 on > `phase/P10-prompt-studio`. Build synchronized reviewed-diff Chat/Manage, > immutable built-ins, complete encrypted user CRUD, core-mode-only schemas, > deterministic recorded instruction resolution, Start snapshotting, protected @@ -1925,7 +2006,7 @@ content and destructive user controls. **Self-contained implementation prompt.** -> Implement P11 from P00-R8 after P06–P10 on +> Implement P11 from P00-R9 after P06–P10 on > `phase/P11-history-recovery`. Add explicit crash Resume/Reset, complete > encrypted archive projection, Settings-only in-memory search/open/delete one/ > all, safe consented individual Markdown/JSON export, read-only archive open, @@ -1989,7 +2070,7 @@ detached statement binds its app semver and post-build package identity. Those exact passing tuples—and no neighboring patch, major version, browser, app build, architecture, or display mode—are the supported macOS/browser/app versions until separately qualified. Qualify each supported tuple separately. -P00-R8 represents no version as supported before the committed matrix, detached +P00-R9 represents no version as supported before the committed matrix, detached release statement, and evidence pass. Entire-display and specific-window require confirmation from remote Meet view or second device and retained high-contrast moving-marker artifacts; one fail makes @@ -2760,6 +2841,18 @@ invocations are validators: | Add one valid independent review, then exact unchanged run 2 | REUSE: `package:mac=0`; pre-existing collection is fully validated; every child raw exit including `verify:release=0`; aggregate `=0`. | All snapshotted statement/package values, including ACL-free state, are identical before and after; no producer or writer runs, so all producer counts remain one. | | Exact unchanged run 3 | REUSE again; every child raw exit and the aggregate are exactly `0`. | The same snapshots, including ACL-free state, are identical and producer/writer counts remain one. | +These are three separate `verify-phase` controller invocations under the same +unchanged active-anchor bytes. Each has a fresh `ControllerRunId`, run root, +closed binding, and terminal record: run 1 ends in `failure.json` because the +reporter aggregate is exactly 1, while runs 2 and 3 end in `success.json`. +Controller IDs are not the P12 qualification `RunId`, whose UUIDv4 lexical +schema and M01/M02 identity remain unchanged. Run 1 may create the fresh M01/M02 +qualification runs required by collection; runs 2 and 3 validate and reuse +those same accepted qualification roots and never mint a replacement +qualification ID, evidence member, bundle member, package, or statement. A +remote observer invocation independently receives a fresh role-bound controller +binding; the pairing challenge cannot supply or correlate controller run IDs. + The lifecycle model and mutation suite must instrument every producer and the writer, attempt statement/package/binding/status/path/root/mode/flag/ACL/link/ canonicalization/signature changes, force checkout-selection attempts, crash @@ -3317,7 +3410,7 @@ signing infrastructure cannot be inferred from unit tests. **Self-contained implementation prompt.** -> Implement P12 from P00-R8 after P01–P11 on +> Implement P12 from P00-R9 after P01–P11 on > `phase/P12-macos-qualification`. Freeze the exact macOS/Chrome/Meet/build/ > architecture matrix, harden macOS-only package/entitlements/identity, add > local-only redacted diagnostic preview/export, scoped failure recovery, @@ -3485,12 +3578,16 @@ product contract: evidence roots, ownership/mode/ACL/link/mount invariants, and hostile-probe behavior. At each phase/review branch cut the controller freezes the exact entrypoint hash, approved packet SHA, live PR head, Node/npm/macOS identities, - dependency closure, and run ID in the active anchor. These are time-bound - execution values, not permission to move the trust root into the candidate - repository or alter the controller contract. - -There is no unresolved material decision and no blocker to the P00-R8 planning -PR. Controller installation plus fresh P00/review-8 executable proof is a hard + and dependency closure in the active anchor. That closed immutable object + never contains a run ID. Only after selecting it for an invocation may + `verify-phase` generate a fresh controller run ID and bind it to the anchor + digest in the separate closed per-run controller/terminal evidence defined + in section 6. These are time-bound execution values, not permission to move + the trust root into the candidate repository or alter the controller + contract. + +There is no unresolved material decision and no blocker to the P00-R9 planning +PR. Controller installation plus fresh P00/review-9 executable proof is a hard P01 admission prerequisite. Future phases must report an unmet prerequisite instead of weakening a criterion. @@ -3524,9 +3621,9 @@ phase: records the immutable anchor/entrypoint identities; author cwd, SHA, artifacts, or reports are never selection authority. 5. Produce every named test and completion artifact only through the fixed - controller invocation. Retain its anchor, sealed-root inventory, broker - exact-command/raw-exit/count/process transcript, reporter JSON/text - aggregates, mutation-matrix results, and final-reopen evidence. + controller invocation. Retain its anchor, per-run binding, sealed-root + inventory, broker exact-command/raw-exit/count/process transcript, reporter + JSON/text aggregates, mutation-matrix results, and final-reopen evidence. 6. Have an independent reviewer re-resolve and freshly arm the exact live PR head, execute the self-contained review prompt from a fresh sealed materialization, reproduce the required hostile/negative controls, and @@ -3543,8 +3640,8 @@ phase: An implementation PR description must list packet revision, phase ID, base and head SHAs, dependencies, scope/non-goals, migration owner, controller -entrypoint/anchor/run identities, planned/resolved/actual command outputs and -counts, completion-artifact links/hashes, mutation-matrix evidence, risks, and -any external prerequisite. “CI green,” a screenshot, a package-owned gate, a -candidate evidence path, or the author’s assurance alone is never completion -evidence. +entrypoint/anchor/per-run-binding identities, planned/resolved/actual command +outputs and counts, completion-artifact links/hashes, mutation-matrix evidence, +risks, and any external prerequisite. “CI green,” a screenshot, a package-owned +gate, a candidate evidence path, or the author’s assurance alone is never +completion evidence.