diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 8005e32..0000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,2 +0,0 @@ -blank_issues_enabled: false -contact_links: [] diff --git a/.github/ISSUE_TEMPLATE/work-item.yml b/.github/ISSUE_TEMPLATE/work-item.yml deleted file mode 100644 index 9cc719e..0000000 --- a/.github/ISSUE_TEMPLATE/work-item.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Shepherd work item -description: Claim one HANDOVER task, defect, assurance check, or PRD requirement. -title: "[TASK-ID] " -body: - - type: markdown - attributes: - value: | - Read `docs/HANDOVER.md` before claiming work. One issue is owned by one agent at a time. Open a linked draft PR immediately after assignment. - - type: input - id: task-id - attributes: - label: HANDOVER task ID - description: Use the stable ID from docs/HANDOVER.md. Do not invent a duplicate ID. - placeholder: GC-01 - validations: - required: true - - type: input - id: prd-reference - attributes: - label: PRD reference - description: Cite every affected docs/PRD.md section or state that this is an operational task. - placeholder: PRD 4.1 Goal 12; 8.1; 11.5; 11.6 journey 3 - validations: - required: true - - type: textarea - id: observed - attributes: - label: Current behavior and evidence - description: Include the assessed commit, reproduction, and existing test or handover evidence. - validations: - required: true - - type: textarea - id: expected - attributes: - label: Expected behavior and acceptance criteria - description: State observable outcomes, negative cases, and the evidence required before completion. - validations: - required: true - - type: textarea - id: scope - attributes: - label: Owned scope - description: List expected files/modules and explicitly excluded adjacent work. - validations: - required: true - - type: textarea - id: dependencies - attributes: - label: Dependencies and stack position - description: List blockers, parent issue/PR/branch, dependants, or "independent from main". - validations: - required: true - - type: textarea - id: verification - attributes: - label: Verification plan - description: List targeted, adjacent, full, browser, live, security, and post-merge checks. Mark non-applicable checks explicitly. - validations: - required: true - - type: checkboxes - id: gates - attributes: - label: Required gates - options: - - label: The change will be the smallest coherent fix and will preserve existing behavior outside this issue. - required: true - - label: Material UI work will preserve `docs/UI.jpeg` and the existing visual language, and will be browser-verified at 1280x800 and 1440x900. - - label: Material security/trust-boundary work will receive independent security review. - - label: Live model/API calls will be opt-in, sparse, bounded, and never print credentials. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 5093686..0000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,61 +0,0 @@ -## Work item - -- HANDOVER ID: -- Linked issue: -- PRD reference(s): -- Head branch: -- Base branch / stack parent: -- Depends on: -- Blocks: -- Owned files/modules: - -Mid-stack PRs must be manually linked to their issue. Do not rely on a closing keyword until the PR targets `main`. - -## Outcome and minimal scope - -Describe the user-visible or trusted-boundary outcome and why this is the smallest coherent change. List intentionally excluded adjacent work. - -## Acceptance evidence - -Record exact commands and observed outcomes. Do not write "should pass" or copy evidence from another commit. - -```text -command -observed result -``` - -- [ ] Targeted regression tests passed. -- [ ] Adjacent tests passed. -- [ ] `npm run check` passed, or the exact justified subset is recorded. -- [ ] Negative/failure cases required by the issue passed. -- [ ] Documentation and `docs/BUILD_LOG.md` were updated when behavior/evidence changed. -- [ ] No secrets, local state, generated workspaces, or unbounded outputs are included. - -## UI evidence, when applicable - -- [ ] Real browser interaction was completed. -- [ ] 1280x800 and 1440x900 screenshots were reviewed against `docs/UI.jpeg` and PRD 11.7. -- [ ] Loading, empty, error, disabled, reconnecting, overflow, keyboard, and focus states were checked as applicable. -- [ ] Independent UI review completed; material findings are resolved or explicitly blocking. - -## Security and integration evidence, when applicable - -- [ ] Authority, redaction, path, persistence, cancellation, public API, file handling, or model-controlled actions received independent security review. -- [ ] Deterministic tests prove safe behavior without external services. -- [ ] Any live model/API smoke was opt-in, bounded, and recorded without credentials. - -## Scoped verdict - -- Confidence (0-100): -- Why this score is justified: -- Remaining uncertainty: -- Review required because confidence is below 100: yes / no -- Ready-for-review SHA: - -`100` means only that every defined acceptance criterion, required test, independent review, and pre-merge gate passed for this PR's scope. It never means that unknown defects are impossible. - -## Post-merge verification - -- [ ] Required checks passed in the merge queue or against the final merge group. -- [ ] The relevant smoke/flow passed on updated `main`. -- [ ] The issue and HANDOVER ledger were updated from evidence at the merged SHA. diff --git a/.github/workflows/pull-request-checks.yml b/.github/workflows/pull-request-checks.yml deleted file mode 100644 index eb2abde..0000000 --- a/.github/workflows/pull-request-checks.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Pull request checks - -on: - pull_request: - branches: [main] - merge_group: - types: [checks_requested] - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - required: - name: Required checks - runs-on: ubuntu-latest - timeout-minutes: 30 - - steps: - - name: Check out repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - - name: Use Node.js 22 - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 22 - package-manager-cache: false - - - name: Install dependencies - run: npm ci - - - name: Run repository checks - run: npm run check diff --git a/.github/workflows/required-checks.yml b/.github/workflows/required-checks.yml deleted file mode 100644 index 55d11fa..0000000 --- a/.github/workflows/required-checks.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Required checks - -on: - pull_request: - push: - branches: - - main - merge_group: - types: - - checks_requested - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - check: - name: Node 22 / npm run check - runs-on: ubuntu-latest - timeout-minutes: 20 - env: - CI: true - SHEPHERD_LIVE_TEST: "false" - steps: - - name: Check out repository - uses: actions/checkout@v6 - with: - persist-credentials: false - - - name: Use Node.js 22 - uses: actions/setup-node@v7 - with: - node-version: 22 - cache: npm - cache-dependency-path: package-lock.json - - - name: Verify Docker runtime - run: docker version - - - name: Install locked dependencies - run: npm ci - - - name: Run repository gate - run: npm run check diff --git a/.impeccable/config.json b/.impeccable/config.json deleted file mode 100644 index c037945..0000000 --- a/.impeccable/config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "detector": { - "ignoreRules": [], - "ignoreFiles": [], - "ignoreValues": [ - { - "rule": "overused-font", - "value": "inter", - "createdAt": "2026-08-31T12:14:04.965Z", - "reason": "Project AGENTS/TASKS UI freeze: accepted typography must be preserved; issue #96 permits functional and accessibility fixes, not redesign" - } - ] - } -} diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 6227d4c..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,83 +0,0 @@ -# Shepherd Agent Instructions - -## Entry point and codebase navigation - -`docs/HANDOVER.md` was intentionally removed. Do not recreate or reference it. - -Read in this order before editing: - -1. [`docs/TASKS.md`](docs/TASKS.md) — current hackathon cut, remaining work, - dependencies, acceptance gates, and evidence status. -2. The GitHub issue for the selected TASKS ID — current owner and branch/PR status. -3. The linked sections of [`docs/PRD.md`](docs/PRD.md) — required behavior. -4. [`docs/SHEPHERD.md`](docs/SHEPHERD.md) — as-built architecture, trust - boundaries, implemented features, limitations, and rubric snapshot. -5. [`docs/LOCAL_POC.md`](docs/LOCAL_POC.md) — startup and manual demo runbook. -6. [`docs/TECHJAM.md`](docs/TECHJAM.md) — Track 1 rules and judging rubric. -7. [`docs/FIXES.md`](docs/FIXES.md) and [`docs/BUILD_LOG.md`](docs/BUILD_LOG.md) - when diagnosing a defect or updating verified evidence. - -Primary code areas are indexed in `docs/TASKS.md` under **Requirement and code -navigation**. The PRD defines required behavior; TASKS records the current state. - -## Claim work before editing - -1. Fetch and prune remote refs. Inspect the issue, open PRs, remote branches, and - worktrees; choose different work if an active owner already exists. -2. **Claim the GitHub issue immediately.** Assign it to yourself when permitted and - leave a visible ownership comment naming the intended branch and primary files. - Do not wait until implementation is complete. -3. Branch from current `origin/main`, or from the explicitly documented parent for - a true dependency stack. Use `feat/`, `fix/`, `test/`, `audit/`, `refactor/`, or - `docs/` plus the issue/TASKS ID. -4. **Push the new branch to `origin` before implementation edits.** This is the - second ownership signal other agents must check. -5. Open a linked draft PR after the first comparable commit. State the issue/TASKS - ID, PRD references, owned files, exclusions, base/parent, acceptance criteria, - and test plan. Keep the issue and PR current. - -Never push directly to protected `main`. Keep each branch narrow. Agents do not -merge their own PRs; the integrator reviews overlap, combined gates, stack order, -and protected-branch integration. - -## Concurrent-agent isolation - -- Use one GitHub issue, branch, and isolated Git worktree per implementation owner. -- Work only in the assigned worktree. Do not check out, commit to, rebase, merge, - reset, delete, or force-push another agent's branch or worktree. -- Parallel branches normally target current `main`. Create a stack only for a real - code dependency documented in both issues/PRs with an explicit merge order. -- Record primary owned files/modules and excluded adjacent work before editing. - Shared central modules have one active owner at a time. Stop and coordinate if an - unexpected required edit overlaps active ownership. - -## UI freeze and minimal-change contract - -- **The accepted UI design is frozen.** Do not redesign, restyle, re-theme, change - layout, or perform visual cleanup. Functionalities, backend features, tests, - reviews, evidence, and documentation are the active work. -- Touch UI code only when indispensable to expose required functional data, restore - broken interaction, accessibility, or truthful state. Reuse existing components, - spacing, typography, colors, and interaction patterns from `docs/UI.jpeg`. -- A minimal fix means the smallest coherent change that fully preserves intended - behavior. It must not remove, disable, hide, stub, weaken, or narrow existing or - required functionality merely to reduce the diff or make tests pass. -- Any unavoidable material UI correction requires browser verification at - `1280x800` and `1440x900`, no document-level X/Y overflow, and read-only UI review. - -## Change and evidence rules - -- Preserve security boundaries, public contracts, deterministic behavior, baseline - Agent CRUD/lifecycle/Playground behavior, and existing test assertions. -- Avoid unrelated refactors, formatting, renames, dependency churn, sleeps, retry - inflation, suppression, or weakened assertions. -- Add causal regression coverage. Run targeted/adjacent checks and `npm run check`; - run browser, live, security, stability, or post-merge gates when the issue requires - them. -- Report only checks actually observed. Update `docs/BUILD_LOG.md` and the relevant - `docs/TASKS.md` evidence when behavior or status changes. -- Never print or commit `.env`, credentials, private paths, raw model prompts or - output, session identifiers, or unbounded logs. Default tests remain network- and - model-free. -- After integration, the integrator verifies the scoped flow on updated `main`, - updates the issue/ledger, and deletes only the merged feature branch when safe. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 2f660e2..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,31 +0,0 @@ -# Claude Code Instructions - -Follow [`AGENTS.md`](AGENTS.md); it is authoritative for ownership, branches, -verification, UI freeze, and minimal-change requirements. - -`docs/HANDOVER.md` was removed. Navigate the repository in this order: - -1. [`docs/TASKS.md`](docs/TASKS.md) for the hackathon cut and work queue. -2. The selected GitHub issue and its linked [`docs/PRD.md`](docs/PRD.md) sections. -3. [`docs/SHEPHERD.md`](docs/SHEPHERD.md) for architecture and current capabilities. -4. [`docs/LOCAL_POC.md`](docs/LOCAL_POC.md) for startup and demo verification. -5. [`docs/TECHJAM.md`](docs/TECHJAM.md) for Track 1 judging requirements. -6. [`docs/FIXES.md`](docs/FIXES.md) and [`docs/BUILD_LOG.md`](docs/BUILD_LOG.md) - for defects and observed evidence. - -Before editing, fetch/prune and inspect issues, PRs, remote branches, and worktrees. -**Claim one issue immediately** by assigning yourself when permitted and posting an -ownership comment with branch and primary files. Create a narrow branch from current -`origin/main` (or its explicitly documented stack parent), then **push it to origin -before implementation edits**. Open a linked draft PR after the first comparable -commit. Never push directly to or self-merge protected `main`. - -The UI design is frozen. Work on functionality, backend features, tests, reviews, -evidence, and documentation. Touch UI code only when required for truthful data, -broken interaction, or accessibility, and preserve the existing theme and layout. -“Minimal fix” means the smallest complete correction; it never permits removing, -hiding, disabling, stubbing, weakening, or narrowing intended functionality. - -Add causal tests, run applicable repository gates including `npm run check`, and do -not claim unobserved results. Never expose secrets, raw prompts, private paths, or -unbounded logs. Update TASKS/build evidence only from observed results. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 20e1df7..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,59 +0,0 @@ -# Contributing - -Start with [docs/TASKS.md](docs/TASKS.md). It is the current implementation, -defect, test-gap, ownership, and verification entry point. `docs/PRD.md` remains -the product-requirement authority; historical build logs are evidence, not the -live task board. Use [docs/LOCAL_POC.md](docs/LOCAL_POC.md) for the runbook. - -Keep changes focused, reproducible, and suitable for a hackathon delivery. - -## Setup - -```bash -npm install -cp .env.example .env -npm run dev -``` - -For container-based Agent execution, follow -[docs/LOCAL_POC.md](docs/LOCAL_POC.md). - -## Validate - -```bash -npm run check -terraform fmt -check -recursive deploy/volcengine -docker compose config -``` - -## Pull requests - -- Claim one TASKS item through a GitHub issue **immediately**: assign yourself when - permitted and comment with the intended branch and primary owned files. If that - issue already has an active owner, branch, or draft PR, choose another task. -- Create a branch from current `origin/main`, push it immediately, and open a - linked draft PR. Dependent work targets the branch below it in a short true stack. -- Keep one concern per PR and include its tests in the same PR. Do not create a - separate "tests later" layer for behavior introduced by the PR. -- Explain the behavior, root cause where applicable, acceptance criteria, - dependency/stack position, and reason for the change. -- Add causal tests for API, lifecycle, persistence, Runtime, or UI changes. -- Record exact commands and observed results; planned results are not evidence. -- Every PR requires independent review. A confidence below 100 remains marked - for review; scoped 100 still requires the normal reviewer gate. -- Material trust-boundary/security changes require independent security review. -- The accepted UI is frozen. Do not redesign or restyle it. Touch UI only when a - required functional state, broken interaction, or accessibility defect cannot be - fixed elsewhere; preserve the existing system and run both viewport/UI gates. -- A minimal correction must still preserve the complete intended functionality. Do - not remove, hide, disable, stub, or weaken behavior merely to reduce the diff. -- Merge only through reviewed PRs into protected `main` after relevant checks pass, - then let the integrator run the scoped post-merge smoke there. -- Update English documentation and `.env.example` when configuration changes. -- Use GitHub Flavored Markdown and relative repository links. -- Never commit credentials, local state, workspaces, build output, or Terraform - state. -- Report security issues according to [SECURITY.md](SECURITY.md). - -The repository PR template is the evidence checklist. See the workflow and -completion rules in [docs/TASKS.md](docs/TASKS.md#working-contract). diff --git a/README.md b/README.md index d511486..0148d93 100644 --- a/README.md +++ b/README.md @@ -1,151 +1,259 @@ -# Volc Agent Launchpad + Shepherd +# Shepherd: Multi-Agent Kernel -> [!IMPORTANT] -> Start with [the Shepherd task ledger](docs/TASKS.md). It is the authoritative -> current-state, defect, remaining-work, evidence, and multi-agent workflow entry -> point. [The PRD](docs/PRD.md) remains the requirement authority, and -> [the Local POC guide](docs/LOCAL_POC.md) is the runbook. -> This README still preserves much of the Starter Kit setup material and is not -> the final PRD Phase 9 project report. +**TikTok TechJam 2026 · Track 1 — Agent Launchpad middleware** -A minimal Agent platform for three-day middleware hackathons. It provides Agent -CRUD, a browser Playground, persistent workspaces, and Codex CLI backed by the -Volcengine Ark Responses API. +Shepherd is a transactional execution kernel for teams of coding Agents. It turns +delegated work into verifiable contracts, detects incompatible assumptions that a +clean Git merge cannot see, executes competing resolutions in isolated Git worlds, +and promotes only an independently verified result. -Run it locally with Docker, Colima, or rootless Podman, or deploy it to -Volcengine ECS. +> [!IMPORTANT] +> This README is the self-contained product overview, operating guide, and +> validation entry point. The retained Hackathon v2 source sections are linked +> under [Hackathon artifacts](#hackathon-artifacts). > [!WARNING] -> This is a single-user proof of concept. It has no production identity, -> multi-tenant authorization, or hardened tenant-isolation boundary. Shepherd -> adds a scoped execution/audit kernel for its managed demo project, but this is -> not a production security claim. Do not use production data or credentials. -> See [SECURITY.md](SECURITY.md). +> This is a single-user proof of concept, not a production identity or multi-tenant +> isolation system. Shepherd enforces scoped authority around its managed projects, +> but the shared bearer token is not user identity, the JSON store is single-process, +> and ordinary containers are not a hardened tenant boundary. Do not use production +> data or credentials. -## Screenshots +## The problem -### Agent Playground +Two coding Agents can both finish their assignments, pass their local checks, and +merge without a textual Git conflict while still making mutually incompatible +system assumptions. The deterministic demo makes that failure concrete: a frontend +uses an HttpOnly session cookie while a backend expects a bearer JWT. -![Agent Playground showing lifecycle controls, starter prompts, and the Codex Runtime](docs/assets/playground.jpg) +Shepherd inserts a trusted decision path between delegation and promotion: -### Create an Agent +```text +Contract -> Execute -> Verify -> Detect Collision + -> Fork Futures -> Verify Futures -> Promote Winner +``` -![Create Agent form with name, description, and workspace instructions](docs/assets/create-agent.jpg) +The UI is Mission Control for that kernel. It displays durable backend evidence; it +does not invent success state in the browser. -## Features +## Three primitives -- Shepherd Execution Contracts, Git-backed Planes, independent verification, - deterministic semantic collision detection, speculative resolution, and - protected promotion for the managed authentication fixture -- Shepherd Mission Control, Project Group, timeline, Plane Tree, Agent role and - authority configuration, and settings UI (with known gaps itemized in the task ledger) -- React and TypeScript Web UI -- Agent create, edit, start, stop, delete, and multi-turn chat -- Fastify control plane with asynchronous Run state -- Persistent Agent workspaces and Codex sessions -- Disposable Docker, Colima, or Podman container for each local turn -- Docker and Terraform deployment paths for Volcengine ECS +1. **Agent Execution Contracts** turn delegation into typed, machine-verifiable + objectives, dependencies, authority, expected artifacts, claims, and acceptance + checks. An Agent cannot certify its own work. +2. **Semantic Collision Detection** compares independently verified claims and + finds behavioral incompatibilities that textual merging misses. +3. **Speculative Conflict Resolution** forks competing futures from one immutable + integration commit, verifies each independently, and promotes only the + evidence-derived winner through a final protected-head gate. -## Requirements +Supporting capabilities include Git-worktree-backed **Planes**, scoped authority, +durable Missions and events, a live execution timeline, a Plane Tree, Project Group +routing, bounded model-assisted review, cancellation/recovery, and human selection +when automatic resolution cannot choose uniquely. -- Node.js 22+ -- npm 10+ -- Docker, Colima, or Podman -- A Volcengine Ark API key and endpoint that supports the Responses API +## Product tour -Codex CLI is included in the Runtime image and is not required on the host. +### Shepherd Mission Control -## Local browser SOP +The Contract stream, execution timeline, semantic collision, competing Resolution +Planes, retained loser, and promoted winner all come from persisted server state. +Changes outside an Execution Contract's writable scope are rejected with durable +evidence, and protected promotion never starts. -For the currently verified deterministic Shepherd command and exact manual test -walkthrough, use [the Local POC runbook](docs/LOCAL_POC.md). +![Shepherd interface reference covering Mission Control, Agents, Project Groups, and Settings](docs/UI.jpeg) -### 1. Check the local tools +### Preserved Agent Launchpad -Install Node.js 22+ and one supported container engine, then verify them: +Shepherd extends the supplied Starter Kit instead of replacing it. Agent create, +edit, start, stop, delete, asynchronous Runs, multi-turn Playground chat, persistent +workspaces/Codex sessions, and real model execution remain available. -```bash -node --version -npm --version -docker --version # Docker Desktop, Docker Engine, or Colima -podman --version # Use this instead when running Podman -``` +![Agent Playground showing lifecycle controls, starter prompts, and the Codex Runtime](docs/assets/playground.jpg) -Only one container engine is required. Codex CLI is already included in the -Runtime image. +![Create Agent form with name, description, and workspace instructions](docs/assets/create-agent.jpg) -### 2. Clone the repository +## Architecture -```bash -git clone volc-agent-launchpad -cd volc-agent-launchpad +![Shepherd multi-agent kernel architecture from API boundary through protected promotion](docs/assets/Shepherd_TechJam_Track1_Architecture.png) + +[Open the latest editable Draw.io source](docs/assets/Shepherd_TechJam_Track1_Architecture.drawio). + +The React application talks only to the Fastify control plane. Trusted server code +owns schema validation, authority intersection, lifecycle state, Git inspection, +manifest ingestion, independent verification, collision rules, winner selection, +final re-verification, and compare-and-swap promotion. Coding Agents and model +output are untrusted inputs. + +```mermaid +flowchart LR + Human["Human"] --> UI["React Web UI"] + UI --> API["Fastify control plane"] + + API --> Launchpad["Starter AgentService"] + Launchpad --> Runtime["Disposable Codex Runtime"] + Runtime --> Ark["Volcengine Ark Responses API"] + + API --> Kernel["Trusted ShepherdService"] + Kernel <--> Store["Durable JSON state and event evidence"] + Kernel --> Contracts["Typed Execution Contracts"] + Contracts --> Planes["Isolated Git Planes"] + Planes --> Runtime + Planes --> Verifier["Credential-free independent verifier"] + Verifier --> Collision["Deterministic collision and winner rules"] + Collision --> Futures["Competing Resolution Planes"] + Futures --> Verifier + Verifier --> Gate["Final verification and protected-head CAS"] + Gate --> Protected["Managed protected branch"] ``` -Skip this step when already working from the repository root. +Each live turn receives only its selected workspace or authority-filtered Plane +export and its own Codex session directory. It does not receive the protected Git +repository or verifier credentials. The deterministic mode exercises the same +kernel without an external model request. + +## Quickstart: deterministic judge flow + +The recommended judging path runs locally with Docker, Colima, or rootless Podman. +It exercises real Contracts, Git Planes, verification, collision handling, +resolution, persistence, and promotion without spending model capacity. + +### Requirements + +- macOS or Linux +- Node.js 22+ +- npm 10+ +- Docker, Colima, or rootless Podman +- A Volcengine Ark API key and Responses-capable endpoint for the preserved live + Agent path; the launcher requires these values, but the deterministic Mission + does not send a model request -### 3. Start the POC +Codex CLI is included in the Runtime image and is not required on the host. -Configure `ARK_API_KEY` and `ARK_MODEL` in the repository's ignored `.env`, then -run the single local entry point without additional parameters: +### 1. Clone and configure ```bash -./scripts/start-local-poc.sh +git clone https://github.com/kyashp/shepherd.git +cd shepherd +cp .env.example .env ``` -The first run installs Node.js dependencies and builds the Runtime image. The -script automatically selects Docker, Colima, or Podman. +Set `ARK_API_KEY` and `ARK_MODEL` in the ignored `.env`. For the reliable +deterministic demo, also set: -### 4. Open the browser +```dotenv +HOST=127.0.0.1 +SHEPHERD_EXECUTION_MODE=deterministic +SHEPHERD_DEMO_MODE=true +``` -Visit , or open it from the terminal: +### 2. Start ```bash -open http://localhost:3000 # macOS -xdg-open http://localhost:3000 # Linux desktop +./scripts/start-local-poc.sh ``` -In the Web UI: +The first run installs dependencies, builds the Runtime image, selects the +available container engine, validates the workspace boundary, and serves the app at +. + +### 3. Run the primary Shepherd Mission + +1. Open **Settings -> General -> Reset demo state**. This removes only the managed + demo state and preserves ordinary Launchpad Agents. +2. Create `Frontend Auth Agent` with role **Frontend** and `Backend Auth Agent` with + role **Backend**. Both must be ready. +3. Open `Frontend Auth Agent`, enable **Route through Shepherd**, and send: + + ```text + Implement the frontend authentication client using an HttpOnly session cookie. + ``` -1. Select **Create Agent**. -2. Enter a name, description, and workspace instructions. -3. Select **Create Agent** again. -4. Enter a task in the Playground, for example: +4. Open `Backend Auth Agent`, enable **Route through Shepherd**, and send: ```text - Create a TypeScript hello-world CLI, add a test, and run it. + Implement the backend authentication service using a bearer JWT. ``` -The Agent can write files, run commands, and continue the same Codex session in -later messages. +5. The second compatible-role prompt atomically starts one Mission. Open + **Shepherd** and wait for `completed`. +6. Verify the visible causal chain: two durable Contracts -> isolated Contract + Planes -> independent verification -> clean textual integration -> + `auth.transport` semantic collision -> two same-base Resolution Planes -> cookie + candidate verified and bearer candidate rejected -> final re-verification -> + protected promotion. +7. Open Contract evidence, use every stream filter, expand the collision, and open + Plane Tree details. Evidence must not expose secrets, private host paths, raw + prompts/model output, or session identifiers. + +The exact prompts become durable Contract objectives. The frontend and backend +source Planes do not compete with each other; their incompatible verified claims +create two resolution futures after integration. + +### 4. Exercise the human-decision path + +1. Reset the demo, then open **Settings -> Execution**. +2. Disable **Automatic resolution** and save. +3. Repeat the two private Agent prompts above. +4. At `attention_required`, inspect the durable human-review ticket. Only an + independently passing future offers **Select verified future**. +5. Select that future and confirm it still passes the same final verification and + promotion gate. Restore **Automatic resolution** afterward. + +This is the recommended recovery/decision story for a manual demo. The automated +authority-denial journey is covered separately by the browser suite. ### 5. Stop and resume -Press `Ctrl+C` in the startup terminal. The script removes temporary Runtime -containers but keeps Agent workspaces and conversations. +Press `Ctrl+C` in the startup terminal. The launcher removes this instance's +temporary Runtime containers but preserves Agents, conversations, Runs, workspaces, +Codex sessions, and Shepherd evidence. -- macOS state: `~/.volc-agent-launchpad/` -- Linux state: `.local/` -- Custom location: set `LOCAL_POC_DATA_ROOT` +- macOS host state: `~/.volc-agent-launchpad/` +- Linux host state: `.local/` +- Custom host location: set `LOCAL_POC_DATA_ROOT` +- Engine-native state: set `LOCAL_POC_STATE_MODE=container-volume` -Run the same `./scripts/start-local-poc.sh` command to continue later. +Run `./scripts/start-local-poc.sh` again to continue. The default `auto` state mode +falls back to the `launchpad-state` volume when a VM-backed host share cannot enforce +the Codex sandbox's per-file access rights. -### Select a specific container engine +## Preserved live Agent flow -Force Podman when multiple engines are installed by setting -`CONTAINER_ENGINE=podman` in `.env`, then run: +The Starter Kit acceptance path remains available and uses real Ark capacity: -```bash -./scripts/start-local-poc.sh -``` +1. Create a **Generalist** Agent named `Manual QA Agent`. +2. In its Playground, send: + + ```text + Create a dependency-free hello.js that prints "Hello, Shepherd", add a Node test, run it, and report the exact test result. + ``` -Colima uses `CONTAINER_ENGINE=docker` because it exposes the Docker CLI. +3. Send the follow-up `Reply with only the exact greeting produced by hello.js.` +4. Confirm `queued -> running -> completed`, the expected file, and continued + conversation context. +5. Stop and restart with the same data root; confirm the Agent, messages, Runs, and + workspace persist. -For a clean Linux host, follow the -[rootless Podman setup](docs/LOCAL_POC.md#rootless-podman-on-linux). +This flow validates the preserved Agent Playground, not Shepherd's deterministic +Mission. It calls the configured external model and should be run only when that +data transfer and capacity use are authorized. A Track 1 rehearsal should pair this +live Starter Kit continuity check with the deterministic Shepherd Mission and its +human-decision or authority-denial evidence. + +## Container engine options + +Set `CONTAINER_ENGINE=podman` in `.env` to force Podman. Colima uses +`CONTAINER_ENGINE=docker` because it exposes the Docker CLI. On a clean Linux host, +use a rootless Podman service and ensure its user socket is available to the launcher. + +Resource limits are controlled with `CONTAINER_CPU_LIMIT`, +`CONTAINER_MEMORY_LIMIT`, and `CONTAINER_PIDS_LIMIT`. The defaults are 2 CPUs, +2 GiB memory, 256 processes, dropped capabilities, and `no-new-privileges`. ## Docker Compose -Create and edit the configuration: +Create the ignored local configuration: ```bash ./scripts/bootstrap-local.sh @@ -158,22 +266,16 @@ ARK_API_KEY=your-ark-api-key ARK_MODEL=ep-your-endpoint-id ``` -`APP_AUTH_TOKEN` is optional and empty by default, so nothing else is needed to -start. The container profile publishes on `127.0.0.1` by default, so the quickstart -is not reachable from the network and a tokenless start is safe. - -To expose it beyond this machine, set `PUBLIC_BIND_ADDR` (for example `0.0.0.0`) and -set `APP_AUTH_TOKEN` to 24+ random URL-safe characters **in the same change**. The -API performs prompt-triggered command and file execution, so an exposed instance -without a token hands that to anyone who can reach the port. - -Start the application: +The base profile publishes on `127.0.0.1` and permits an empty `APP_AUTH_TOKEN`. +To expose the service beyond the machine, set `PUBLIC_BIND_ADDR=0.0.0.0` and a +24+ character `APP_AUTH_TOKEN` in the same change. This API can trigger model, +command, and file execution; never expose a tokenless instance. ```bash docker compose up --build ``` -Open . Stop it without deleting Agent data: +Open . Stop without deleting Agent data: ```bash docker compose down @@ -191,7 +293,7 @@ npm run dev - Web UI: - API: -Use local paths in `.env` when running outside Docker: +Use host-local paths in `.env` when running outside Docker: ```dotenv APP_DATA_DIR=.data @@ -199,62 +301,95 @@ AGENT_WORKSPACE_ROOT=workspaces CODEX_HOME=codex-home ``` -## Optional cloud deployment +The first Playground turn uses `codex exec`; later turns resume the stored Codex +thread. Deleting an Agent archives its workspace under `workspaces/.deleted/`. -Local Docker, Colima, or Podman is the recommended judging path; see -[the Local POC guide](docs/LOCAL_POC.md). The repository retains optional existing -ECS and Terraform deployment scripts, but cloud deployment does not improve the -Track 1 score by itself. +## Configuration -### Existing Linux ECS +| Variable | Default | Purpose | +| --- | --- | --- | +| `ARK_API_KEY` | Required by local launcher | Ark credential for live Agent and Shepherd execution. | +| `ARK_MODEL` | Required by local launcher | Responses-capable endpoint or model ID. | +| `ARK_BASE_URL` | Beijing v3 endpoint | Ark OpenAI-compatible API URL. | +| `APP_AUTH_TOKEN` | Empty on loopback | Shared demo token; use 24+ random URL-safe characters remotely. | +| `SHEPHERD_EXECUTION_MODE` | `auto` | `deterministic`, `live`, or automatic selection. | +| `SHEPHERD_DEMO_MODE` | `false` | Enables the server-owned deterministic demo fixture. | +| `SHEPHERD_MODEL` | Empty | Optional bounded advisory reviewer; never verifies or promotes. | +| `SHEPHERD_AUTO_RESOLUTION` | `true` | Startup seed for automatic candidate selection. | +| `SHEPHERD_MAX_PARALLEL_PLANES` | `2` | Startup seed for bounded Plane concurrency. | +| `RUNTIME_PROVIDER` | `local-process` | `container` for disposable local Runtime containers. | +| `CODEX_SANDBOX_MODE` | `workspace-write` | Inner Codex sandbox request. | +| `CODEX_TIMEOUT_MS` | `600000` | Maximum duration of one Agent turn. | +| `LOCAL_POC_DATA_ROOT` | Platform-specific | Host metadata, workspace, and session root. | +| `LOCAL_POC_STATE_MODE` | `auto` | Host bind, engine volume, or automatic safe fallback. | + +See [.env.example](.env.example) for verifier, timeout, Runtime image, mirror, +state-volume, and resource-limit options. -Use a dedicated Ubuntu 22.04/24.04, Debian 12, or veLinux 2 instance with at -least 2 vCPU, 4 GiB RAM, a 40 GiB disk, Docker Engine 24+, and the Compose plugin. -The path was verified on veLinux 2 with Docker Engine 29.6.2 and Compose 5.3.1; -Debian 10 is unsupported. Follow Docker's official repository instructions, -verify the downloaded signing-key fingerprint, log in again after group changes, -and check `docker version`, `docker compose version`, and -`docker run --rm hello-world` before deployment. Do not replace the engine on a -host that contains important workloads. +## Validation and evidence -veLinux 2 uses Docker's Debian 12 Bookworm repository. Resolve the supported parent -before following the official Docker key/repository installation steps: +The default test suites do not call Ark. Dependency, browser, Terraform, and image +setup may still download their pinned artifacts: ```bash -. /etc/os-release -case "$ID" in - ubuntu|debian) - DOCKER_DISTRO="$ID" - DOCKER_CODENAME="$VERSION_CODENAME" - ;; - velinux) - DOCKER_DISTRO=debian - DOCKER_CODENAME=bookworm - ;; - *) - echo "Use the Docker-supported parent distribution." - exit 1 - ;; -esac +npm ci +npm run check +npm run test:coverage +npm run test:e2e:install +npm run test:e2e:harness +npm run test:terraform +npm run test:shepherd:live:preflight +npm audit --json ``` -Install `ca-certificates`, `curl`, `gnupg`, `git`, and `openssl`; download the key -from `https://download.docker.com/linux/$DOCKER_DISTRO/gpg`; compare its complete -fingerprint with Docker's official installation guide; place the dearmored key in -`/etc/apt/keyrings/docker.gpg`; and configure the stable repository with -`$DOCKER_CODENAME`. Then install Docker Engine, CLI, containerd, Buildx, and Compose. +- `npm run check` runs strict production and test-source typechecks, root script + tests, Server/Web tests, and production builds. +- `npm run test:coverage` enforces at least 80% statements, branches, functions, + and lines for both Server and browser-owned Web source, with every production + source file present. +- `npm run test:e2e:harness` runs the deterministic Chromium matrix configured in + `playwright.config.ts`. +- `npm run test:terraform` validates a disposable Terraform module using local + Terraform or the pinned `hashicorp/terraform:1.9.8` image. +- `npm run test:shepherd:live:preflight` builds and inspects the exact-tree live + Runtime boundary without contacting Ark. -The existing-ECS script deploys from the current source tree: +The bounded external Shepherd gate is deliberately separate: + +```bash +npm run test:shepherd:live +``` + +It sends repository-derived prompts and scoped source content to the configured Ark +endpoint and consumes real capacity. Run it only with explicit authorization. Never +attach raw prompts, model output, credentials, session identifiers, or private paths +to issues or reports. + +When publishing results, record the exact tested commit, environment, pass counts, +coverage, failures, and any evidence gaps. Do not present an earlier run as evidence +for a newer tree. + +## Optional cloud deployment + +Local Docker, Colima, or Podman is the recommended judging path. ECS is optional +and does not increase the Track 1 score by itself. + +### Existing Linux ECS + +Use a dedicated Ubuntu 22.04/24.04, Debian 12, or veLinux 2 instance with at least +2 vCPU, 4 GiB RAM, a 40 GiB disk, Docker Engine 24+, and the Compose plugin. The +existing-ECS script deploys the current source tree: ```bash cp .env.example .env.production openssl rand -hex 32 -# Set PUBLIC_PORT, ARK_API_KEY, ARK_MODEL, and the generated APP_AUTH_TOKEN. +# Set PUBLIC_BIND_ADDR=0.0.0.0, PUBLIC_PORT, ARK_API_KEY, ARK_MODEL, +# and the generated APP_AUTH_TOKEN in .env.production. chmod 600 .env.production ./scripts/deploy-existing-ecs.sh .env.production ``` -Verify the result without printing credentials: +Verify without printing credentials: ```bash read -rsp 'APP_AUTH_TOKEN: ' APP_AUTH_TOKEN; export APP_AUTH_TOKEN; printf '\n' @@ -263,21 +398,17 @@ curl -H "Authorization: Bearer $APP_AUTH_TOKEN" http://127.0.0.1/api/system docker compose --env-file .env.production ps ``` -This profile is meant to be reachable, so set `PUBLIC_BIND_ADDR=0.0.0.0` in -`.env.production` alongside `APP_AUTH_TOKEN`; the deploy script refuses to start -without a valid token. Deploy updates with `git pull --ff-only` and rerun the same -script. Allow inbound HTTP only from the event network, SSH only from administrator addresses, and -outbound HTTPS only where required. Add HTTPS before sending the shared bearer token -over an untrusted network. `docker compose --env-file .env.production down` stops -the service without deleting Agent data. +Allow inbound HTTP only from the event network, SSH only from administrator +addresses, and outbound HTTPS only where required. Add HTTPS before sending the +shared bearer token over an untrusted network. Rerun the same deploy script after +`git pull --ff-only`; `docker compose --env-file .env.production down` stops the +service without deleting Agent data. ### Terraform The Terraform path requires Terraform 1.6+, a Volcengine account with scoped resource-creation permission, an existing ECS SSH key pair, a compatible image and -instance type in the selected region, and a public repository URL. - -The Terraform path provisions VPC, subnet, security group, ECS, and EIP: +instance type, and a public repository URL. ```bash cp .env.example .env.production @@ -291,80 +422,36 @@ export VOLCENGINE_SSH_USER=ubuntu ./scripts/deploy-volcengine.sh ``` -Set Ark values only in `.env.production` and region/zone/image/instance/key/CIDR/ -repository values in `terraform.tfvars`. Provide Volcengine account credentials only -through the current shell; never give account AK/SK values to an Agent Runtime. -Terraform provisions only infrastructure and public repository metadata. The deploy -script waits for `cloud-init status --wait`, copies the ignored `.env.production` -over SSH, installs it as root-owned mode `0600`, and then starts the application. -Runtime credentials therefore do not enter Terraform variables, plans, state, +Put Ark/runtime values only in `.env.production` and infrastructure values in +`terraform.tfvars`. Volcengine account credentials stay in the current shell and +must never be given to an Agent Runtime. The deploy script waits for cloud-init, +copies the ignored environment over SSH as root-owned mode `0600`, and starts the +application; runtime credentials do not enter Terraform variables, plans, state, cloud-init, or instance user data. Use a dedicated test instance. Never commit `.env.production`, Terraform variables or state, Ark keys, SSH keys, or Volcengine account credentials. Protect Terraform state because it still contains infrastructure identifiers and network metadata. `terraform -chdir=deploy/volcengine destroy` removes the ECS instance, system disk, -and Agent workspaces—back up required code and data first. - -## Configuration - -| Variable | Default | Purpose | -| --- | --- | --- | -| `ARK_API_KEY` | Required | Ark model API key. | -| `ARK_MODEL` | Required | Responses-capable endpoint or model ID. | -| `ARK_BASE_URL` | Beijing v3 endpoint | Ark OpenAI-compatible API URL. | -| `APP_AUTH_TOKEN` | Empty | Optional shared demo token. Empty requires no credential; use 24+ random characters remotely. | -| `RUNTIME_PROVIDER` | `local-process` | `container` for disposable local Runtime containers. | -| `CODEX_SANDBOX_MODE` | `workspace-write` | Codex inner sandbox mode. | -| `CODEX_TIMEOUT_MS` | `600000` | Maximum duration of one turn. | -| `LOCAL_POC_DATA_ROOT` | Platform-specific | Local metadata, workspace, and session directory. | - -See [.env.example](.env.example) for all Runtime and resource-limit options. - -## How it works - -```mermaid -flowchart LR - UI["React Web UI"] --> API["Fastify control plane"] - API --> Store["JSON metadata and Agent workspaces"] - API --> Runtime{"Runtime provider"} - Runtime -->|Local POC| Container["Disposable Docker / Colima / Podman container"] - Runtime -->|ECS profile| Codex["Codex CLI in application container"] - Container --> Ark["Volcengine Ark Responses API"] - Codex --> Ark -``` - -The first turn uses `codex exec`; later turns resume the stored Codex thread. -Deleting an Agent archives its workspace under `workspaces/.deleted/`. - -See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for component and extension -boundaries. - -## Validation - -```bash -npm run check -npm run test:coverage -npm run test:terraform -docker compose config -``` - -`npm run test:terraform` uses local Terraform when available and otherwise the -pinned `hashicorp/terraform:1.9.8` image. It formats, initializes, and validates a -disposable copy so generated provider files never dirty the checkout. - -## Documentation - -- [Current task ledger and completion cut](docs/TASKS.md) -- [Shepherd product requirements](docs/PRD.md) -- [Shepherd design and trust boundaries](docs/SHEPHERD.md) -- [Architecture](docs/ARCHITECTURE.md) -- [Release test report](docs/SHEPHERD_TEST_REPORT.md) -- [Local POC](docs/LOCAL_POC.md) -- [Track 1 TechJam brief](docs/TECHJAM.md) -- [Hackathon extension guide](docs/HACKATHON_EXTENSION_GUIDE.md) -- [Security policy](SECURITY.md) -- [Contributing](CONTRIBUTING.md) +and Agent workspaces. + +## Hackathon artifacts + +- [Interface reference](docs/UI.jpeg) +- [Rendered architecture diagram](docs/assets/Shepherd_TechJam_Track1_Architecture.png) +- [Latest editable architecture diagram](docs/assets/Shepherd_TechJam_Track1_Architecture.drawio) +- [Agent Playground screenshot](docs/assets/playground.jpg) +- [Create Agent screenshot](docs/assets/create-agent.jpg) +- [Hackathon v2 skeleton](docs/hackathon-v2-skeleton.xml) +- [Section 1](docs/hackathon-v2-section-1.xml) +- [Section 2](docs/hackathon-v2-section-2.xml) +- [Section 3](docs/hackathon-v2-section-3.xml) +- [Section 4](docs/hackathon-v2-section-4.xml) +- [Section 5](docs/hackathon-v2-section-5.xml) +- [Section 6](docs/hackathon-v2-section-6.xml) +- [Section 7](docs/hackathon-v2-section-7.xml) +- [Section 8](docs/hackathon-v2-section-8.xml) +- [Section 9](docs/hackathon-v2-section-9.xml) ## License diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 88e196a..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,45 +0,0 @@ -# Security policy - -Volc Agent Launchpad is a hackathon proof of concept. Only the latest revision -on the default branch is supported. - -Shepherd adds stricter authority, Git Plane, verifier, redaction, and promotion -boundaries for its managed demo project. These do not turn the broader Starter -Kit into a production identity or tenant-isolation system. Current security -evidence and pending review are tracked in [docs/TASKS.md](docs/TASKS.md), with -material interpretations in [docs/DEVIATIONS.md](docs/DEVIATIONS.md). - -## Report a vulnerability - -Send the repository owner or event organizer the affected revision, -reproduction steps, impact, and suggested mitigation. Do not publish -credentials, personal data, or exploit details in an issue. - -## Known limitations - -- Shared demo token; no user identity, authorization, RBAC, or tenant isolation -- No CSRF protection -- No per-Agent container boundary in ECS mode -- Ordinary local containers, not hardened multi-tenant sandboxes -- Broad outbound network access -- Prompt-triggered command and file execution -- Control plane holds the container engine socket in `container-volume` mode, which is equivalent to control of the engine; see `docs/DEVIATIONS.md` -- Ark key available to the server and active Runtime container -- Ark key stored in Terraform POC state - -## Safe use - -- Use a dedicated development machine or disposable ECS instance. -- Use a scoped, revocable Ark key. -- `APP_AUTH_TOKEN` is optional and empty by default, so a server started without - one serves every API route to anyone who can reach the port. That is acceptable - on loopback. Set a unique token before exposing the server beyond the local - machine, including any ECS deployment. -- Keep local use on loopback and restrict ECS Web and SSH CIDRs. -- Add HTTPS before sending a shared token over an untrusted network. -- Never mount production data or provide Volcengine account AK/SK to Agents. -- Stop the POC, destroy test resources, and revoke keys after the event. - -Codex uses `workspace-write` when Landlock is available. On unsupported kernels, -startup warns and relies on the outer Docker or rootless Podman boundary. This -fallback is not tenant isolation. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md deleted file mode 100644 index ddb7b24..0000000 --- a/docs/ARCHITECTURE.md +++ /dev/null @@ -1,592 +0,0 @@ -# Agent Middleware Architecture - -This document describes the as-built architecture on protected `main` at -`c0802e8`. It covers both the original Agent Launchpad path and the Shepherd -multi-Agent middleware layered beside it. The implementation is authoritative; -[`PRD.md`](PRD.md) defines the intended product, [`SHEPHERD.md`](SHEPHERD.md) -records the as-built trust model, and [`TASKS.md`](TASKS.md) records current -completion and evidence status. - -Shepherd is a single-node transactional control plane for coding Agents. It turns -an assignment into a durable Execution Contract, runs the Agent against an isolated -Git-backed Plane, independently verifies the resulting commit, detects incompatible -semantic claims, executes competing resolutions from the same integration commit, -and advances the protected branch only through an evidence-gated compare-and-swap. - -> **Contract → isolated execution → trusted import → authority validation → -> independent verification → semantic collision → speculative resolution → -> deterministic selection → final re-verification → protected promotion** - -## Full end-to-end architecture - -Solid edges are control/data flow. Dashed edges are polling, advisory analysis, or -recovery. Red nodes contain untrusted input or execution, green nodes make trusted -decisions, blue nodes are durable state or Git artifacts, and purple nodes are -external systems. - -```mermaid -flowchart TB - Human["Human operator"] - - subgraph Browser["Experience layer — browser, untrusted input"] - React["React 19 single-page application"] - AgentUI["Agents / Create / Edit / Playground"] - ShepherdUI["Contract stream / timeline / Plane tree"] - GroupUI["Project Group"] - SettingsUI["Settings / reset / human selection"] - Poller["1.1 s state, event, and group-message polling"] - Token["In-memory shared demo bearer token"] - React --> AgentUI - React --> ShepherdUI - React --> GroupUI - React --> SettingsUI - ShepherdUI --> Poller - GroupUI --> Poller - Token --> React - end - - subgraph HTTP["Fastify boundary — trusted validation and public projection"] - Auth["Bearer gate for /api except health and auth"] - Zod["Zod schemas: bounded IDs, bodies, cursors, settings"] - AgentAPI["Legacy Agent / message / Run / system routes"] - ShepherdAPI["Shepherd state / Mission / events / details / controls"] - PublicDTO["Redacted public DTOs: no prompts, host paths, raw logs, or session IDs"] - Errors["Typed status mapping and bounded generic 500"] - Static["Production React assets and SPA fallback"] - Auth --> Zod - Zod --> AgentAPI - Zod --> ShepherdAPI - AgentAPI --> PublicDTO - ShepherdAPI --> PublicDTO - Errors --> PublicDTO - end - - subgraph Legacy["Existing Agent control plane — AgentService"] - AgentCRUD["Agent CRUD, roles, authority presets, lifecycle"] - Playground["Message admission and one active Run per Agent"] - LegacyRecovery["Restart: active Runs → cancelled; busy Agents → ready"] - WorkspaceManager["Server-derived workspaces; no-follow files; archive on delete"] - RunnerFactory{"RUNTIME_PROVIDER"} - LocalRunner["CodexRunner: bounded local child process"] - ContainerRunner["ContainerCodexRunner: disposable local Runtime"] - Thread["Resumable legacy Codex thread per Agent"] - AgentCRUD --> WorkspaceManager - Playground --> WorkspaceManager - Playground --> RunnerFactory - RunnerFactory -->|"local-process"| LocalRunner - RunnerFactory -->|"container"| ContainerRunner - LocalRunner --> Thread - ContainerRunner --> Thread - end - - subgraph Kernel["Shepherd control plane — trusted orchestration"] - Intake["Fixed auth-demo intake and idempotent request binding"] - Reserve["Validate Agent role, readiness, authority; reserve Agent"] - Contracts["Persist Mission and two typed Execution Contracts"] - DAG["Validate DAG and select maximal safe runnable batch"] - StateMachine["Actor-gated Mission and Contract state machines"] - EventWriter["State transition plus bounded event in one mutation"] - Concurrency["Project lock, Agent occupancy, Plane-capacity bound"] - Cancel["Durable cancellation before exact Runtime cancellation"] - Intake --> Reserve --> Contracts --> DAG --> Concurrency - Contracts --> StateMachine --> EventWriter - Cancel --> StateMachine - end - - subgraph GitPlane["Git / Plane boundary — trusted, argv-only, sentinel-guarded"] - ProtectedRepo["Managed auth fixture repository\nprotected branch + expected HEAD"] - PlaneManager["PlaneManager derives all branches and paths"] - GitClient["GitClient: sanitized refs/paths; no shell/hooks/credentials; bounded I/O"] - ContractWT["Contract worktrees from Mission base SHA"] - Export["Authority-filtered Git-free execution export"] - Import["Bounded no-follow staging import; reject links, special files, metadata, and denied diff"] - Manifest["Strict result-manifest ingestion; validate claims/evidence; then remove"] - TrustedCommit["Rebuild trusted Contract commit from base; exclude control metadata"] - VerifySnapshot["Fresh Git-free read-only snapshot of exact commit"] - IntegrationWT["Integration Plane merges verified Contract commits"] - IntegrationSHA["Immutable integration commit"] - ResolutionWT["Two resolution worktrees from identical integration SHA"] - CandidateCommit["Trusted candidate commits; no manifest channel"] - PromotionCAS["Protected fast-forward CAS plus checked-out worktree synchronization"] - PlaneManager --> GitClient --> ProtectedRepo - PlaneManager --> ContractWT --> Export - Import -->|"Contract"| Manifest --> TrustedCommit - Import -->|"Resolution candidate; manifest forbidden"| CandidateCommit - TrustedCommit --> VerifySnapshot - TrustedCommit --> IntegrationWT --> IntegrationSHA --> ResolutionWT - PromotionCAS --> ProtectedRepo - end - - subgraph AgentExecution["Agent Runtime boundary — untrusted model output and files"] - Executor{"Resolved Shepherd execution mode"} - FixtureExecutor["DeterministicFixtureExecutor\nnetwork-free deterministic writes"] - Prompt["Bounded JSON prompt envelope\nidentity, objective, context, authority, artifacts, claims"] - PrivateHome["Fresh private CODEX_HOME per execution\nminimal config; deleted afterward"] - LiveExecutor["CodexShepherdExecutor\none-use execution and session identities"] - RuntimeContainer["Disposable non-root container\nread-only root, dropped caps, limits, bridge network"] - Codex["codex exec --ephemeral --json\nprompt on stdin; workspace-write sandbox"] - AgentFiles["Agent-authored project files and Contract result manifest"] - SessionHash["Require one fresh thread ID; persist only SHA-256 fingerprint"] - Executor -->|"deterministic"| FixtureExecutor --> AgentFiles - Executor -->|"live"| Prompt --> LiveExecutor --> PrivateHome --> RuntimeContainer --> Codex - Codex --> AgentFiles - Codex --> SessionHash - end - - subgraph Verification["Independent verification — trusted interpretation, untrusted code under test"] - Registry["TrustedCheckRegistry: profile ID → server-owned argv"] - Verifier["ContainerVerifier validates target, checks, path, limits, ownership"] - VerifyContainer["One disposable container per check\nno network/key/session; read-only mount/root; bounded resources"] - Evidence["Bounded redacted VerificationEvidence"] - Corroborate["Corroborate semantic transport from verifier output"] - Registry --> Verifier --> VerifyContainer --> Evidence --> Corroborate - end - - subgraph Semantics["Collision and speculative resolution — trusted policy"] - Claims["Normalized, evidence-backed exclusive claims"] - Advisory["Optional ArkModelReviewer\nstrict structured advisory output"] - Detect["Deterministic collision predicate"] - Collision["Durable auth.transport collision without Git conflict"] - Strategies["Generate exact left-value and right-value strategies"] - CandidateExec["Execute resolution Planes concurrently"] - CandidateVerify["Verify frontend, backend, project security, and exact target"] - Winner{"Deterministic winner policy"} - Auto["Exactly one mandatory-pass candidate selected"] - Attention["Both fail, tie, paused automation, or unsafe result → attention_required"] - HumanSelect["Human may select only an eligible verified candidate"] - FinalGate["Re-read selection; immutable head; actual-diff authority; fresh verification; expected protected HEAD"] - Claims --> Detect --> Collision --> Strategies --> CandidateExec --> CandidateVerify --> Winner - Advisory -.-> Detect - Winner -->|"one passes"| Auto --> FinalGate - Winner -->|"none / tie / paused"| Attention - Attention -->|"valid tie or confirmation"| HumanSelect --> FinalGate - end - - subgraph Persistence["Durable single-process state boundary"] - Store["JsonStore queue: clone, scrub, schema-validate, size-bound"] - DB["launchpad.json v2\nAgents, Runs, Missions, Contracts, Planes, claims, collisions, candidates, events, messages, settings"] - Atomic["Exclusive temp → fsync → atomic rename → directory fsync"] - Journal["Narrow Mission-verification persistence-intent journal"] - Cursor["Monotonic durable event cursor"] - Startup["Startup reconciliation: owned artifacts, Git state, in-flight lifecycle, post-CAS evidence"] - Store --> Atomic --> DB - Store --> Journal - Store --> Cursor - DB -.-> Startup - end - - subgraph External["External systems"] - Ark["Volcengine Ark Responses API"] - Engine["Docker / Colima / Podman"] - end - - Human --> React - Static --> React - React --> Auth - Poller -.-> Auth - PublicDTO --> React - AgentAPI --> AgentCRUD - AgentAPI --> Playground - ShepherdAPI --> Intake - ShepherdAPI --> Cancel - ShepherdAPI --> HumanSelect - AgentCRUD --> Store - Playground --> Store - LegacyRecovery --> Store - WorkspaceManager --> Store - LocalRunner --> Ark - ContainerRunner --> Engine - ContainerRunner --> Ark - EventWriter --> Store - Contracts --> Store - Concurrency --> PlaneManager - PlaneManager --> Store - Export --> Executor - AgentFiles --> Import - SessionHash --> Store - VerifySnapshot --> Verifier - Corroborate --> Claims - Corroborate --> StateMachine - StateMachine --> IntegrationWT - IntegrationSHA --> Advisory - Advisory -.-> Ark - Strategies --> ResolutionWT - ResolutionWT --> Export - CandidateCommit --> VerifySnapshot - Evidence --> CandidateVerify - FinalGate --> VerifySnapshot - Evidence -->|"fresh promotion evidence"| FinalGate - FinalGate --> PromotionCAS - Collision --> Store - CandidateVerify --> Store - Winner --> Store - FinalGate --> Store - RuntimeContainer --> Engine - VerifyContainer --> Engine - Codex --> Ark - Startup -.-> Store - Startup -.-> PlaneManager - Startup -.-> Engine - - classDef untrusted fill:#fff1f0,stroke:#b42318,color:#5f160f,stroke-width:2px - classDef trusted fill:#ecfdf3,stroke:#027a48,color:#054f31,stroke-width:2px - classDef durable fill:#eff8ff,stroke:#175cd3,color:#102a56,stroke-width:2px - classDef external fill:#f4f3ff,stroke:#6938ef,color:#2d1b69,stroke-width:2px - class Human,React,AgentUI,ShepherdUI,GroupUI,SettingsUI,Poller,Token,FixtureExecutor,Prompt,PrivateHome,LiveExecutor,RuntimeContainer,Codex,AgentFiles,VerifyContainer untrusted - class Auth,Zod,AgentAPI,ShepherdAPI,PublicDTO,Errors,AgentCRUD,Playground,LegacyRecovery,WorkspaceManager,RunnerFactory,LocalRunner,ContainerRunner,Intake,Reserve,Contracts,DAG,StateMachine,EventWriter,Concurrency,Cancel,PlaneManager,GitClient,Import,Manifest,TrustedCommit,Registry,Verifier,Corroborate,Claims,Advisory,Detect,Collision,Strategies,CandidateVerify,Winner,Auto,Attention,HumanSelect,FinalGate,PromotionCAS trusted - class ProtectedRepo,ContractWT,Export,VerifySnapshot,IntegrationWT,IntegrationSHA,ResolutionWT,CandidateCommit,Thread,SessionHash,Evidence,Store,DB,Atomic,Journal,Cursor,Startup durable - class Ark,Engine external -``` - -## Boundaries and responsibilities - -Shepherd is not implemented by expanding `AgentService`. The process composes two -control planes over one durable store: - -| Boundary | Responsibility | It must not do | -| --- | --- | --- | -| React experience | Render Agents, Missions, Contracts, events, evidence, timeline, Plane lineage, Project Group, and settings; submit typed controls; poll durable state. | Choose winners, validate authority, interpret verification, or submit host paths/commands. | -| Fastify | Authenticate shared-demo API calls, validate request shapes, map typed errors, and create safe public DTOs. | Return repository/worktree/workspace paths, Run prompts, raw verifier output, or session IDs. | -| `AgentService` | Preserve Agent CRUD, lifecycle, workspaces, Playground, resumable Runs, and one-active-Run admission. | Own Missions, Contracts, Planes, collisions, or promotion. | -| `ShepherdService` | Own Mission lifecycle and orchestrate scheduling, Planes, execution, import, verification, collision, candidates, selection, promotion, cancellation, reset, events, and recovery. | Trust an Agent report, execute browser commands, or mutate protected Git directly. | -| `PlaneManager` / `GitClient` | Derive managed paths/branches, create worktrees, export/import Git-free trees, inspect actual diffs, build commits, merge, and perform the only protected CAS. | Give an Agent a worktree, invoke a shell, inherit Git credentials/hooks, or accept unvalidated paths/refs. | -| Agent executor | Produce files for exactly one execution identity in an exported workspace. | Certify acceptance, select a candidate, access protected Git, or reuse a Shepherd session. | -| Independent verifier | Run registry-owned checks against a read-only exact-commit snapshot and return bounded evidence. | Receive Ark credentials, Codex state, network, writable project storage, or Agent-selected commands. | -| Deterministic policy | Corroborate claims, detect collisions, assess mandatory evidence, handle ties, and gate promotion. | Treat advisory model output as authority or prefer a strategy by name. | -| `JsonStore` | Serialize and atomically publish a validated/redacted database and allocate events with state changes. | Support multiple writers or distributed coordination. | - -## Process composition and startup - -`apps/server/src/index.ts` is the composition root: - -1. `loadConfig()` validates environment configuration. A non-loopback bind requires - a strong shared bearer token. `auto` Shepherd mode resolves to `live` only with a - container Runtime and usable Ark Agent configuration; otherwise it is - `deterministic`. -2. The process writes shared legacy Codex configuration, resolves a restart-stable - installation owner from a persisted nonce, and creates one `JsonStore`, - `WorkspaceManager`, and `AgentRunner`. -3. `AgentService.initialize()` initializes storage/workspaces, validates persisted - workspace identity, cancels interrupted legacy Runs, and releases busy Agents. -4. The process registers trusted frontend, backend, and project-security check - profiles, then chooses `CodexShepherdExecutor` or - `DeterministicFixtureExecutor`. A usable `SHEPHERD_MODEL` also composes the - advisory `ArkModelReviewer`. -5. `ShepherdService.initialize()` reconciles a persistence intent, validates or - establishes sentinel-guarded roots, cleans only installation-owned Runtime and - verifier artifacts, reconciles durable Git/lifecycle state, and runs the - credential-free live Runtime preflight. -6. Fastify registers the API and serves the compiled React app in production. - -Startup fails closed on ambiguous sentinels, unexpected managed-root contents, -unsafe workspace identities, an untrusted protected checkout, incomplete owned -container cleanup, or a failed live preflight. - -## Flow A: legacy Agent Playground - -1. The browser creates or updates an Agent with a role and normalized authority - preset. `WorkspaceManager` derives its directory from the server-generated ID - and manages instructions/files with no-follow operations. -2. A Playground message creates a durable user message and queued `AgentRun` in the - same mutation that atomically sets the Agent `busy`. Concurrent admission permits - only one Run per Agent. -3. `RunnerFactory` selects bounded host-process Codex or a disposable local Runtime - container mounting the Agent workspace and shared legacy `CODEX_HOME`. -4. A successful first turn persists the Codex thread ID. Follow-ups use - `codex exec resume`, preserving legacy conversation continuity. -5. Output, usage, Run state, assistant message, and Agent state persist. Public - responses omit Run prompts and workspace paths. -6. Stop/cancel terminates the exact process/container. Restart converts active Runs - to `cancelled`; no interrupted Run is reported complete. - -Legacy authority metadata constrains future Shepherd assignment. It is not enforced -as a filesystem sandbox for ordinary Playground turns. - -## Flow B: Shepherd Mission - -### 1. Intake and Contract creation - -Protected main accepts one constrained plan: the authentication demo. The browser -may supply bounded intent, two different ready Agents with Frontend/Backend roles, -and two different typed transports. It cannot supply repository paths, Plane paths, -Git refs, verification commands, or arbitrary plan structure. - -Admission binds each client message ID to a fingerprint of intent and assignments, -enforces one active mutating Mission, revalidates the protected repository and -expected HEAD, intersects Contract authority with Agent authority, reserves both -Agents, and atomically persists the Mission, two Contracts, initial events, and -group message. Each Contract durably records its objective, Agent, dependencies, -semantic scope and canonical claim key, authority, expected artifact, trusted -acceptance check, manifest location, lifecycle, failure, and verification evidence. - -### 2. DAG scheduling - -The scheduler validates general acyclic Contract graphs and rejects unknown, -duplicate, self, cyclic, cross-Mission, or inconsistent dependency data. A Contract -runs only when the Mission is active, required dependencies are `verified`, the -Agent is free, the mutation lock permits it, and Plane capacity remains. It returns -the maximal stable-ID-ordered safe batch and typed block reasons. - -The current Mission creates two independent Contracts with no edges, so both run in -one wave. The scheduler is general, but protected-main orchestration does not yet -create arbitrary multi-wave plans. - -### 3. Contract Plane and Agent execution - -`PlaneManager` creates each Contract branch/worktree from the immutable Mission base. -All identities, branches, and paths are server-derived beneath a sentinel-guarded -root. The Agent never receives the worktree. Shepherd instead exports a private, -Git-free tree containing only readable-authority files and rejects symlinks, special -files, protected metadata, excessive trees/files, concurrent identity changes, and -root escapes. - -Shepherd builds a bounded secret-scanned JSON prompt envelope with Agent identity, -objective, context and verified dependency outputs, authority, expected artifacts, -canonical claims/scopes, and result-manifest schema. In deterministic mode, fixture -code writes known outputs. In live mode, every Contract/candidate gets a never-reused -execution ID, fresh private `CODEX_HOME`, and fresh `codex exec --ephemeral` turn; -the prompt travels on stdin, not argv. - -The live container is non-root, capability-free, `no-new-privileges`, resource -bounded, and read-only except for tmpfs and mounted workspace/private home. Bridge -networking lets the Codex control process call Ark. Startup preflight proves -model-authored shell code inside the configured `workspace-write` sandbox can write -the workspace, cannot write the private home, and cannot listen/connect via TCP. -Exactly one fresh thread ID is required; reuse is rejected, the raw value is -discarded, and only a SHA-256 fingerprint persists privately. - -### 4. Trusted import and authority - -After execution stops, the complete Git-free tree is copied through a detached -staging worktree at the source commit using bounded no-follow regular-file -operations. Shepherd derives the actual staging diff and enforces normalized write -and forbidden patterns. Forbidden and always-protected paths override grants. Only -after validation does staging replace the trusted Plane tree; the diff is then -re-derived and compared. A partially touched Plane is restored on failure. - -`.shepherd/result.json` is the sole Contract import exception. It is non-integrable -control data, never product code. Resolution candidates have no manifest exception. - -### 5. Manifest and independent verification - -Manifest ingestion requires one bounded regular file with the exact schema and -Contract ID, required artifacts, canonical declared claim keys/scopes, normalized -values, and valid project-contained evidence relevant to actual changes. Agent test -outcomes remain informational. The manifest is removed before `commitPlane()` -rebuilds one trusted commit from the immutable base and approved integrable paths, -thereby stripping Agent commits and control metadata. - -Verification runs on a fresh Git-free read-only snapshot of the exact commit. Each -acceptance check resolves to server-owned argv in `TrustedCheckRegistry` and gets a -disposable container with no network, Ark key, app token, Codex state, Docker socket, -or unrelated host environment; the root and project mount are read-only and CPU, -memory, PID, time, output, and tmpfs are bounded. - -Only the independent-verifier actor can transition `verifying → verified`, and every -mandatory check must have coherent passing evidence. For the auth fixture, trusted -code also derives the observed transport from verifier output and requires it to -corroborate the Agent claim. - -### 6. Integration and collision - -An integration Plane from the Mission base merges both trusted Contract commits with -argv-only Git. Textual conflicts are recorded and safely aborted. In the hero path, -different files merge cleanly and the resulting commit becomes the immutable -resolution base. - -An optional model reviewer receives only bounded trusted objectives, ingested -summaries, corroborated claims, changed files, and diff summaries. Strict structured -completion or explicit degradation is recorded, but reviewer output cannot create -the authoritative collision, verify work, choose, or promote. - -The deterministic collision predicate requires different verified Contracts in one -Mission, correctly attached claims, equal normalized key/scope, `exclusive` modes, -different normalized values, valid evidence, and no dependency supersession. It -therefore detects `bearer-jwt` versus `http-only-session-cookie` even though Git had -no conflict. - -### 7. Speculative resolution and winner - -Shepherd creates two resolution Planes—make the left value true or make the right -value true—from the same integration SHA. Each has independent execution/session -identity and bounded authority across both source scopes. Candidates run concurrently -and are verified against frontend, backend, and project-security profiles. Verifier -output must corroborate the exact persisted target, preventing target substitution. - -Winner policy accepts exactly two candidates: - -- exactly one passes mandatory verification → select it; -- neither passes → select none and require attention; -- both pass → apply only predeclared objective tie-breakers; -- still tied → require human selection between verified candidates. - -A transient Runtime/timeout/verification-infrastructure failure may retry once in a -fresh Plane from the same integration commit; the original attempt remains durable. -Disabling automatic resolution still executes and verifies both futures, then pauses -for manual confirmation of an eligible candidate. - -### 8. Final promotion - -`PromotionGate` rechecks candidate/Plane/persisted-selection identity, immutable -candidate HEAD, absence of unfinalized product changes, actual-diff authority, fresh -independent verification, selection after verification, and expected protected HEAD. -It then durably persists passing promotion evidence and `promoting`, proves -fast-forward ancestry, and performs atomic `update-ref ` plus -checked-out index/worktree synchronization. - -Synchronization failure triggers ref/worktree rollback attempts with distinct -evidence. Any mismatch, denial, failed verification, moved HEAD, dirty checkout, -non-fast-forward, persistence failure, or ambiguous rollback stops non-green. On -success, one mutation records promotion evidence, resolved collision, new protected -HEAD, events/group summaries, and Mission completion. The losing Plane remains -inspectable. - -## Persistence, cancellation, and recovery - -The version-2 JSON database preserves legacy Agent/message/Run collections and adds -Projects, Missions, Contracts, Planes, claims, collisions, candidates, events, -Project Group messages, settings, and the next event cursor. Version-1 legacy values -migrate without alteration. - -`JsonStore` is one-process-per-data-root: mutations serialize through one queue, -operate on scrubbed clones, remove configured/common credentials from all strings, -validate the complete database and 64 MiB limit, then publish through an exclusive -temporary file, file sync, atomic rename, and directory sync. Memory advances only -after publication. State transitions and events share a mutation; failed persistence -does not consume a cursor. - -A narrow digest-backed persistence-intent journal protects the transition after both -source Contracts verify and before integration. Restart either recognizes the -committed rename or records explicit `persistence_error` attention evidence. - -Cancellation is durable-first: one mutation sets the Mission `cancelled`, terminalizes -eligible Contracts, interrupts candidates/Planes, releases Agents/project, and emits -events. Only then are exact executor/verifier identities cancelled. Cancellation is -rejected after the durable pre-CAS marker. - -Startup removes only exactly owner-labelled containers and sentinel-owned ephemeral -artifacts, re-resolves project identity, and checks protected ref, checked-out branch, -HEAD, index, cleanliness, registered worktrees/branches, and persisted commits. It -classifies unchanged state, a narrowly corroborated post-CAS winner, external head -movement, or worktree mismatch. All in-flight entities become explicit interrupted -or `attention_required` evidence; artifact presence alone never means completed. - -## HTTP and browser projection - -All `/api/**` routes except health/auth use the optional shared bearer boundary. It -is a demo token, not identity or RBAC. The API exposes legacy Agent controls and -Shepherd state, Mission/events/details, Project Group, cancellation, human selection, -settings, and guarded reset. Strict schemas bound inputs; no route accepts host paths, -Git refs, arbitrary plans, verifier commands, or shell input. - -Public projection removes project repository paths, Plane worktree paths, execution -identities, raw session fingerprints, manifest content, verifier stdout/stderr/error, -legacy workspace paths, and Run prompts. It retains logical state, changed-file -lists, short Git evidence, check status/duration, and a boolean that a Runtime session -was established. - -The React app uses a small History API router: - -| Route | Role | -| --- | --- | -| `/shepherd` | Mission submission and Agent/transport assignment; durable events, contract evidence, actual-time timeline, collisions, candidates, attention controls, and Plane lineage/detail. | -| `/project-group` | Durable human/Shepherd/Agent messages and explicit `@Agent` routing. | -| `/agents`, `/agents/new`, `/agents/:id`, `/agents/:id/edit` | Agent list, role/authority configuration, lifecycle, current Contract context, and legacy Playground. | -| `/settings` | Persisted timeouts, concurrency, auto-resolution/model-review preferences, immutable security controls, and guarded reset. | - -`useShepherdPolling()` concurrently fetches state and events after the last cursor -every 1.1 seconds, deduplicates events, retains the latest 500, and preserves the last -good snapshot while reconnecting. Project Group polls independently. The UI never -makes trusted decisions: timeline bars derive from timestamps, Plane nodes from -durable lineage, and controls wait for server state. - -## Trust model and invariants - -Untrusted inputs include browser/human content, model output, Agent files/manifests, -claim text/evidence before ingestion, candidate code, code under verification, and -advisory review output. Trusted code owns schemas, derived identities/paths/refs, -authority intersection and actual-diff checks, lifecycle actors, manifest ingestion, -check profiles and evidence interpretation, collision/winner policy, promotion, -redaction, persistence, and recovery. - -Core invariants: - -1. No transition exists from `agent_completed` directly to `verified`. -2. Only independent-verifier evidence matching all mandatory checks can certify a - Contract. -3. Agents never receive protected Git, a linked Plane worktree, verification storage, - or browser-selected host paths. -4. Contract authority is a subset of Agent authority; forbidden/protected paths win. -5. The result manifest exists only as a Contract ingestion exception and never enters - a trusted commit or promotion. -6. Every live Shepherd turn uses fresh execution, private-home, container, and session - identities; only a session fingerprint persists. -7. Verification is credential-free, session-free, no-network, and read-only against - an exact immutable commit. -8. Advisory model output cannot affect deterministic detection, verification, - selection, or promotion. -9. Winner selection comes from coherent persisted evidence, never strategy name or - Agent self-report. -10. Protected state advances only through expected-head fast-forward CAS after durable - passing promotion evidence. -11. Unsafe or ambiguous outcomes stop non-green with retained evidence. -12. One process owns one data root; distributed/multi-writer operation is unsupported. - -## Deployment profiles - -| Profile | Legacy Agent Runtime | Shepherd execution | Independent verification | -| --- | --- | --- | --- | -| Local PoC launcher | Disposable Docker/Colima/Podman container per turn | Deterministic or live disposable container; live preflight required | Disposable no-network container per check | -| Local development default | Host Codex child process | `auto` resolves deterministic because provider is not `container` | Requires reachable container engine/image when a Mission verifies | -| Docker Compose / ECS starter | Codex in the application container unless reconfigured | `auto` resolves deterministic; shipped profile lacks the nested local-container boundary required by live Shepherd | No parity claim without reachable engine and validated mounts | - -The supported Shepherd isolation profile is local Docker/Colima/Podman. Ordinary -containers are a PoC boundary, not hardened hostile multi-tenant isolation. - -## As-built limits - -This document does not imply the generalized PRD is complete: - -- Mission decomposition is the fixed two-Contract auth demo. The scheduler validates - general DAGs, but service orchestration does not create arbitrary multi-wave plans. -- Unmentioned Project Group messages persist as Shepherd-routed messages but do not - start general work. `@Agent` with the fixed preset targets an existing Contract in - an active auth-demo Mission; it does not create a free-form Contract. -- Trusted lifecycle/verified-manifest summaries exist; general Agent group chatter is - intentionally absent. -- The timeline uses actual persisted times but does not produce labeled estimates. -- `SHEPHERD_AUTO_RESOLUTION` and `SHEPHERD_MAX_PARALLEL_PLANES` are composed into - `ShepherdService` at startup. They seed a pristine store only while the persisted - value is still the factory default, so a later Settings update stays authoritative - across restarts. -- Completed/losing Planes are retained; the parsed delete setting does not activate - automatic cleanup. -- The model reviewer is connected when usable but remains advisory and can run in - deterministic Agent-execution mode. -- Promotion updates the managed fixture repository under `SHEPHERD_ROOT`, never this - application's source repository. -- Service, store, scheduler invocation, and project locking are single-node and - single-process. - -See [`TASKS.md`](TASKS.md) and [`DEVIATIONS.md`](DEVIATIONS.md) for the live evidence -ledger. Architectural presence does not imply every browser, live, stability, -security, performance, or rehearsal gate has passed. - -## Code map - -| Concern | Primary implementation | -| --- | --- | -| Composition/configuration | `apps/server/src/index.ts`, `config.ts`, `runner-factory.ts` | -| HTTP/public projection | `apps/server/src/app.ts` | -| Legacy Agents/Playground | `agent-service.ts`, `workspace.ts`, `codex-runner.ts`, `container-codex-runner.ts` | -| Domain/lifecycle | `shepherd/domain.ts`, `state-machine.ts`, `database-schema.ts` | -| Orchestration/scheduling | `shepherd/service.ts`, `scheduler.ts` | -| Authority/manifests/prompts | `shepherd/authority.ts`, `manifest.ts`, `prompt.ts` | -| Git/Planes | `shepherd/git-client.ts`, `plane-manager.ts`, `demo-project.ts` | -| Agent execution | `shepherd/executor.ts`, `codex-executor.ts` | -| Verification | `shepherd/verifier.ts`, `auth-fixture.ts` | -| Collision/review/resolution | `shepherd/collision.ts`, `model-reviewer.ts`, `resolution.ts` | -| Promotion | `shepherd/promotion-gate.ts` | -| Persistence/redaction/recovery | `store.ts`, `database.ts`, `database-schema.ts`, `shepherd/redaction.ts`, `shepherd/recovery.ts` | -| Browser/polling | `apps/web/src/App.tsx`, `Shell.tsx`, `api.ts`, `shepherd-hooks.ts`, `pages/` | -| Runtime/deployment | `Dockerfile*`, `docker-compose.yml`, `scripts/start-local-poc.sh`, `deploy/volcengine/` | diff --git a/docs/BUILD_LOG.md b/docs/BUILD_LOG.md deleted file mode 100644 index c9bb707..0000000 --- a/docs/BUILD_LOG.md +++ /dev/null @@ -1,5777 +0,0 @@ -# Shepherd Build Log - -This log records commands actually executed and evidence actually observed. Secrets, raw prompts, and unbounded process output are intentionally excluded. - -This is a chronological evidence record, not the current task/status authority. -Branch and phase statements remain true only for the commit named in their entry. -Use [`TASKS.md`](TASKS.md) for the current repository snapshot, defects, -pending checks, and workflow. - -## 2026-08-31 — STABILITY protected-main integration closeout - -Issue [#48](https://github.com/kyashp/shepherd/issues/48) implementation and -evidence [PR #93](https://github.com/kyashp/shepherd/pull/93) merged to protected -`main` as `b05a4aad10d0c4c0e9f7d54fed2cdd5c779c16b0`. Its parents are the -frozen integrated base `a2a464d6be697ab949b254944b81c355a9be5403` and final -evidence head `ec015b6414b56df297a83489004edae441243483`; `git diff` between -the merge tree and that second parent is empty. - -A fresh detached worktree whose HEAD and `origin/main` were both exact `b05a4aa` -ran one literal `npm run check` with no environment, worker, timeout, or retry -override. It exited 0: all four production/test-source typechecks passed; -launcher/deploy passed 12/12; Server passed 846 with three unchanged documented -opt-in skips in 140.70s; Web passed 20/20; and both production builds passed. No -warning, live/model request, product/UI mutation, or tracked-file change occurred. - -The merge-triggered protected-main workflow run -[`33353622211`](https://github.com/kyashp/shepherd/actions/runs/33353622211) -also completed successfully on exact `b05a4aa`; its `Node 22 / npm run check` -job ran for 3m40s. Together with the immutable five-run candidate campaign at -`10c95da`, this establishes both issue gates `C` and `I`. This is an integration -verification record, not a claim of a separate independent audit. - -## 2026-08-31 — STABILITY candidate passed five consecutive literal gates - -Issue [#48](https://github.com/kyashp/shepherd/issues/48), draft -[PR #93](https://github.com/kyashp/shepherd/pull/93). The immutable campaign -candidate was `10c95da098755c513a5908615313b030bd866391`, rebased directly on -integrated feature-freeze `origin/main@a2a464d6be697ab949b254944b81c355a9be5403` -after PR #94 merged. Local HEAD, remote branch, and `origin/main` were checked -before, between, and after the runs; all stayed exact and the worktree stayed -clean. No live/model request ran. - -The earlier `bd77952` sequence remains invalid: its first three checks passed, -then run 4 exposed the five-second Git-backed PERF-01 harness timeout. The count -was reset to zero before any correction. The completed candidate contains four -causal stability fixes: - -- fixture Git commands use an allowlisted child environment and prove nested - repository identity, so inherited outer `GIT_DIR` / `GIT_WORK_TREE` selectors - cannot redirect staging or commits; -- F-03 snapshot-removal tests join an exact post-cleanup service checkpoint and - retain the final `ENOENT` assertion instead of consuming OS file watchers; -- the unchanged production `allSettledBounded` primitive is exported from the - scheduler module and its overlap/cap/order contracts are tested directly, - avoiding a full Git-backed Mission inside a five-second timing assertion; -- the candidate-cleanup fixture performs the executor's public preflight before - concurrent candidates, so first-use sentinel adoption cannot replace the - cleanup failure that the row is intended to assert. - -### Formal candidate campaign - -Each row below is one separate, literal `npm run check` invocation. The terminal -retained the Server start and the next Web start as wall-clock markers, the exact -Server duration, and the final process exit; it did not print a whole-command -start timestamp, so none is invented here. All four workspace/test-source -typechecks passed on every run. The three Server skips are the unchanged documented -opt-in rows. Both production builds passed and no warning was observed. - -| Run | Result / exit | Server → Web start (SGT) | launcher / deploy | Server | Web | Types / builds | Warnings | candidate / base | -|---:|---|---|---:|---:|---:|---|---|---| -| 1 | PASS / 0 | 10:50:15 → 10:52:44 | 12/12 | 846 passed / 3 skipped; 149.16s | 20/20 | 4/4 / 2/2 | none | `10c95da` / `a2a464d` | -| 2 | PASS / 0 | 10:53:37 → 10:56:03 | 12/12 | 846 passed / 3 skipped; 145.77s | 20/20 | 4/4 / 2/2 | none | `10c95da` / `a2a464d` | -| 3 | PASS / 0 | 10:56:34 → 10:58:59 | 12/12 | 846 passed / 3 skipped; 144.00s | 20/20 | 4/4 / 2/2 | none | `10c95da` / `a2a464d` | -| 4 | PASS / 0 | 10:59:26 → 11:01:52 | 12/12 | 846 passed / 3 skipped; 145.19s | 20/20 | 4/4 / 2/2 | none | `10c95da` / `a2a464d` | -| 5 | PASS / 0 | 11:02:21 → 11:04:39 | 12/12 | 846 passed / 3 skipped; 137.87s | 20/20 | 4/4 / 2/2 | none | `10c95da` / `a2a464d` | - -The same exact candidate also passed both required hosted checks: `Required -checks` run `33351880563` in 2m51s and `Node 22 / npm run check` run -`33351880571` in 2m55s. No sleep, timeout/retry increase, hidden worker, skip, -suppression, or weakened assertion was introduced. This establishes candidate -gate `C`; the documentation-only evidence descendant, integrator review/merge, -and fresh protected-main gate remain required for `I`. The issue is not closed by -this candidate record. - -## 2026-08-31 — UI-GATE protected-main integration evidence - -PR #87 merged to protected `main` as -`cf4dd0fa5886979f2af823efa65fd028dbb03334`; its direct second parent is final -candidate `adbb7aa25ed464c3c7080bc6c9c29690ce20d18e`, and `git diff` between those -trees is empty. The source branch had already passed hosted runs `33329742705` -and `33329742709`. - -- An exact `cf4dd0fa` archive ran the real-server UI gate through Playwright - Chromium with one worker. All 12/12 tests passed in 35.6s across exact - `1280x800` and `1440x900` viewports. -- The integration run regenerated exactly 36 non-empty PNGs: 18 at 1280x800 and - 18 at 1440x900, with zero unexpected dimensions and 3,225,044 bytes total. - All 18 byte-changed captures were visually re-inspected; no clipping, - document overflow, obstruction, or theme regression was found. That exact-main - corpus now replaces the candidate corpus under `docs/ui-review/ui-gate/`. -- Protected-main push run `33329997913` completed successfully on exact - `cf4dd0fa`; its `Node 22 / npm run check` job installed locked dependencies and - passed the literal repository gate in 2m54s. -- No live/model request ran. The local Windows Node harness limitation remains - `spawn EFTYPE` with 15/19 passing and is not presented as a pass. The hosted - Linux gate covers the complete repository check. - -UI-GATE gates `C`, `B`, and `I` are passed. Independent usability gate `U` -remains pending, so issue #45 stays open and the row is not called audited. - -## 2026-08-31 — UI-GATE reviewable candidate and current-main refresh - -Issue #45 / draft PR #87 on `test/45-ui-gate`. Causal UI fixes are at -`bbc7c81`; the reviewed current-main candidate is merge `d41613b`, which includes -protected `origin/main` `0ed41dd`. No live/model request ran. - -- The real-server Playwright matrix covers all six PRD UI surfaces plus adjacent - authentication, Agents, Settings, and not-found states at `1280x800` and - `1440x900`. The explicit one-worker evidence run on `d41613b` passed 12/12 and - produced exactly 36 non-empty PNGs with the declared dimensions and a bounded - total of 3,229,473 bytes under `docs/ui-review/ui-gate/`. -- Preserved REDs measured muted-copy contrast at 4.15:1 and 3.87:1, found 5px of - long-Agent document Y overflow at 1280x800, and exposed no-op Settings Discard, - incomplete Settings tab keyboard/relationships, inaccessible full Plane IDs, - and Project Group mentions enabled before initialization without a non-color - unavailable cue. The smallest page/CSS corrections made each causal assertion - green without changing API, persistence, dependency, runtime, or security scope. -- Keyboard-modality assertions activate sidebar/recovery links, Contract filters, - and Plane nodes with Enter; Settings and drawer tabs use arrows/Home/End; - Escape closes the labelled non-modal drawer and restores opener focus. Named - internal panes own overflow, two 1,900-character unbroken group messages wrap, - and bounded DOM/API/log canary scans pass without echoing a matched value. -- Web tests passed 20/20. Strict Web production and test-source typechecks passed. - Web production build transformed 41 modules and Server production build passed. - Adjacent two-viewport browser journeys passed 8/8. `git diff --check` passed. -- The local Node harness is not green and is not reported as one: Windows - reproduced `spawn EFTYPE`, with 15/19 passing and the four process-spawn/server - cases failing. Hosted Node 22 run `33329417868` passed literal `npm run check` - in 2m54s on evidence commit `38ac907`; the post-current-main documentation and - evidence head still requires its own hosted result. -- All 36 screenshots were reviewed against `docs/UI.jpeg`. No High/Medium visual - defect remained. `AUDIT.md` records the compact 25px desktop mention-chip target - exception, 1280x800 Create-form scroll depth, focused drawer capture position, - no connected in-app browser session, and no manual screen-reader claim. - -Candidate browser gate `B` is passed. Exact-final-head `C`, independent `U`, and -protected-main `I` remain pending; this implementation-owner record is not an -independent audit. -## 2026-08-31 — SEC-REVIEW part 4 review run; five High findings fixed - -Branch `fix/89-absolute-form-auth-bypass` from `main` at `0ed41dd`, for issue #89. -No live or model call ran. - -**What kind of review this was.** Seven adversarial lenses were run over the whole -trust boundary, each with fresh context, each instructed to break the system rather -than confirm it, and each told that much of the security-relevant code was written by -a prior agent already found defective three times. Every High and Medium was then put -to a separate verifier whose default was to refute it. **19 findings were confirmed -and 0 were refuted.** These reviewers are not a different party from the author, and -this entry does not claim they are; issue #89's acceptance asks for review by someone -other than the author of the code under review, and whether this satisfies that is -the maintainer's call, not the author's. - -Five High findings are fixed here. Each is filed in `FIXES.md` with its reproduction. - -- **`SEC-02`** — the bearer hook was bypassed by an absolute-form request target. - `GET http://host/api/system` returned 200 unauthenticated on every route including - the destructive reset, reproduced over a raw socket against the real `createApp`. - The `SEC-01` correction decoded the raw target but still tested the raw string, so - it closed percent-encoded spellings and left this one open. The hook now decides - from the parsed, decoded pathname. **The first regression test written for this - used `app.inject`, which normalizes the target and cannot express the attack; it - reported a false pass.** The test goes over a real socket. -- **`SEC-03`** — the deploy guard was silently inert. Its CLI entry point was gated - on `import.meta.url === "file://" + process.argv[1]`, which is not a sound - comparison: a space, `#` or non-ASCII percent-encodes, and macOS reports filenames - in NFD against an NFC argument. From a directory named `My Deploy Repo #1 é` the - guard body never ran and the deploy proceeded with an empty token. Both sides are - now resolved through the filesystem. A first correction using `pathToFileURL` still - failed on NFD and was caught by the new spawning test. -- **`SEC-04`** — the prompt, and on the resume path a stored thread id, reached the - Codex CLI as unseparated positionals on the same argv as `--sandbox`, so a prompt - beginning with `-` parsed as an option. The repository already applies the `--` - discipline to every Git invocation; the legacy runner was the one path missing it. -- **`SEC-05`** — mandatory promotion re-verification ran against the live Plane - worktree rather than the commit being promoted, because the snapshot fast path - copied any worktree `git status` called clean, and that test plus every authority - query are ignore-blind. Ignore rules are agent-controlled, so files under a - committed `.gitignore` were invisible to every check yet present in the verified - tree. Two corrections, each sufficient alone and kept together: the snapshot always - materializes the exact commit, and the authority queries are ignore-aware. - Reverting both reproduces; reverting either alone does not. -- **`SEC-06`** — the carried `OPS-06` High. The base compose profile published on - every interface while the token defaults to empty and the quickstart says nothing - else is needed to start. The published address now defaults to loopback with an - explicit `PUBLIC_BIND_ADDR` opt-in, mirroring the state-volume profile which - already did this. An earlier decision on this row rejected pinning to loopback - because it would remove intended reachability; that was right about pinning and - wrong about the remedy, and the defaulted variable keeps the reachability as an - opt-in while making only the default safe. The existing deploy guard is left - unchanged rather than made conditional, so no existing control is relaxed. - -**Observed.** `npm run typecheck` passed; `app`, `config`, `codex-runner` and -`container-codex-runner` 88/88; the Git/Plane promotion integration suite 28/28; -`plane-manager`, `promotion-gate`, `failure-matrix` and `authority` 52/52; script -tests 7/7 plus launcher 5/5; web 20/20; both production builds passed. Every fix was -mutation-checked against the defect it closes. - -**Not fixed here, and still open on #89:** unbounded retention on durable -collections; CSRF on the tokenless default, materially reduced by `SEC-06` but not -eliminated; credentials in ECS instance user-data and Terraform state; and four Low -findings. Part 5 is therefore incomplete and the `SEC-REVIEW` row stays `PARTIAL`. - -## 2026-08-31 — `TST-26`: the recovery-process failures were a defect, not host speed - -Branch `fix/48-recovery-ipc-flush` from `main` at `e552959`, investigating the five -`recovery.process.test.ts` failures that this campaign had repeatedly recorded as a -host-speed timing condition. **That characterisation was wrong.** - -- **They reproduce in isolation on an idle machine**: 5/5 fail, 168.75s for five - tests, each `Timed out waiting for recovered` with empty stderr. Nothing else was - running. -- **They are not slow.** Raising the message timeout to 400s produced the same - timeout. A direct probe of the recover child showed it exits **code 0**, sends - **zero** IPC messages, and writes nothing to stderr or stdout. -- **Cause.** In `test-fixtures/recovery-process.ts` the recover branch called - `send({ type: "recovered", ... })` and then `process.exit(0)` on the next line. - `process.send` is asynchronous, so the child can terminate before the IPC frame is - flushed. The parent never receives the message; and because the exit code is 0, the - harness's exit handler — which only rejects on a non-zero code — does not fire - either. The test therefore waits out its entire timeout for a result that had been - computed correctly and simply never left the process. -- **Why it looked like host speed.** On a faster host, and in Linux CI, the flush - wins the race. The failure is real everywhere; only its probability varies. Two - earlier entries in this log attributed these five tests to machine slowness. That - attribution is superseded by this entry. -- **Correction.** Exit from the `process.send` flush callback. No timeout was raised, - no sleep added, no assertion weakened. -- **Defence in depth.** The harness now rejects when a child exits cleanly without - ever sending the awaited message. The diagnosis is then in the failure text rather - than in an anonymous timeout. -- **Observed.** With the fix, `recovery.process.test.ts` passes **5/5** and the file - drops from 168.75s to 52s. Reverting only the fixture, with the hardened harness in - place, fails 5/5 in 48s with `Fixture exited 0/null without sending recovered` — - both changes are causal, and the second turns a 168s silent timeout into a 48s - named cause. Strict typecheck passed. -- **Bearing on `STABILITY` (#48).** Its acceptance requires diagnosing and fixing any - flake causally rather than excusing it. Five of the seven failures this host - produces were this defect. The remaining two are `service.test.ts` cases and have - not been investigated here. - -## 2026-08-31 — SEC-REVIEW parts 4-5 moved to a successor issue - -Documentation only; no product code. Protected `main` at `c158480`. - -- `SEC-REVIEW` `#49` was closed three times with its scope unsatisfied: manually on - 2026-08-30 at 08:30 before the OPS-06 `S` review had run, reopened at 16:40, then - closed again at 17:16 by **PR #86, which left `#49` in its closing references while - its own body stated that parts 4 and 5 were not claimed**. That third closure was - the author's own error and was not noticed at merge. -- Rather than reopen a fourth time, the remaining scope moved to issue `#89`, whose - title and acceptance match what is actually left: the independent read-only review, - the fixes that depend on it, and an explicit decision on the carried `OPS-06` - compose exposure. `#49` is left closed with the history recorded on it. -- Pointers corrected: the `SEC-REVIEW` row, the `OPS-06` row's owner reference for - the carried High finding, and the hackathon-cut list all named `#49`. The closure - comment posted on `#47` named it too and was corrected in a follow-up comment. -- Nothing about any gate changed. `SEC-REVIEW` stays `PARTIAL` at 70% with parts 1-3 - evidenced, and `OPS-06` keeps its scoped 100 with the High finding carried. -- `#89` records the instruction that closed `#49` twice: do not put a closing keyword - for it in a PR body unless that PR completes every part. - -## 2026-08-31 — ST-01 and OPS-06 integration rerun, self-performed - -Protected `main` at `a62e29b` (merge of PR #86). Branch -`docs/44-47-integration-rerun`. No live or model call ran. - -- **This rerun was performed by the author of the implementations under test.** - `docs/TASKS.md` reserves `AUDITED` for independent end-to-end evidence and defines - the `I` gate as a rerun by the auditor. Neither row is marked `AUDITED` on the - strength of this entry, and an independent rerun is still owed for both. -- **Hosted exact-head gate.** Run `33324819058` on `a62e29b`, literal - `npm run check` on `ubuntu-latest` / Node 22: success. This is the primary - evidence, and it is platform-independent of the notes below. -- **Local gate on the same SHA.** `npm run typecheck` passed. Launcher and deploy - script tests 9/9. Web 20/20. Both production builds passed. The server suite run - serially reported **837 passed, 7 failed, 2 skipped** across 34 files. -- **On those 7 local failures.** A second serial run on the same SHA reproduced the - identical set — 837 passed, 7 failed, 2 skipped, same tests — so this is a stable - host condition rather than a varying draw. Enumerated: five in - `recovery.process.test.ts` (the four SIGKILL-checkpoint cases and the - update-ref/read-tree fail-closed case), and two in `service.test.ts` (the `PERF-01` - scheduled-interval case and the `cancels tracked attention-required Missions` - case). Every one is a timing failure — `Timed out waiting for recovered`, - `Test timed out in 5000ms`, and the recorded - `expected 'resolving' to be 'attention_required'` `vi.waitFor` flake. No assertion - failure of substance appears in either run. The same commit passes the full suite - on Linux in CI, and this host's documented inability to run the suite green — - recorded since the OPS-06 work, where pristine `main` itself failed 39 and the - branch 61, all timeouts — is the standing explanation. No local figure in this - entry is offered as a pass. -- **Targeted surfaces on the same head passed**: the ST-01, composition, - verifier-container, codex-executor, app and config suites together 149/149, plus - the 9/9 script tests. These are the rows' own surfaces and are unaffected by the - suite-wide timing condition. -- **A stale claim corrected.** The OPS-06 row still said the carried High finding had - "no open owner" because `SEC-REVIEW` was closed. `#49` was reopened on 2026-08-31, - so the row now names it as the owner. -- **Why the independent rerun still matters for OPS-06.** The `SEC-REVIEW` boundary - audit found `SEC-01`, an authentication bypass reachable by percent-encoding the - `/api/` prefix, on the same `APP_AUTH_TOKEN` boundary this row's `S` gate covers. - The author of that gate had worked beside the hook repeatedly without noticing it, - and the first correction offered for it silently widened an exemption. Both were - caught by someone else looking. - -## 2026-08-31 — SEC-REVIEW parts 1-3, and an authentication bypass found and fixed - -Branch `audit/49-sec-review-evidence` from `main` at `bd9b093`; hosted exact-head -gate on that head is run `33323137812`. Issue #49 reopened after being closed on -2026-08-30 with its row unsatisfied. Parts 1-3 of its acceptance are claimed here; -parts 4 and 5 are not. No live or model call ran. - -### `SEC-01` — the bearer hook was bypassable by percent-encoding the prefix - -- Reproduced against the real `createApp`, with `APP_AUTH_TOKEN` configured and no - `Authorization` header: `GET /api/system` returns 401 while `GET /%61pi/system` - returns **200** and executes the handler. -- Cause: the `onRequest` hook decided whether to authenticate from `request.url`, - the raw request target, while Fastify percent-decodes static path segments before - route matching. Any encoded spelling of `/api/` failed the hook's string test, so - the hook returned early and the router still resolved the request. -- Every route was affected, including destructive ones: the audit observed - `PATCH /%61pi/shepherd/settings`, `POST /%61pi/shepherd/demo/reset` and - `DELETE /%61pi/agents/` all returning 200 and executing their service calls. - The reset route removes Plane worktrees and restores the protected HEAD. -- Reachable remotely wherever the token is the only control, because - `docker-compose.yml` binds `0.0.0.0` and publishes its port with no address prefix. -- **Not introduced by any recent change, and not caught by the suite.** The existing - auth tests only ever exercised canonical spellings, so `app.test.ts`, - `authority.test.ts` and `manifest.test.ts` passed while the bypass was live. -- Corrected by deciding from the decoded target, treating an undecodable target as - protected rather than exempt. The `/api/health` and `/api/auth` exemptions stay - exact-match, so a query string on a public route still fails closed — an earlier - form of this fix stripped the query string and thereby widened those exemptions, - which is a behaviour change and was reverted. Both properties are asserted. -- Causal: reverting the hook to the raw-URL test fails the new test. `app.test.ts` - 21/21, `config.test.ts` included 55/55, web 20/20, strict typecheck clean. - -### Part 1 — canary scan: pass with two low observations - -- Exactly two configuration values are credentials, both assembled into one - `sensitiveValues` set and threaded to the store, verifier, service, prompt builder - and model reviewer, with the API layer reconstructing the same pair independently. -- No path was found by which either reaches the persisted state, a model prompt, a - 4xx or 5xx response body, the DOM, browser storage, a URL, the logger, or a tracked - file. The Ark key is never placed in argv — the runner passes the name only and - injects the value through the child environment — and never written into the - generated Codex configuration. The prompt builder fails the whole turn rather than - emit a prompt containing a secret. -- Mechanically confirmed here: no credential file is tracked, `.gitignore` covers - `.env` and `.env.production`, the only key-shaped literal in tracked source is a - deliberately planted canary in `redaction.test.ts`, and the web client holds the - token in a module variable and sends it only as an `Authorization` header — no - `localStorage`, `sessionStorage`, cookie or query parameter anywhere in the client. -- Observations, both low and neither exploitable with a normally shaped credential: - `/api/system` is the only response serializer with no redaction pass, and - `ARK_API_KEY` has no minimum length while the redaction sets apply a 4-character - floor. - -### Part 2 — five invariant-mutation evidence cases - -Each invariant was broken in production source and an existing test caught it. All -source was restored after each; `git status` clean. Baseline before mutating: 66/66. - -| Invariant | Mutation | Caught by | -|---|---|---| -| Bearer auth enforced on every `/api/` route | `app.ts` `if (!valid)` to `if (false)` | 2 failed, including *protects API routes with the configured shared token* | -| No promotion without passing final mandatory re-verification | `promotion-gate.ts` `if (!evidence.passed)` to `if (false)` | *FM-01 ... persists failed final re-verification evidence without promotion* | -| Protected branch advances only by expected-HEAD CAS | `git-client.ts` `before !== persistedHead` to `false` | 1 failed in `git-plane-promotion.integration` | -| Writes must fall inside declared writable authority | `authority.ts` `matchesAny(path, grants)` to `true` | 2 failed in `authority.test.ts` | -| Verification Plane stays inside the managed root | `verifier.ts` containment check to `if (false)` | 1 failed in `verifier.container.test.ts` | - -Two invariants were deliberately excluded and the reason recorded: the hook's -constant-time comparison has no mutation coverage, because replacing -`timingSafeEqual` with a plain comparison is behaviourally identical and no test can -distinguish it; and the promotion gate's own expected-HEAD check is not detectable in -isolation because the Git layer re-checks the same condition and the gate maps the -error to the same reason. The second is defence in depth working, which is why the -CAS is demonstrated at the Git layer instead. - -### Part 3 — boundary audit: FAIL on one sub-surface - -Route inventory carries no debug, introspection or diagnostic route; static serving -and the not-found handler are traversal-proof; every identifier reaching a filesystem -path, Git ref or container name is server-generated and revalidated; the Contract -authority model cannot be broadened by a manifest or a model-produced plan; and -promotion cannot proceed without mandatory independent re-verification of the exact -commit, behind a real `git update-ref `. The bypass sub-surface -failed, which is `SEC-01` above. Other evasion vectors were probed and hold: casing, -trailing slash, query string, dot segments, encoded separator, double slash, and -method. There is no websocket or SSE upgrade. - -### Not claimed - -Parts 4 and 5 are unclaimed. The independent read-only security review must not be -performed by the author of `config.ts`'s token floor, -`scripts/check-deploy-auth-token.mjs`, the deploy guard, the `OPS-06` `A`-gate tests, -or the `SEC-01` fix above — all of which sit inside this issue's audit surface. The -carried `OPS-06` High finding remains a posture decision for that reviewer and the -maintainer: `docker-compose.yml` binds `0.0.0.0` with an unprefixed port while -`README` documents two entry points a deploy-script guard cannot reach. - -## 2026-08-31 — OPS-06 and ST-01 integrated; the OPS-06 High finding is carried - -Protected `main` at `3087b69` (merge of PR #69). That head also carries PR #73 -merge `a8d2266` (ST-01) and PR #68 merge `6137f36` (OPS-06 `A` gate). No live or -model call ran. - -- **Hosted exact-head gate.** Run `33322423938` on `3087b69`, job - `Node 22 / npm run check` on `ubuntu-latest`: success. -- **Observed on the integrated head.** The startup-settings, composition, - verifier-container, config and app suites passed 76/76; the deploy-token and - launcher script tests passed 9/9. These are targeted and adjacent runs by the - implementer, not the auditor's `I` rerun, which is still required before either - row is called audited. -- **`OPS-06` reaches scoped 100 with `T,A,C,S,I`.** `A` is integrated at `6137f36` - and `S` at `3087b69`. Scoped 100 means every gate listed for that row passed; it - does not mean the trust boundary is closed. -- **The `S` review's High finding is carried, not closed.** The independent review - returned FAIL on the merged range because `e6a5878` removed the non-loopback - `APP_AUTH_TOKEN` requirement and the documented existing-ECS path then started an - unauthenticated Agent-execution API on every interface. `scripts/deploy-existing-ecs.sh` - now refuses that deploy, resolving the token through `docker compose config` so the - check and the container share one parser and one rule. But `docker-compose.yml` - still binds `0.0.0.0` and publishes its port with no address prefix, and `README` - documents two other entry points against it — `docker compose up --build` and - `docker compose --env-file .env.production up -d` — which the script guard cannot - reach. Pinning that file to loopback was rejected because the profile is meant to - be reachable behind a security group and the same file serves the local Docker - path. The remainder is `SEC-REVIEW` (`#49`) scope. **No row may be read as closing - it.** -- **`ST-01` is integrated at `a8d2266`,** with the behaviour change it carries - recorded in the entry for that work: `SHEPHERD_MAX_PARALLEL_PLANES=1` previously - booted because the parsed value was discarded and now fails at `loadConfig`, and a - host that never set the variable moves from a nominal 4 to the 2 it actually ran - with. -- **Process note.** The three branches were authored and, apart from PR #69, merged - by the same person. `AGENTS.md` assigns merges and the `I` rerun to the integrator - and auditor precisely so neither is self-certified; the `I` gate for both rows - remains open on that basis. - -## 2026-08-30 — ST-01 startup settings composed into the service - -Branch `fix/44-st-01-startup-settings`, PR #73, against `main` at `07f4202`. No -live or model call ran. - -- `SHEPHERD_AUTO_RESOLUTION` and `SHEPHERD_MAX_PARALLEL_PLANES` were parsed by - `loadConfig` and then discarded: `ShepherdServiceOptions` had no field for either - and the only production construction passed neither. The gap was invisible in E2E - because the harness sets values equal to the persisted defaults. -- Both options are now declared, passed from resolved configuration, and applied by - the pristine-store seeding block. Seeding applies only while the persisted value - is still the factory default, so an operator change away from that default - survives restart. **Stated limit, now asserted by a test rather than only - commented:** an operator who sets the value back TO the factory default is - indistinguishable from one who never chose it, and startup configuration seeds - over that choice on the next restart while the store is still pristine. Removing - the limit needs a persisted "changed by operator" marker, which is a schema change - beyond this correction. -- **Stated behaviour change.** `SHEPHERD_MAX_PARALLEL_PLANES` moves from - `min(1).default(4)` to `min(2).default(2)`. A host that sets `1` previously booted - because the value was discarded; it now fails at `loadConfig`. That is deliberate: - `database-schema.ts`, `updateSettings` and the API all require at least 2, so once - composition works a `1` would fail on its first seed write, and a parse-time error - is the honest place for it. A host that never set the variable moves from a - nominal 4 to 2, which is the value it actually ran with before, since the parsed - number never reached the service. `.env.example` shipped `4` and is aligned to `2` - so the documented template matches the schema default. -- Eight causal tests in `apps/server/src/shepherd/startup-settings.test.ts`. Each - verified by mutating the guard it covers: dropping both options from `index.ts`, - disabling the seeding branch, removing the still-at-default guard so an operator - value is clobbered, and restoring the `min(1)`/`default(4)` schema all turn their - tests red. -- An earlier hosted run failed on this branch with `ENOENT` from `mkdtemp`: the test - allocated case roots under `.tmp/startup-settings` without creating it, and `.tmp` - is gitignored, so a clean checkout had no such directory. It passed locally only - because that directory had been created by hand. Corrected in the test; production - code was unaffected and the same run passed 809 other tests. -- Local full-suite figures from this host are not recorded as evidence: the run - spanned a branch switch and observed a mixed tree. The hosted exact-head gate is - the evidence for this branch. - -## 2026-08-30 — issue #43 integrated verification - -PR #75 merged to protected `main` as -`fbc937fed21ad4441e24ab301f591fe5aa03a025`; issue #43 closed and GitHub -removed the remote feature branch. The required integrated verification ran in -the clean issue worktree detached at that exact SHA before the docs-only -closeout branch was created. - -- `git diff` found no tree difference between reviewed candidate `66e0c0e` and - merge `fbc937f`, so the independent security/UI audit and re-review apply to - the integrated bytes with no remaining Critical, Important or Minor finding. -- Fresh literal `npm run check` passed: launcher 3/3, Server 808 passed plus - three explicit skips, Web 20/20, all production/test-source typechecks and - both builds. The PR's `Required checks` and `Node 22 / npm run check` hosted - jobs also completed successfully before merge. -- Fresh integrated Chromium passed the real-service unauthorized-diff journey - 2/2 at `1280x800` and `1440x900`, including durable reload, typed visible - denial, unchanged stored and actual protected heads, zero Candidates, - integration Planes or promotion, keyboard focus/activation, bounded public - evidence and no document/body overflow. -- The four reviewed E2E-04 screenshot hashes remain unchanged. No live Runtime, - model call, credential, product, CSS, schema, dependency or protected-branch - mutation ran during closeout. Candidate-time unrelated harness limitations - remain recorded in the preceding entry rather than being reclassified. - -## 2026-08-30 — FM-01 integrated verification and event-evidence follow-up - -PR #72 merged to `main` as `2e4058107311170ab12cadc6a6d283aeaefef895`. -Issue #42 closed and the feature branch was removed. The required integrated -verification ran from a clean detached worktree at that exact SHA. - -- **Integrated evidence:** the FM-01 plus database/service/Git-promotion/recovery - slice passed 187/187. Literal `npm run check` passed launcher 3/3, Server - 808/808 with three explicit skips, Web 19/19, all production/test typechecks and - both builds. A lock-backed clean install and `npm audit` reported zero - vulnerabilities; the merged feature files matched the reviewed branch bytes. -- **Independent audit finding:** the final re-verification row asserted - `promotion_started` and no completion, but not the resulting - `resolving -> attention_required` event. The event had a bounded reason but not - the matching failure code/stage, so event removal or misclassification could - remain false-green. No schema-widening, protected-promotion, authorization, - secret-exposure or data-loss blocker was found. -- **Causal follow-up:** branch `test/42-fm-01-final-event-evidence`, implementation - `471f5e8`, draft PR #74. RED passed 5/6 and failed only because the causal event - lacked `failureCode` and `stage`. The existing atomic transition now carries - those two fixed fields, and the matrix asserts its exact summary, - `resolving -> attention_required`, reason, code and stage through both durable - service state and the public events API. -- **Follow-up evidence:** matrix 6/6, adjacent 187/187, Server production/test - types, and a fresh literal gate with the same fully green counts passed. The - same read-only Auditor returned PASS with no remaining blocker. - `git diff --check` passed. No UI, dependency, schema, promotion-gate, live - Runtime or model change ran. -- `T,A,C` are complete. `I` remains pending until PR #74 is integrated and the - corrected focused flow is rerun on updated `origin/main`. - -## 2026-08-30 — issue #43 unauthorized-diff denial candidate - -Branch `fix/43-ui-01-unauthorized-denial`, initially based on protected `main` -`2e4058107311170ab12cadc6a6d283aeaefef895` and rebased onto current `main` -`18daa3a`. This is reviewed candidate evidence for issue #43; protected-main -integration is not claimed. - -- **RED/correction:** an ordinary failed Mission rendered only a generic Failed - timeline pill even though its denied Contract retained - `unauthorized_file_change` at `contract_authority`. The existing attention - panel now uses that precise Contract cause for failed Missions, labels the - safety stop and no-promotion outcome, and keeps the shortened Contract ID - traceable through its full-value title. The focused presentation regression - failed for each missing behavior before its correction and passes 6/6. -- **Causal browser proof:** a test-only executor wrapper uses the real compiled - service, store and host-trusted verifier to modify `policy.json` outside a - delegated `src/frontend/**` scope. The real authority boundary rejects it, - durable state reloads through the production server, and authenticated - Chromium proves the typed Contract denial, failed Mission, unchanged stored - and actual protected heads, zero Candidates, zero integration or promotion, - keyboard/focus evidence expansion, bounded public evidence and no page - overflow at `1280x800` and `1440x900`. The focused journey passed 2/2; all - four committed screenshots were inspected under `docs/ui-review/e2e-04/`. -- **Checks observed:** Web passed 20/20, the exact real-service authority test - passed, both production builds passed, harness unit passed 7/7, strict syntax - checks and `git diff --check` passed, and literal `npm run check` passed with - launcher 3/3, Server 808 passed plus three explicit skips, Web 20/20, strict - production/test-source types and both builds. `npm audit` reported zero - vulnerabilities across 251 dependencies. -- The subsequent pre-push hook reproduced the existing parallel interrupted-policy - cleanup race: Server 806 passed plus three skips while two - `general-project.test.ts` cases failed. That file then passed 8/8 alone. The - hook-created staged `policy.json` artifact was cleared, and only the documented - hook was bypassed for the branch update; no test or assertion was changed. -- The full browser harness passed 22/24. Both failures are unchanged - `starter-kit.spec.mjs` behavior outside the owned surface and reproduce in - that spec alone: a 0.09375px legacy viewport-boundary assertion at 1280 and a - 30-second legacy follow-up response timeout at 1440. No assertion, retry, - timeout, starter UI or unrelated source was changed to conceal them. -- Independent read-only audit and re-review found no remaining Critical, - Important or Minor issue in #43 scope and returned Pass for security and UI. - No production backend/schema, CSS, dependency, live Runtime or model path - changed; the accepted UI design remains frozen. Protected-main integration - and its rerun remain pending. - -## 2026-08-30 — FM-01 deterministic failure matrix candidate - -Branch `feat/42-fm-01-failure-matrix`, implementation `051b32a`, draft PR #72. -This is candidate evidence for issue #42; protected-main integration and audit are -not claimed. - -- **RED:** the first six-case run passed only the existing objective-tie path. Four - missing/malformed/omitted-key/acceptance cases persisted `unknown` at Mission - level, and failed final re-verification omitted its promotion evidence. -- **Correction:** known Contract-boundary failures now retain the exact fixed code - and stage on Mission, Contract, Plane and bounded event details. Final failed - promotion evidence is retained on the selected Candidate and linked from its - Plane; the database admits this only for a promotion-stage - `final_reverification_failure` while retaining target, diff, mandatory-profile - and Plane-link invariants. -- **Causal evidence:** `failure-matrix.test.ts` passed 6/6 without sleeps, retries, - network or model calls. Each case verifies service state, durable reload, public - Mission/events API, absence of `promotion_completed`, stored protected-head - immutability and the repository's actual Git HEAD. -- **Adjacent evidence:** database, service, Git promotion and recovery passed - 181/181. Server production and test-source TypeScript checks passed. The root - production build completed for both Web and Server, and `npm audit` reported - zero vulnerabilities across 251 dependencies. -- **Literal gate:** the pre-push hook reached Server 806 passed plus three explicit - skips, with two failures in the pre-existing parallel-only interrupted-policy - cleanup rows in `general-project.test.ts`. The same failures were observed before - FM-01 edits; the file passes 8/8 in isolation. The hook-created staged - `policy.json` artifact was cleared, and only the documented hook was skipped for - the branch push. `C` remains pending rather than inferred. -- No UI, dependency, live Runtime, model, credential or protected-branch change - ran. UI evidence remains assigned to the dependent E2E rows. - -## 2026-08-30 — issue #41 audited Project Group journey candidate - -Branch `feat/41-project-group-journey`, draft PR #64. This is candidate evidence; -protected-main integration is not claimed. - -- An explicit Project Group initialization creates the fixed idle auth-demo - Project without starting a Mission, Contract, Plane, executor, shell or model. - Unmentioned bounded messages persist with a bounded Shepherd reply. A leading - ready Frontend/Backend mention captures one fixed authentication transport; a - complementary opposite-role request enters the existing deterministic - two-Contract Mission with server-authored objectives and authority. -- Agent-authored Group messages are derived only from verified persisted manifest - summaries and remain bound to the exact sender, target, Contract and Mission. - Hostile V2 checks cover non-verified and missing-manifest states from valid - nonterminal controls, plus wrong sender, target, Contract and summary. The - pre-Agent-summary V2 shape remains compatible. -- Audit correction made Project Group routing atomic across ordinary and Contract - idempotency namespaces. The causal regression failed with two accepted requests - before the correction and passes with exactly one accepted message afterward. - Private-chat and Project Group pending prompts cannot pair across intake - provenance, and Mission-preparation failure rolls back only the new prompt. -- Literal `npm run check` passed: launcher 3/3, Server 795 passed with three - explicit skips, Web 19/19, all production/test-source typechecks and both builds. - The focused Database plus Shepherd suite passed 136/136; the final independent - re-review passed its 3 targeted tests and `git diff --check` with no remaining - finding. -- Authenticated focused Chromium passed 2/2 at `1280x800` and `1440x900` from the - real mention button through verified Contract evidence; the adjacent Shepherd - hero journey also passed 2/2. The broader direct Playwright run passed 18/20; - the two failures were unchanged legacy harness issues outside #41: a 0.09375px - starter-kit viewport rounding assertion and a separate response timeout. Harness - unit tests passed 6/7; the one unchanged macOS fixture compares canonical - `/private/var/...` and non-canonical `/var/...` temporary paths. -- `npm audit` reported zero vulnerabilities. No live/model request ran, no secret - or raw prompt/output was persisted in evidence, and the accepted UI design was - not redesigned. - -## 2026-08-30 — CRUD-01 clarification-only Agent deletion candidate - -- **Branch/review:** `fix/66-crud-01-clarification-draft-delete`, issue #66, - draft PR #67. No Web or CSS source changed. -- **RED:** a stopped Agent with only unbound `general-contract` - `clarification_required` messages, zero Contracts/Missions/Planes/events, and an - inactive managed Project failed deletion with `Cannot delete an Agent referenced - by durable Shepherd history`. -- **Correction:** deletion classifies only exact human-authored, unbound general - clarification messages as discardable. All durable or ambiguous references keep - the 409. Before deleting the exact managed Project, the server validates the - managed-root sentinel, metadata identity, main-only Git worktree state, absence of - Shepherd branches and empty private Plane roots. Fixed-schema, fsynced workspace - intent and Project deletion journals are written before database publication and - reconciled from on-disk durable Agent/Project state after restart. General Project - creation/policy journaling now begins inside the serialized Store mutation after - Agent revalidation, so a racing follow-up cannot strand a journal. -- **Observed checks:** production/test typechecks; focused Agent lifecycle/general - Project 29/29, including injected pre-publication and post-rename persistence - faults, exact follow-up/delete and direct-run/delete barriers, active-run join, - and clean restarts; adjacent API/Shepherd 77/77; literal `npm run check` with - launcher 3/3, Server 791 passed - plus two explicit opt-in skips, Web 18/18, and both - production builds. Authenticated deterministic Chromium passed 2/2 at 1280x800 - and 1440x900, including two clarification turns, exact 200 deletion, empty Agent - UI/state, exact filesystem absence and no document/body overflow. All four - screenshots were inspected. Independent UI review found no High/Medium issue; - it confirmed the frozen theme/layout and keyboard-operable native lifecycle - controls. Final independent security re-review at `171089b` passed with no High - or Medium finding after the direct-run race was also reserved, cancelled and - joined causally. Protected-main integration remains pending. The same-OS-user - recursive-path swap and Project-journal sudden-power-loss ordering are retained as - Low residuals under the existing single-owner local PoC threat/availability model. -## 2026-08-30 — the deploy guard is resolved through Compose, not re-parsed - -Branches `fix/47-ops-06-auth-boundary` (PR #69) and `test/47-ops-06-adjacent-coverage` -(PR #68), against `main` at `07f4202`. No live or model call ran. - -- **The shell guard was the wrong mechanism, not merely buggy.** Adversarial review - found six environment-file shapes where `sed -n 's/^APP_AUTH_TOKEN=//p'` reads a - valid token while Docker Compose resolves the variable to empty or absent, so the - deploy was approved and the container then started with the bearer boundary - disabled on the `0.0.0.0` bind this profile publishes. Reproduced directly: a file - whose valid line is followed by `export APP_AUTH_TOKEN=` gives `sed` the token and - `docker compose config` `APP_AUTH_TOKEN: ""`. `sed` does not implement compose-go's - handling of `export`, leading whitespace, quoting, escape sequences, multi-line - values or `${VAR}` interpolation, and every divergence is a chance to approve a - token the container never receives. Three further shapes passed the guard and then - aborted the container at startup, contradicting the guard's own stated guarantee. -- **Correction.** `scripts/check-deploy-auth-token.mjs` resolves the value through - `docker compose config --format json` — Compose's own parser, with - `LAUNCHPAD_ENV_FILE` set as the deploy script sets it — and applies the same rule - as `apps/server/src/config.ts`: trim, URL-safe shape, 24-character floor, no - `replace-` placeholder. `scripts/deploy-existing-ecs.sh` delegates to it. Because - the check and the container now read one parser and one rule, neither the bypass - class nor the approved-then-rejected class remains. -- **Observed against the real Compose parser** on this host: the `export` override, - the indented override, a quoted run of spaces, an undefined interpolation, a - trailing comment padding the line length, and a CRLF empty value all resolve to - refusal; a quoted 23-character token and a quoted `replace-` placeholder resolve - to `weak` where a shell parse counted the quotes and passed; a genuine 36-character - token resolves to `ok`. Tests 4/4. Causality checked by mutation: removing the - 24-character floor fails 2 cases, removing the trim fails 1. -- **Ledger.** `PR #63` merged ahead of both evidence branches and left the OPS-06 row - claiming `T,A,C,S,I` while neither was integrated. Both branches now carry the same - row text, which claims neither `A` nor `S` until its PR is an ancestor of - `origin/main`; identical text on both sides also removes the merge conflict the two - earlier, differing corrections created. The two should land back-to-back and both - gates be flipped in one follow-up. -- **Still not closed.** The High finding remains partly open: this guards the deploy - script, while `README` still documents `docker compose up --build` and - `docker compose --env-file .env.production up -d` against the same unguarded - `docker-compose.yml`. Carried into `SEC-REVIEW`. - -## 2026-08-30 — OPS-06 `A` and `S` gates, and a corrected reconciliation - -Protected `main` advanced to `f900656` (PR #71) while this reconciliation branch was -open; hosted exact-head gate run `33305530655` passed on it. The entry below remains -true for `b80af11`, the head it names. No live or model call ran. - -- **`A` gate (PR #68).** Four guards introduced or relied on by the container state - volume appeared only in source and in no test, so each could be deleted with a - green suite. Eight causal tests were added for the verifier fail-closed branch, - the three executor state-root guards, the `index.ts` verifier composition and the - launcher probe/fallback selection. Each was proven by mutating its guard and - observing the test fail; all source was restored afterwards. Two of the tests - initially passed for the wrong reason — one assertion was satisfied by the - following guard's message, since both end in `escaped CONTAINER_STATE_ROOT`, and - the launcher assertions read `stdout` while the launcher logs to `stderr`. Both - were corrected. -- **`S` gate (PR #69).** An independent read-only review of the merged range - returned **FAIL**: one High and two Medium findings, all against `e6a5878`, which - removed the non-loopback `APP_AUTH_TOKEN` requirement inside the same merge with - `gh pr view 56 --json reviews` returning `[]`. The container state volume itself - passed: the mount construction was attacked directly and no escape was found. -- **Adversarial re-review of both branches then found three defects in the first - corrections, each reproduced rather than argued.** The new deploy guard was - defeated by a whitespace-only token and by a CRLF environment file, because the - shell tested only for the empty string while the server trims before validating, - so both shapes reached the container as an empty token and disabled the bearer - boundary — the original finding verbatim. The guard now strips CR and surrounding - whitespace as the schema does and applies the same 24-character non-placeholder - floor as `config.ts` and `deploy/volcengine/variables.tf`. Separately, that - guard's only regression test was executed by no gate: the root `test` script names - a single file under `scripts/` and is not a glob, so `npm run check` would have - stayed green with the guard deleted; it is now named in that script, and deleting - the guard fails the gate. Finally, `index.composition.test.ts` could pass on the - exact regression it exists to catch, because its `indexOf("});")` end anchor - overshoots when the call is closed in the expanded argument style; the anchor is - now a close at column zero, comments are stripped from the window, and the - reproduction now fails both assertions. -- **The High finding is only partly closed.** The guarded deploy script is one of - three documented compose entry points; `README` still documents - `docker compose up --build` and `docker compose --env-file .env.production up -d` - against the same unguarded `docker-compose.yml`, which binds `0.0.0.0` and - publishes its port with no address prefix. Pinning that file to loopback was - rejected because the profile is meant to be reachable behind a security group and - the same file serves the local Docker path. The remainder is carried into - `SEC-REVIEW`. This merge must not be recorded as closing it. -- **Corrections to this branch's own earlier entry.** The `CHAT-01` row was left - internally contradictory: a guarded replacement silently matched nothing, so the - row still opened `REVIEWED CANDIDATE` while its body already said integration was - done. It now reads `INTEGRATED` at `cd82ec4`. An earlier local suite run reported - here was discarded rather than recorded, because it spanned a branch switch and - observed a mixed tree: it counted 32 test files where `main` has 29. -- **`TST-25` is resolved** at `e06357c` (PR #71, issue #70) by canonicalizing the - test's own temporary root before `mkdtemp`, leaving the fixture assertion intact. - -## 2026-08-30 — post-merge reconciliation at integrated `b80af11` - -Protected `main` at `b80af11` (merge of PR #56). That head also carries PR #57 -merge `cd82ec4` and PR #60 merge `39cd800`. Same affected host as the entries -below. No live or model call ran; no Mission was started. - -- **Hosted exact-head gate.** Run `33300759535`, event `push`, head branch `main`, - head SHA `b80af11`, job `Node 22 / npm run check` on `ubuntu-latest`: success, - every step green, 08:06:09Z to 08:08:43Z. This is the green Linux full gate that - the `OPS-06` row previously listed as outstanding. -- **Local rerun on the same SHA.** `npm run typecheck` passed; launcher tests 3/3; - web 18/18; both production builds passed. The server suite run serially - (`--no-file-parallelism --maxWorkers=1`) reported **745 passed, 6 failed, 6 - skipped**. The six failures are the recorded affected-host timing condition, not - regressions: five in `recovery.process.test.ts` (`Timed out waiting for - recovered` with empty child stderr — the forked `--import tsx` child never - crashed, it simply exceeded the 25s budget), plus the previously recorded - `expected 'resolving' to be 'attention_required'` flake in `service.test.ts`. - An earlier attempt to run the suite from the repository root is not evidence: - that invocation left `process.cwd()` outside the workspace, so the executor's - source-inventory test raised `ENOENT` and the Playwright specs were globbed into - the Vitest run. -- **`npm run test:e2e:harness:unit` on `b80af11`: 6 passed, 1 failed.** The failure - is `fake Codex fixture implements bounded deterministic version, run, and - resume`, with `fake-codex: workspace identity must be canonical`. This is a real - test-only defect, not an environment quirk: `tests/e2e/harness.test.mjs:38` - builds its workspace with `mkdtemp(path.join(os.tmpdir(), …))`, and on macOS - `os.tmpdir()` is a symlink, so the deliberate `realpath` identity assertion at - `tests/e2e/fixtures/fake-codex.mjs:69` correctly rejects it. The repository's own - idiom is already `tests/e2e/support/test-app.mjs:93`. This target is not part of - `npm run check`, so no hosted run covers it. Recorded as a new defect; the - fixture's assertion must not be weakened. -- **`LIVE-01` cannot run on this host, and the attempt was deliberately not - spent.** `live-runtime.integration.test.ts:182-185` pins - `CONTAINER_STATE_ROOT` and `CONTAINER_STATE_VOLUME` to `undefined`, so the gate - bind-mounts `.tmp/shepherd-live-gate/…` — a host share on this machine — and the - OPS-06 container-volume correction cannot apply to it. Two zero-spend probes - against the Runtime image confirmed the split on the exact gate path: a plain - write to a host-share bind mount inside the container succeeded (exit 0), while - the identical write under `codex sandbox linux --full-auto` was denied - (`cannot create /workspace/.p: Permission denied`, exit 2). A named-volume - control was inconclusive because a freshly created volume is root-owned, so the - denial there was ownership rather than Landlock; the bind-mount pair above is the - discriminating evidence. Running the gate here would therefore fail at - `stage=container_start reason=sandbox_probe_failed` and consume the no-retry - allowance for no evidence. `LIVE-01` needs a Linux host, or a change making the - gate volume-aware, which is outside an `L` run. -- **Ledger reconciliation.** The header pointer, the baseline hosted-gate and - server-suite rows, the presentation-host caveat, and the `OPS-06`, `CHAT-01` and - `LIVE-01` rows described merged work as unmerged candidates and cited hosted runs - that were not on the exact head. Corrected from the evidence above. - `docs/FIXES.md` carried the same stale `CANDIDATE PENDING AFFECTED-HOST GATE` - wording for `OPS-06` and was corrected with it. -- **Issue split.** `#47` bundled `OPS-06` and `LIVE-01`, which need different - hosts, so neither could close. `LIVE-01` moved to issue `#65` with the probe - evidence above; `#47` is re-scoped to `OPS-06` only and remains closeable on this - host once `A` and `S` land. `main` has since advanced to `a1f1fcc` (PR #62); the - evidence in this entry is scoped to `b80af11` and is not restated for that head. -- **Not claimed.** The `A` and `S` gates for `OPS-06` remain open. `A` is missing - the verifier composition at `apps/server/src/index.ts:77-78`, the launcher - probe/fallback selection, and the verifier fail-closed branch. `S` is unmet and - must also cover `e6a5878`, which removed the non-loopback `APP_AUTH_TOKEN` - requirement inside the same merge and carries no recorded independent review. - -## 2026-08-30 — the launcher selects its own state layout - -Same branch and host. `LOCAL_POC_STATE_MODE` defaulted to `host-bind`, so the -affected host had to be told to use the container state volume even though the -launcher's own probes already knew. The probe, not the operating system, is the -correct signal: what matters is whether the engine sees a native filesystem, and a -host can fail that on any platform. - -- Default is now `auto`. The state selection, mount specification and both probes - became functions, so the launcher can apply the host layout, probe it, and on - failure apply the volume layout and probe again within one run. `run_state_probes` - returns a typed status — 1 the engine cannot mount and write the state, 2 the - Codex sandbox cannot govern the workspace — so the fallback message names the - actual reason. An explicit `host-bind` or `container-volume` disables the - fallback, so a host that should work still fails loudly. -- Observed on the affected host with no environment variables set at all: - - ``` - [local-poc] Persistent state: /Users/…/.volc-agent-launchpad - [local-poc] Checking that the Runtime can mount and write the configured state directories. - [local-poc] Checking that the Codex sandbox can govern the configured workspace. - [local-poc] The Codex sandbox cannot govern a workspace on /Users/…/.volc-agent-launchpad. - [local-poc] Switching to the launchpad-state-auto container state volume and retrying. - [local-poc] Preparing the launchpad-state-auto state volume for the Agent Runtime. - [local-poc] Persistent state: launchpad-state-auto (container volume) - [local-poc] Checking that the Runtime can mount and write the configured state directories. - [local-poc] Checking that the Codex sandbox can govern the configured workspace. - [local-poc] Building and starting the containerized control plane. - ``` - - The mount-and-write probe passed on the host share and the sandbox probe failed, - which is the expected split. `GET /api/health` then returned - `{"ok":true,"service":"volc-agent-launchpad"}` and the running control plane - resolved `executionMode: "live"`, `authTokenLength: 0`. The smoke volume was - removed afterwards. -- `scripts/start-local-poc-launcher.test.mjs` passed 3/3, including the darwin case - that pins the five exported host paths: under `auto` its stub engine reports - success, the host layout is kept, and the exported paths are unchanged. - -## 2026-08-30 — APP_AUTH_TOKEN requirement removed, capability retained - -Same branch and host as the entry below. Requested scope was the requirement, not -the feature: the bearer boundary stays in the product and stays enforced whenever -a token is configured. - -- The request originally read as deleting the token entirely. Survey first: the - request hook at `apps/server/src/app.ts:843` already returns early when the - token is empty, so every route is open and `/api/auth` reports - `required:false`. Exactly one line forced a value — the non-loopback guard in - `loadConfig`. Removing the whole feature would have touched 18 non-test source - references and 26 test references and left `deploy/volcengine/main.tf` serving - an unauthenticated Agent-execution API on a public interface, so the narrower - correction was agreed instead. -- Removed the guard and its two now-unused helpers. Removed the matching guard - from `scripts/start-local-poc.sh` and the required interpolation in - `docker-compose.state-volume.yml`. The schema still rejects a token that cannot - be sent as a bearer credential — non-URL-safe characters, or over 128. -- Replaced rather than deleted the affected assertions. The former - "requires a strong non-placeholder token for every non-loopback bind" now proves - the new contract: `0.0.0.0`, `192.0.2.10`, `127.0.0.1` and `::` all start with an - empty token across all three `NODE_ENV` values, and a short or placeholder value - is carried verbatim instead of refused. A second case keeps the bearer-shape - rejections. The reviewer-clone test keeps its non-mutation assertions without the - removed throw. -- Verified on the affected host with **no token set at all**. The launcher logged - `No APP_AUTH_TOKEN is set, so the control plane will not require one`, the - control plane started, `/api/auth` returned `{"required":false}`, and - `GET /api/system` with no `Authorization` header returned `200`. Resolved - configuration inside the container was `executionMode: "live"`, - `authTokenLength: 0`, `host: 0.0.0.0` — so the Codex Runtime preflight still - passes with the boundary disabled. The smoke volume was removed afterwards. -- Enforcement with a token configured is unchanged: `config.test.ts` and - `app.test.ts` passed 52/52, including the 401 paths. -- Documentation updated to describe the token as optional in `README.md`, - `.env.example`, `docs/LOCAL_POC.md`, `docs/SHEPHERD.md` and - `docker-compose.state-volume.yml`. `SECURITY.md` now states plainly that a - server started without a token serves every route to anyone who can reach the - port, and that a token must be set before exposing it beyond the local machine, - including ECS. Prior log entries are left as written; they remain true for the - commits they name. - -## 2026-08-30 — OPS-06 affected-host cause reproduced and corrected - -Branch `fix/47-ops-06-container-state-volume`, PR #56, on the affected host -(macOS, Docker Desktop 29.5.3, LinuxKit 6.12 aarch64, `volc-agent-runtime:local`). - -- Reproduced the reported failure from the repository's own generated preflight - arguments: `docker create` succeeded, `docker start --attach` exited 49, and the - only Runtime stderr was - `sh: 1: cannot create /workspace/.shepherd-sandbox-probe: Permission denied`. -- Isolated the cause by holding image, Codex configuration and container flags - fixed and varying only the workspace filesystem. Inside - `codex sandbox linux --full-auto`, an ext4 named volume, the image overlayfs and - a tmpfs all permitted `: > file`; the macOS host share denied it. On that share - `mkdir`, `rmdir` and `unlink` succeeded while `open()` for read, write, create - and truncate returned `EACCES`, and the file was left behind by the denied - create — Landlock grants `MAKE_REG` there but not `WRITE_FILE`. -- `strace -f -y` on both a passing and a failing run showed byte-identical - `landlock_create_ruleset`, five `landlock_add_rule` calls over the same paths - (`/`, `/dev/null`, `/codex-home/memories`, `/workspace`, `/tmp`) and - `landlock_restrict_self`, all returning 0. Only the subsequent - `openat(AT_FDCWD, "w1", O_WRONLY|O_CREAT|O_TRUNC)` differed: `-1 EACCES` versus a - file descriptor. The ruleset is identical; the filesystem cannot enforce it. -- Confirmed the independent `touch` probe defect: on the same share `touch` - exited 0 **and created the file**, while `: >` in the same shell was denied. -- Verified the correction on the same host. With - `--mount type=volume,...,volume-subpath=...,volume-nocopy=true`, workspace read, - workspace write and a full `git init`/`add`/`commit` all succeeded inside the - sandbox while the private `CODEX_HOME` write stayed denied. The **unmodified** - preflight script then printed `codex-cli 0.111.0` and - `SHEPHERD_RUNTIME_PREFLIGHT_OK` with exit 0. -- Established that `volume-nocopy` is mandatory. Without it an empty subpath is - served with the image's own `/workspace` ownership: `ls -ldn` reported `0 0` - through the mount while the directory on the volume was `10001 10001`, and a - plain non-sandbox write was already denied. With `volume-nocopy=true` ownership - was preserved and both the plain write and the sandboxed write succeeded. -- Proved the full loop: a non-root containerized control plane (uid 10001, - joined to the engine socket group) created its workspace and private home, - derived the state-relative subpaths, started the sibling Runtime container, - and read back the file the sandboxed Agent had written. -- Repository gate on this host is **not green, before or after the change**. - Pristine `origin/main` (`c0802e8`) failed `npm run test -w @launchpad/server` - with 39 failed / 696 passed; the branch failed with 61 failed / 686 passed. - Every failure in both runs is `Test timed out` or a `vi.waitFor` state - assertion behind one, and the `main` failure set is a strict subset of the - branch set — this machine is too slow to run the suite in parallel with the - container engine, not a regression. Run serially - (`--no-file-parallelism --maxWorkers=1`), the five heaviest files passed - **167/168** on the branch in 434s; the single failure, - `expected 'resolving' to be 'attention_required'`, is the same timing flake - observed on pristine `main`. `npm run typecheck` and `npm run build` passed. - `npm run test:e2e:harness:unit` passed 6/7; the one failure is the documented - macOS non-canonical `os.tmpdir()` issue in a fixture this change does not - touch, and the fake-container-engine test pinning the read-only bind mount - passed. A green full gate on a Linux host remains required before integration. -- Ran the default `host-bind` launch on the affected host after the probe - correction. It now stops at startup with - `Codex workspace-write Landlock cannot govern the configured workspace in the - hardened non-root Runtime`, naming `LOCAL_POC_STATE_MODE=container-volume`, - instead of passing a false gate and crashing later inside the server. The - mount-and-write probe passed in the same run, which is the expected split: a - plain write to the host share succeeds while the Landlock-governed write does - not. -- Ran the `container-volume` startup smoke on the affected host with a one-off - token supplied in the environment; the repository `.env` was not modified. The - first attempt exposed a real wiring defect: the launcher validated its resolved - `APP_AUTH_TOKEN` while the control plane re-read a different value from - `env_file`, so the container crash-looped on - `APP_AUTH_TOKEN must be a non-placeholder token`. Corrected by pinning - `APP_AUTH_TOKEN` in the compose `environment:` block from the caller's resolved - value and exporting it from the launcher, so the validated token is the token - the server receives. -- After that correction the profile came up on the first try: both preflight - probes passed in volume mode, the control-plane image built, and - `GET /api/health` returned `{"ok":true,"service":"volc-agent-launchpad"}` with - the port published to `127.0.0.1` only. Resolved configuration inside the - running container was `executionMode: "live"`, `runtimeProvider: "container"`, - `containerStateRoot: /app/state`, `codexSandboxMode: workspace-write`. Live mode - means `CodexShepherdExecutor.preflight()` ran and passed inside the server — - the exact call that previously threw - `Live Shepherd Runtime preflight failed (stage=container_start - reason=sandbox_probe_failed)`. The smoke volume was removed afterwards. -- No live or model call ran; no Mission was started. -## 2026-08-30 — default general Agent Contract-intake candidate - -- Ownership: issue #58, branch `feat/58-general-contract-intake`, stacked draft - PR #59 on private-chat PR #57. No protected-main integration is claimed. -- Shepherd-managed routing is now the default in every Agent chat; the existing - toggle remains a direct-Playground escape hatch. The fixed Frontend/Backend auth - prompts retain their two-Contract collision path. -- Other prompts enter a constrained deterministic planner. It accepts 1–8 bounded - messages, requires a concrete change, writable project-relative artifact(s), and - explicit `Acceptance:` evidence. Missing or authority-incompatible fields produce - a durable in-chat clarification and create no Mission, Contract, or Plane. -- A confirmed draft creates one authority-intersected Contract in a sentinel-bound - managed project seeded from a secret-filtered Agent snapshot. The existing - Git-free executor/import path, strict manifest ingestion and exact-diff authority - check run unchanged. A registry-owned static check independently verifies the - declared artifacts; the verified Contract is merged into an integration Plane, - independently re-verified, promoted by expected-head compare-and-swap, and only - its declared artifacts are synchronized back to the Agent workspace. -- Causal tests cover planner bounds/normalization/authority, secret-filtered project - initialization, verifier policy, symlink-safe artifact sync, deterministic output, - clarification idempotency/conflict, absence of premature executable state, final - verified lifecycle, promotion and workspace output. Security regressions additionally - reject negated/compound Acceptance criteria, retain post-CAS evidence across a - one-shot final persistence fault/restart, and roll back an exact journaled policy - commit when its Project head was not persisted. The literal `npm run check` passed: - launcher 3/3, Server 771 passed plus two opt-in skips, Web 18/18, strict - production/test type checks and both builds. -- Authenticated Playwright passed 6/6 across exact `1280x800` and `1440x900`: - unchanged user-created auth collision, default route plus direct opt-out, general - clarification and follow-up, verified promotion/workspace output, human-review - fallback, stale-Agent-status reconciliation and no document overflow. A first - focused E2E run correctly exposed that the fake verifier allowlist lacked the new - registry-owned check; adding that exact static check made every rerun pass. -- No live/model request was made. Independent UI and security re-reviews returned - ready with no High/Medium finding; integration against protected `main` remains - pending. The final deterministic browser rerun - passed 6/6 after the direct-Playground fixture was explicitly configured with its - bounded fake Agent Runtime; the direct request returned 202 and emitted no managed - Contract request. -## 2026-08-30 — private Agent-chat Contract candidate - -- Ownership: issue #55, branch `feat/55-private-chat-contracts`, draft PR #57; - implementation `6018352`, reviewed correction head `e1fe067`. Protected-main - integration remains pending. -- Frontend and Backend Agents now have an explicit **Route through Shepherd** mode - in their existing private chat. Bounded server parsing accepts exactly one - HttpOnly-cookie assignment and one bearer-JWT assignment; ambiguous, absent, - same-role, same-transport, stopped/busy, authority-incompatible and reused-ID - inputs fail closed. Legacy Playground behavior remains available when the mode is - off. -- The first exact bounded prompt and the second prompt are durable before their - respective filesystem/Mission work. A restart can resume intake; the second - prompt idempotently creates one Mission whose two Contract objectives are the - original user assignments. The existing isolated Contract Planes, independent - verification, integration, semantic collision, same-base resolution candidates, - final re-verification and protected promotion remain authoritative. -- The old Shepherd Agent/transport selectors and their unused CSS were removed. - Private chat shows collection and verified Contract status. A route-mode identity - regression prevents Frontend state leaking into a Generalist or Backend. Narrow - `/shepherd` flex containment keeps the full fallback composer in viewport while - preserving designated internal panel scrolling and the accepted theme. -- Verification found and corrected three causal defects. The first restart RED was - `Shepherd startup artifact reconciliation failed` because a pending Project lacked - its trusted Plane-root sentinel. UI review then reproduced hidden route state on a - Generalist and main-container Y overflow. Security review found Agent deletion - could archive a workspace while private intake persisted a reference or created - pre-mutation Project artifacts. Final intake/delete operations serialize through - the Store queue; actual barrier coverage proves both orderings keep Agent, - workspace, Project and prompt state consistent and restartable. -- Final literal `npm run check` passed: launcher 3/3; Server 742 passed plus two - explicit opt-in skips; Web 18/18; strict production/test type checks and both - production builds passed. Focused security/intake regressions passed 3/3. -- Final authenticated Playwright passed 4/4 at exact `1280x800` and `1440x900`: - private Frontend prompt, Generalist isolation, private Backend prompt, verified - private status, exact Contract assignment, complete evidence, collision/candidate - outcome, human-review fallback, keyboard opt-in, and document/main-container - no-overflow/composer-in-viewport checks. A source-only rerun before rebuilding the - production Web bundle served stale assets and failed the new identity assertion; - the explicit build and every final rerun passed. -- Independent security and UI re-reviews passed with no remaining blocker. The - configured custom reviewer roles were unavailable, so repository-instructed - read-only fallback reviewers were used. No live/model request ran; this evidence - covers deterministic local behavior only. The separate Project Group `@Agent` - journey remains issue #41. - -## 2026-08-30 — protected-main promotion and exact post-merge gate - -- PR #52 passed hosted `Node 22 / npm run check` and merged the documentation and - workflow candidate into retained campaign branch `mock-main` at `017e07e`. -- Promotion PR #53 was mergeable with no main-only commit. Both hosted checks— - `Required checks` and `Node 22 / npm run check`—passed before it merged into - protected `main` at `5ccd0f143146b2c303be90dc1337e02bb6986459`. -- On that exact protected-main merge, literal `npm run check` passed locally: - launcher 3/3; Server 739 passed plus two explicit opt-in skips; Web 18/18; strict - production/test type checks and both production builds passed. -- The campaign branch was intentionally retained. This follow-up changes only - promotion provenance in documentation; it does not change product or UI code. - -## 2026-08-30 — protected-main hackathon integration candidate - -- Base: campaign integration merge `005a51e02ab39a995803b4ed3717ee0ee55cae6c`, - which contains the independently reviewed user-selected Contract flow from PR #40. - Branch `docs/hackathon-main-integration` was pushed before edits. -- Active contribution instructions now target protected `main`, require immediate - issue assignment/comment plus an early remote branch, and provide the replacement - navigation path after intentional removal of `HANDOVER.md`. `AGENTS.md`, - `CLAUDE.md`, `CONTRIBUTING.md`, `TASKS.md`, and the active Fixer rules all freeze - visual design and define “minimal” as a complete functionality-preserving fix. -- `SHEPHERD.md` now inventories implemented Track 1 backend capabilities, separates - current evidence from open gates, links the today-feasible work, and records the - dated internal assessment: 82% hackathon completion, 90% core demo readiness, - 85/100 weighted rubric score, 74/100 current winning confidence, and 91/100 - novelty confidence. The deductions and the dependency/rubric weighting method are - explicit; no official-judge or guaranteed-win claim is made. -- Read-only GitHub audit found only two stale open issues. #35 (MR-02) and #36 - (CI-01) were closed as completed with their integrated evidence; none was deleted. - Unassigned, dependency-aware issues #41–#51 now cover only the minimum - hackathon-ready cut and carry `hackathon-ready` plus `priority:P0` labels. -- The manual runbook now creates/selects user Frontend and Backend Agents, displays - both complete Contracts, explains source versus competing Resolution Planes, and - verifies the internal human-review ticket. Project Group's unfinished behavior - remains explicitly open. -- `docs/PRD.md` remained byte-identical at SHA-256 - `478ca55f201b52ba75c5c2134e0eef9d8ded4eb74f6a35d32062927413a70ced`. - All local Markdown links resolved across 15 files and `git diff --check` passed. -- Literal `npm run check` passed on the candidate: launcher 3/3; Server 739 passed - plus two explicit opt-in skips; Web 18/18; strict production/test type checks and - both builds passed. Neither `actionlint` nor the Ruby YAML fallback exists in this - environment, so no local parser pass is claimed for the one-line workflow trigger - removal; the hosted required check remains the merge gate. -- No product source, runtime, schema, dependency, secret, live/model request, or UI - implementation changed in this documentation/workflow candidate. - -## 2026-08-30 — user-selected Agent Contract demo candidate - -- Base: `mock-main` at `6fddb0e84608a8614f745bcfdcd92b091e4f7fdf`. - Branch: `feat/demo-agent-contract-flow`, pushed before edits. -- The existing Shepherd Mission composer can now assign one ready user-created - Frontend Agent and one ready user-created Backend Agent to opposite typed auth - transports. Reservation and authority are revalidated in the final serialized - mutation; Mission request idempotency is fingerprinted and persisted atomically - with the Mission, Contracts and originating human message. -- Every Contract-linked stream event can disclose the complete bounded Execution - Contract: identity and assignment, objective, dependencies, semantic contract, - contextual inputs, scoped authority, artifacts, acceptance checks and profile, - tie-breakers, manifest path and timestamps. Existing evidence remains alongside - it; public responses do not expose the server-only request fingerprint. -- Collision evidence explains that both Resolution Planes fork from the same - immutable integration commit and compete by independent project-invariant - verification. Non-automatic or non-unique outcomes show a truthful internal - human-review ticket with the full durable collision/Mission reference; no - external issue-tracker integration is claimed. -- Causal tests cover selected Agents with reversed transports, concurrent and - restart-safe idempotency, assignment mismatch, the stop-versus-reservation race, - full Contract rendering and human-review behavior. Literal `npm run check` - passed launcher 3/3, Server 739 passed plus two explicit opt-in skips, Web 18/18, - all strict production/test typechecks and both builds. -- The focused real-browser gate passed 4/4: normal completion and forced human - review at exact `1280x800` and `1440x900`, including Agent creation/selection, - exact Contract assignment/objectives, both Resolution Planes, full evidence, - keyboard focus and no document/body overflow. Independent UI review passed at - 5.31:1 minimum contrast; independent security re-review passed with no remaining - scoped blocker. After the final ticket-label wording edit, the first browser - invocation served the prior production bundle: both unchanged completion cases - passed and both new-label assertions failed. Rebuilding the Web bundle and - repeating the exact command passed 4/4. No live/model request was made. -- This candidate does not claim completion of `GC-03/04`: the separate Project - Group `@Agent` click/type → Contract → Agent-summary journey remains open. - -## 2026-08-30 — DEL-04 documentation consolidation candidate - -- Base: `mock-main` at `43fb5d3f40a0b90a744aec70b2ab02a8adab5ed9`. -- Branch: `docs/hackathon-doc-consolidation`, pushed before edits as the ownership - signal. Documentation and root navigation are the only owned surfaces. -- `TASKS.md` is now the canonical entrypoint and explicitly separates the minimum - hackathon-ready cut from additional full-PRD work. Its ledger was mechanically - recounted as 69 work items: 40 fully audited and 29 not fully audited. -- The current startup/manual demo SOP moved to `LOCAL_POC.md`; current as-built - behavior remains in `SHEPHERD.md`; the competition brief was reduced to Track 1 - and renamed `TECHJAM.md`; optional deployment essentials moved into `README.md`. -- Obsolete `HANDOVER.md`, `DEPLOYMENT.md`, and the five-track source digest were - removed only after all actionable repository links were redirected. Historical - mentions inside this immutable chronological log were intentionally retained. -- `PRD.md` remained byte-identical with SHA-256 - `478ca55f201b52ba75c5c2134e0eef9d8ded4eb74f6a35d32062927413a70ced`. -- A repository-local link checker inspected 15 retained Markdown files; every local - target resolved. `TECHJAM.md` contains no Track 2–5 section, `git diff --check` - passed, and the stale deviation/browser/count statements were reconciled. -- Literal `npm run check` passed: launcher 3/3; Server 27 files passed with two - explicit opt-in files skipped and 736 tests passed with two skipped; Web 3 files - and 17/17 tests passed; strict production/test typechecks passed; Web production - build transformed 41 modules; Server production build passed. -- No product, UI, schema, dependency, Runtime, secret, or live-model behavior changed; - no live/model request was made. -- Independent read-only review rejected five stale/incomplete statements; the exact - E2E-02, branch identity, authenticated deployment verification, link-count, and - veLinux mapping corrections were applied and the re-review passed with no blocker. -- The reviewed commit `5a38d37a210c255781055648c43896597497f50f` was fast-forwarded - into `mock-main`. The post-merge local-link/PRD/task-count/Track-1 checks passed, - literal `npm run check` repeated the 3/3 launcher, 736-pass Server, 17/17 Web, - strict typecheck, and two-build result, and `origin/mock-main` was verified at the - same exact commit before this bookkeeping update. - -## 2026-08-30 — F-06 and TST-21–24 integrated and audited - -Auditor integrated exact corrected chain -`7d51ec69d1ac6c807d42e872b4616b6357967f48` onto `mock-main`. Independent -evidence passed TST-23 20/20, TST-24 30/30, Store 70/70, and combined Store/ -recovery/service 133/133. Literal `npm run check` passed launcher 3/3, Server -736 passed plus two explicit opt-in skips, Web 17/17, strict production/test -typechecks and both builds. Independent final security review returned 0 High and -0 Medium; all prior journal-read and sensitive-temp crash-prefix blockers closed. -Hosted Node 22 Required checks run `33286090602` passed the implementation head. - -The accepted Low residual is the documented same-UID parent-directory swap or -concurrent independent-Store race under the existing single-process managed-root -threat model. Windows narrowly lacks Unix directory-fsync/mode guarantees; Unix and -macOS errors are not swallowed. F-06 is explicitly representative of the Mission -running-to-verifying boundary and does not claim arbitrary store-mutation recovery. -No live/model/UI call was needed. - -## 2026-08-30 — TST-24 Fixer candidate restores the TST-22/F-06 full gate - -After visible persistence-error attention, the exact fixture now uses bounded -`vi.waitFor` on `store.persistenceRecoveryIntent()` becoming null and then awaits a -test-owned no-op `store.mutate` sentinel. This proves recovery-journal unlink, -directory sync, in-memory intent clearing and all earlier original-store queue work -have finished before durable reads, cancellation, reset or root teardown. No sleep, -retry, timeout increase, suppression, cleanup catch or product change was added. - -The exact row passed 30/30. Combined Store/recovery/service coverage including -TST-23 passed 138/138 without an unhandled rejection or retained artifact. Two -consecutive literal `npm run check` executions each passed launcher 3/3; Server 736 -with two explicitly opt-in skips; Web 17/17; strict production/test typechecks; and -both builds. TST-22's prior independent security verdict remains 0 High / 0 Medium -with only the documented same-UID parent-directory swap Low. Auditor integration -and hosted evidence remain pending. - -## 2026-08-30 — TST-24 reconciliation-quiescence RED preserved - -Auditor tested exact corrected chain -`7d8483a3ef5998002dab6331bd53532640f953ec`. The transient Mission verification -persistence row passed once, then passed 18 contention repetitions before failing -iteration 19. The Mission was visibly `attention_required`, but the complete -recovery intent remained non-null; a late Store operation also rejected with fixed -`recovery_pending`. - -Source ordering confirms `mutateForPersistenceReconciliation` publishes attention -before `clearPersistenceRecoveryIntent` finishes journal unlink, parent-directory -sync and in-memory intent clearing. The test must wait for that exact intent to clear -and queue a test-owned no-op mutation sentinel on the original Store before durable/ -reload/cancel/teardown work. No sleep, retry, timeout, suppression, assertion -weakening or product edit is authorized. No `mock-main`, hosted, live, model or UI -action occurred. - -## 2026-08-30 — TST-23 Fixer candidate - -The TST-17 Plane-unwind attention row now awaits one test-owned no-op -`store.mutate` sentinel after observing `attention_required` and before reading -durable reload state. Because Store operations are serialized, this joins all prior -original-store persistence without sleeping, retrying, suppressing a rejection or -changing product behavior. The exact row passed 20/20; combined Store, recovery and -service coverage passed 138/138 with no unhandled rejection or retained root/temp. - -The first literal full gate advanced past TST-23 but stopped in a distinct transient -Mission-verification persistence row: Server reported 735 passed, two opt-in skips -and one failure because the row observed attention before its recovery intent was -cleared. That row passed 10/10 isolated, establishing contention sensitivity rather -than closure. It is outside TST-23 ownership and is not edited or hidden here; the -TST-22/F-06 full gate remains blocked pending separately owned evidence/correction. - -## 2026-08-30 — TST-23 independently reproduced on TST-22 checkpoint - -On exact checkpoint `619e3ddd369d2dd8a0ce3b04134c0064c240142e`, Auditor ran only -`fails closed with bounded attention evidence when initial Plane unwind fails`. -Its assertions passed 1/1, but the command failed with one unhandled cause-free -`PersistenceBoundaryError(cleanup, cleanup_pending)` from `JsonStore.persist` on -the original Store queue. Source ordering confirms the row observes service memory, -then initializes a second Store before joining that queue. The corrected TST-22 -marker authority is correctly fail-closed under concurrent independent access. - -TST-23 therefore requires only a test-owned no-op Store sentinel after attention -and before reload/teardown, with immediate rejection observation/finally join if -needed. No sleep/retry/timeout/suppression/cleanup catch or production change is -permitted. No `mock-main` push or full/hosted/live/model/UI gate is claimed. - -## 2026-08-30 — TST-22 Fixer candidate: crash-safe managed-temp state machine - -The correction replaces post-failure temp registration with pre-registration: -before either database or recovery-journal sensitive temp is opened, a small fixed -schema containing only kind, strict temp basename and publication UUID is written, -file-synced, atomically published and directory-synced. All markers and sensitive -temps live in an adjacent fixed-name private directory validated as a current-owner -regular directory with mode `0700` and no symlink. Database/journal rename remains -on the same filesystem; the target parent and private directory are synced at their -respective transitions. - -One idempotent cleanup path handles marker+temp and marker+missing-temp states, -preserves the primary database/journal failure with bounded `cleanupPending`, and -consumes any prior marker before another same-instance write can publish. Marker -publication files are opened no-follow and validated through the same handle; -schema-bound UUID provenance is required before deletion. General-parent -lookalikes, malformed foreign files, hostile directory/marker/publication symlinks -and outside canaries remain untouched. - -Observed focused evidence: strict test typecheck passed; Store passed 70/70; the -selected Store/recovery/service slice passed 134/134 before the private-directory -hardening and Store returned 70/70 after it. The matrix includes 12 publication -checkpoints, eight removal checkpoints, primary/journal double faults, -same-instance retry, two fresh restarts, missing-temp idempotence and repeated-write -no-accumulation. Independent final security review found 0 High / 0 Medium; the -documented Low residual is a same-UID parent-directory swap race because Node lacks -portable `openat`-style anchored operations, and such an actor already controls the -database parent. - -The post-hardening adjacent run exposed a separate deterministic test-quiescence -defect in the TST-17 cleanup-double-fault row: 138/138 assertions passed but Vitest -reported a late unhandled Store rejection; isolated stress failed on repetition 2. -The row observes in-memory `attention_required` then starts a second `JsonStore` -before the original Store queue is quiescent. The private marker correctly fails -closed during that overlap. This is not hidden as TST-22 success; a test-owned Store -queue sentinel is required before reload/teardown. The first post-hardening literal -gate likewise stopped at Server tests (735 passed, two opt-in skips, one teardown -failure). Auditor integration/hosted evidence remains pending. - -## 2026-08-30 — F-06/TST-21 correction blocked by TST-22 marker lifecycle - -Auditor fast-forwarded exact corrected candidate -`f65681aa48a3bfd384d36fc9320ea63e045d3261` only on the audit ownership branch. -Store passed 43/43; the selected persistence/journal/Plane slice passed 21/21; and -the previously order-sensitive initial Plane-unwind attention row passed 20/20, so -no causal lifecycle or fault-seam-reset defect reproduced there. - -The recovery-intent open/stat/read/close boundary is now fixed and cause-free, but -the temp-marker protocol remains Medium-blocked. Auditor changed only the existing -double-fault test's recovery instance for a causal probe: same-instance recovery -failed database and journal rows 2/2 with `cleanup_pending`. The in-memory pass -removes the temp without its marker, then marker scanning rejects the missing temp. -Independent security re-review also confirmed unhandled crash prefixes: marker -publication failure can leave an unmarked full-state temp; temp removal followed by -marker removal failure or a partial marker can permanently block restart. The probe -edit was reverted byte-clean. TST-22 records the required idempotent state-machine -boundary. No product commit was pushed to `mock-main`; full/hosted/live/UI/model -gates were not claimed after the Medium blocker. - -## 2026-08-30 — TST-21 Fixer candidate - -The correction closes recovery intent open/stat/read/close operational faults as -fixed cause-free `PersistenceBoundaryError(recovery_intent_read, unavailable)` while -retaining fixed schema/symlink/size/owner validation. Database and journal UUID temps -are registered in memory; a primary plus temp-unlink double fault preserves the -primary failure and durably marks the exact artifact. Before state becomes observable on -restart, only a strict matching marker is considered, then fixed content, lstat -regular-file/no-symlink, owner, mode and database/journal size limits are enforced -before exact unlink and parent-directory sync. Two restart rows prove removal; a matching marker symlink remains untouched with its outside -canary unchanged. Two marker-write triple-fault rows preserve the original primary/ -journal identity, expose only bounded `cleanupPending`, and consume exact in-memory -ownership on same-instance initialize. Focused store coverage passed 43/43; Auditor remains pending. -The final literal gate passed launcher 3/3, Server 709 passed plus two opt-in skips, -Web 17/17 and both builds. Independent final security review approved with 0 High / -0 Medium; Low residuals are same-UID data-directory races and fail-closed handling -when an external actor removes an exact pending temp. - -## 2026-08-30 — F-06 audit blocked by TST-21 persistence-boundary defects - -Auditor replayed exact Worker candidate -`6bc67b3272b530897149aa5a9507e46c2393453a` locally as `1a3be1a` over canonical -`mock-main` `19876cb740d80c2e868d401f4b5f6164e20ff330`. The focused persistence/journal -selection passed once (18 passed, 62 skipped) and then passed 10/10 repeated -invocations. The exact-byte digest, bounded schema, no-follow/size/mode/owner -checks, pending-recovery mutation/event lock, representative running-to-verifying -scope, and immediate/two-restart reconciliation design were inspected; no broader -arbitrary-store recovery claim is accepted. - -Integration is blocked. Independent read-only security review found two Medium -gaps outside the existing single-stage fault matrix. First, non-`ENOENT`/`ELOOP` -journal open/stat/read failures escape initialization as raw native errors, including -configured path and OS diagnostic. Second, database or journal primary failure plus -temp-unlink failure suppresses the cleanup fault; a database temp can retain the -complete serialized state with no tracking/restart reconciliation, and repetitions -can accumulate sensitive artifacts. Existing tests have no unlink fault checkpoint -or native read-fault rows. These are recorded as `TST-21`; no F-06 product commit was -pushed to `mock-main`, and no full/hosted gate or live/model/UI call was claimed. - -## 2026-08-30 — TST-20 audited; F-05 final stability restored - -Exact test-only `cdcfa95` passed Auditor row stress 30/30, service/store 56/56, -strict test types and literal `npm run check` (launcher 3/3, Server 676 passed plus -two opt-in skips, Web 17/17, both builds). Rejection observation attaches before the -gates; unconditional `finally` releases and joins the blocked backend checkpoint, -then a test-owned store mutation drains the persistence queue before teardown. No -setImmediate, sleep, retry, timeout increase, suppression, cleanup catch, assertion -weakening or product edit exists. Hosted Node 22 implementation run `33282600354` -passed. F-05/TST18/19 scoped 100% is restored pending the final docs-head hosted gate. - -## 2026-08-30 — TST-20 Fixer candidate - -The hosted RED returned from the test while its released backend checkpoint and store -queue were not owned through teardown. The test-only correction attaches Mission -rejection observation immediately, always releases and joins the exact backend -checkpoint lifecycle, and then awaits a test-owned no-op `store.mutate` sentinel. -The prior `setImmediate` timing assumption is removed. The exact fail-fast/no-sibling- -verifier/state/no-promotion row passed 20/20 locally; hosted Auditor evidence remains -pending. No product, timeout, retry, cleanup suppression or assertion change was made. -The service/store slice passed 56/56 and two literal local gates each passed launcher -3/3, Server 676 passed plus two opt-in skips, Web 17/17 and both builds. - -## 2026-08-30 — F-05 implementation green; final hosted blocked by TST-20 - -Implementation hosted run `33281977834` passed exact `f8d7f71`. Final docs-head run -`33282108035` failed with an unhandled `JsonStore.persist` rename ENOENT beneath the -case root for service test `does not invoke a sibling verifier after infrastructure -terminalization`. The fail-fast Mission promise had returned, the test released its -blocked sibling and waited only one event-loop turn, and teardown removed the root -while late sibling/store persistence remained active. Exact targeted candidate- -cleanup repeats 10/10 did not reproduce the earlier local contention symptom; this -hosted failure is preserved separately as TST-20. F-05/TST18/19 product/security -evidence remains green, but final hosted I and scoped 100% are withdrawn until the -test owns and joins the exact sibling lifecycle. No retry was used. - -## 2026-08-30 — F-05 / TST-18–19 audited and integrated - -Exact `f8d7f71` passed the 28-case real-Git suite five consecutive times (140/140), -combined Git/service 72/72, adjacent API/store/state/recovery/executor/verifier -133/133, and literal `npm run check` (launcher 3/3, Server 676 passed plus two opt-in -skips, Web 17/17, both builds). The nine-case identity/cleanup matrix proves clean -ordinary conflict restoration and zero-mutation rejection for detached, sibling- -branch, moved-head, dirty and preexisting-MERGE_HEAD states; target/source refs, -status, MERGE metadata, protected HEAD/canary and downstream state remain unchanged. -Cleanup uncertainty persists bounded attention evidence and cancel→reset exact -resource removal. Independent security review found no High/Medium issue. Hosted -Node 22 run `33281977834` passed. The Low same-host multi-command TOCTOU residual is -documented; no live/model/UI call ran. - -## 2026-08-30 — TST-19 Fixer candidate - -The source-confirmed RED allowed a clean integration checkout on the wrong persisted -branch/head to reach `git merge`. The candidate passes the persisted Plane branch and -head into the Git boundary and, before mutation, proves no `MERGE_HEAD`, clean -porcelain, the exact symbolic branch and exact HEAD. Real-Git rows for detached HEAD, -sibling branch at the same OID, moved head, dirty worktree and preexisting MERGE_HEAD -all return the fixed cause-free cleanup boundary while preserving integration -HEAD/status/all head refs, exact `MERGE_HEAD` metadata and source HEAD. The existing service maps this typed result -to failed integration Plane plus active-project Mission attention, with released -Agents and no candidate/promotion. Independent review reported 0 High / 0 Medium; -the remaining Low local-host TOCTOU window requires an actor with independent write -access and is not a new privilege boundary. Auditor integration remains pending. -Focused identity rows passed 25/25 across five repeats, combined conflict/identity -passed 9/9, and adjacent Git/service/recovery passed 72/72. Two literal final -`npm run check` gates each passed launcher 3/3, Server 676 passed plus two opt-in -skips, Web 17/17 and both builds. - -## 2026-08-30 — TST-18 passes locally; F-05 blocked by TST-19 - -Auditor replayed exact `53c8415`. Focused Git/service passed 67/67; the two service -conflict rows repeated 10/10 invocations (20/20 cases), and adjacent API/store/state/ -recovery/executor/verifier passed 133/133. Enumeration, abort and post-inspection -cleanup rows are fixed/cause-free; ordinary conflict proves absent MERGE_HEAD, clean -status, exact observed pre-head and persisted branch. The attention path retains -truthful cleanup state; an ephemeral cancel-then-reset check removed its exact retained -Plane successfully. The earlier scheduling symptom did not reproduce in 10/10 focused -candidate-cleanup repeats; however one literal full run later failed that pre-existing -candidate-cleanup assertion under contention, so no global-stability claim is made. - -Independent security review found a distinct Medium precondition defect: expected -Plane branch/head are compared only after conflict cleanup, not before merge mutation. -A clean worktree switched to another branch/head can be mutated first. TST-19 requires -pre-mutation identity proof. The candidate was not pushed to `mock-main`. - -## 2026-08-30 — TST-18 Fixer candidate - -The preserved implementation RED showed conflict enumeration/path validation before -abort, accepted abort exit 128, and no combined proof of absent `MERGE_HEAD`, clean -status and unchanged integration HEAD. The candidate makes abort mandatory, validates -and caps paths only afterward, and requires all three post-abort facts. Injected real -conflict rows cover enumeration, abort and inspection failures: each returns the fixed -cause-free cleanup boundary; enumeration/inspection faults leave a clean worktree, -while abort failure truthfully leaves it dirty for operator recovery. The service -persists `git_conflict/integration_cleanup`, a failed integration Plane and an -`attention_required` Mission with active project, verified Contracts, released Agents, -no collision/candidate/promotion and no planted diagnostics. Auditor integration is -still pending. Focused conflict rows passed 4/4, service clean/attention rows 2/2, -and adjacent Git/service/recovery passed 67/67. The final literal `npm run check` -passed launcher 3/3, Server 671 passed plus two opt-in skips, Web 17/17 and both -builds. `npm audit --omit=dev` reported zero vulnerabilities. A read-only security -fallback's initial Medium branch-integrity finding was corrected by also proving the -persisted symbolic branch. Final read-only re-review reported 0 High / 0 Medium and -passed the scoped security boundary. - -## 2026-08-30 — F-05 integration blocked by TST-18 merge-abort precedence - -Candidate `0208713` was replayed onto canonical F-04 docs as `a7b669b`. Auditor -passed ordinary real conflict/path gates 3/3: the ten-file add/add Mission retained a -clean failed integration Plane, bounded count 10 / preview cap 8 / path length 48, -verified Contracts, released Agents, protected HEAD/canary, no candidates/promotion, -reload/API evidence and explicit reset removal; the lower real-Git conflict stayed -clean. No candidate-owned test artifact remained. - -An independent cleanup-double-fault injected a planted exception specifically at -`merge abort` after the real conflict was detected. The exact test reproduced 1/1: -`mergePlane` rejected with the planted raw abort diagnostic instead of returning the -validated conflict, proving original-conflict precedence and clean-retention claims -are not closed. Independent security review additionally found conflict enumeration -and path validation occur before abort, exit 128 is accepted without checking cleanup, -and post-merge inspection does not assert clean/head state. Temporary audit -instrumentation was removed. TST-18 requires a mandatory abort/restore boundary, -bounded primary conflict and truthful cleanup state; F-05 was not pushed to -`mock-main`. - -## 2026-08-30 — F-04 / TST-17 audited and integrated - -Exact implementation `2cef988` passed Auditor focused creation/unwind/double-fault -3/3, real Git 20/20, adjacent service/executor/container/recovery/store/API/state/ -verifier 174/174, and literal `npm run check` (launcher 3/3, Server 665 passed plus -two opt-in skips, Web 17/17, both builds). Successful unwind removes only exact -current-batch durable Plane associations, worktrees and branches; cleanup failure -truthfully retains a failed Plane and interrupted Contract under bounded -`plane_unwind` evidence while Mission keeps the primary `plane_creation` failure. -Agents release, active-project and protected-head invariants hold, and no downstream -work runs. Independent security fallback found no High/Medium issue. Hosted Node 22 -run `33280187821` passed. F-04 and TST-17 are audited scoped 100%. The Low partial- -teardown injection granularity limitation is documented; no live/model/UI call ran. - -## 2026-08-30 — TST-17 transactional initial Plane unwind candidate - -The Fixer preserved the second-of-two RED from `5cc24f5`: one durable ready Plane, -Contract association, worktree and branch survived after the sibling creation failed. -Candidate `fix/f04-plane-unwind` now tracks only Planes successfully created by that -initial batch and destroys them through `PlaneManager` in reverse order before -removing their exact durable records and Contract associations. The original failed -Contract and Mission remain `worktree_creation_failure` / `plane_creation`; Agents -and the terminal Mission's project are released. No downstream executor, verifier, -integration, collision, candidate or promotion path runs, and protected HEAD plus an -outside canary remain unchanged across reload. - -A cleanup double-fault retains the exact failed Plane and interrupted Contract, -releases all Agents, and transitions the Mission to existing nonterminal -`attention_required` / `plane_unwind_failed` while retaining the project as required -by the active-Mission invariant. Fixed cleanup evidence is -`worktree_creation_failure` / `plane_unwind`; it does not claim F-06's reserved -`persistence_error`. Raw cleanup secret/path/OS diagnostics do not reach durable, -reload or public DTO surfaces. Causal rows passed 2/2, service plus real-Git 61/61, -security/F-01/recovery/API adjacency 186/186, strict test types and two literal -checks passed (each: launcher 3/3, Server 665 plus two opt-in skips, Web 17/17 and -both builds). Independent security review found no High/Medium issue; explicit -reload-state and non-busy Agent assertions address its actionable Low notes. No -UI/live/model call ran. Auditor integration remains pending. - -## 2026-08-30 — F-04 integration blocked by TST-17 batch unwind - -The Auditor rebased candidate `d988292` onto canonical docs as `5cc24f5` and -independently passed the focused Contract failure 1/1, real partial-Git rollback 1/1, -both changed suites 59/59, and adjacent executor/container/recovery/store/API/state -125/125. The real-Git case removes the partial worktree and Shepherd branch while -preserving protected HEAD/canary; bounded public failure and candidate-owned temp -cleanup passed. No other-agent artifact was removed. - -A causal second-of-two creation injection failed 1/1: after Plane 1 succeeded and -Plane 2 failed, Mission state was failed but one durable `ready` Plane, its Contract -association, worktree and branch remained. Source tracing confirmed no batch unwind -in `executePreparedMission` or `recordMissionFailure`. Independent security fallback -classified this Medium. The temporary audit test was removed after preserving the -RED; product candidate was not pushed to `mock-main`. TST-17 requires exact -batch-owned durable and physical cleanup without weakening the first-call behavior. - -## 2026-08-30 — F-01/02 and TST-13–16 independently audited and integrated - -Exact implementation `83cc1d0` was pushed to `mock-main`. Auditor verification -passed executor 67/67, combined runner/executor/service 127/127, adjacent API/store/ -container/state/recovery/verifier 66/66, and literal `npm run check` (launcher 3/3, -Server 661 passed plus two explicit opt-in skips, Web 17/17, both builds). Manual -inspection matched all 47 executor-owned filesystem/config expressions to a closed -boundary and all 31 injected call-site/double-fault rows. Independent security -fallback returned READY with no High/Medium issue. Secret/artifact/diff scans were -clean apart from documented placeholders and test canaries. Hosted Node 22 run -`33278994572` is the implementation integration gate. No external/model/UI call ran. -The Low restart-invalid-sentinel residual remains fail-closed and may require manual -operator cleanup; cross-process retry is not claimed. - -## 2026-08-30 — TST-16 complete filesystem boundary candidate - -The Fixer candidate `fix/f-01-02-filesystem-boundary` closes the remaining raw -executor-owned filesystem/config paths with fixed stages for private-root -preparation, private-home and preflight-workspace reconciliation, preflight setup -and execution setup. It preserves existing fixed policy/invariant errors, -containment/symlink checks, typed runtime/cancellation behavior and exact cleanup -precedence; raw native errors are not attached as causes or durable fields. - -The causal matrix injects 31 filesystem/config call-site failures across all stages -failures and proves bounded stage/reason output, exact retained-target cleanup and -retry, including distinct canonical roots/workspace and sentinel handle/post-create -edges. TST-15 retains complementary open/handle/unlink/rm coverage. A frozen source -inventory tracks 47 executor filesystem/config expressions. Contract and candidate tests scan -Error/cause/stack/inspect, console, store/reload, Mission/Contract/Plane/Agent/event, -public DTO and real HTTP response surfaces with opaque, secret, path, errno and OS -canaries; no candidate promotes or moves protected head. Executor 55/55, adjacent -runtime/service/config/verifier 141/141, strict test typecheck and the first literal -`npm run check` passed (launcher 3/3, Server 649 plus two explicit opt-in skips, Web -17/17 and both builds). After the first security review identified missing distinct -call-site evidence, the matrix expanded to 31 rows and the inventory to all 47 calls; -focused 67/67, adjacent 154/154 and two corrected literal checks passed (each: -launcher 3/3, Server 661 plus two skips, Web 17/17 and both builds). Independent -security re-review found no remaining material -issue. No model/live/UI call ran. Independent Auditor integration remains pending. -The existing Low restart-only invalid-sentinel manual-cleanup -residual remains fail-closed and is not claimed as cross-process automatic recovery. - -## 2026-08-30 — TST-15 passes; F-01/02 blocked by complete TST-16 boundary - -The Auditor reviewed exact unintegrated chain `8c7cfc1`. Focused runner/executor/ -service passed 93/93 and API/store/container-service/state-machine/recovery/verifier -adjacency passed 66/66. TST-15's sentinel open/close/unlink and exact interrupted- -artifact rm fault matrix, bounded double-fault precedence, same-process pending- -unlink retry, retained cleanup target and containment behavior passed. - -The mandated full-source review found remaining Medium raw filesystem/config paths: -private-root preparation, reconciliation enumeration, preflight setup and execution -setup still call mkdir/mkdtemp/lstat/readdir/realpath/chmod/config write outside the -closed boundary. These can expose raw startup inspection or persist as unknown -Contract/candidate failures. The chain was not pushed to `mock-main`; broad checks -stopped after the causal boundary was established. TST-16 must complete the fixed -stage policy and fault matrix. A process restart after both sentinel adoption and -unlink failure remains fail-closed but may require operator cleanup; this is a -documented Low availability residual, not a PRD trust-boundary bypass. - -## 2026-08-30 — TST-14 passes; F-01/02 blocked by TST-15 cleanup family - -The Auditor reviewed exact unintegrated chain `3afc452`. Focused runner/executor/ -service passed 81/81; API/store/container-service/state-machine/recovery/verifier -adjacency passed 66/66; literal `npm run check` passed launcher 3/3, Server 615/615 -plus two explicit opt-in skips, Web 17/17, strict test/source types and both builds. -TST-14's success/cancel/timeout/execution precedence, fixed cleanup-only failure, -retained-home reconciliation, retry, Contract/candidate durable/public/Fastify HTTP/ -log canary exclusion and no-promotion/head-move behavior passed. No external call ran. - -The required exhaustive executor review found one remaining Medium cleanup family: -sentinel open carries raw cause; sentinel validation/adoption close can override -bounded primary errors; failed adoption unlink is swallowed; and interrupted-home/ -preflight-workspace reconciliation rm failures escape raw. These paths lack causal -fault coverage. The chain was not pushed to `mock-main`; TST-15 requires fixed -bounded precedence, actionable retained-artifact retry and clean startup/log Error -surfaces before integration. - -## 2026-08-30 — F-01/02 + TST-13 remain blocked by TST-14 cleanup path - -The Auditor reviewed exact corrected chain `c7b5175`. Focused runner/executor/ -service passed 75/75; API/store/container-service/state-machine/recovery/verifier -adjacency passed 66/66; literal `npm run check` passed launcher 3/3, Server 609/609 -plus two explicit opt-in skips, Web 17/17, strict test/source types and both builds. -TST-13 successfully bounded parsed stdout/stderr, create/start/spawn/container- -cleanup and hostile typed fields across Contract and candidate durable/public paths; -candidate failure retained attention/no-promotion/protected-head behavior. No -live/model/UI call ran. - -Independent exhaustive security fallback found a separate Medium defect: executor -execution-private-home `rm()` runs directly in `finally`. Its raw exception can -leak path/OS detail and override typed timeout/execution or cancellation identity. -That path is not covered by TST-12 preflight or runner container cleanup tests. The -chain was not pushed to `mock-main`; TST-14 requires bounded cleanup precedence and -opaque-canary durable/public regression coverage before integration. - -## 2026-08-30 — F-01/02 integration blocked by TST-13 stderr exposure - -The Auditor reviewed exact unintegrated candidate `685e4ff`. Focused runner, -executor and service passed 72/72; API/store/container-service/state-machine/ -recovery/verifier adjacency passed 66/66; literal `npm run check` passed launcher -3/3, Server 606/606 plus two explicit opt-in skips, Web 17/17, strict test/source -types and both builds. Typed timeout/execution identity, untyped unknown, -cancellation precedence, durable state codes, ownership release and no-promotion -behavior were correct. No live/model/UI call ran. - -Independent security fallback found one Medium defect: arbitrary parsed Runtime -error/stderr remains in `RuntimeExecutionError.message`; bounded secret/path -redaction does not remove opaque attacker/runtime-controlled text, which is then -persisted and publicly exposed through Contract, Plane, Mission, Agent, event, -reload and DTO surfaces. F-01/02 was not pushed to `mock-main`. TST-13 requires a -fixed public execution message plus a causal opaque-stderr canary across the full -runner → executor → service boundary before integration. - -## 2026-08-30 — OPS-06 diagnostics integrated; TST-12 audited - -The Auditor integrated exact corrected chain `68dbd59` into `mock-main`. Focused -runner/executor/config/service/live-runtime tests passed 95 with one explicit live -skip. Literal `npm run check` passed launcher 3/3, Server 602/602 plus two explicit -opt-in skips, Web 17/17, strict test/source types and both builds. Hosted Node 22 -required-check run `33274769957` passed. - -Independent security fallback returned READY with no finding. The planted cleanup -fault is absent from message, String, stack, deep inspection, JSON and cause -surfaces; private-home cleanup continues, the preflight cache resets and a clean -retry succeeds. Typed diagnostics, non-root/private-home/network/version gates, -output bound, secret exclusion and owner-scoped cleanup remain fail-closed. No -live/model call ran. TST-12 is closed at scoped 100%; OPS-06 has `T,A,C,S,I` -evidence, but affected collaborator/macOS `L` remains explicitly unverified and no -macOS compatibility claim is made. - -## 2026-08-30 — TST-12 executor preflight redaction candidate - -The Fixer reproduced the source-confirmed Medium leak on exact Auditor evidence -`ed3ceb6`: an injected cleanup failure containing planted secret, private macOS -path and OS diagnostic text emerged unchanged as the uncaught executor preflight -rejection's `Error.cause`. Inspection-capable startup handling could therefore -expose detail despite the fixed outer message. - -The minimal executor correction removes the raw cause and rejects with only -`Live Shepherd Runtime preflight failed (stage=cleanup reason=cleanup_failed)`. -The causal regression checks the Error message, String conversion, stack, -`util.inspect`, JSON serialization and cause inspection; none contains the planted -detail. Cleanup remains fail-closed, both mount removals are still attempted, the -cached failure permits a bounded retry, and the existing primary container-start -stage/reason assertion is unchanged. No runner mapping, non-root/read-only-home, -socket-denial, exact-version, output-cap, owner cleanup, fallback, UI or dependency -behavior changed. - -Focused cleanup/primary rows passed 3/3. Adjacent config, runner, executor, service -and live-runtime coverage passed 95 tests plus one explicit opt-in skip. Strict -Server test typecheck passed. Two literal `npm run check` gates each passed launcher -3/3, Server 602/602 plus two opt-in skips, Web 17/17, strict types and both builds. -Dependency, diff, credential and artifact/root scans were clean. No live, model or -external request ran. Independent security fallback passed executor/runner 34/34 -and strict test typecheck with no High, Medium or Low finding. Affected-macOS -validation and hosted Auditor integration remain required before OPS-06 is audited. - -## 2026-08-30 — OPS-06 integration blocked by TST-12 security finding - -The Auditor rebased candidate `5a1aef9` onto audited `mock-main` as local -`34477e8`. Focused runner/executor tests passed 186/186 and literal `npm run check` -passed launcher 3/3, Server 601/601 plus two explicit opt-in skips, Web 17/17, -strict test/source types and both builds. No live/model request ran. - -Configured `security-reviewer` was unavailable; independent read-only fallback -found one Medium defect. Executor-side preflight mount cleanup attaches raw -`cleanupError` as `Error.cause`; an uncaught startup failure may render a private -path or OS detail even though runner stage/reason diagnostics are closed enums. -The remaining typed mapping, fail-closed sandbox/private-home/non-root/version -gates, output cap, raw stderr discard and owner-scoped cleanup were READY. OPS-06 -was not pushed to `mock-main`; TST-12 requires a fixed bounded executor cleanup -error and planted-path causal regression before integration or macOS validation. - -## 2026-08-30 — OPS-06 bounded live-preflight diagnostics candidate - -The Fixer source-traced the macOS message loss without a live/model request: -`ContainerCodexRunner.isEphemeralAvailable` caught create/start/output/cleanup -failures into one boolean. The candidate uses a closed typed result limited to safe -stage/reason enums. Explicit exits distinguish non-root, private-home denial, -Codex-version and sandbox listen/connect/generic probe classes; unknown engine -failures discard raw content. No path, command, secret, endpoint, prompt, stderr or -fallback is exposed. - -All original gates remain mandatory: non-root, read-only root with bounded tmpfs, -writable workspace, denied private-home write, denied listen/connect, exact version, -bounded output, success marker and owner-scoped cleanup. Cleanup failure overrides -success. Runner/executor tests passed 33/33; config/runner/executor/service/default- -live adjacency passed 87 plus one opt-in skip; production/strict Server typechecks -passed. Independent security review found no issue; its mapping/cleanup coverage -note was closed with final table and cleanup regressions. Two final literal checks -passed: launcher 3/3, Server 601/601 with two opt-in live skips, Web 17/17, strict -test projects and both builds. Diff, credential, dependency and artifact scans -passed before commit. - -No live/model call ran. Mocked Linux/engine evidence is not affected-macOS evidence: -macOS validation and Auditor integration remain pending, with no compatibility -bypass or full OPS-06 claim. - -## 2026-08-30 — E2E-02, TST-10 and TST-11 independently audited - -The Auditor integrated exact corrected chain `338f1e4` into `mock-main` only after -four focused real-backend deterministic journeys passed. Harness units passed -14/14 across those invocations; all 52 screenshot observations were reviewed; -13/13 named claims were visibly supported at both 1280x800 and 1440x900; and all -26 final hashes were unique. Exact stages 06, 09, 10 and 11 visibly showed -promotion start, selected Candidate evidence, distinct final re-verification and -rejected Candidate evidence with positive pane/drawer/browser intersection. - -Full harness passed unit 7/7 plus Chromium 12/12. Literal `npm run check` passed -launcher 3/3, Server 592/592 plus two explicit opt-in skips, Web 17/17, strict -test/source types and both builds. Independent rendered/security fallback returned -READY with no finding; no production UI/CSS, live/model/network request, secret, -private path, residual process/root or tracked artifact was introduced. Hosted -Node 22 required-check run `33273947769` passed on the integrated implementation. -This closes only E2E-02/TST-10/TST-11; `GC-06` and `UI-02` remain unclaimed. - -## 2026-08-30 — TST-11 visible drawer-evidence candidate - -The Fixer reproduced the Auditor's four visual REDs on exact parent `041521b`: -stages 09 and 11 at both viewports showed Plane metadata while their named selected -or rejected Candidate verification summaries remained below the internally -scrolling drawer. DOM text assertions alone did not prove screenshot visibility. - -The test-only correction scrolls each exact evidence summary inside -`.detail-drawer`, asserts positive intersection with both the drawer content -viewport and browser viewport, and then requires that marker visibly present before -capture. It preserves stage 10's ArrowRight/focus/selected final-promotion evidence, -TST-10's promotion-event visibility, Escape/opener focus, and all functional and -security assertions. No production, frontend, CSS, theme, timeout, retry, sleep, -dependency, live or model behavior changed. - -Two focused invocations passed both viewports (4/4 journeys; 52 capture -observations). Manual review of every final image confirmed all 13 named semantic -claims visibly present at both viewports, and all 26 PNGs had unique hashes. Full -harness passed unit 7/7 and Chromium 12/12. Two literal `npm run check` gates each -passed launcher 3/3, Server 592/592 plus two explicit opt-in skips, Web 17/17, -strict server/web test typechecks and both builds. Dependency, cleanup, ignored -artifact, bounded-output, diff and visual-theme review were clean. No external, -live, model or network request ran. Independent hosted Auditor integration remains -required before TST-11 or E2E-02 can be called audited. - -## 2026-08-30 — E2E-02 remains blocked by TST-11 drawer evidence - -The Auditor independently verified TST-10 on exact corrected chain `79da51a`: -two focused invocations passed harness unit 14/14 and Chromium 4/4; each corpus had -26/26 unique hashes; stage 05/06 differed at both viewports; and promotion start -was visibly intersecting the Contract pane. All 52 captures were inspected. Full -harness passed unit 7/7 plus Chromium 12/12. Literal `npm run check` passed launcher -3/3, Server 592/592 plus two explicit opt-in skips, Web 17/17, strict types and -builds. Dependency audit, diff, ignored-artifact, process/root cleanup, UI and -security scans were clean. No live/model/network request ran. - -Before integration, a second independent exhaustive semantic manifest review found -`TST-11`: stage 09 selected-candidate evidence and stage 11 rejected-candidate -evidence show only Plane header/metadata at both 1280x800 and 1440x900. Their DOM -text exists below the internally scrolling drawer but is not in the capture. The -other eleven stage markers are visibly supported in both viewports, and all hashes -are distinct. The minimal correction is test-only scrolling plus drawer/browser -intersection proof for the exact candidate-evidence region before stages 09/11; -stage 10 final evidence and TST-10 must remain intact. Candidate `79da51a` was not -pushed to `mock-main`; E2E-02 and hosted integration remain blocked. - -## 2026-08-30 — TST-10 visible promotion-stage candidate - -The Fixer reproduced the preserved E2E-02 visual RED on the exact candidate plus -Auditor evidence: stage 05 and stage 06 were byte-identical at both 1280x800 and -1440x900. The DOM assertion located a promotion-start event below the internally -scrolling Contract pane, so it did not establish visible screenshot evidence. - -The test-only correction selects the exact persisted `promotion_started` event, -scrolls that card into `.event-list`, asserts positive intersection with both the -pane and browser viewport, and compares the written stage-05/stage-06 PNG bytes. -No production, frontend, CSS, theme, timeout, retry, sleep or dependency changed. - -Two corrected focused invocations passed both viewports (4/4), yielding 52 capture -observations. The final 26-file corpus had 26 distinct hashes and every image was -manually inspected; stage 06 visibly shows “Started final authority and independent -verification gate,” while stage 05 remains a distinct candidate-outcome view. Full -harness passed unit 7/7 and Chromium 12/12. Strict test typecheck and two literal -`npm run check` gates passed, each with launcher 3/3, Server 592/592 plus two -explicit opt-in skips, Web 17/17, strict types and both builds. Dependency, -cleanup, ignored-artifact, bounded-output, diff and visual-theme reviews were clean. -No live/model/network request ran. Independent hosted Auditor integration remains -required before TST-10 or E2E-02 can be called audited. - -## 2026-08-30 — E2E-02 candidate audit blocked by TST-10 visual evidence - -The Auditor reviewed exact candidate -`85550e0a6c6c8f2263375943b22271d72c814c05` without pushing it to -`mock-main`. Its diff is five test/harness/docs files (+420/-2) and contains no -production or UI change. Two focused invocations passed harness unit 14/14 and -Chromium 4/4 across 1280x800 and 1440x900. Full harness passed unit 7/7 plus -Chromium 12/12. Literal `npm run check` passed launcher 3/3, Server 592/592 plus -two explicit opt-in skips, Web 17/17, strict typechecks and both builds; dependency -audit reported zero vulnerabilities. API/Git/store assertions prove the immutable -base, two verified Contracts, exact semantic collision, cookie selection, bearer -rejection, distinct final evidence, protected-main output, preserved loser, -Shepherd-authored Project Group lifecycle, 401 boundary, no network/model use, -source/outside-canary safety and exact reset/process/port/container/root cleanup. - -Independent review found `TST-10`: stage 05 and stage 06 are byte-identical at -both viewports (1280 hash `66159d4f...`; 1440 hash `f35e34c3...`). Although the DOM -assertion proves the promotion-start event exists, it is below the internally -scrollable contract pane and is absent from the named stage-06 capture. Therefore -only 24/26 screenshots are distinct, and “13 material stages” is not yet supported -visually. The minimal correction is confined to scrolling and intersection-proof -inside `shepherd-hero.spec.mjs`; no product/UI/theme change, wait inflation or -assertion weakening is authorized. E2E-02 remains blocked and unintegrated. No -live/model request ran. - -## 2026-08-30 — UI-04 and verifier fixture integrated audit - -The Auditor integrated the bounded verifier fixture, UI-04 frontend correction and -explicit keyboard audit at `412a010`. Independent gates passed: fixture/harness -7/7, Web 17/17, focused Chromium 2/2 twice, full Chromium 10/10 at 1280x800 and -1440x900, and literal `npm run check` with launcher 3/3, Server 592/592 plus two -opt-in skips, Web 17/17, strict types and builds. Screenshots showed the final -promotion marker under the promotion event and distinct candidate/final drawer -tabs without overflow/theme drift. Tab, Space, arrows, Home, End, Enter, Escape, -focus-visible and opener restoration passed. Planted private fields stayed absent -from API/DOM/store/log surfaces. - -The fixture accepts only the exact independent-verifier create/start/rm/ps -protocol and validates network-none, readonly/non-root/capability/resource/tmpfs/ -environment/check allowlists with bounded output and cleanup. It introduces no -production debug or live path. Configured custom security/UI reviewer roles were -unavailable; independent manual fallbacks found no material issue. Dependency and -artifact scans were clean. Hosted Required checks run `33271397185` passed. UI-04 -is audited scoped 100; the fixture prerequisite is integrated, while E2E-02 remains -incomplete and ready for Worker continuation. No live/model call ran. - -## 2026-08-30 — UI-04 truthful promotion evidence candidate - -The Fixer preserved the API/DOM RED, then changed only Shepherd frontend, scoped -styles and tests. Completed promotion events now bind final promotion -re-verification evidence; candidate events retain candidate verification and a -promotion-started event cannot imply final evidence exists. The Resolution Plane -drawer exposes both safe stages through the existing compact filter visual language -with candidate default and one/none fallback. Roving tab focus, arrows/Home/End, -Tab/Enter/Space, focus-visible, drawer initial focus, Escape close, opener restore, -plane reset and drawer-local scrolling are covered. No backend/schema/API/model -authority or live behavior changed. - -Observed local gates: - -- causal Web helper/component 4/4 and full Web 17/17; -- harness unit 7/7; focused Chromium 2/2 and full deterministic Chromium 10/10 - across 1280x800 and 1440x900; -- both final screenshots visually preserved the Launchpad theme/layout with zero - document/body X/Y overflow and readable candidate/final labels; -- planted private evidence ID/stdout/stderr/error values remained absent from body - text and serialized DOM; public API private-field and store/log route-marker scans - passed; -- strict test projects, Web build, and two final literal `npm run check` passes: - launcher 3/3, Server 592/592 with two opt-in live skips, Web 17/17 and both builds; -- independent UI and security re-reviews passed with no remaining finding after - roving tabs, drawer focus lifecycle and inactive-tab contrast were corrected. - -No live/model request ran. Auditor integration/hosted evidence remains pending; -UI-04 is not audited and broader E2E-02 remains incomplete. - -## 2026-08-30 — UI-04 promotion evidence misbinding reproduced - -After final hosted run `33270319210` passed on `3846591`, the Auditor rebased the -bounded fake-container verifier fixture onto an isolated ownership branch and ran -a fresh 1280x800 browser/API reproduction. The real completed candidate contained -distinct verification and promotion evidence IDs. A route-scoped public-response -decoration assigned safe distinct summaries; expanding the real -`promotion_completed` event displayed the verification marker and omitted the -promotion marker. Screenshot inspection confirmed the wrong evidence under the -promotion card without unrelated theme/layout damage. Source inspection confirms -the same unconditional verification selection in `EventEvidence` and -`PlaneDetailDrawer`. Product code was not changed; UI-04 is ready for a minimal UI -selection fix and two-viewport regression. - -## 2026-08-30 — MR-01/MR-03/TST-08/TST-09 integrated audit - -Auditor gates passed at `35ec268`: config 27/27 plus one default live skip, -TST-08 returned 20/20 and paired 40/40, reviewer/service/config 165/165, harness -unit 6/6 and Chromium 8/8, and literal check with launcher 3/3, Server 592/592 -plus two opt-in skips, Web 13/13, strict types and builds. Audit reported zero -vulnerabilities; diff, credential, snapshot and artifact scans were clean. - -The corrected explicit live command was command attempt two overall but made the -only external reviewer request (1/1); the earlier attempt made zero. Bounded result: -`completed findings=2`. The test proved exactly one advisory event, unchanged -deterministic collision/winner/promotion, exact promoted HEAD, store/state secret -absence and live-root cleanup. The 21-byte ignored outcome file was read once and -removed. Hosted Required checks run `33270168480` passed. LIVE-01's reviewer -component is satisfied; its current live Shepherd Mission remains open. - -## 2026-08-30 — TST-09 reviewer-only environment isolation candidate - -Without making another live request, the Fixer corrected only the reviewer live -test and causal config coverage. The test now calls `loadConfig` with a clone of -the real process environment whose sole override is loopback `HOST`. This isolated -test never starts HTTP; actual Ark credentials/model/base URL, SHEPHERD model -resolution, all other configuration, the production reviewer predicate and -sensitive-value filter, and fatal authentication/configuration handling remain -unchanged. The source environment and ignored `.env` are not mutated. - -Observed local gates: - -- causal config plus default-skipped live file: 27 passed, one live test skipped; - the package script still has both opt-in gates, exact test path, one worker, - `bail=1` and retry 0; -- TST-08 exact row 20/20 and paired infrastructure rows 40/40; -- MR-03 reviewer/service/config matrix 165/165 and strict Server test typecheck; -- two literal `npm run check` passes: launcher 3/3, Server 592/592 with two - opt-in live skips, Web 13/13, strict test projects and both builds. - -External reviewer/model/network calls by the Fixer remain **0**. Independent -read-only security review passed with no finding; diff, dependency, credential and -live-artifact scans also passed. Auditor integration and the one explicitly -authorized live gate remain pending; this entry makes no audited or 100% claim. - -## 2026-08-30 — TST-09: MR-03 live gate blocked before egress - -The Auditor independently passed the TST-08 returned row 20/20, paired -infrastructure rows 40/40, MR-03 reviewer/service/config 164/164, adjacent 100/100, -harness unit 6/6 and Chromium 8/8, and literal `npm run check` (launcher 3/3, -Server 591/591 with two opt-in skips, Web 13/13, strict types and builds). Diff, -dependency, credential and exact snapshot-removal checks passed; MR-03 remains -schema/ref bounded and advisory-only. - -After every deterministic gate was green, the explicit live-review command was -invoked exactly once with retry disabled. It failed during `loadConfig`, before -reviewer construction or network egress, because the local non-loopback runtime's -`APP_AUTH_TOKEN` was a placeholder/too short. External reviewer call count was -therefore **0**. No retry was made, no live root remained, and no secret or raw -configuration value was printed. MR-01/MR-03 `L` and integration remain open. - -## 2026-08-30 — TST-08 returned-evidence teardown quiescence candidate - -The Fixer preserved the literal-gate RED and isolated 20/20 scheduling evidence, -then changed only the returned-infrastructure test fixture. It now coordinates both -Contract arrivals, attaches the Mission rejection observer immediately, captures -and validates the exact contained sibling `VerificationRequest.planePath`, proves -rejection precedes removal, arms an exact-basename watcher before release, and -joins the sibling, Mission and removal in `finally`. This closes the fixture's -background-work gap without changing production, MR-03, the cleanup walker, -timeouts, retry behavior or assertions. No live/model request ran. - -Observed local gates: - -- exact returned-infrastructure row 20/20 and paired thrown/returned rows 40/40; -- MR-03 reviewer/service/config matrix 164/164; -- service/container/API/store/recovery adjacency 82/82; -- strict Server test-source typecheck; -- two literal `npm run check` passes: launcher 3/3, Server 591/591 with two - opt-in live skips, Web 13/13, strict test-source projects and both builds; -- diff, credential and stale trusted-snapshot cleanup scans passed. Auditor - integration/hosted evidence and MR-03's single bounded live gate remain pending, - so this entry makes no audited or 100% claim. - -## 2026-08-30 — MR-03 integration blocked by TST-08 - -MR-03 merged conflict-free locally as `3c878b3` but was not pushed to `mock-main`. -The focused reviewer/service/config matrix passed 164/164, adjacent service/API/ -store/F-03/recovery/container passed 100/100, and deterministic harness passed unit -6/6 plus Chromium 8/8. Literal `npm run check` then failed one of 591 executed -Server tests: returned Contract verification infrastructure evidence reached -teardown while a sibling exact trusted snapshot root was removed, producing -`makeDeletable -> realpath -> ENOENT`. The isolated row passed 1/1 and 20/20, -supporting a scheduling-dependent test coordination gap rather than an MR-03 -product regression. No live/model request ran (call count zero). Ownership was -published on `audit/tst-08-mr03-cleanup`; MR-03 integration/live remains blocked. - -## 2026-08-30 — MR-01/MR-02 integrated audit - -The Auditor integrated the controlled MR-01 merge and truthful MR-02 capability -correction on `mock-main` at `577255e6f4980499f032451d18557f8eefcf80ef`. -Independent local gates passed: reviewer/config/service 173/173, Settings 5/5, -adjacent service/API/store/recovery/state/container 100/100, harness unit 6/6 and -Chromium 8/8 at both required viewports. Four MR-02 screenshots were inspected: -configured and unavailable states preserve the accepted theme with no document -overflow or clipping. The literal repository gate passed launcher 3/3, Server -588/588 with two opt-in live skips, Web 13/13, both strict test typechecks and both -builds. Dependency audit reported zero vulnerabilities; credential/private-output -and tracked-artifact scans were clean. Configured reviewer roles were unavailable; -independent manual security/UI review found no material issue, consistent with the -candidate's prior independent fallbacks. Hosted Node 22 Required checks run -`33268567614` passed. No live/model call ran. MR-01 remains below final scoped 100 -until MR-03 and one bounded live reviewer gate; MR-02 is audited scoped 100. - -## 2026-08-30 — MR-02 truthful reviewer capability candidate - -The Fixer reproduced the no-reviewer mismatch before product edits: persisted -`modelReviewEnabled=true` rendered as an enabled “Run advisory” control and allowed -false/true PATCH even though production composed no reviewer. The candidate adds -one public `shepherdModelReviewConfigured` boolean, computed from the same -fail-closed startup predicate used by `index.ts`. Settings preserves the stored -preference but renders the existing native toggle disabled with explicit -**Unavailable** process-scoped copy when false; configured mode remains editable. -No credential, model, endpoint or failed-predicate reason is exposed, and no live -request ran. - -Observed local gates: - -- causal Server 12/12 and Settings component 5/5; -- reviewer/config/API adjacency 71/71 and harness unit 6/6; -- dedicated Chromium 2/2 at 1280x800 and 1440x900, proving zero PATCH while - unavailable, exactly two successful mouse/keyboard PATCHes while configured, - persisted state, disabled/status semantics, no overflow and no fixture secret in - persistence, DOM or logs; -- full deterministic Chromium 8/8; four screenshots under ignored `.tmp` were - visually inspected without theme/layout drift; -- strict Server/Web test typechecks, two literal `npm run check` passes, clean diff - and credential/root scans, and `npm audit` with zero vulnerabilities; -- independent read-only security review passed with no findings. The configured - UI reviewer role was unavailable; a read-only fallback UI review passed with no - Critical/High/Medium finding and only the non-blocking absence of stored-off - browser screenshots (covered by component tests). Auditor integration/hosted - evidence remains pending, so this entry makes no audited or 100% claim. - -## 2026-08-30 — MR-01 local audit and MR-02 reproduced blocker - -The Auditor published ownership branch `audit/mr-01-integration`, then merged -current `main` `403fc095b07d60e17de1cb3f82b4e16b6a778919` locally into -`mock-main` as `1422fd6` without pushing `mock-main`. The resulting tree exactly -matched the precomputed conflict-free merge tree `804aa74c`. It preserves the -audited F-03/TST/service work, strict Server/Web tests, E2E harness and both CI -workflows while adding MR-01's 14-file bounded reviewer composition. - -Line review confirmed that only verified Contracts contribute bounded trusted -objectives, ingested manifest summaries, valid corroborated claims, non-protected -changed files and committed diff summaries. Closed runtime validation restricts -result keys, enums, contract pairs and evidence references. The service consumes -no finding value: it records only sparse bounded advisory metadata, returns void, -then runs unchanged deterministic collision/candidate/winner/promotion logic. -Deadline and durable cancellation win over an abort-ignoring reviewer; configured -sensitive values are excluded/rejected. The independent security fallback found no -High/Medium issue and returned READY for this provider-free scope. Configured -`security-reviewer` was unavailable. MR-03 partial-finding behavior and the single -final live reviewer gate remain deliberately pending; no network/model call ran. - -Observed local gates: - -- model-reviewer adapter/schema/evidence/redaction, MR service 14-case matrix and - readiness config: 3 files, 161/161; -- Settings rendering: 1/1; API/store: 31/31; -- F-03/service/container-verifier/recovery/state-machine adjacency: 69/69; -- deterministic harness: Node 6/6 and Chromium 6/6; -- literal `npm run check`: launcher 3/3, Server 587/587 with two opt-in live files - skipped, Web 9/9, both strict test-source projects and both builds. - -The dedicated real-browser audit passed 2/2 at 1280x800 and 1440x900 for real -Tab/Enter/Space focus semantics, true→false→true PATCH persistence, advisory -degradation event visibility, exact viewport/document/body overflow, screenshots, -and absence of auth/private/raw-prompt text. It also reproduced MR-02 causally: -the real no-Ark process reports `arkConfigured=false` while persisted -`modelReviewEnabled=true`; Settings presents an enabled checked “Run advisory” -toggle with no unavailable/not-configured state, and both PATCHes succeed even -though production deliberately composes no reviewer. Therefore the preference -cannot cause a call or outcome and silence can look like “no findings.” - -MR-02 owns the minimal fix: preserve preference, expose only bounded server-derived -reviewer capability/operational truth, and reuse current Settings/event visuals. -Never expose/probe credentials, model IDs, endpoints, prompts or provider state in -the browser. MR-01 remains a passing provider-free local candidate, but is blocked -from `mock-main` integration and cannot claim `I` or `L` until MR-02 is corrected; -MR-03 should integrate before exactly one final sparse live review. - -## 2026-08-30 — deviations hard-ledger reconciliation - -The Auditor reconciled every section of `docs/DEVIATIONS.md` against the PRD, -current `mock-main`, exact tested evidence and the canonical task/defect ledgers. -Each item is now classified as a clarification, actual deviation, environment -limitation or permanent PRD scope statement, with explicit OPEN/PARTIAL/RESOLVED -status and existing task IDs. No new task ID was required. The correction prevents -backend-only or hosted-only evidence from closing browser/live/second-machine -requirements, identifies completed-Plane cleanup as an allowed future policy rather -than a shipped automatic cleaner, and makes every actual deviation completion- -blocking until its named gates pass. - -A fresh GitHub/ref audit also found PR #16 (`MR-01`) merged to current `main` as -`403fc095b07d60e17de1cb3f82b4e16b6a778919`; it is therefore no longer externally -held, but it is not yet an ancestor of `mock-main` and remains unaudited integration -work. Draft PR #25 (`MR-03`) remains the sole external hold. This was a read-only -ownership check; no product branch was merged and no live/model request was made. - -## 2026-08-30 — GC-01 and TST-07 integrated audit - -The Auditor merged current `main` `662a7e7` into the previously audited -`mock-main` line as merge `c834c39`, preserved every prior audited mock commit, -then integrated the test-ownership correction as `de3e631`. The effective product -change is the bounded GC-01 parser-safe mention helper and Project Group buttons; -TST-07 only moves the complete eight-case regression to Web ownership and adds -explicit Web Vitest/strict-test configuration plus root scripts and the matching -lockfile entries. Server JSX/rootDir, product authority, Shepherd lifecycle, CSS -and schemas are unchanged. Both CI workflows are retained: `required-checks.yml` -remains the stable push/PR/merge-queue Docker gate, while the main-sourced -`pull-request-checks.yml` is a narrower PR/merge-queue duplicate that should be -consolidated only as a separately owned CI task. - -Independent focused evidence passed: Web GC 8/8, full Web 9/9, Server group -routing 10/10, strict Server and Web test typechecks, `npm ci`, and `npm audit` -with zero vulnerabilities. The real browser protocol passed 2/2 at 1280x800 and -1440x900 for mouse and real Tab/Enter/Space activation, focus-visible and composer -refocus/caret, multiline preservation, safe/spaced/escaped/Unicode/NFKC/ID-fallback -mentions, exact 2,000 acceptance/2,001 unchanged rejection, in-flight native -disable/no duplicate submission, parser-exact Agent ID, zero document/body X/Y -overflow, and absence of the auth token/private run root in rendered text. The -top-of-page frame places the composer partly below the visible area when the -runtime banner is present; the accepted internal main-content scroll brings the -entire composer/helper/send control into both viewports with no overlap. This is -recorded honestly as a Low UI-GATE framing item, together with the mention button's -subtle disabled visual distinction; it is not a document-overflow or GC-01 blocker. -The configured `ui-reviewer` role was unavailable, so an independent read-only -fallback inspected both frames and the source. - -The full deterministic harness passed Node 6/6 and Chromium 6/6. Literal -`npm run check` passed launcher 3/3, Server 563/563 with one unchanged opt-in live -skip, Web 9/9, both strict test-source projects and both production builds. No -live/model call was made. Hosted Node 22 Required checks run -`33266624301` passed on `de3e631`. GC-01 and TST-07 are therefore independently -audited at scoped 100%; this does not claim GC-03/04 targeted lifecycle completion. - -## TST-07 correct Web test ownership candidate - -**Date:** 2026-08-30 (Asia/Singapore) -**Branch/base:** `fix/mock-main` from canonical blocker head `6e4e230` - -The Fixer reproduced the required strict RED exactly: Server test typecheck exited -2 with TS6142 for the imported Web TSX component and TS6059 for the Web formatter -outside Server `rootDir`. The cause was test packaging, not formatter/parser/UI -behavior. The complete eight-case GC-01 regression moved from Server to Web. Web -gained explicit Vitest and strict test-source configuration/scripts, while root -`test` and `typecheck` now execute both workspaces. The production component, -formatter, parser, Server JSX/rootDir and every assertion remain unchanged. - -Observed candidate evidence: - -- relocated Web regression 8/8 and adjacent Server group-routing 10/10 passed; -- strict Web and Server test-source checks passed; Web production typecheck/build - passed; -- literal `npm run check` passed twice: launcher 3/3, Server 563/563 plus one - unchanged opt-in live skip, Web 9/9, strict/production typechecks and both builds; -- `npm ci --ignore-scripts --dry-run` completed from the lockfile and `npm audit` - reported zero vulnerabilities; `git diff --check` passed; -- diff is limited to test relocation, Web/root test configuration and scripts, - lockfile, and TST-07/GC-01 evidence docs. Default tests remain model/network-free - with Web Vitest temp output under repo-local `.tmp/web-tests`. - -This is a candidate, not an audit/100% claim. GC-01 still requires independent -two-viewport browser interaction plus integrated/hosted gates; TST-07 `I` is pending. - -## TST-07 blocks current-main / GC-01 integration before push - -**Date:** 2026-08-30 (Asia/Singapore) -**Ownership branch:** `test/tst-07-gc-01-strict-typecheck` -**Local merge:** `c834c3907abe84fb0bd79250ac93c2bbf78c87c0` -**Source main:** `662a7e7d2f54cd7eb6e6f33aa761a1d06901f609` - -The Auditor real-merged current `origin/main` into audited `mock-main` head -`5469c1f` only on the dedicated ownership branch. All prior audited mock commits -remain ancestors and the effective main delta is GC-01, its evidence docs and the -second CI workflow. Nothing was pushed to `mock-main`. - -The first required gate produced a deterministic RED: - -```text -npm run typecheck:tests -w @launchpad/server -src/project-group-mention.test.ts(5,43): TS6142: Web ProjectGroupPage.tsx was -resolved, but --jsx is not set -src/project-group-mention.test.ts(11,8): TS6059: Web project-group-mention.ts is -outside apps/server/src rootDir -exit 2 -``` - -The new Server test imports both Web TSX and a Web helper. That packaging made the -test discoverable by the default Server Vitest suite on main, but violates the -strict test-source ownership gate already audited on `mock-main`. Literal -`npm run check` is therefore known red and was not misreported or rerun broadly. -No browser/full/hosted GC-01 acceptance claim is made from this branch. - -`TST-07` owns the minimal test-only correction: place formatter/component and -production parser round-trip coverage under correctly discovered, strictly typed -workspace ownership without broadening Server JSX/rootDir, suppressing/excluding -tests, weakening the multiline/disabled/exact-boundary/ID assertions, or changing -product code. GC-01 remains integration-blocked until Fixer correction and the full -Auditor gates pass. - -## TST-05/TST-06 and E2E-01 independent integration closeout - -**Date:** 2026-08-30 (Asia/Singapore) -**Candidate:** `e1d9c349226913a1192702fab3fa21c36514055e` -**Integrated implementation:** `f6df2d9503a3a482da2cb2882eb913ca2285501c` -**Committed review evidence:** `284994d` - -The candidate was exactly one commit above canonical docs head `3b9137b`. Its diff -contains only harness fixtures/support, Playwright configuration/scripts/tests and -canonical evidence docs: no production React, CSS, server, service, schema, -dependency or debug-route change. The prior E2E candidate and stale screenshot set -were not integrated. - -Independent gates passed: - -- harness unit 6/6 and Chromium 6/6 at exact `1280x800` and `1440x900`, repeated - three times (unit 18/18 and browser 18/18 total); every run left no `run-*` root; -- all 16 E2E stages and four adjacent harness/UI-03 ephemeral images were visually - inspected. Create is reachable at 1280 through the existing inner scroll and has - the established purple focus outline; empty, active, completed, stopped and - restarted states preserve the accepted Launchpad theme without document X/Y - overflow, clipping or overlap; -- actual Tab traversal, focus-visible treatment and Enter activation passed for - Create, Stop and Start. The journey also proved 401/auth, disabled active composer, - exact two-turn fake thread continuity, exact hello files and independent Node - artifact tests 2/2, outside canary and symlink confinement, port closure, same-root - restart, durable Agent/messages/runs/files, and bounded public/store/DOM/log scans; -- strict server test-source typecheck and literal `npm run check` passed with - launcher 3/3, server 563/563 plus one unchanged opt-in live skip, all typechecks - and both builds; -- default screenshots went only to ignored `.tmp`. Hash sets for all tracked review - images were identical before and after each ordinary run. The explicit evidence - command passed 2/2 and wrote exactly 16 intended `docs/ui-review/e2e-01` PNGs, - with no blank down-state or unrelated evidence; a subsequent ordinary full - harness again left those files byte-identical; -- secret values reach only boolean comparisons, not matcher formatting; live trace, - screenshots and video are disabled; retries remain zero; live entry requires the - exact opt-in and preserves the two-turn cap, loopback binding, bearer auth, child - environment allowlist and empty live `SHEPHERD_MODEL`. Repository, `.tmp`, harness - and run-root identities are lstat/realpath checked before allocation/removal. - Causal tests cover ancestor symlink rejection, retained-root cleanup after restart - failure, fresh setup-failure cleanup and reusable-root rejection. No credential, - private path, live artifact or retained root was found. - -Configured `ui-reviewer` and `security-reviewer` roles were unavailable. An -independent rendered fallback re-reviewed the exact 20 ephemeral PNGs and returned -READY with no severity finding; the Auditor's independent security review found no -High/Medium issue. Low residuals remain for hostile same-user mutation between -identity check and recursive removal and exceptional spawn/concurrent-mkdir timing; -these are bounded local-test-harness conditions and not production authority. - -The previously authorized live legacy evidence was accepted without another call: -exactly two successful ARK turns, no retry, one real Codex thread, generated artifact -test 2/2, restart persistence, bounded/redacted evidence and cleanup, with no -Shepherd Mission/model-review invocation. This closes only the PRD 11.6.1 baseline; -`LIVE-01` remains open for its separately scoped Shepherd/model-review smoke. - -Hosted Required checks run -[`33265640400`](https://github.com/kyashp/shepherd/actions/runs/33265640400) -passed Node 22, Docker, locked install and literal repository gate in 1m42s. - -**Verdict:** `TST-05` and `TST-06` are **AUDITED at scoped 100%** with 5/5 gates; -`E2E-01` is **AUDITED at scoped 100%** with `C,B,L,S,U,I` 6/6. - -## TST-05/TST-06 deterministic E2E harness correction candidate - -**Date:** 2026-08-30 (Asia/Singapore) -**Branch:** `fix/mock-main` (pending commit/Auditor integration) - -The Fixer imported the unintegrated E2E-01 harness candidate without its stale -ledger or screenshots, then changed only test/harness/configuration files. Ordinary -screenshots now go to ignored `.tmp/playwright-evidence`; only the explicit -`npm run test:e2e:starter-kit:evidence` mode writes review images. The empty -server-down canvas was removed: the test records only the observed closed port and -reserves reconnect UI for E2E-08. At both viewports the existing Create form is -scrolled until its primary action is visible, and Create, Stop and Start are reached -with actual Tab focus, checked for the existing focus-visible outline, and activated -with Enter. No production or UI/theme file changed. - -Harness assertions no longer pass credentials or sensitive bodies to matcher -formatting. Live Playwright trace, screenshot and video are off. Exact live opt-in, -two-turn/no-retry limit, loopback binding, bearer auth, child environment allowlist -and empty live `SHEPHERD_MODEL` remain. The repository, `.tmp`, harness and selected -run-root identities are lstat/realpath checked before allocation/removal. Added fault -tests reject a repo-contained symlinked harness ancestor without following it and -prove a previously retained stopped root can be removed after a restart failure. - -Observed evidence, with no live/model call: - -- harness unit: 6/6 passed, including ancestor-symlink, retained-root restart and - fresh-allocation setup-failure cleanup tests; -- deterministic Chromium: 6/6 passed in 17.5 seconds at exact `1280x800` and - `1440x900`; all 16 E2E-01 stage captures were visually inspected under ignored - output and the four adjacent harness/UI-03 captures were produced there too; -- tracked `docs/ui-review` SHA-256 sets were identical before/after the ordinary - run; `git diff -- docs/ui-review` was empty and no server-down image was produced; -- strict server test-source typecheck passed; literal `npm run check` passed twice, - each with launcher 3/3, server 563/563 plus one unchanged opt-in live skip, all - typechecks and both builds; -- `git diff --check` passed; stale roots created by the initial controlled failing - iteration were explicitly confined and removed, and the final harness root had - no `run-*` child. - -The earlier independently bounded live legacy evidence remains exactly two -successful turns with no retry. It was not invoked again. `TST-05`, `TST-06` and -`E2E-01` remain candidates pending independent UI/security/integrated/hosted audit; -no `U` or `I` gate is claimed here. - -An independent read-only security review found the initial candidate could retain a -freshly allocated root when setup failed before child spawn. The transaction was -extended over every post-allocation pre-spawn setup step and the new missing-Codex -fault regression proves the harness root returns to the exact prior `run-*` set. -Independent re-review closed the Medium finding and found no remaining High/Medium -issue. Low local residuals remain for same-user mutation between identity validation -and recursive removal, an exceptional synchronous `spawn()` throw, and theoretical -concurrent sibling mkdir completion after a `Promise.all` rejection. These require -adversarial or exceptional concurrent conditions outside this local harness threat -model; no broad filesystem refactor was attempted. - -## E2E-01 independent audit rejection: visual evidence and failure-path safety - -**Date:** 2026-08-30 (Asia/Singapore) -**Candidate:** `592699d140145165c5ca0d9511478171e5051271` (parent `949cec1`) - -The Auditor reviewed the exact candidate in an isolated worktree. It remains -**unintegrated**. No candidate product, test, screenshot, or documentation file was -cherry-picked to `mock-main`. - -Passing evidence was substantial but insufficient for integration: harness unit -tests passed 3/3; Chromium passed 6/6 across exact `1280x800` and `1440x900` projects; -strict server test-source typecheck passed; and literal `npm run check` passed with -launcher 3/3, server 563/563 plus one unchanged opt-in live skip, all typechecks and -both builds. All 18 regenerated E2E captures were manually inspected. The previously -bounded live evidence remains exactly two successful legacy ARK turns, no retry, -one real Codex thread, generated artifact/test 2/2, restart persistence, redacted -evidence and cleanup; the Auditor did not consume another live call. - -Two blocking gates failed. First, the successful routine harness run modified 16 of -18 tracked E2E-01 PNGs and the unrelated tracked UI-03 1280 PNG. Only the two -server-down files stayed byte-identical. Both were blank white canvases: the test -asserts the port closed, catches reload failure, then screenshots without any DOM or -visible-state assertion. Calling that a visually inspected application down state -overclaims the evidence. The 1280 Create Agent image also does not demonstrate that -the primary action is reachable, and actual Tab/focus-visible/lifecycle keyboard -coverage is incomplete. This is recorded as `TST-05`; production UI and the accepted -design must remain unchanged. - -Second, source audit found failure-path safety gaps recorded as `TST-06`: a secret is -passed directly to Playwright matcher output; a retained run root cannot be cleaned -by a later idempotent stop after restart failure; managed harness ancestor symlinks -are not canonically rejected before temporary-root creation/removal; and opt-in live -failure traces/screenshots may retain prompts or output. These require causal fault -tests and the narrow redaction/confinement/cleanup changes in `FIXES.md`, without -broadening environment or filesystem authority. - -**Verdict:** E2E-01 remains blocked and unintegrated. `TST-05` and `TST-06` must pass -their targeted, browser/security-review, full, integrated and hosted gates before -the journey can be marked audited. - -## TST-04 independent integration audit and hosted closeout - -**Date:** 2026-08-30 (Asia/Singapore) - -Auditor inspected the exact candidate and integrated it as -`00c81ae067961d43ee63acb777bf070ca808c113`. The diff changes only -`service.test.ts` and evidence docs. It leaves `makeDeletable`, product/service/ -verifier/UI code, timeouts, retries, sleeps, behavioral assertions, sentinel checks, -path confinement and symlink rejection unchanged. - -The captured backend `planePath` is resolved beneath the sentinel-owned case root, -with exact `.trusted-verification` parent and `verify-*` basename assertions. The -two-arrival barrier ensures capture before the selected frontend failure; the test -then observes typed Mission rejection while that root still exists. The watcher is -armed on the exact parent before sibling release, filters the exact basename, and -accepts quiescence only after `lstat` returns `ENOENT`. `finally` idempotently -releases all gates and joins the Mission, sibling return and conditional removal -promise without replacing the primary assertion failure. - -Independent evidence: exact row 20/20 in 28 seconds; service/container-verifier -slice 43/43; strict test-source typecheck; literal `npm run check` twice in 38/40 -seconds with launcher 3/3, server 563/563 plus one opt-in live skip and both builds; -integrated focused row 1/1; and `git diff --check`. Hosted Node 22 run -[`33263688794`](https://github.com/kyashp/shepherd/actions/runs/33263688794) -passed the locked install, Docker and literal repository gate in 1m42s. - -**Verdict:** TST-04 is **AUDITED at scoped 100%**, `T,A,C,I` 4/4. E2E-01 is -unblocked. No live/model/browser request occurred. - -## TST-04 exact verification-snapshot quiescence candidate - -**Date:** 2026-08-30 (Asia/Singapore) -**Branch/base:** `fix/mock-main` / `4f7da60a4b45415fb6283eaa3a60360102875856` - -The preserved RED is the full-suite `afterEach` failure recorded below: after all -typechecks, `makeDeletable -> readdir` received `ENOENT` beneath a sibling -`.trusted-verification/verify-*/src`, while the exact isolated behavioral row passed. -The disappearing owned path and order dependence implicated teardown beginning -before a sibling `withVerificationSnapshot` finalizer finished. - -The correction is test-only. `SnapshotTrackingContractThrowingVerifier` records the -blocked backend request's real `planePath` and uses the existing two-arrival barrier, -so the selected frontend infrastructure failure is not released before the backend -snapshot is observable. The Mission promise gets an immediate success/rejection -observer. After the typed rejection, the test asserts the captured absolute root is -inside the sentinel-owned case root, its parent is exactly `.trusted-verification`, -its basename matches `verify-`, and that exact directory still exists. This is -the controlled proof that fail-fast rejection precedes sibling snapshot cleanup. - -Before releasing the backend, the test arms `fs.promises.watch` on the exact root's -parent. Its quiescence signal requires an event for the captured basename followed -by `lstat(capturedRoot)` returning `ENOENT`, bounded by the existing five-second -`settleWithin` helper. A `finally` block idempotently releases the Contract pair and -sibling and joins the Mission, sibling return, and removal outcome. The test cannot -finish into `afterEach` while that background snapshot cleanup remains active. -Existing typed terminalization, bounded diagnostics, ownership release, -no-collision/candidate/promotion and public/store assertions remain unchanged. - -Observed GREEN evidence: - -- focused causal row: 1/1 passed initially, 560ms test time; -- 20 independent exact-row invocations: 20/20 passed in 28s; -- service/container-verifier slice: 43/43 passed in 33.22s; -- strict server test-source typecheck: passed; -- literal `npm run check` passed twice under normal contention, 39s/39s each: - production and strict test typechecks, launcher 3/3, server 563/563 with one - opt-in live skip, and both production builds passed; -- `git diff --check`: passed. - -No `ENOENT` was swallowed in `makeDeletable`; no sleep, retry, timeout increase, -cleanup-sentinel/path/symlink weakening, product/service/verifier/UI edit, or -live/model call occurred. `TST-04` is a **100% scoped candidate** with `T,A,C` -passed; integrated Auditor/hosted `I` remains pending. E2E-01 stays paused only on -that deterministic baseline audit. - -## ST-02 main-to-mock integration audit - -**Date:** 2026-08-30 (Asia/Singapore) - -PR #13 merged to `main` as `d27dea670108e5a06eac20de7df88f756b68e404`. -The Auditor merged that mainline into `mock-main` as -`d5df930923503cf337f865f8c0361fa1b3bd8530`, retaining both histories in the sole -`BUILD_LOG.md` conflict. The effective product delta is only -`SettingsPage.tsx` plus its focused test: public Settings schemas/persistence and -all kernel, harness, strict-type, CI, UI-03 and TST-03 implementation remain intact. -No notification delivery, external integration, model request, or credential path -was added. - -Observed independent evidence: - -- focused static-render regression: 1/1 passed; -- web production typecheck and 40-module build: passed; -- real Chromium Settings audit at exact `1280x800` and `1440x900`: three disabled - accessible notification controls, three **Reserved** labels, one **Unavailable** - label, disabled controls skipped in Tab order, forced interaction sent zero - Settings `PATCH` requests, and document/body X/Y scroll sizes equalled client - sizes at both viewports; -- screenshots `docs/ui-review/st-02-settings/{1280x800,1440x900}.png` were inspected - and preserve the accepted Launchpad theme with no clipping or overlap; -- deterministic harness unit 2/2 and Chromium 4/4 passed; -- literal `npm run check` passed in 39 seconds: launcher 3/3, server 563/563 with - one opt-in live skip, strict test-source and production typechecks, and both - production builds; -- `git diff --check` and the bounded diff/artifact review passed. - -The configured `ui-reviewer` role was unavailable. An independent read-only rendered -fallback returned **READY with no scoped findings**. It confirmed truthful copy, -native disabled semantics, persisted checked-state visibility, non-color-only labels, -responsive layout and design fidelity. It noted only pre-existing non-blocking -Settings tablist ARIA/arrow-key and small secondary-type debt; ST-02 does not broaden -into those shared concerns. - -**Verdict:** ST-02 is **AUDITED at scoped 100%**, `T,C,B,U,I` 5/5. This is one -observed green repository run, not a claim that separately reproduced TST-04 -background-cleanup instability is resolved. - -Final hosted Node 22 run -[`33262928516`](https://github.com/kyashp/shepherd/actions/runs/33262928516) -passed the locked install, Docker availability and literal repository gate on audit -head `7f5a719` in 1m42s. -## TST-04 F-03 snapshot-cleanup teardown race - -**Date:** 2026-08-30 (Asia/Singapore) -**Branch/base:** `work/mock-main` / `e88dbef27b0a7f55acbdab3a7f89b67c9e6900c1` - -The literal repository gate passed both production typechecks and the strict server -test-source typecheck, then failed one F-03 service test during `afterEach` cleanup. -The behavioral assertions did not fail. The cleanup walker attempted to read a -sibling trusted-verification snapshot subtree while its owning -`withVerificationSnapshot` finalizer was removing it: - -```text -service.test.ts > Shepherd deterministic walking skeleton > -terminalizes Contract verification infrastructure failures without promotion or sensitive diagnostics - -afterEach -> removeServiceCaseRoot -> makeDeletable -> readdir -ENOENT: .tmp/shepherd-tests/service-*/managed/planes/auth-demo/ - .trusted-verification/verify-*/src -``` - -```sh -npm run check -# RED after typechecks: server 562 passed, 1 failed, 1 opt-in skipped -# build phase did not run - -npm run test -w @launchpad/server -- --run src/shepherd/service.test.ts \ - -t 'terminalizes Contract verification infrastructure failures without promotion or sensitive diagnostics' -# isolated GREEN: 1 passed, 33 skipped -``` - -The full-suite-only RED, immediate isolated GREEN, fail-fast concurrent Contract -verification path, and disappearing snapshot path strongly support an ordering race. -The required next discriminating check is to record the sibling -`VerificationRequest.planePath` and prove teardown starts before that exact snapshot -cleanup/Contract batch is quiescent. No product, UI, test, timeout, or cleanup -behavior was changed during this diagnosis. The paused E2E-01 deterministic work is -preserved separately; no live/model call was made. - -Auditor source inspection confirmed that the failing `makeDeletable` recursion does -not suppress a directory disappearing between its entry `chmod` and `readdir`, while -each concurrent Contract verifier owns a `withVerificationSnapshot(...finally)` -cleanup. The unmodified current-tree literal gate passed 563/563 plus one opt-in skip, -which is consistent with an intermittent ordering defect and does not close the -preserved RED. The Fixer must still prove the exact sibling-path ordering causally -before changing the fixture. - -## TST-03 independent integration audit and hosted closeout - -**Date:** 2026-08-30 (Asia/Singapore) - -**Integrated implementation:** `0b1c4017f01d37823b13c5da7360f00a8d8e7814` - -Auditor inspected the exact candidate diff and confirmed it changes only the test -fixture and evidence docs: no product, service, verifier, API, persistence, UI, -workflow, dependency, timeout, sleep, retry, rejection suppression, or weakened -assertion. Both parameter rows passed 40/40 across 20 independent invocations; the -service/container-verifier slice passed 43/43; strict test-source typecheck passed; -the literal repository gate passed locally in 39 seconds with launcher 3/3, server -563/563 plus one opt-in live skip, and both production builds; integrated focused -rows passed 2/2. `git diff --check` passed. - -Required hosted Node 22 run -[`33262227553`](https://github.com/kyashp/shepherd/actions/runs/33262227553) -passed on `0b1c401` in 1m38s, including locked install, Docker availability and the -literal repository gate. TST-03 is **AUDITED at scoped 100%**, `T,C,I` 3/3. This -restores UI-03 to **AUDITED at scoped 100%**, `T,C,B,U,I` 5/5, and unblocks E2E-01. -No live/model call occurred. - -## TST-03 deterministic concurrent-verifier regression candidate - -**Date:** 2026-08-30 (Asia/Singapore) -**Branch/base:** `fix/mock-main` / `346ab91bd807ee787ac275d43f10bfe08b5a5532` - -The controlled RED remains hosted run -[`33261198788`](https://github.com/kyashp/shepherd/actions/runs/33261198788): -the thrown-verifier row exhausted its existing 30-second budget and emitted an -unhandled `ContractVerificationInfrastructureError` after 558 passed, 5 skipped, -and 1 failed tests. The prior disposable backend pre-verifier hold reproduced the -same ordering defect in one second. A subsequent unmodified docs-only hosted run -[`33261491905`](https://github.com/kyashp/shepherd/actions/runs/33261491905) on -`346ab91` passed, which corroborates schedule sensitivity but does not make the -fixture deterministic. - -The candidate changes only `service.test.ts`. A reusable two-arrival barrier makes -the selected frontend thrown/returned infrastructure outcome wait until the backend -has entered the verifier. A `then` success/failure observer is attached to the -Mission promise immediately, before `siblingEntered` or any other gate is awaited. -The assertion still requires the typed infrastructure failure. `finally` releases -the pair and sibling gates idempotently and joins both the Mission and sibling exit, -so an assertion failure cannot strand deferred work or create an unhandled -rejection. Existing atomic terminalization, durable reload, ownership release, -late-return, no `verification_passed`, no collision/candidate/promotion, and bounded -Plane assertions remain intact. - -Observed GREEN evidence: - -- focused parameterized test: 2/2 passed initially in 1.47s (929ms test time); -- 20 independent focused invocations: both parameter rows passed 40/40 in 37s; -- Shepherd service/container-verifier slice: 43/43 passed in 32.29s; -- strict `typecheck:tests`: passed; -- literal `npm run check` passed twice, in 39s and 40s: both production and strict - test-source typechecks, launcher 3/3, server 563/563 with one opt-in live skip, - and both production builds passed; -- `git diff --check`: passed. - -No timeout changed, no sleep/retry was added, no failure was swallowed, and no -product, service, verifier, API, persistence, UI, workflow, dependency, or live/model -path changed. `TST-03` is a **100% scoped candidate** with `T,C` passed; integrated -Auditor/hosted gate `I` is pending. UI-03 stays at 98% until that hosted closeout, -and E2E-01 remains blocked only on the deterministic baseline integration. - -## TEST-TS strict server test-source typecheck candidate - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/base:** `work/mock-main` / `39211213bc1f77e8873673eda9e7c87da2b24abd` - -The production server compiler excludes `*.test.ts`, so its existing typecheck did -not validate test sources. A separate `tsconfig.test.json` now reuses the production -compiler options with `noEmit`, includes production and test sources, and is invoked -after the unchanged workspace production typechecks by the root `typecheck` script. -The production build/emit configuration remains unchanged. - -The initial strict RED found 14 errors across four test files: four implicit callback -types, five Vitest 4 matcher calls using removed generic parameters, four promotion -fixtures missing the required persistence callback, and one container verifier fixture -missing its required owner identity. Restoring matcher typing then exposed two nullable -fixture values. The test-only fixes add exact inferred/imported types, use `satisfies` -for matcher shapes, complete the fixtures with inert deterministic callbacks/identity, -and assert the already-established non-null candidate-head invariant. No assertion, -production behavior, UI, compiler strictness, or test coverage was removed. - -```sh -./node_modules/.bin/tsc -p apps/server/tsconfig.test.json --pretty false -# RED: exit 2; 14 errors across 4 files in the categories recorded above - -npm run typecheck:tests -w @launchpad/server -npm run typecheck -w @launchpad/server -npm run build -w @launchpad/server -# all passed; test-source and production typechecks plus production server emit - -npm run test -w @launchpad/server -- --run src/app.test.ts \ - src/shepherd/git-plane-promotion.integration.test.ts \ - src/shepherd/service.container.test.ts src/shepherd/service.test.ts -# 4 files passed; 73/73 tests passed - -npm run check -# both workspace production typechecks and the new server test-source typecheck passed -# launcher tests: 3/3 passed -# server: 26 files passed, 1 opt-in file skipped; -# 563 tests passed, 1 opt-in test skipped -# web 40-module production build and server production build passed -``` - -This is implementation evidence only. Independent Auditor integration/review on -`mock-main` remains the `I` gate, so confidence is scoped to 95%, not 100%. - -### TEST-TS independent integration audit - -The Auditor reviewed and integrated the candidate as `8995605`. The new config is -strict, no-emit, and additive: the production server `tsconfig.json`, emitted files, -web compiler, dependencies, runtime, API, and UI are unchanged. Source review found -no `ts-nocheck`/`ts-ignore`, new broad exclusion, `skipLibCheck` weakening, blanket -`any`, assertion removal, or matcher weakening. Runtime matcher objects are unchanged; -the required fixture callback and owner identity complete existing production -contracts, while the non-null assertions encode commit invariants already established -earlier in the same tests. - -Independent candidate and integrated evidence: - -```sh -npm run typecheck:tests -w @launchpad/server -# passed on candidate and integrated implementation - -npm run typecheck -w @launchpad/server -npm run typecheck -w @launchpad/web -npm run build -w @launchpad/server -npm run build -w @launchpad/web -# both production typechecks and builds passed; web transformed 40 modules - -npm run test -w @launchpad/server -- --run src/app.test.ts \ - src/shepherd/git-plane-promotion.integration.test.ts \ - src/shepherd/service.container.test.ts src/shepherd/service.test.ts -# 4 files passed; 73/73 tests passed - -npm run check -# passed on candidate and integrated implementation: launcher 3/3; server 26 -# files and 563/563 tests passed with one unchanged opt-in live file/test skipped; -# strict test-source and production typechecks plus web/server builds passed - -git diff --check -# passed -``` - -The recorded RED categories match the exact corrected sites and TypeScript/Vitest -contracts; the audit did not retain a weakening mutation merely to recreate them. -`TEST-TS` is **AUDITED, scoped 100%**, with `T,C,I` passed 3/3. Hosted Node 22 -evidence is recorded after the final audit-documentation push. - -## UI-03 Create Agent preset-radio overflow correction - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/base:** `fix/mock-main` / `39211213bc1f77e8873673eda9e7c87da2b24abd` - -The causal real-browser regression was added before production CSS changed. At -`1280x800`, Create Agent failed with document scroll/client width `2299/1280`; at -`1440x900`, it failed with `2579/1440`. The accessible four-radio group, initial -Generalist selection, one native Tab stop, ArrowLeft focus/selection, and wrapping -label click all passed before the overflow assertion, preserving the existing -semantic baseline. - -The correction changes only the preset-radio CSS: each transparent absolute native -radio is `1x1`, and inherited `min-height`, margin, padding, and border are reset. -No ancestor overflow rule, React/API contract, visible card geometry, or theme was -changed. Independent read-only review then found that the global focus outline was -computed on the transparent radio rather than visibly painted on its card. A second -minimal selector applies the same existing purple 2px focus outline to the wrapping -label through `:has(input:focus-visible)`; the browser regression asserts that -visible card treatment directly. - -Observed final evidence: - -- focused Chromium: 2/2 passed at exact `1280x800` and `1440x900`; document - scroll/client widths were `1280/1280` and `1440/1440`, document/body X/Y - invariants passed, and all four computed radio boxes were `1x1` with zero - inherited minimum height and spacing; -- semantics: four radios under the `Authority preset` group, Generalist initially - checked, one Tab stop, arrow-key focus plus selection, visible focused-card - outline, all four wrapping labels selectable, and exactly one checked radio; -- full deterministic browser harness: 4/4 passed across the two viewports; -- screenshots inspected at - `docs/ui-review/ui-03-create-agent/{1280x800,1440x900}.png`; hashes are - `b64a61aa0c01566a710e3a480f6186a95e97075a06d97c89c327ea10cfec2de9` and - `ac630408a97445d439f79305b8c25854bdc07d3bb6fa741f45e3509055a26804`; -- literal `npm run check`: both typechecks, launcher 3/3, server 563/563 with one - opt-in live skip, and both production builds passed. - -The independent read-only re-review reran the focused browser slice 2/2, observed -the visible card outline, passed `git diff --check`, and closed its earlier Medium -finding with no remaining UI-03 findings. - -No live/model request was made. `UI-03` is a **100% scoped candidate** with -`T,C,B,U` passed; integrated Auditor gate `I`, `E2E-01`, and `UI-GATE` remain -pending and are not claimed here. - -### UI-03 independent integration audit - -The Auditor integrated the candidate as `83954f7` while preserving the newer -TEST-TS gate and its evidence. The only product change remains eleven lines in the -existing preset-radio CSS: a locally bounded transparent native input and the -existing purple two-pixel focus treatment painted on its wrapping card. No React, -API, navigation, ancestor overflow, dependency, runtime, or unrelated design change -was introduced. - -Independent integrated evidence: - -```sh -node --test tests/e2e/harness.test.mjs -# 2/2 passed - -PLAYWRIGHT_BROWSERS_PATH=.tmp/playwright-browsers \ - npx playwright test --config=playwright.config.ts -g "Create Agent presets" -# 2/2 passed at 1280x800 and 1440x900 - -PLAYWRIGHT_BROWSERS_PATH=.tmp/playwright-browsers \ - npx playwright test --config=playwright.config.ts -# 4/4 passed across both required viewports - -npm run check -# strict server test-source plus both production typechecks passed; launcher 3/3; -# server 26 files and 563/563 tests passed with one unchanged opt-in live skip; -# web 40-module and server production builds passed - -git diff --check -# passed -``` - -The browser gate observed document/body scroll width and height within client -geometry, four `1x1` radios with zero inherited minimum height/padding/border/margin, -an accessible `Authority preset` group and radio names, Generalist initially checked, -one native Tab stop, ArrowLeft focus/selection, a visible theme-matched 2px outline, -all four label clicks, and exactly one checked radio. Regenerated screenshots exactly -matched the committed hashes and were visually inspected for adjacent layout, -spacing, hierarchy, clipping, and theme consistency. The authenticated token was not -rendered, temporary browser/run artifacts remained ignored, and no model/network call -occurred. This establishes `T,B,U,I` for UI-03. Final hosted `C` remained pending -the audit-documentation push. - -### UI-03 hosted closeout failure / TST-03 - -Required-check run -[`33261198788`](https://github.com/kyashp/shepherd/actions/runs/33261198788), -job `99123330844`, failed on final audit head `2ba5cb9`. Setup, checkout, Node 22, -Docker and locked install passed. The repository gate reached server tests, then -`atomically interrupts a blocked sibling after 'thrown verifier exception'` timed -out at 30 seconds and emitted an unhandled -`ContractVerificationInfrastructureError`. Hosted results were 24 files passed, 2 -skipped and 1 failed; 558 tests passed, 5 environment-gated skipped and 1 failed. -Builds did not run. The five-skip hosted profile was unchanged. - -The UI-03 diff does not touch that backend service test or orchestration. Source -inspection instead found a schedule-sensitive test contract: it awaits the backend -fixture's `siblingEntered` promise before attaching rejection handling to the -already-started Mission. Under contention, the frontend can terminalize first, so -the awaited sibling signal never arrives and the Mission rejection becomes -temporarily unhandled. The test has no unconditional sibling release/join when a -timeout or assertion wins. Five isolated local repetitions subsequently passed 5/5, -which confirms intermittency and does not correct the hosted RED. - -A disposable controlled fault probe then held the backend only at -`contract_verification_snapshot_ready`, immediately before verifier entry, and -shortened only that temporary test's budget to one second. The thrown-verifier row -deterministically timed out and Vitest reported the same unhandled -`ContractVerificationInfrastructureError`. The mutation lived only in the Auditor's -temporary worktree and was not integrated. This separates the orchestration race -from machine speed and directly validates the supported root cause. - -`TST-03` now owns the smallest test-only correction: deterministic two-arrival -coordination, immediate rejection handling, and unconditional bounded release/join; -no sleep, timeout increase, swallowed rejection, weakened F-03 assertion, or product -change. Until its repeated/full/hosted acceptance is green, UI-03 remains **98% -scoped** with `T,B,U,I` passed 4/5 and hosted `C` pending; E2E-01 remains blocked by -the baseline rather than by its resolved Create Agent browser prerequisite. - -## CI-01 required-check workflow candidate - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/base:** `work/mock-main` / `7217c1c055df76ace392d3804bc6517df85ce768` - -The repository had no workflow capable of reporting the stable required status -named `Required checks / Node 22 / npm run check`. This candidate adds one workflow -and changes no product, UI, server, test, package, lockfile, dependency, or runtime -configuration. - -The workflow follows the current official GitHub Actions contracts reviewed on -2026-08-29: every `pull_request` runs; `push` is limited to `main` and `mock-main`; -and `merge_group` is limited to `checks_requested`, which GitHub documents as -necessary for merge-queue required checks. Workflow concurrency is scoped by the -workflow name and event ref, so a newer run cancels only an older run for the same -workflow/ref. The job runs on `ubuntu-latest`, installs Node 22 through -`actions/setup-node@v7`, caches npm's download cache against the checked-in -`package-lock.json`, verifies the hosted Docker client/daemon, executes `npm ci`, -and then executes the literal `npm run check`. The job has a 20-minute timeout. - -Security and isolation are explicit: - -- top-level token permission is only `contents: read`; all unspecified permissions - are `none` under GitHub's workflow permission semantics; -- `actions/checkout@v6` uses `persist-credentials: false`; -- no `pull_request_target`, write permission, secret reference, `.env` loader, - artifact upload, custom/privileged action, deployment, or external/live/model - command exists; -- `SHEPHERD_LIVE_TEST` is fixed to `false`, and repository secrets are not mapped - into the job environment. - -No Action-specific linter was installed on this host. The available PyYAML 6.0.1 -parser loaded the workflow with `BaseLoader`, and custom structural assertions -verified the exact events/branches, merge-group activity, permission, runner, -timeout, official action versions, and command sequence: - -```sh -python3 -c '' -# workflow YAML and required structure: pass - -docker version --format '{{.Client.Version}} {{.Server.Version}}' -# client 29.7.2; server 29.7.2 - -npm run check -# Node 24.17.0 / npm 11.17.0 local evidence -# both workspace typechecks passed -# launcher tests: 3/3 passed -# server: 26 files passed, 1 opt-in file skipped; -# 555 tests passed, 1 opt-in test skipped -# web and server production builds passed - -git diff --check -# passed -``` - -The Worker branch is intentionally not a `push` trigger, and the user prohibited a -PR for this campaign. After pushing the candidate, the authenticated read-only -query `gh run list --repo kyashp/shepherd --branch work/mock-main ...` returned -`[]`, confirming no hosted run exists for that branch. CI-01 remains below 100% -until the Auditor integrates it into `mock-main`, observes the real hosted Node -22/Docker run, records the resulting check identity, and confirms the -protected/merge-queue rule consumes that stable status. No external model request -was made. - -### Independent Auditor pre-hosted integration review - -**Candidate:** `bdab32da9305a3787ec4b0c1d2061d521230eeae` - -**Integrated workflow:** `cda2446584d0f5d6c07ec8d2521d08fb6711f971` - -The Auditor independently confirmed the exact three-file diff: the workflow plus -`TASKS.md` and this log. Product, UI, server, tests, dependencies, lockfile, runtime -configuration, and environment examples are unchanged. PyYAML `BaseLoader` parsing -and structural assertions covered the complete event map, branch filters, -`checks_requested`, permissions, concurrency expression, runner, timeout, child -environment, action inputs, and exact command sequence. - -Current official GitHub documentation reviewed on 2026-08-29 confirms that -`pull_request:` without filters runs every PR; `push.branches` limits pushes to the -two named branches; merge queues require the separate `merge_group` trigger and -currently support `checks_requested`; unspecified permissions become `none`; the -workflow/ref concurrency expression cancels only an older matching run; and the -20-minute positive integer is a valid bounded job timeout. Official action refs -also resolve: `actions/checkout@v6` is still supported, while v7 is latest and its -documented breaking safety change concerns `pull_request_target`, which this -workflow does not use; `actions/setup-node@v7` is current and its npm cache hashes -the named `package-lock.json` while caching npm data rather than `node_modules`. - -Independent local evidence on the candidate: - -```sh -python3 -c '' -# pass - -docker version --format 'client={{.Client.Version}} server={{.Server.Version}}' -# client=29.7.2 server=29.7.2 - -npm run check -# typechecks passed; launcher 3/3; server 26 files and 555 tests passed; -# one opt-in live file/test skipped; web 40-module and server builds passed - -git diff --check -# pass -``` - -The workflow maps no repository secret and invokes no env loader, model/live test, -artifact upload, deployment, privileged container, or write-capable command. -`contents: read` is the only token permission and checkout credential persistence -is disabled. Hosted Node 22, `npm ci`, Docker daemon availability, the emitted check -identity, and the real trigger remain pending until the first `mock-main` push run -completes; CI-01 is not yet marked audited. - -### Hosted integration result - -The combined `mock-main` push at `cd23488b29d9f45ba854e11ef1b6bf41c1bcda3f` -triggered the newly integrated workflow exactly once: - -- run: `33259565232` -- URL: `https://github.com/kyashp/shepherd/actions/runs/33259565232` -- event/ref: `push` / `mock-main` -- job/check: `Node 22 / npm run check` (`99119063014`) -- conclusion: `success` -- duration: 91 seconds, from `2026-08-29T15:11:31Z` to `15:13:02Z` - -Every hosted step succeeded: checkout with credential persistence disabled, -setup-node, Docker client/daemon probe, `npm ci`, literal repository gate, both -post-action cleanups, and job completion. Bounded logs established the real hosted -environment and counts: - -```text -Node 22.23.2; npm 10.9.8 -Docker client 28.0.4; server 28.0.4 -launcher: 3/3 passed -server: 25 files passed, 2 environment-gated files skipped; - 551 tests passed, 5 skipped, 556 total -web: 40 modules transformed; production build passed -server: TypeScript production build passed -``` - -The hosted skip delta is explicit rather than hidden: local Docker evidence passed -555 server tests with only the opt-in live test skipped, while hosted `CI=true` -retained five repository-defined environment-gated skips. The dedicated hosted -Docker probe proved both client and daemon availability independently. No secret, -model, live-test, deployment, artifact, or write-capable path ran. - -**Verdict:** `CI-01` is **AUDITED at scoped 100%**, `C,I` 2/2. The stable branch -protection check to select is `Node 22 / npm run check` from workflow `Required -checks`. A repository administrator must still add this check to the protected -`main` ruleset/branch-protection rule (and enable merge queue there if desired); -that external administrative mutation was not performed by an agent. - -## E2E-01 stopped at Create Agent overflow defect - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/base:** `work/mock-main` / `ace01ae0a6875f102ea0fec30e871a0e2f6d60a8` - -The Worker extended only the deterministic test composition toward PRD 11.6.1, -then stopped at the first reproduced production defect as required. Before the -browser stage, the real web/server production build passed and the existing -isolated harness causal tests passed 2/2. No `.env` was read and no external/model -request was made. - -The focused command drove the built authenticated application with Playwright -`1.62.1` / Chromium `151.0.7922.34`: - -```sh -npm run test:e2e:starter-kit -# build passed; harness unit 2/2 passed -# browser 0/2: Create Agent overflow assertion failed at both viewports -# 1280x800: document scrollWidth 2299, clientWidth 1280 -# 1440x900: document scrollWidth 2579, clientWidth 1440 -``` - -The earliest divergence occurs after the four recommended authority radios render, -before creating an Agent, calling fake Codex, changing workspace files, or testing -restart continuity. A one-project diagnostic rerun at `1280x800` enumerated every -overflowing element. Each transparent absolute `.preset-grid input` retained the -global `input { width: 100%; min-height: 38px; ... }` sizing: all four inputs had -`clientWidth=1280`, and their static grid positions produced right edges `1589`, -`1826`, `2063`, and `2299`. The accepted visible form looked clipped only because -the main content surface hides X overflow; the document geometry was still invalid. - -This establishes `UI-03` causally. The minimal correction belongs to the Fixer: -bound only the visually hidden native radio dimensions while preserving labels, -selection, keyboard semantics, and all accepted styling. The Worker did not edit -React, CSS, or any production file, did not weaken the no-overflow gate, and did not -attempt the separately labelled sparse live acceptance while deterministic E2E-01 -was red. Live call count: **0**. E2E-01 remains blocked with no acceptance gate -claimed. - -### Independent Auditor reproduction - -**Evidence candidate:** `7b92813550f192d2b45e3e4e39f473b99c084615` - -**Docs integrated as:** `eb44d8633aa7e78cc7b89ea69e9215e3755be178` - -The candidate diff from `ace01ae` contains only this log, `FIXES.md`, and the -`E2E-01` ledger row. It does not contain the Worker's unfinished E2E-01 code or any -React, CSS, API, runtime, test configuration, dependency, or production change. -The Auditor independently drove the integrated built application through access -token unlock and the Create Agent link using the audited deterministic harness. - -At `1280x800`, document geometry was `clientWidth=1280`, `scrollWidth=2299`; -the four transparent absolute radios were each `1280x38`, with bounds ending at -`1589`, `1825.75`, `2062.5`, and `2299.25`. At `1440x900`, document geometry was -`clientWidth=1440`, `scrollWidth=2579`; the radios were each `1440x38`, ending at -`1749`, `2025.75`, `2302.5`, and `2579.25`. In both cases document height and all -body X/Y measurements stayed within the viewport. This isolates the failure to -the root X extent created by the hidden inputs; it is not ordinary page content or -a vertical-overflow defect. - -The browser-computed radio style was `position:absolute`, `opacity:0`, and -`pointer-events:none`, while global form rules still supplied `width:100%`, -`min-height:38px`, padding, and a border. The source/geometry causal account is -therefore confirmed. Existing native semantics were also measured as the -preservation baseline: Generalist was the initial checked radio and the radio group -was reached as one Tab stop; ArrowLeft moved both focus and selection to -Verification; direct focus plus ArrowRight selected the next radio; clicking the -wrapping Verification label left exactly one radio checked. - -No live/model request, Agent creation, fake Codex turn, product edit, or sibling -branch integration occurred. Temporary screenshots/scripts and the isolated run -root were removed; no server process remained. - -**Verdict:** `UI-03` is independently reproduced with **100% causal-diagnosis -confidence** and **0% correction completion**. The Fixer must constrain only the -hidden radio box, explicitly overriding inherited size/spacing properties without -changing the visible form or native focus/selection/label contract. Required gates -are focused causal Playwright coverage, `1280x800` and `1440x900` browser/screenshots -with document/body X/Y invariants, literal `npm run check`, independent rendered -`ui-reviewer`, and post-integration Auditor rerun. `E2E-01` remains blocked. - -## E2E-HARNESS deterministic browser foundation - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/base:** `work/mock-main` / `42d3b517c05a20f6a9e526390e9e82d95306e859` - -The repository had the Playwright package but no checked-in configuration, browser -test, deterministic real-server composition, or fake Codex executable. This -candidate adds only test infrastructure, two baseline screenshots, root test -scripts, and evidence documentation. Production server, React, CSS, API, and -runtime behavior are unchanged. - -`tests/e2e/support/test-app.mjs` starts the built Fastify application directly on -an ephemeral loopback port. Every data, workspace, home, temporary, Codex, and -Shepherd path is under one exact `.tmp/playwright-harness/run-*` directory. The -child environment is constructed from an allowlist instead of spreading -`process.env`: Ark/model values are empty, the execution mode is deterministic, -and no `.env` loader or live model path runs. Startup uses a bounded fake Codex -protocol executable and a startup-only fake container engine that permits only the -two ownership-filtered empty `ps` reconciliation calls. There is no production -debug/fault route. Readiness polls the real health endpoint; teardown sends -`SIGTERM`, bounds the wait, retains a `SIGKILL` fallback, removes only the exact -allocated run root, and is tested to close the port. - -Observed focused verification with Playwright `1.62.1` and repo-local Chrome for -Testing/Chromium `151.0.7922.34`: - -```sh -npm run test:e2e:install -# Chromium, headless shell, and FFmpeg installed below ignored .tmp/ - -npm run test:e2e:harness -# build passed -# Node harness tests: 2/2 passed -# Playwright Chromium: 2/2 passed using one worker -``` - -The Node tests verify the fake Codex version/run/resume protocol, output/prompt -bounds, real HTTP health, required bearer authentication, unauthenticated 401, -authenticated system state, `codexAvailable=true`, deterministic/local runtime, -real production HTML, ambient-Ark exclusion, and state/process/port cleanup. A -planted ambient Ark canary and the test bearer token were absent from persisted -state, the system API payload, and bounded server logs. - -The Playwright test unlocks the real app through the access-token form, waits for -the Shepherd heading and `Kernel online`, verifies the exact browser dimensions, -asserts document and body scroll sizes do not exceed their client dimensions on -either axis, and verifies the token is absent from rendered text. Captures were -written to: - -- `docs/ui-review/e2e-harness/1280x800.png` -- `docs/ui-review/e2e-harness/1440x900.png` - -Both captures were visually inspected against PRD 11.7. They preserve the accepted -cream surface, charcoal sidebar, violet accent, restrained borders/shadows, -typography and spacing, with no overlap, raw state, or document-level overflow. -The expected deterministic clean-start runtime warning and empty Mission panels -are visible. This is harness/baseline evidence only; it does not satisfy the eight -full PRD journeys, populated/intermediate states, accessibility review, or the -independent `UI-GATE`. - -Repository regression evidence: - -```sh -npm run check -# both workspace typechecks passed -# launcher tests: 3/3 passed -# server: 26 files passed, 1 opt-in file skipped; -# 555 tests passed, 1 opt-in test skipped -# web and server production builds passed - -git diff --check -# passed -``` - -No external/model API request was made. Secret isolation was exercised through -store/API/log/DOM checks; no production trust boundary changed, so an independent -security-reviewer is not required for this test-only candidate. `T`, `C`, `B`, and -`S` are evidenced. Auditor integration and the `I` gate remain pending. - -### Independent Auditor integration - -**Candidate:** `fd4953defd4a2e9331bb7dc39f79aea8fbc05342` - -**Integrated implementation:** `5b152a0c54ac1ed97c69d69cc84a7e093f5250e9` - -The Auditor reviewed the exact parent-relative diff and dependency graph before -integration. The implementation scope is the Playwright configuration, root test -scripts, E2E support/fixtures/tests, two PNG baselines, and evidence documentation. -The existing Playwright `1.62.1` lock entry is reused; `package-lock.json` did not -change. No server source, web source, CSS, API route, runtime configuration, -production launcher, `.env` example, or production debug/fault route changed. - -Source and focused runtime review confirmed that the built server is spawned -directly with a constructed child-environment allowlist rather than `process.env`; -there is no env-file flag or dotenv loader. Ark/model variables are empty, the -runtime is deterministic and loopback-only, and no model request is possible in -the exercised state. The real API still requires bearer authentication. The fake -Codex limits invocation shape, prompt size and output; the fake container engine -returns only an empty result for the two ownership-filtered startup `ps` probes. -Readiness is capped at 15 seconds, captured output at 16 KiB, and shutdown at -`SIGTERM` plus a bounded `SIGKILL` fallback. Each run uses a single exact -repository-local ignored root; tests proved state-root deletion and port closure. - -The candidate was independently tested in a detached audit worktree, then the -same gates were repeated after integration on `mock-main`: - -```sh -npm run test:e2e:harness:unit -# build passed; Node harness 2/2 passed - -PLAYWRIGHT_BROWSERS_PATH=.tmp/playwright-browsers \ - npx playwright test --config=playwright.config.ts -# Chromium 2/2 passed: 1280x800 and 1440x900 - -npm run check -# typechecks passed; launcher 3/3; server 26 files and 555 tests passed; -# one opt-in live file/test skipped; web 40-module build and server build passed - -git diff --check -# passed -``` - -Both fresh screenshots had the exact committed dimensions and hashes: - -- `1280x800.png`: `07acf85b0cdfe947aca71a3bf26c476a20305761aa7d2f4bf0dca334014bfd05` -- `1440x900.png`: `3b54e1afe689acee16a8c6a0991e3178f7440f6d2cd9118a03a480bb975ed355` - -The Auditor visually inspected both captures. They preserve the accepted charcoal, -cream and violet design language with legible empty-state hierarchy, no overlap, -and no document/body X/Y overflow. The access token is absent from DOM text and -the screenshots; the ambient Ark canary is absent from state, API payloads and -bounded logs. No server process or per-run state remained after either run. Only -the expected ignored browser binaries and Playwright last-run metadata remain. - -**Verdict:** `E2E-HARNESS` is **AUDITED at scoped 100%** with `T,C,B,S,I` 5/5. -No independent UI or security reviewer was required because production UI and -trust-boundary code did not change. This verdict covers only the deterministic -authenticated clean-shell foundation. `E2E-01` through `E2E-08`, populated and -composer interactions, accessibility, live-model acceptance, and `UI-GATE` remain -separate pending work. -## F-03 Contract verifier infrastructure failure candidate - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/base:** `fix/mock-main` / `origin/mock-main@ace01ae` - -The causal regression planted a Contract-only verifier exception containing a -canary and private diagnostic path. Before the correction, the raw exception -escaped; the Mission became `failed` with code `unknown` at -`deterministic_demo`, both Contracts remained `verifying`, both Contract Planes -remained `inspecting`, and both Agents remained `busy` with -`currentContractId` retained. - -The correction is confined to the existing Contract verification service and -verifier cancellation boundaries. A thrown verifier infrastructure error or a -returned mandatory check with status `infrastructure_error` now produces fixed -`verification_infrastructure_error` evidence at `contract_verification`. Ordinary -mandatory checks with status `failed` retain `failed_independent_acceptance`. -One durable mutation sets the throwing/returning Contract and its Plane to -`verification_failed`/`failed`, interrupts every active sibling Contract/Plane, -releases all mission-owned Agent and project ownership, and fails the Mission. -The batch returns promptly, makes bounded best-effort cancellation calls, and -rejects late sibling completion. Target cancellation remains sticky across -sequential checks and reserved container creation, prevents later invocation or -container start, contains repeated cancellation during bounded removal, and allows -clean exact-ID reuse only after cleanup. Passing verification still requires -independent evidence; no integration, candidate, or promotion path is entered. - -Three read-only review rounds prevented incomplete candidates from release. The -first found an active sibling beneath a failed Mission. The second fault probe -found the production container verifier returns infrastructure evidence rather -than always throwing, plus non-sticky sequential/reserved cancellation. The third -found a repeated cancel during delayed removal could leave a stale marker and -cancel later same-ID work. Regressions preserve each failure: blocked sibling plus -durable reload and late return; returned mandatory infrastructure evidence; -no sibling verifier invocation; no second sequential check; no `start` after -reserved cancellation; and delayed removal plus repeated cancel and bounded ID -reuse. Final re-review reported no blocker, high, or medium finding. The configured -custom reviewer role was unavailable, so reviews used a separate read-only -fallback agent. - -Observed verification: - -```sh -npm run test -w @launchpad/server -- --run \ - src/shepherd/service.test.ts src/shepherd/verifier.container.test.ts \ - -t "terminalizes Contract verification infrastructure failures without promotion or sensitive diagnostics|terminalizes returned Contract verification infrastructure evidence|preserves ordinary failed mandatory Contract acceptance semantics|atomically interrupts a blocked sibling after|does not invoke a sibling verifier after infrastructure terminalization|keeps target cancellation sticky across sequential checks and permits bounded ID reuse|keeps cancellation sticky across reserved container creation before start" -# 2 files; 8 passed, 34 skipped - -npm run test -w @launchpad/server -- --run \ - src/shepherd/service.test.ts src/shepherd/verifier.container.test.ts \ - src/shepherd/codex-executor.test.ts src/shepherd/executor.test.ts src/app.test.ts \ - src/shepherd/recovery.test.ts src/shepherd/recovery.process.test.ts \ - src/shepherd/state-machine.test.ts src/database.test.ts src/store.test.ts -# 10 files passed; 185/185 tests passed - -npm run check -# exit 0: both workspace typechecks; launcher 3/3; server 26 files and -# 563/563 tests passed with one opt-in live file/test skipped; -# web and server production builds passed - -git diff --check -# exit 0 -``` - -The planted canary, private path, and raw verifier message were absent from the -durable Mission detail, public Mission DTO, and persisted store file. No Ark/model -request was made. Browser/UI and live Runtime gates were not run because this -candidate changes only backend failure/cancellation orchestration and deterministic tests. -`T,A,C,S` are fixer-verified; independent Auditor integration gate `I` remains -pending. - -### F-03 independent integration audit - -The Auditor reviewed and integrated the corrected candidate as `dc87553` without -changing UI, dependencies, runtime configuration, public routes, or the existing -required-check workflow. The state transition uses fixed bounded -`verification_infrastructure_error` evidence, preserves ordinary mandatory -acceptance failure, terminalizes all Mission-owned Contract/Plane/Agent/project -ownership in one durable mutation, and rejects late sibling success before any -integration, collision, candidate, or promotion path. The container boundary keeps -cancellation sticky through sequential checks and reserved creation/removal, -contains repeated cancellation, and releases only the exact target for bounded -same-ID reuse. - -Independent observed results on the candidate and integrated tree: - -```sh -# exact corrected service/verifier selection -# 2 files passed; 8 passed, 34 skipped - -# service/API/recovery/store/state-machine/executor/verifier adjacency -# 10 files passed; 185/185 tests passed - -npm run check -# launcher 3/3; server 26 files and 563/563 tests passed with one opt-in live -# file/test skipped; both workspace typechecks and production builds passed - -git diff --check -# passed -``` - -The failure regressions reload the durable store after terminalization, release a -blocked late sibling, and assert the terminal state is unchanged with no green -verification, integration, collision, candidate, selection, or promotion evidence. -Canary diagnostics and private paths remain absent from durable state, public DTOs, -and the store file. No model/network call was made. `F-03` is **AUDITED, scoped -100%** with `T,A,C,S,I` passed 5/5; hosted Node 22 evidence is recorded after the -final audit documentation push. - -## TST-02 deterministic recovery fixture clock - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/base:** `work/mock-main` / `6f7660d` - -The post-CAS startup-reconciliation fixture created its Git Planes with -`PlaneManager`'s wall clock but reconciled them at the fixed instant -`2026-08-29T12:05:00.000Z`. Once wall time passed that instant, recovery attempted -to persist an `updatedAt` earlier than the Plane's `createdAt`; the store correctly -rejected the invalid lifecycle state. - -The original isolated reproduction was preserved before editing: - -```sh -npm run test -w @launchpad/server -- --run src/shepherd/recovery.test.ts \ - -t "fails closed, recognizes the exact post-CAS window, cleans private artifacts, and is idempotent" -# RED: 1 failed, 16 skipped; JsonStore reported -# "Refusing to persist invalid database state" -``` - -The smallest correction is test-only: the affected fixture now passes its existing -deterministic `12:00Z` clock to `PlaneManager`, so Plane creation precedes the -deliberate `12:05Z` recovery instant. Production recovery, store validation, and -lifecycle ordering assertions are unchanged. - -Observed GREEN verification: - -```sh -npm run test -w @launchpad/server -- --run src/shepherd/recovery.test.ts \ - -t "fails closed, recognizes the exact post-CAS window, cleans private artifacts, and is idempotent" -# 1 passed, 16 skipped - -npm run test -w @launchpad/server -- --run src/shepherd/recovery.test.ts -# 17/17 passed - -npm run check -# exit 0: both workspace typechecks passed; launcher 3/3 passed; -# server 26 files and 555 tests passed with one opt-in live file/test skipped; -# web and server production builds passed -``` - -No Ark/model request was made. The implementation has `T`, `A`, and `C` evidence; -independent Auditor integration and the `I` gate remain pending. - -### Independent Auditor integration - -**Candidate:** `bab6de18e7c28e5f8a132f8d80163f509c890a1e` - -**Integrated implementation:** `0cb431a0420e3d7f77784fe4c62b42f92710446c` - -The Auditor fetched the candidate without touching the Worker's worktree, reviewed -the exact parent-relative diff, and found one production-adjacent test change: -`recovery.test.ts` injects the fixture's existing `12:00Z` clock into its -`PlaneManager`. The only other changes were this build-log entry and the task row. -No production, UI, store, recovery, lifecycle-validation, API, security, dependency, -or configuration file changed. `git show --check` and the parent-to-candidate diff -check passed. - -The candidate was first verified in a separate detached repository-local audit -worktree: - -```sh -npm run test -w @launchpad/server -- --run src/shepherd/recovery.test.ts \ - -t "fails closed, recognizes the exact post-CAS window, cleans private artifacts, and is idempotent" -# 1 passed, 16 skipped - -npm run test -w @launchpad/server -- --run src/shepherd/recovery.test.ts -# 17/17 passed - -npm run check -# launcher 3/3; server 26 files and 555 tests passed; -# one opt-in live file/test skipped; both production builds passed -``` - -After cherry-picking the candidate onto `mock-main` as `0cb431a`, the Auditor ran -the same integrated-SHA gates again with the same counts: isolated 1/1, recovery -17/17, launcher 3/3, server 555/555 with one opt-in skip, and both builds green. -The audit worktree was clean and removed after verification; the main worktree was -clean before integration. - -**Verdict:** `TST-02` is **AUDITED at scoped 100%** with `T,A,C,I` 4/4. The fixed -fixture clock removes the time-dependent test failure while strict lifecycle/store -validation remains unchanged. Browser, live-model, UI-review, and security-review -gates were not run because this correction changes only deterministic test setup -and evidence documentation. -## TST-02 recovery fixture clock candidate - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch:** `fix/33-recovery-fixture-clock` -**Issue:** [#33](https://github.com/kyashp/shepherd/issues/33) -**Draft PR:** [#34](https://github.com/kyashp/shepherd/pull/34) - -The exact post-CAS recovery test created its Plane through a `PlaneManager` using -the real wall clock, then reconciled it with fixed `recoveredAt` -`2026-08-29T12:05:00.000Z`. Once real time passed 12:05Z, recovery assigned an -`updatedAt` earlier than the Plane's real `createdAt`, and database validation -correctly rejected the state. The unmodified targeted test reproduced the causal -RED with `Refusing to persist invalid database state` after 12:05Z. - -The candidate injects the test's existing `2026-08-29T12:00:00.000Z` timestamp -through `PlaneManager`'s existing `now` option. It changes no production code, -schema, validator, assertion, launcher, dependency, UI file, or ST-02/PR #13 file. - -Observed against code commit -`1dc3133c332b9fd31ec27d2ed5e8d620a0dae08f`: - -- the exact targeted test passed 1/1 at the real post-rollover time 15:08Z; -- the complete `recovery.test.ts` file passed 17/17 at the real post-rollover time; -- literal `npm run check` in a clean Node 24 Linux workspace, with only the process - wall clock held at the shared 12:00Z fixture baseline, passed: launcher 3/3, - server 25 files passed and 2 opt-in files skipped, 551 tests passed and 5 skipped, - and both production builds completed; -- unconstrained real-clock full-suite attempts still exposed unrelated current-main - cross-suite instability in unchanged service/recovery-process cases, while the - changed recovery file remained 17/17; the full unchanged `service.test.ts` and - `recovery.process.test.ts` files then passed 28/28 and 5/5 in isolation; -- `npm audit --json` reported 0 vulnerabilities across 251 dependencies; -- `git diff --check` passed. - -An independent read-only review of the exact code range -`349897d3d9167fe711bf720f7c3fadd213938d11...1dc3133c332b9fd31ec27d2ed5e8d620a0dae08f` -reported no Critical, Important, or Minor finding and returned **Ready to merge: -Yes**. It confirmed the injected clock owns the persisted Plane lifecycle -timestamps, produces a fresh fixed `Date` on each call, precedes recovery by five -minutes, and leaves every fail-closed, cleanup, event, and idempotency assertion -unchanged. - -The clock-controlled full check is recorded as controlled evidence, not as an -unconstrained real-clock pass. The real-clock targeted and full-file results are the -post-rollover proof for this narrowly scoped correction. - -## OPS-05 canonical launcher-entry candidate - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch:** `fix/31-ops-05-canonical-launcher-entry` -**Issue:** [#31](https://github.com/kyashp/shepherd/issues/31) - -On macOS, `os.tmpdir()` returned a lexical `/var/...` path while `realpath()` -returned its `/private/var/...` filesystem identity. The launcher compared the -lexical `process.argv[1]` with ESM's canonical module path, misclassified direct -execution as an import, and exited before starting its child. The preserved initial -launcher suite RED was 1/2: the direct-shell fixture failed with missing -`startup-environment`. A new deterministic symlink-entry RED then failed 0/1 -because its child-side-effect marker was absent even though the launcher exited 0. - -The launcher now canonicalizes both entry paths with `realpath()` before comparing -them. An identity-resolution failure is an explicit generic launcher error (exit 1), -never a safe import classification. The regression invokes a symlink alias and -asserts that its child writes the marker. The existing direct-shell fixture now uses -a temporary `HOME` and asserts Darwin's documented user-local state root while -retaining Linux's repository-local root; exact Docker-default localization, explicit -custom paths, Node-only dotenv parsing, inherited child environment, and secret -non-disclosure assertions remain intact. - -Observed GREEN verification: - -```sh -node --test scripts/start-local-poc-launcher.test.mjs -# 3/3 passed, repeated five consecutive times - -npm run check -# exit 0: workspace typechecks passed; launcher 3/3; server 25 files passed, -# 550 tests passed, 2 opt-in tests skipped; web and server production builds passed - -npm audit -# found 0 vulnerabilities -``` - -No Ark or Shepherd model request was made. A real zero-parameter Docker smoke was -unavailable in this session: the Docker CLI was installed but `docker info` exited -1, so no live Runtime claim is recorded. - -## OPS-04 local loopback candidate - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/commit:** `fix/29-ops-04-local-loopback` / `a0a2d60` -**Issue:** [#29](https://github.com/kyashp/shepherd/issues/29) - -The first exact post-#28 command, `./scripts/start-local-poc.sh`, used the real -ignored `.env` without printing values. Runtime preflight and both builds passed, -but server configuration then failed closed because the inherited host was an -any-address value and the configured application token was a placeholder. A -classification-only check confirmed those facts without exposing either value. - -The candidate changes only the local launcher: an empty host or the exact container -any-address values `0.0.0.0` and `::` become `127.0.0.1`. Other custom hosts remain -unchanged, and the server's non-loopback token validation is untouched. The causal -RED fixture captured `0.0.0.0`; GREEN captured `127.0.0.1` through the real launcher -boundary. - -The exact direct command was then run from the candidate worktree against the real -ignored `.env` through a temporary ignored symlink; no credential was copied, -printed, or committed. Observed results: - -- listener: `127.0.0.1:3000` only; -- `GET /api/health`: 200; -- `GET /`: 200; -- unauthenticated `GET /api/system`: 401; -- authenticated `GET /api/system`: 200 with Ark configured, Codex available, and - the container/Docker Runtime selected; -- SIGINT closed port 3000 and left zero Runtime containers owned by the configured - instance; the temporary `.env` symlink was removed; -- no Agent or Shepherd model request was made. - -Final local verification before PR creation: - -```sh -node --test scripts/start-local-poc-launcher.test.mjs -# 2/2 passed - -npm run check -# exit 0: both workspace typechecks passed -# launcher tests 2/2 passed -# 26 server test files passed, 1 opt-in live file skipped -# 551 tests passed, 1 opt-in live test skipped -# web and server production builds passed -``` - -The configured custom security-reviewer role was unavailable. An independent -read-only fallback review reported no high or medium finding and confirmed that -non-loopback hosts still reach the unchanged server token-enforcement boundary. -It reported one Low test gap for empty, IPv6-any, and explicit custom hosts. The -launcher regression now covers empty and `::` normalization plus preservation of -the concrete documentation-range host `192.0.2.10`; the focused test remains 2/2. - -## OPS-02 direct local startup candidate - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch/commit:** `fix/27-ops-02-direct-env-launch` / `e4cb2e5` -**Draft PR:** [#28](https://github.com/kyashp/shepherd/pull/28) - -Direct `./scripts/start-local-poc.sh` previously exited 2 before Runtime detection -because it did not read the repository `.env`. The preserved RED launcher fixture -observed the generic missing-Ark-variable error. The candidate performs one guarded -handoff through Node's dotenv parser and marks the returned shell environment to -prevent recursion; `.env` is never sourced or printed. - -The same fixture established the adjacent host-path defect: `.env.example` Docker -defaults would otherwise remain `/app/...`. The candidate maps only those exact -defaults into the existing platform local-state root and leaves explicit custom host -paths unchanged. The fake engine/npm boundary captures values only in a private -temporary test file and asserts that planted Ark/model sentinels never reach stdout -or stderr. - -Observed verification: - -```sh -node --test scripts/start-local-poc-launcher.test.mjs -# 2/2 passed: npm launcher compatibility; direct dotenv/path behavior - -bash -n scripts/start-local-poc.sh -node --check scripts/start-local-poc-launcher.mjs -git diff --check -# all passed - -npm run check -# exit 0: both workspace typechecks passed -# launcher tests 2/2 passed -# 26 server test files passed, 1 opt-in live file skipped -# 551 tests passed, 1 opt-in live test skipped -# web and server production builds passed -``` - -No live Ark or Shepherd-model request was made. The configured custom security -reviewer role was unavailable, so an independent read-only fallback reviewer -inspected the exact `origin/main...8266c46` delta. It reported no critical, high, -medium, or low finding: Node parses rather than executes `.env`; the recursion -marker adds no privilege boundary; paths remain quoted; only exact Docker defaults -are localized; and container isolation is unchanged. It reran the launcher suite -2/2. A post-merge real zero-parameter startup smoke remains before `OPS-02` may be -marked complete on `main`. - -## Phase 0 — Baseline Lock - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch:** `feature/shepherd-phase-0-baseline` -**Starting commit:** `12479cf` -**Environment:** Node 24.17.0, npm 11.17.0, Git 2.43.0, Docker client/server 29.7.2, Linux host. The application Runtime image is based on Node 22. - -### Configuration and credential hygiene - -- Confirmed ignored `.env` contains configured `ARK_API_KEY`, `ARK_MODEL`, `SHEPHERD_MODEL`, and `ARK_BASE_URL` without printing their values. -- Removed real values from tracked `.env.example`; it now contains placeholders only. -- Direct Responses API probes returned HTTP 200 and exact output `OK` for the configured Agent model (`gpt-5.6-terra`) and Shepherd model (`gpt-5.6-sol`). -- Added ignored `.tmp/` so test/browser temporary state can remain inside the repository boundary. - -### Locked dependency baseline - -Commands: - -```sh -npm ci -npm audit fix -npm audit -``` - -Observed: - -- Locked install completed. -- The initial audit reported five high and one moderate advisory. -- Non-force audit remediation updated seven transitive packages. -- Final audit: `found 0 vulnerabilities`. -- Added exact development dependency `@playwright/test@1.62.1`; Chromium 151 test binaries are held under ignored repository-local `.tmp/`. - -### Real starter Runtime acceptance - -Started the actual local PoC on loopback with repository-local persistent state and the disposable Docker Runtime. The first build produced `volc-agent-runtime:local`. Runtime preflight observed that Landlock was unavailable and correctly used the documented `danger-full-access` inner fallback inside the disposable outer container. - -Observed API/system state: - -```json -{ - "arkConfigured": true, - "arkModel": "gpt-5.6-terra", - "codexAvailable": true, - "runtimeProvider": "container", - "containerEngine": "docker" -} -``` - -Acceptance journey: - -1. Created one real Agent through `POST /api/agents`; it entered `ready`. -2. Sent a dependency-free hello-world CLI task through `POST /api/agents/:id/messages`. -3. Observed Run transition `queued → running → completed`. -4. Agent created `hello.js` and `hello.test.js`; the exact Runtime-container command `node --test hello.test.js` passed 1/1. -5. Sent a minimal follow-up in the same persisted Codex thread; observed exact response `Hello, world!`. -6. Stopped and restarted the server against the same data root. -7. After restart, observed the Agent still `ready`, its Codex thread present, four ordered messages (`user, assistant, user, assistant`), two completed Runs, and the original workspace files. - -The first live turn reported 79,196 input tokens (58,062 cached) and the follow-up reported 91,339 input tokens (67,739 cached). This is why later live-model verification is intentionally limited to required gates. - -### Diagnosed baseline discrepancy - -Reproduction on the host: - -```sh -node --test .local/baseline-poc/workspaces//hello.test.js -``` - -Observed: failure because the host resolves the nested workspace under the repository's root `"type": "module"`, while the Agent generated CommonJS `.js` files. - -Root cause: the same mounted workspace is `/workspace` inside the disposable Runtime and has no ancestor `package.json`; Node therefore evaluates the generated files as CommonJS there. Re-running the exact test in `volc-agent-runtime:local` passed 1/1. No starter code was changed because the supported execution boundary behaved correctly; the host-only command is not the Runtime acceptance path. - -### Rendered baseline evidence - -Used headless Chromium against the real production server and real persisted backend data. - -- `docs/ui-review/baseline/1440x900.png`: Agent, session, first response, and follow-up rendered; no horizontal overflow. -- `docs/ui-review/baseline/1280x800.png`: same persisted state rendered; no horizontal overflow. - -Both screenshots were visually inspected. They establish the starter's cream surface, charcoal sidebar, violet accent, typography, spacing, chat treatment, and compact control conventions to preserve. - -### Phase 0 gate - -Commands and observed results: - -```sh -TMPDIR="$PWD/.tmp/test-temp" npm run check -# type checks passed; 5 test files / 12 tests passed; web and server builds passed - -terraform fmt -check -recursive deploy/volcengine -# passed - -docker compose config --quiet -# passed - -npm audit -# found 0 vulnerabilities - -git diff --check -# passed -``` - -**Verdict:** starter deterministic checks, real model/container execution, session continuation, restart persistence, and rendered baseline are verified for this local environment. This does not yet establish any Shepherd behavior. - -## Phase 1 — Deterministic Walking Skeleton - -**Date:** 2026-08-29 (Asia/Singapore) - -**Branch:** `feature/shepherd-phase-1-kernel` - -### Built kernel chain - -Implemented the deterministic chain before connecting any live model: - -```text -Contracts → real Git worktrees → deterministic executors → manifest ingestion -→ actual-diff authority → independent Docker verification → trusted integration -→ normalized semantic collision → concurrent resolution Planes -→ independent candidate evidence → deterministic selection -→ final re-verification + expected-HEAD CAS promotion -``` - -The V2 store migration preserves the captured V1 Agent/message/Run fixture. Mission and Contract transitions, 22 failure codes, authority envelopes, Plane/candidate evidence, collision state, group messages, settings, and monotonically sequenced events are durable. Store mutations are serialized and written through an atomic temporary-file rename. - -The managed authentication fixture uses different frontend/backend files, so both contract commits merge without a textual conflict. Their normalized exclusive `auth.transport` claims conflict semantically. Under the default invariant the cookie candidate passes and is promoted; flipping the invariant selects bearer instead. Both resolution Planes begin at the exact same integration SHA. - -### Trust-boundary verification - -- Git is invoked with argv arrays, sanitized refs, disabled prompts/hooks/signing, bounded output, and explicit timeouts. -- Public protected-worktree/ref mutation methods reject direct use; the configured protected branch changes only through the final promotion gate. -- Contract and candidate executors receive authority-filtered, Git-free exports with opaque handles; they never receive a linked Git worktree or trusted repository metadata. -- Trusted import compares the complete exported tree with the source Plane, validates the derived actual diff, and rejects escapes, symlinks, FIFOs/special files, `.git`, protected `.shepherd` contents, and out-of-scope writes. A partial import is restored before the error is surfaced. -- Contract and candidate commits are inspected against actual changed paths at the import/Plane boundary and again before promotion. -- Result manifests are strict-schema parsed. The exact `.shepherd/result.json` ingestion exception is removed before trusted commit creation and is absent from every Plane commit. -- The independent verifier creates a fresh snapshot of the exact trusted commit, creates a named container, mounts only that snapshot read-only, uses `--network none`, no capabilities, no new privileges, cleared environment, bounded resources/output/time, then forcibly removes both the container and snapshot on every exit path. -- Independently observed fixture facts must corroborate manifest claim values before claims are persisted as collision inputs. A forged value produces `claim_rejected` and `invalid_semantic_evidence` instead of participating in selection. -- Protected compare-and-swap promotion rolls the ref back to the expected commit if worktree synchronization fails and proves both ref and worktree restoration. Synchronization failure and unprovable rollback are distinct fail-closed errors. -- Agent workspaces use isolated execution UUIDs outside all protected repositories and Planes. Public DTOs expose allowlisted logical fields only. -- Server binding defaults to loopback. Every non-loopback bind requires a URL-safe, non-placeholder token of at least 24 characters; internal errors are bounded/redacted and public 500 responses are generic. -- The JSON store sanitizes configured canaries and common credential forms before state can become observable in memory or on disk. Public Shepherd DTOs strip repository, worktree, and Agent workspace host paths. - -An independent read-only security review first identified mutable verification input, linked worktree metadata at the executor boundary, public-bind authentication defaults, uncorroborated claims, incomplete production authority intersection, raw error/path exposure, and a protected-ref synchronization edge. Each finding received a regression test and the smallest fail-closed remediation above. A second independent review re-ran its focused 38-test security slice and reported no remaining critical, high, or medium findings. - -### Automated and real-boundary evidence - -Focused real-container Mission test: - -```sh -npm run test -w @launchpad/server -- --run src/shepherd/service.container.test.ts -# 1 file / 1 test passed; real Docker Mission completed in 5.53 s -``` - -The test observed persisted contract/candidate/final-promotion evidence, the cookie winner, common resolution base SHA, selected Plane HEAD equal to protected HEAD, trusted profile output, no committed `.shepherd` path, and no remaining containers owned by that Mission. - -Full parallel server suite after integration: - -```sh -npm run test -w @launchpad/server -# 19 files / 225 tests passed -``` - -Real built-server HTTP smoke used isolated repository-local data and the real `volc-agent-runtime:local` verification image. Observed: - -```json -{ - "unauthenticatedStatus": 401, - "rejectedInputStatus": 400, - "missionState": "completed", - "selectedTransport": "http-only-session-cookie", - "corroboratedClaimEvents": 2, - "eventCount": 33, - "elapsedMs": 6798, - "pathAndTokenLeakCheck": "passed" -} -``` - -After graceful stop/restart against the same store, the Mission remained `completed`, persisted protected HEAD matched real Git `HEAD`, no control metadata was tracked, and neither the configured Ark key nor application token appeared in the persisted JSON. The execution-export, trusted-materialization, and trusted-verification directories were empty; Git listed no materialization worktrees; a global Docker label query returned zero remaining verifier containers. - -### Five invariant mutation checks - -Each guard was temporarily disabled only in the working tree, its hostile test was run red, the guard was restored, and the same test was run green. No mutation was retained. - -| Invariant | Temporary mutation | Red observation | Restored observation | -| --- | --- | --- | --- | -| Agent cannot self-certify | Allowed `agent_runtime` to perform `verifying → verified` | Independent-actor assertion failed (1 failed / 7 passed) | State-machine suite 8/8 passed | -| Out-of-scope changes cannot integrate/promote | Forced writable-scope result to `true` | Authority suite failed twice and direct Plane-boundary bypass test failed | Authority + Git suites 56/56 passed | -| Protected branch only changes through promotion | Disabled protected-root mutation guard | Structural bypass test resolved instead of rejecting | Git/Plane suite 10/10 passed | -| Winner is evidence-derived | Forced first assessment to pass | Invariant-flip expected cookie but selected bearer (1 failed / 27 passed) | Resolution suite 28/28 passed | -| Secrets never persist | Replaced recursive redaction with identity | New-write and existing-V2 canaries both leaked (2 failed / 5 passed) | Store suite 7/7 passed | - -### Problem-resolution record: parallel Docker cleanup assertion - -Reproduction: - -```sh -npm run check -# verifier.container.test.ts reported containers owned by service.container.test.ts -``` - -Root cause: Vitest runs test files in parallel, while both real-container tests queried the shared `io.codejam.shepherd=independent-verifier` label and incorrectly treated another test's live container as their own leak. - -Fix: cleanup assertions now combine the shared label with each test's owned `io.codejam.verification-target` labels. This preserves parallelism and still proves each executor destroys its own containers. The original full-suite reproduction then passed 19/19 files and 225/225 tests; an additional phase-boundary global query proves no actual leftovers after all work stops. - -### Problem-resolution record: authority denial misclassification - -Reproduction: an executor changed an out-of-scope file after Git-free export, and the service initially persisted generic `execution_failed` because trusted import occurred inside the broad executor error boundary. - -Root cause: authority validation had moved to the trusted import boundary, but the orchestration layer still classified every pre-import exception as an execution failure. - -Fix: execution completion and trusted import now have distinct transitions/error handling. An import-scope rejection durably records `authority_denied` (and candidate `unauthorized_file_change`) while preserving the fail-closed Plane. The focused service/container/Git slice passed 23/23 after the original reproduction was rerun. - -### Problem-resolution record: real-Git integration timeout under suite load - -Reproduction: the full parallel suite crossed Vitest's generic 5-second default in one real-Git background Mission journey (observed 5.13 seconds) even though the Mission was progressing normally. - -Root cause: the integration test intentionally performs multiple real worktree, commit, merge, snapshot, and container-adjacent operations and can exceed a unit-test timeout under parallel contention. - -Fix: only that real-boundary integration test declares a 30-second ceiling; unit-test defaults remain unchanged. No sleep or polling delay was added. The full 225-test server suite passed afterward. - -### Problem-resolution record: empty control directory in snapshots - -Reproduction: after trusted import removed `.shepherd/result.json`, the optimized snapshot copier rejected the now-empty root `.shepherd/` directory even though no control content could enter the snapshot. - -Root cause: the hardened tree copier correctly rejected protected control content but did not distinguish a harmless empty root directory left by manifest ingestion from actual metadata. - -Fix: snapshot creation skips only an empty root `.shepherd/`; any file or nested content still rejects the source. A regression also proves `.git`, live-only files, and control content never enter a verification snapshot and every snapshot is removed. - -### Hardened Phase 1 focused gate - -```sh -npm run test -w @launchpad/server -- --run \ - src/config.test.ts src/app.test.ts src/shepherd/auth-fixture.test.ts \ - src/shepherd/service.test.ts src/shepherd/git-plane-promotion.integration.test.ts -# 5 files / 38 tests passed - -npm run test -w @launchpad/server -# 19 files / 225 tests passed (includes the real Docker Mission) - -npm run typecheck -w @launchpad/server -# passed -``` - -**Security review verdict:** no critical, high, or medium findings remain at the Phase 1 boundary. - -### Phase 1 branch gate - -```sh -TMPDIR="$PWD/.tmp/test-temp" npm run check -# exit 0: both workspace type checks passed; 19 files / 225 server tests -# passed; web and server production builds passed - -npm audit -# found 0 vulnerabilities - -terraform fmt -check -recursive deploy/volcengine -# passed - -docker compose config --quiet -# passed - -git diff --check -# passed -``` - -A repository-wide text scan compared the configured non-placeholder Ark credential against 145 files (excluding the ignored source `.env`, dependency/build/browser scratch, and Git metadata) and found zero occurrences. The global verifier-container label query returned zero containers. - -The sample environment now defaults `HOST` to `127.0.0.1`; Compose and Terraform retain explicit service binds with their required application token. The user's current ignored `.env` has both requested models and the Ark credential configured, but also has a non-loopback host without a strong application token. Test/rehearsal processes therefore use an explicit loopback override until the private file is intentionally changed; the server correctly refuses that unsafe combination. - -**Phase verdict:** the deterministic kernel, its hardened executor/import/verifier boundaries, real Git/container/HTTP path, restart persistence at a completed boundary, and all Phase 1 security regressions are verified. General in-flight recovery and the remaining PRD capabilities are intentionally deferred to subsequent phase gates. - -## Phase 2 — Domain, Persistence, and Crash Recovery Hardening - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch:** `feature/shepherd-phase-2-recovery` - -### Strict durable state - -The version-2 store now validates every persisted and outgoing field with strict, -bounded schemas rather than accepting shape-compatible JSON. Validation covers -canonical host and project-relative paths, supported authority patterns, safe Git -branches, full object IDs, bounded collections/text/numbers/timestamps, unique IDs, -references, event cursors, one active non-terminal Mission, and lifecycle/evidence -relationships. The captured version-1 fixture is independently validated before its -lossless migration. - -False-green completion is rejected unless verified Contracts have non-vacuous -mandatory acceptance evidence tied to their exact Plane diff and manifest claims. -Collision sources must be verified Contracts with canonical embedded claims. For the -managed authentication fixture, candidate evidence must contain exactly the trusted -frontend, backend, and project-security mandatory suite; final promotion evidence -must repeat that exact suite. Completed collision Missions require one resolved, -selected, promoted candidate whose verified Plane HEAD matches the protected project -HEAD. A no-collision completion requires a verified integration Plane at the promoted -protected HEAD. - -The JSON reader uses bounded, no-follow, non-blocking regular-file reads. Outgoing -state is validated and recursively scrubbed before a unique exclusive `0600` -temporary file is synced and atomically renamed. Oversized reads/writes, symlinks, -fixed-name temporary symlinks, FIFOs, invalid outgoing state, and persistence failure -before in-memory publication all have negative tests. The supported concurrency model -is one server process per data root; mutation serialization is in-process and the JSON -store is not a distributed database. - -### Restart reconciliation and trust adoption - -Startup now validates the sentinel-bound managed root, project metadata, repository, -Plane roots, Plane sentinels, Git worktree registration, protected branch, index, and -worktree before serving. Trusted identity files are bounded `O_NOFOLLOW | O_NONBLOCK` -reads with pre/opened inode and size checks. Persisted host paths are comparison values -only; server-derived sentinel identities select filesystem locations. Missing, -substituted, symlinked, special-file, out-of-root, dirty, detached, unregistered, or -unexpected artifacts fail closed. - -In-flight Contracts, candidates, and Planes become `interrupted`; their Mission and -Collision become `attention_required`; Agent leases are released; private execution, -materialization, and verification artifacts are removed. Evidence and the event cursor -are preserved, and a second restart is idempotent. - -Promotion has a durable intent boundary. After final authority, immutable-head, -selection, protected-head, and independent-verification checks—and immediately before -compare-and-swap—Shepherd atomically records `promotionState=promoting`, the complete -passing promotion evidence, and its Plane evidence link. Recovery never trusts the -earlier `reverifying` state. It recognizes a post-CAS window only when the exact -selected resolution Plane, expected-head ancestry, derived branch/worktree identity, -live Git registration, clean/index-synchronized protected checkout, candidate HEAD, -and complete verifier suite all corroborate. Ordinary post-marker promotion failures -retain evidence and fence the project in `attention_required`; a same-process second -Mission cannot silently adopt an external branch move. - -An empty/replaced database cannot establish a new trust root over old managed project -artifacts. Only a missing/empty root or an existing sentinel-only root with empty known -containers is a valid zero-project state. A non-empty unsentinelled root is still never -adopted. - -### Stable verifier and Agent identities - -Verifier cleanup ownership is installation-scoped and restart-stable: -`verifier..<128-bit persisted nonce>`. A separately persisted marker -distinguishes first boot/one-time upgrade from nonce loss; corruption, symlink/special -files, or deletion after establishment fail closed. Concurrent first starts converge -on one nonce, while different data roots remain distinct. Cleanup targets only the -exact owner label. - -Persisted Agent workspaces are revalidated at startup and before execution against the -canonical configured workspace root and exact Agent-ID-derived path. Escapes, -cross-Agent substitutions, root/leaf symlinks, and durable Shepherd references during -Agent deletion are rejected. - -### Problem-resolution records - -**Persisted state initially proved shape, not truth.** Hostile V2 fixtures could label -evidence-free or weakly related records as verified/completed. The root cause was that -the first V2 loader validated DTO shapes and references but not completion proofs. -Strict semantic/lifecycle validation plus false-green fixtures now rejects invented, -substituted, incomplete, or cross-target evidence. - -**A restart-unstable verifier owner could collide or leak cleanup scope.** A random -per-process fallback changed on every boot and a configured default could be shared by -unrelated installations. Persisted installation identity and exact-owner cleanup -remove both ambiguities. - -**A persisted `reverifying` candidate was not proof that CAS had been attempted.** An -external move to the candidate SHA during re-verification could resemble a post-CAS -crash. The durable pre-CAS evidence marker makes the distinction explicit; recovery -accepts only `promoting` with the exact full suite. A kill immediately before CAS keeps -the trusted/protected head unchanged, while a kill immediately after a successful CAS -can be corroborated and adopted. - -**Promotion failure could release the project fence.** The initial compensation marked -only the Candidate/Collision before generic failure handling terminalized the Mission -and cleared `activeMissionId`. The fixed atomic compensation preserves final evidence, -sets Candidate promotion failure plus Mission/Collision `attention_required`, and keeps -the project fenced. A synchronous regression proves a second Mission is rejected and -neither the stored trusted head nor externally moved Git head changes. - -**Deleting only the database could orphan and then re-adopt an old repository.** The -empty state previously looked like first boot. Startup now rejects any established -managed project artifacts when no durable Project record exists; a hostile external -branch move remains untrusted. - -**A live server could adopt an external head between Missions.** Startup reconciliation -runs once, while the fixture re-opener returns the repository's current branch head. -After a completed Mission, an external commit could therefore become the next Mission's -base without a restart. Mission preparation now re-derives the sentinel-backed project -identity and requires the protected ref, checked-out branch, HEAD, index, and worktree -to equal the durable trusted record before any new Mission, Plane, Agent, workspace, or -store mutation. A regression completes one Mission, commits externally, and proves a -second synchronous run is rejected with all durable counts and both heads unchanged. - -**No-follow reads could still block on a FIFO.** Opening a FIFO read-only can block -before `fstat`. Adding `O_NONBLOCK` while retaining post-open regular-file and identity -checks makes database, verifier identity, sentinel, metadata, and policy reads reject -special files immediately. - -**A real-Git winner-flip test retained a unit-test timeout.** An independent full-suite -run exceeded Vitest's five-second default while parallel real-Git tests were active; -the still-running test then raced teardown of a read-only snapshot. The production path -was not failing. That integration-style test now has the same 30-second ceiling as its -adjacent real-Git journeys. Two consecutive complete server-suite reruns passed after -the fix (31.31 s and 31.47 s) with no teardown failure. - -### Phase 2 verification evidence - -Real process tests send `SIGKILL` at five boundaries: - -1. contract execution workspace ready; -2. contract verification snapshot ready; -3. complete promotion proof persisted immediately before CAS; -4. successful CAS complete before final database persistence; and -5. protected ref updated before protected index/worktree synchronization. - -Each ordinary boundary is restarted twice and proves non-green durable state, -artifact cleanup, and cursor idempotence. The internal ref/index gap is rejected on -both restarts with the original trusted head preserved. - -Commands and observed results: - -```sh -TMPDIR="$PWD/.tmp/test-temp" npm run test -w @launchpad/server -- \ - src/database.test.ts src/shepherd/git-plane-promotion.integration.test.ts \ - src/shepherd/recovery.test.ts src/shepherd/recovery.process.test.ts \ - src/shepherd/service.test.ts -# 5 files / 111 tests passed - -TMPDIR="$PWD/.tmp/test-temp" npm run check -# exit 0: both workspace type checks passed; server suite passed; -# web and server production builds passed - -TMPDIR="$PWD/.tmp/test-temp" npm run test -w @launchpad/server -- \ - --reporter=json --outputFile="$PWD/.tmp/phase2-vitest.json" -# 21 files / 326 tests passed; 0 failed or pending - -# repeated twice after stabilizing the real-Git test ceiling -# run 1: 21 files / 326 tests passed in 31.31 s -# run 2: 21 files / 326 tests passed in 31.47 s - -npm audit -# found 0 vulnerabilities - -terraform fmt -check -recursive deploy/volcengine -docker compose config --quiet -git diff --check -# all passed -``` - -A repository-local exact-value scan checked 150 tracked/ignored project files outside -`.env`, Git metadata, dependencies, builds, and test/browser scratch against the one -configured non-placeholder secret and found zero matching files. The global verifier -container label query returned zero containers after the suite. - -The dedicated `security-reviewer` role was requested after stabilization but was not -available in this environment. A separate read-only fallback reviewer inspected the -complete Phase 2 trust boundary and ran a 5-file/111-test security slice, server -typecheck/build, production fault-seam scan, and whole-tree diff check. Its final -verdict was **no remaining critical, high, or medium findings**. Residual lows are: -directory entries are not explicitly fsynced after atomic rename (process-crash, not -sudden-power-loss, durability is tested); one server per data root is operationally -required; `RUNTIME_INSTANCE_ID` must remain stable for prior-owner container cleanup; -and test-only fault seams remain constructor-injectable but are absent from config, -API, and production composition. - -**Phase verdict:** strict persistence, exact evidence proof, stable ownership, -sentinel-bound identity, five process-kill boundaries, idempotent reconciliation, -pre/post-CAS distinction, live-process protected-head fencing, secret scanning, and -the complete deterministic gate are verified for Phase 2. - -## Phase 3 — Live Plane Runtime and Bounded Advisory Modules - -**Date:** 2026-08-29 (Asia/Singapore) - -**Branch:** `feature/shepherd-phase-3-live-runtime` - -### Versioned execution envelopes and semantic authority - -Contract and resolution work now receive bounded, JSON-escaped -`SHEPHERD_EXECUTION_ENVELOPE_V1` prompts assembled by trusted code. Prompts contain -logical IDs, the intersected authority, expected artifacts, dependency outputs, and -the exact strategy or objective; configured secret values are rejected before a -prompt can be returned. Contract Agents must write the one schema-validated -`.shepherd/result.json` ingestion artifact. Resolution Agents are explicitly forbidden -from writing any `.shepherd/**` path and are evaluated from the imported Git diff and -independent evidence instead. - -Contract envelopes now include both the declared canonical claim keys and the -Contract's declared canonical semantic scopes. Manifest ingestion rejects an -undeclared scope, just as it already rejected an undeclared or omitted key. This -prevents independently correct Contracts from avoiding collision only because their -model-selected scope labels differ. - -Resolution envelopes state the candidate's exact canonical key/value strategy and -forbid substituting a different value based on project policy. Prompt compliance is -not trusted: after the fixed candidate acceptance suite runs, server code derives the -verified `auth.transport` fact from its outputs and requires it to equal the -candidate's persisted target. A candidate whose checks pass for a substituted target -fails with `invalid_semantic_evidence` at -`candidate_target_corroboration`; it cannot tie, win, or promote. - -### Isolated live Codex execution - -`SHEPHERD_EXECUTION_MODE` now accepts `auto`, `live`, or `deterministic`. `auto` -selects live execution only when a usable Ark Agent-model configuration and the -container Runtime are both present. Explicit `live` fails closed if either condition -is absent, and live execution additionally requires `CODEX_SANDBOX_MODE=workspace-write`. -The resolved mode is exposed by system/demo metadata so a deterministic run cannot be -presented as live-model evidence. - -Each Contract or candidate execution uses a fresh Git-free export, a unique opaque -execution identity, a new private `0700` `CODEX_HOME`, and one disposable container. -The exact in-container Codex shape is: - -```text -codex exec --ephemeral --json --sandbox workspace-write \ - --skip-git-repo-check -C /workspace - -``` - -The complete prompt is sent only on standard input. No thread is resumed. The Runtime -container is created first and then started/attached by the validated immutable -container ID, avoiding name-retargeting between creation and attachment. The -container runs non-root with a read-only root filesystem, a dedicated `/tmp` tmpfs, -all capabilities dropped, `no-new-privileges`, and configured CPU, memory, and PID -limits. Only the Git-free workspace and that execution's private home are mounted. - -The outer container uses bridge networking because the Codex control process must -reach Ark. The generated Codex config gives model-authored shell processes a fixed, -key-free environment. Startup preflight, without an Ark credential, requires the -exact pinned `codex-cli 0.111.0`, proves a sandboxed write succeeds in `/workspace`, -proves a write to `/codex-home` is denied, and proves sandboxed TCP listen and connect -attempts are denied. This is distinct from the independent acceptance verifier, which -continues to run with no network and no model credential at all. - -Private-home roots use an exact sentinel and refuse non-empty unsentinelled adoption. -Runtime containers carry the restart-stable installation owner labels introduced in -Phase 2. Startup reconciliation removes only exact-owner interrupted containers, -private homes, and preflight workspaces; normal completion and timeout/cancellation -paths also verify cleanup. - -Codex thread IDs exist only long enough to validate that exactly one fresh session was -created. Shepherd persists only a SHA-256 fingerprint and rejects fingerprint reuse -across Plane executions. Public state and Mission DTOs omit that fingerprint and -expose only `runtimeSessionEstablished: boolean`. Raw session IDs, raw prompts, and -prompt-envelope text are not persisted or returned. - -### Implemented modules not yet connected to Mission orchestration - -Three Phase 3 modules are implemented with focused deterministic tests, but are not -yet invoked by `ShepherdService` or exposed by the current HTTP/UI surfaces: - -- The DAG scheduler validates the duplicate/unknown/self/cyclic dependency cases and - selects a stable maximal batch subject to verified dependencies, failed-dependency - blocking, one active assignment per Agent, the mutation lock, and configured Plane - capacity. -- Project Group routing normalizes and bounds input, routes unmentioned text to - Shepherd, resolves one leading Agent name/ID mention, supports JSON-quoted names, - and rejects malformed, ambiguous, unknown, or multiple mentions. It interprets no - paths or commands. -- `ArkModelReviewer` is an advisory-only Responses client. It canonicalizes and caps - input at 48 KiB, performs at most one HTTPS request with redirects rejected, - `store:false`, no tools, no prior-response chain, and a strict structured-output - schema. It caps streamed response bytes at 128 KiB, output tokens at 1,536, - findings at eight, evidence references at six per finding, and its deadline at - 120 seconds (30-second default). All provider/configuration/timeout/schema/storage - failures return an explicit typed degraded result; no result grants authority or - changes deterministic collision/selection. The current service does not yet call - this adapter or emit its `model_review_degraded` event. **Superseded by the - Phase 4 composition recorded below (`MR-01`).** - -### Live-gate corrective episodes - -The opt-in gate uses the configured Agent model only for this explicit evidence path: - -```sh -npm run test:shepherd:live -``` - -It is single-worker, has no test retries, and creates fresh Mission state inside the -sentinel-guarded repository-local live-gate root. Four failed gate episodes were -preserved as causal evidence before the final pass: - -1. **Two sessions, no semantic collision.** Both contract executions and their - independent checks passed, but one model used a file-oriented scope while the - other used a conceptual scope, so the exact-scope collision predicate found zero - collisions. Root cause: semantic scopes existed on the Contract but were absent - from the prompt and were not checked during manifest ingestion. Supplying the - canonical declared scope and rejecting undeclared scopes fixed the contract. -2. **Four sessions, objective tie.** The collision then appeared and both candidates - ran, but the bearer-target candidate substituted the policy-preferred cookie - implementation. Its independent checks passed the cookie implementation, as did - the actual cookie candidate, so the deterministic selector correctly stopped in - `attention_required` with `objective_tie`. Root cause: the prompt did not make - speculative target fidelity sufficiently explicit and trusted selection checked - acceptance success without corroborating the implemented value against the - candidate target. The exact-target rules and trusted target corroboration above - close both gaps. -3. **Completed Mission, outdated all-pass assertion.** After those product fixes, the - Mission completed with the secure cookie candidate selected and the bearer - alternative objectively rejected by the project-security check. The gate itself - still expected every candidate's verification to pass. The assertion was corrected - to require the evidence-derived bearer failure and cookie promotion; no production - behavior changed for this harness-only failure. -4. **Completed Mission, missing test import.** The next product Mission again - completed, after which the test referenced a fixture transport constant it had not - imported. The missing test-only import was added; no production behavior changed. - -The final gate then passed in **121.49 seconds**. It completed two fresh Missions with -eight total live Codex sessions: two Contract and two resolution sessions per Mission. -Both Missions persisted two verified Contracts, one resolved semantic collision, the -bearer candidate rejected by independent acceptance, the cookie candidate selected -and promoted, and 33 bounded events. All eight persisted session fingerprints were -present, valid, and unique; no raw session ID was stored or exposed. Both resolution -Planes shared their Mission's exact immutable integration base. - -The gate also proved the protected repository HEAD equals the promoted result, -`.shepherd/**` is absent from the promoted tree, and no prompt-envelope marker or -configured secret appears in persisted state, reachable Git blobs, or managed -worktree files. Exact-owner queries found no remaining live-Runtime or verifier -containers, and every per-execution private home and Git-free execution export was -gone after cleanup. - -### Security review and verification evidence - -The independent Phase 3 live-Runtime review identified four Medium findings during -implementation: unsafe private-root adoption, an incomplete sandbox preflight, raw -Runtime error/secret propagation, and a cleanup rejection race. Sentinel-only -adoption, the positive/negative filesystem plus socket probes, bounded redacted -Runtime errors, and immediately handled/awaited cleanup failures closed them. The -reviewer's final 58-test focused slice reported no remaining critical, high, or -medium finding at the live-Runtime boundary. - -The independent model-reviewer review later found two Medium stream-handling issues: - -- **M1:** a hostile asynchronous `reader.cancel()` rejection could surface as an - unhandled rejection. Every fire-and-forget cancellation now attaches a rejection - handler, with an exact regression. -- **M2:** an endless stream of zero-byte chunks could make no byte progress and starve - the intended deadline path. Zero-byte chunks are now rejected immediately as an - invalid response, with an exact regression. - -The same reviewer re-inspected both fixes and reported both Mediums closed, no new -critical/high/medium findings, and a **PASS** merge gate. Its fake-only focused suite -passed **121/121**; the review made no network call and did not read `.env`. - -A final independent security delta review then covered the canonical-scope and -candidate-target changes together with the live-gate scanner and Ark adapter. Its -focused suite passed **174 tests with the opt-in live test skipped**, its diff check -passed, and it reported **no critical, high, or medium finding**. It made no network -call and did not read `.env` or credentials. Residual lows are recorded explicitly: -the generic manifest-ingestion API treats an omitted declared-scope list as -unrestricted, although every production service call supplies a non-empty list; the -live gate scans current/reachable Git blobs and managed worktrees rather than dangling -Git objects; and the Ark reviewer requires a trusted HTTPS endpoint configuration but -does not pin a hostname. - -The first final repository check exposed one test-harness concurrency flake: an -executor test used a 15 ms sleep as a proxy for proving two Contract executions had -overlapped. Under full-suite scheduling, the first execution could finish before the -second arrived even though production still dispatched them concurrently. The test -now uses a deterministic two-arrival barrier and still records the maximum active -executions. Its focused service suite passed **12/12** after the correction. - -Final commands and observed results: - -```sh -npm_config_cache="$PWD/.tmp/npm-cache" \ - TMPDIR="$PWD/.tmp/test-temp" npm run check -# exit 0: both workspace type checks passed -# 26 test files passed, 1 opt-in live file skipped -# 520 tests passed, 1 opt-in live test skipped -# web and server production builds passed - -npm run build -w @launchpad/server -# passed on a separate rerun -``` - -The final exact-owner container query returned no container. The two-Mission live -gate above is separate opt-in evidence; its PASS is not presented as proof of -unrelated UI or Phase 4 behavior. - -**Phase 3 scope verdict:** isolated live Contract/candidate execution and the fixed -demo Mission are proven across two fresh end-to-end Missions. Scheduler, Project -Group parser, and Ark advisory-reviewer modules exist and are focused-test-backed, but -their service/API integration remains Phase 4 work and is not claimed here. - -## 2026-08-29 — GC-01 draft correction - -[Draft PR #9](https://github.com/kyashp/shepherd/pull/9) implements the bounded -`GC-01` correction discovered while verifying Project Group mentions: - -- Project Group mention buttons generate the parser's JSON-quoted syntax for Agent - names containing whitespace or unsafe token characters. The pure prepend contract - preserves existing multiline composer content; the page retains its existing - request-animation-frame focus/caret restoration. - -Strict TDD evidence: - -- Mention formatting RED received `@Frontend Agent` instead of - `@"Frontend Agent"`; focused GREEN passed 2/2. -- Draft preservation RED reported a missing prepend contract; focused GREEN passed - 3/3 after the helper and page integration. - -The final pre-merge `npm run check` passed with 25 test files passed and 2 skipped, -544 tests passed and 2 skipped, and successful web/server typechecks and production -builds. - -Browser interaction and screenshots are not claimed: the browser runtime exposed no -attachable browser. `docs/HANDOVER.md` records the remaining `GC-01` keyboard, -focus/caret, and `1280x800`/`1440x900` gates plus separate `GC-02..07` work. - -## RST-01 — Idempotent and Serialized Demo Reset - -**Date:** 2026-08-29 (Asia/Singapore) - -**Branch:** `fix/7-rst-01-idempotent-reset` - -**Draft PR:** [#10](https://github.com/kyashp/shepherd/pull/10) - -**Reviewed implementation commit:** `19a2e45f7a67c575d9acced3dfcfbc6a32f5718e` - -### Root cause and correction - -`resetDeterministicDemo()` classified a missing durable `auth-demo` project as -`not_found`, although a missing project is the expected state before the first demo -Mission. The initial empty-result correction then exposed a check-without-reserve -race: reset checked `activeProjects` but did not claim `auth-demo` across its later -asynchronous validation and cleanup work. - -The scoped correction: - -- returns a deliberate path-free empty success with `restoredHead: null` and zero - removal counts when the durable project is absent; -- creates no Mission, Agent, repository, worktree, or fixture merely to reset; -- still calls `assertNoManagedProjectState()` so the empty path fails closed on - orphaned, symlinked, or unknown managed-root artifacts; -- synchronously reserves `auth-demo` before the first reset await and releases it in - `finally`, serializing both clean and initialized resets against Mission startup; -- leaves initialized trusted-identity checks, guarded Git/Plane cleanup, unrelated - data preservation, cursor high-water preservation, and partial-reset recovery - intact. - -### TDD and verification evidence - -Original clean-start RED: - -```sh -npm test -w @launchpad/server -- src/shepherd/service.test.ts src/app.test.ts \ - -t "returns the same empty result|returns an authenticated empty demo reset" -# 2 failed as intended: service rejected "Auth demo was not found"; -# authenticated API returned 404 instead of 200 -``` - -Concurrency RED and GREEN: - -```sh -npm test -w @launchpad/server -- src/shepherd/service.test.ts \ - -t "reserves .* demo reset against a concurrent Mission start" -# RED: 2 failed; clean start reached the executor and initialized reset lost the race -# GREEN after reservation: 2 passed, 21 skipped -``` - -Additional observed results: - -- reset-focused service/API selection: **8 passed, 34 skipped**; -- adjacent persistence/recovery suites: **100 passed**; -- complete Shepherd service suite: **23 passed**; -- complete server suite with one worker: **25 files passed, 2 skipped; 547 tests - passed, 2 skipped**; -- `npm run check` under Node 24.17.0/npm 11.17.0 with Vitest externally constrained - to one worker: both workspace typechecks, the same complete server suite, and both - production builds passed; -- `npm audit --json`: **0 vulnerabilities across 251 dependencies**; -- `git diff --check`: passed. - -Three unconstrained `npm run check` attempts after the concurrency correction hit -different existing fixed 1-second/5-second timeouts in Git-heavy service, recovery, -and Plane integration tests. Every affected test passed isolated, and the complete -suite passed serialized without weakening assertions. This is recorded as `TST-01` -in `HANDOVER.md`; no unrelated timeout or test behavior changed in PR #10. - -### Current-main integration verification - -After OPS-05 merged through PR #32 at -`8110aa3ed49bd0586cbb275d7c4067552cd9a144`, only `origin/main` was merged into -the RST-01 branch. Merge commit -`4673edfff0d6a205b48ca4d90821ce852a9952e4` had conflicts only in this file and -`docs/HANDOVER.md`; resolution preserved current-main evidence and reapplied only -RST-01-specific entries. The effective diff against `origin/main` remained limited -to the three reset implementation/test files and these two evidence files. - -Fresh results observed on that integrated commit: - -- reset-focused service/API selection: **2 files passed; 8 tests passed, 39 - skipped**; -- complete `service.test.ts`: **28/28 passed**; -- complete `app.test.ts`: **19/19 passed**; -- `npm run typecheck`: both workspace typechecks passed; -- `npm run build`: web and server production builds passed; -- literal `npm run check` with no worker or timeout override: launcher tests - **3/3 passed**; server **25 files passed, 2 skipped; 554 tests passed, 2 - skipped**; both production builds passed; -- `npm audit --json`: **0 vulnerabilities across 251 dependencies**; -- `git diff --check origin/main...HEAD`: passed; worktree status was clean. - -Browser evidence is not applicable to this service/API-only correction. No UI -source, layout, interaction, or response consumer changed; the authenticated -reset route is exercised through the real Fastify injection boundary in -`app.test.ts`. - -### Independent review and remaining gates - -An independent read-only security/correctness review found the reset/start race. -After causal regressions and the reservation fix, its follow-up reported no Critical, -Important, or Minor finding and marked the implementation ready to merge. - -A final independent read-only review of the OPS-05-bearing integrated diff at -`ecd14228e0b83f8a9087d8bce675a3ae689fd29e` likewise reported no Critical, -Important, or Minor finding. It confirmed the synchronous reservation and `finally` -release, fail-closed empty-root validation, initialized path/head guards, causal -concurrency and authenticated API coverage, exact five-file scope, and browser -non-applicability, with a **Ready to merge: Yes** verdict. - -GitHub reported the draft PR open and mergeable at this checkpoint, but with no -automated status checks. `CI-01` tracks required pull-request automation separately. -The remaining RST-01 work is lifecycle evidence: the final literal check/push gate, -required/merge-group checks when available, clean and initialized reset verification -on updated `main`, issue closure, and a merged-SHA ledger update. None requires -another scoped product-code change on this branch. - -## Phase 4 — Mission-composed advisory model review (`MR-01`, `MR-02`) - -Assessed on branch `feat/12-mr-01-compose-model-reviewer` at `4a46f72`, stacked on -`fix/7-rst-01-idempotent-reset`. This entry supersedes the Phase 3 statement that the -bounded reviewer is not connected to Mission orchestration. - -### What is now composed - -`ShepherdServiceOptions` gained an optional `reviewer?: ModelReviewer`, injected as an -interface instance in the same style as `verifier` and `executor` and defaulting to -`null`. `apps/server/src/index.ts` constructs an `ArkModelReviewer` only when the new -`isShepherdModelReviewConfigured(config)` predicate holds, which gives -`config.shepherdModel` — fed by the documented `SHEPHERD_MODEL` — its first and only -consumer. An unconfigured server composes no reviewer and emits no advisory event, -rather than degrading every Mission with a false `configuration_error`. - -`runAdvisoryModelReview()` runs between `integrateContracts()` and -`detectAndPersistCollision()`, gated at call time on `settings().modelReviewEnabled` -so the persisted setting is genuinely causal. - -### Why the advisory result cannot reach authority - -`runAdvisoryModelReview` returns `Promise`, and `detectAndPersistCollision` has -**zero diff** in this change: its only nearby hunk appends two new private methods -after its closing brace. There is therefore no parameter, field, or closure through -which a finding can reach the deterministic detector, the winner policy, or the -promotion gate. The independence claim is structural rather than conventional. - -### Containment and bounds - -A reviewer that throws is converted into a durable `provider_error` degradation rather -than being swallowed, so a failure can never present as a fake "safe". A service-side -deadline bounds any injected reviewer that does not bound itself; the composed -`ArkModelReviewer` bounds itself at 20 seconds. A 250 ms poller aborts an in-flight -review once durable cancellation is visible, so `cancelMission` cannot block on it. -The outer catch is total, and cancellation is re-derived from durable state by -`detectAndPersistCollision`'s own `ensureMissionRunnable` on the very next statement. - -`model_review_completed` was added additively to `ShepherdEventType` -(`shepherd/domain.ts`), the persisted `z.enum` (`database-schema.ts`), and the browser -mirror (`apps/web/src/types.ts`). No store version bump and no migration were -required: `databaseV2Schema` remains `version: z.literal(2)` and the change only -widens what parses. Persisted advisory details are closed enums, counts, and claim -keys Shepherd itself supplied. Free model prose (`finding.reason`) is deliberately -never persisted or rendered. - -### Observed evidence - -```sh -npx vitest run --config apps/server/vitest.config.ts \ - apps/server/src/shepherd/service.model-review.test.ts -# repository default config, no flags -# Test Files 1 passed (1) -# Tests 9 passed (9) -# Duration 110.54s - -npm run typecheck -# PASS: server and web TypeScript checks - -npm run build -# PASS: web production build, 40 modules transformed -# PASS: server production build - -git diff --check -# clean -``` - -Each test declares the budget it needs, because every one drives a full Mission with -real Git worktrees and real trusted fixture checks. The file therefore passes under -the repository default configuration rather than depending on a `--testTimeout` flag. - -The composition predicate was checked against a configured environment, reporting -booleans only and printing no secret: - -```text -arkConfigured: true -shepherdModelReviewConfigured: true -shepherdModel is distinct from arkModel: true -shepherdExecutionMode: deterministic -``` - -This confirms two design choices. Reusing `isArkConfigured` would have been wrong, -because it validates `arkModel` while the reviewer consumes the genuinely distinct -`shepherdModel`. Gating the reviewer on `shepherdExecutionMode` would have left the -feature unreachable in exactly the configuration the deterministic demo runs in, -since `auto` resolves to `deterministic` without a container engine. - -RED was observed before implementation on the same file: `3 failed | 1 passed`, each -failure on `expect(reviewer.inputs).toHaveLength(1)`. `MR-T05` — the PRD 8.6 mandate -that collision detection succeeds with the reviewer disabled — passed both before and -after, because it is the baseline invariant rather than a new capability. Every -independence assertion carries the call-count expectation; without it those tests -would pass vacuously against an uncomposed service. - -`MR-T14` injects a finding naming a non-existent claim key and arguing for the losing -transport, then asserts the persisted collision, the selected candidate, and the -promoted SHA are unchanged, that `attentionReason` stays null, and that the hostile -prose appears in neither the collision nor the event trail. `MR-T16` drives a real -`ArkModelReviewer` through an injected `fetchImpl`, proving both that the -service-built input satisfies `reviewInputSchema` end to end and that a configured -secret never reaches the outbound request body. - -### Recorded limitations - -- `npm run check` was **not** observed passing unmodified on this host, and that is - pre-existing. On the unmodified stack parent the server suite reports - `24 failed | 518 passed`, every failure at ~5000 ms with no assertion failures, - because `apps/server/vitest.config.ts` leaves Vitest's 5 s default `testTimeout` - against tests that perform real Git work. Raising the flag takes - `git-plane-promotion.integration.test.ts` from `13 failed` to `19/19 passed`. -- This change causes no functional regression, established by isolation rather than - by assertion. Under `--testTimeout=60000` the parent reports - `8 failed | 534 passed | 547` and this branch reports `12 failed | 543 passed | 556` - — nine tests added, nine passing. `service.test.ts` shows 3 failures on the parent - and 6 on this branch in a full run, but **1 failed / 20 passed when run in - isolation** on this branch. Five of those six therefore exist only under full-suite - parallelism, and the remaining one fails on the parent too. With no reviewer - injected `runAdvisoryModelReview` returns on its first line, so it cannot slow a - Mission; what the new file adds is roughly 110 s of parallel Mission load, which - pushes an already-marginal suite further past its timing budget. -### Opt-in live `SHEPHERD_MODEL` gate - -HANDOVER pending-ledger item 5 was executed after item 4 passed, via the new -`npm run test:shepherd:model-review:live` script and -`apps/server/src/shepherd/live-model-review.integration.test.ts`. The suite is behind -a double gate (`SHEPHERD_LIVE_TEST` **and** `SHEPHERD_LIVE_MODEL_REVIEW`) so the -existing `test:shepherd:live` script cannot trigger it; both the default run and a -`SHEPHERD_LIVE_TEST=true`-only run were confirmed to skip it. The Mission itself stays -deterministic and container-free, so the gate costs exactly one provider request. - -```sh -npm run test:shepherd:model-review:live -# Test Files 1 passed (1) -# Tests 1 passed (1) -# Duration 14.55s -# observed outcome: degraded reason=invalid_response retryable=false -``` - -The composition is proven against the real provider: one request was sent, a response -was received, the degradation was recorded durably, and the deterministic collision, -winner, and promoted head were unchanged. **The review itself did not succeed**, and -that is reported as a defect rather than as a pass. - -Bounded diagnosis using the adapter's own schema and instructions with a two-contract -payload: HTTP 200, `object: "response"`, `status: "completed"`, `store: false`, -`error: null`, `incomplete_details: null`, one `reasoning` item followed by one -assistant `output_text` message whose text parses as schema-valid JSON. The envelope -contract in `extractOutputText` is therefore satisfied, and the model produced a -genuinely correct review naming the real `auth.transport` conflict with high -confidence. - -The rejection happens later. `evidenceReferenceExists` requires -`source: "manifest"` refs to equal the literal sentinel `manifest_summary`, while the -model supplied the manifest summary text; and `validateAndNormalizeFindings` returns -`null` when any single finding fails, so one ambiguous reference discards the entire -review including its valid findings. Tracked as `MR-03`. `ArkModelReviewer` is -deliberately unmodified by this change. - -### Composition defect found by adversarial review - -An adversarial review of the branch diff found a high-severity defect in the -composition itself. `apps/server/src/index.ts` passed `[arkApiKey, authToken]` -unfiltered into `ArkModelReviewer`. `validateConfiguration` rejects the entire -configuration when any supplied sensitive value is shorter than eight characters, and -`config.authToken` is legitimately `""` on the documented loopback default, where -`APP_AUTH_TOKEN` is required only for non-loopback listeners. The reviewer was -therefore permanently inert: every qualifying Mission emitted -`model_review_degraded / configuration_error` **without ever attempting a request**, -behind a reason that reads as a credential problem. - -Reproduced with the compiled adapter and an empty auth token: - -```text -as shipped -> degraded/configuration_error | fetch attempted: false -with >= 8 filter -> completed | fetch attempted: true -``` - -Fixed by filtering at the construction site. `MR-T17` pins the exact composition -`index.ts` performs and was confirmed to fail without the filter -(`expected 'degraded' to be 'completed'`). - -Nothing caught this earlier because every service test used a scripted fake with -`sensitiveValues: []`, `MR-T16` supplied a single long key, and the live gate -pre-filtered at `>= 4`, which dropped the empty token and exercised a composition the -server never uses. The live gate now filters at `>= 8` to match production exactly. - -The remaining adapter-side weakness is deliberately out of this branch's scope: -`validateConfiguration` rejects a whole configuration for one unusable sensitive -value rather than dropping it or naming a caller-side mistake. - -### Recorded limitations - -- The live gate has never observed a `completed` review; only the degradation path is - live-proven. Until `MR-03` is fixed, the advisory reviewer is safe but silent. -- Mid-review cancellation is covered by `MR-T13`, which blocks a reviewer until its - caller signal aborts, cancels the Mission in flight, and asserts the signal was - aborted, that no advisory event was recorded, and that no collision, candidate, or - protected-head change survived. The test pins `deadlineMs` far out of reach so only - the cancellation poller can settle the review: an earlier version passed with the - poller disabled because the service deadline aborted instead, which mutation - testing caught. -- Both UI changes (the Verification stream filter and the `degraded` tone) are - untested: the web workspace has no test runner, so there is nowhere to put one. -- `apps/server/src/index.ts` is a top-level-`await` entrypoint with no export, so its - composition is build-verified rather than test-verified. -- No container runtime was available, so the two container-gated suites skipped as - designed. The new tests require none; they drive full Missions through an - in-process trusted fixture verifier. -- During final integration, the two presentation-only regex changes (`model_review` - joining the Verification stream filter and `degraded` mapping to the existing - amber tone) were removed with user approval because this GPT CLI device has no - connected browser runtime. The event contract typing remains, but the final diff - adds no rendered UI behavior and therefore has no UI-specific browser gate. - -### Integrated current-main verification - -**Date:** 2026-08-30 (Asia/Singapore) -**Branch:** `feat/12-mr-01-compose-model-reviewer` -**Final integrated base:** `origin/main` at `fae0852` -**Integration commits:** `fbf3038` (base `d27dea6`), then `5972aa8` (base `fae0852`) -**Verified implementation checkpoint before the final base refresh:** `a2afbf3` - -The initial `d27dea6` `origin/main` base was merged without rebasing or -force-pushing. All code merged automatically; the only conflict was this build log, -where the complete MR-01 and current-main evidence blocks were both preserved. - -Immediately before final review, refreshed refs showed that PRs #9 and #37 had -advanced `origin/main` to `fae0852`. That base was merged at `5972aa8`. Source and -workflow changes merged automatically; the HANDOVER conflict was resolved by -preserving both the newly merged Group Chat/required-check evidence and PR #16's -model-review status. A new exact-head Node 24 gate is required after the final -evidence commit; the earlier result is not presented as covering the refreshed base. - -The first focused baseline exposed an environmental timing failure rather than a -reviewer defect: `JsonStore.persist()` rejected lifecycle state after Docker Desktop -stepped its wall clock backwards. Path-only diagnostics isolated -`updatedAt < createdAt` across Project, Contract, and Plane records. A standalone -Node 24 probe then measured two backward steps in 40 seconds, with a largest step of -`-35,921 ms`, while the monotonic timer advanced normally. The new Mission test -fixture now uses the service's existing `now` seam with a strictly monotonic -per-service test clock; production timestamp and reviewer behavior are unchanged. - -RED was observed repeatedly before that test-only correction. Fresh GREEN evidence: - -```text -npx vitest run --config apps/server/vitest.config.ts \ - apps/server/src/shepherd/service.model-review.test.ts -# host isolation: 1 file passed; 13/13 tests; 100.10s - -# Node 24, focused model-review + config gate -# 2 files passed; 33/33 tests; 219.95s -``` - -The first bind-mounted literal check was not reported green: it stopped in the -launcher suite because Windows checkout conversion produced a `bash\r` shebang. -The committed head was therefore cloned into a fresh Linux Docker volume so Git -materialized LF files, and the same unmodified command passed: - -```text -npm run check -# launcher: 3/3 passed -# server: 26 files passed, 3 skipped; 568 tests passed, 6 skipped -# web and server typechecks passed -# web production build: 40 modules transformed -# server production build passed - -npm audit --json -# 0 vulnerabilities across 251 dependencies -``` - -After the presentation-only deltas were removed, the same literal Node 24 gate was -rerun against exact commit `a2afbf3` in a fresh LF-native Linux volume. It passed -with the same totals: launcher 3/3, server 568 passed/6 skipped, both typechecks, -both production builds, and a zero-vulnerability audit across 251 dependencies. - -The local Vite UI was started for the two-regex rendered gate, but the required -browser runtime reported no connected in-app or extension browser. The server was -stopped and no screenshot, viewport, or visual claim is made. With user approval, -both presentation-only regex deltas were then removed; the final diff adds no -rendered UI behavior. The final security/correctness review, push/required checks, -merge, and post-merge verification remain separate gates and are not implied by -this entry. - -### Final-review correctness corrections - -The independent final review of integrated checkpoint `aa76ebf` found three -important service-boundary gaps. All three were reproduced with causal tests before -production changes: - -- the readiness predicate accepted six configurations that `ArkModelReviewer` - rejects (short/control-character keys, an invalid model identifier, and insecure, - credential-bearing, or query-bearing endpoints); -- malformed injected reviewer results could bypass an explicit durable degradation; -- durable Mission cancellation only aborted the injected reviewer signal, so a - reviewer that ignored aborts held `cancelMission()` until the 1.5-second test - deadline. - -The combined RED run observed 32 passing and 8 failing assertions across the two -affected files. The correction keeps `model-reviewer.ts` unchanged because active -stacked PR #25 owns that adapter. Instead, `config.ts` mirrors the adapter's exact -credential/model/HTTPS endpoint acceptance rules, while `ShepherdService` validates -the closed, bounded result shape from any injected reviewer and converts invalid -values to `invalid_response`. A service-owned cancellation settlement now races both -the reviewer and deadline, so cancellation remains bounded even when the injected -implementation never settles. The result validator accepts the bounded optional -`droppedFindingCount` field planned by the stacked `MR-03` change without persisting -it or giving it authority. - -Fresh Node 24 follow-up evidence: - -```text -apps/server/src/config.test.ts -# 1 file passed; 26/26 tests - -service.model-review.test.ts -t MR-T10b -# 1/1 passed; 13 skipped - -service.model-review.test.ts -t MR-T13 -# 1/1 passed; 13 skipped - -npm run typecheck --workspace @launchpad/server -# passed -``` - -One aggregate affected-file run reached 39/40 before a Git-fixture `worktree` command -exited 128 in `MR-T12`; that case then passed 1/1 immediately in isolation. This is -recorded as an infrastructure interruption, not presented as a clean aggregate pass. -The literal exact-head Node 24 check, final independent follow-up, push/required -checks, merge, and post-merge verification remain lifecycle gates. - -## ST-02 — Truthful unavailable notification preferences - -**Date:** 2026-08-29 (Asia/Singapore) -**Branch:** `fix/6-st-02-notification-truth` -**Pull request:** [#13](https://github.com/kyashp/shepherd/pull/13) - -### Root cause and bounded correction - -The notification booleans were persisted and round-tripped by the settings API, but -no delivery or in-app behavior read them. `SettingsPage` nevertheless bound all three -values to enabled toggles with functional descriptions, so the browser presented -stored-only values as active product controls. - -The Notifications tab now identifies the capability as **Reserved for a future -release** and **Unavailable**. It continues to render each stored value through a -native disabled toggle paired with a `Reserved` label. The settings schema, -persistence, model-review control, other tabs, and notification delivery remain -unchanged. - -### Original RED/GREEN and branch evidence - -The focused server-rendered React regression was added before the section component. -Its first valid run failed because `NotificationSettingsSection` was undefined; after -the minimal implementation, the same test passed and proved all three controls were -disabled while two supplied checked values remained visible. - -Before current-main integration, fresh branch-local evidence passed: - -```sh -npx vitest run apps/web/src/pages/SettingsPage.test.tsx -# 1 file / 1 test passed - -npm run typecheck -w @launchpad/web -# passed - -npm run build -w @launchpad/web -# passed; Vite transformed 40 modules - -git diff --check -# passed -``` - -A disposable terminal Playwright/Chromium proof rendered the real Vite application -with deterministic API responses at `1280x800` and `1440x900`. At both viewports it -observed stored states `[true, false, true]`, three natively disabled controls, -rejected programmatic and sequential focus, unchanged mouse/keyboard activation -attempts, disabled Save, zero settings `PATCH` requests, zero horizontal overflow, -zero clipping/overlap, and no console, page, or request errors. Temporary screenshots -were visually inspected against `docs/UI.jpeg` and were not committed. - -### Current-main integration - -OPS-05 merged through PR #32 at `8110aa3ed49bd0586cbb275d7c4067552cd9a144`, -then priority PR #10 merged at `349897d3d9167fe711bf720f7c3fadd213938d11`. -Only that latest `origin/main` was merged into this branch. Source and regression -files merged automatically; conflicts were limited to this file and `HANDOVER.md`. -Resolution restored current-main documentation and reapplied only ST-02-specific -evidence. Fresh integrated verification and independent-review results are recorded -in a follow-up entry only after they are observed. - -### Integrated current-main verification - -On merge commit `066009b6eda658eee9a66135224d69b3a4dae515`, the effective -diff against `origin/main` contained exactly the notification page section, its -focused regression, and these two ST-02 evidence files. Observed results: - -```sh -npx vitest run apps/web/src/pages/SettingsPage.test.tsx -# 1 file / 1 test passed - -npm run typecheck -w @launchpad/web -# passed - -npm run build -w @launchpad/web -# passed; Vite transformed 40 modules - -npm run check -# launcher 3/3 passed -# server: 25 files passed, 2 skipped; 554 tests passed, 2 skipped -# web and server production builds passed - -npm audit --json -# 0 vulnerabilities across 251 dependencies - -git diff --check origin/main...HEAD -# passed -``` - -Terminal Playwright/Chromium then repeated the real Vite-page proof at `1280x800` -and `1440x900`. Both viewports preserved `[true, false, true]`, exposed all three -checkboxes as natively disabled, rejected direct and sequential focus, and remained -unchanged after forced label clicks and keyboard activation attempts. Save stayed -disabled, no settings `PATCH` occurred, and automated geometry checks found no -horizontal overflow, clipping, or overlap. Console, page, and request error lists -were empty. The final temporary screenshots were visually inspected against -`docs/UI.jpeg`; current-main's cream canvas, dark sidebar, updated Shepherd icon, -purple accent, restrained borders, typography, spacing, and locked-control language -were preserved. No screenshot binary was added to the effective branch diff. - -### Independent final review - -An independent read-only quality audit reviewed the exact -`349897d3d9167fe711bf720f7c3fadd213938d11..87b4b12e894233e2a2d852db90bfde2fe1714386` -diff plus both final screenshots. It confirmed the exact four-file scope, native -disabled semantics, stored-value preservation, absence of a notification interaction -path to the unchanged `PATCH` submit handler, regression coverage, current-main UI -preservation, and honest documentation of unimplemented delivery and broader UI -gaps. It reported no Critical, Important, or Minor finding and returned **Ready to -merge: Yes**. This review-status entry is documentation-only; the same auditor must -confirm the final follow-up diff before push. - -### Final dependency-gated current-main refresh - -TST-02 merged through PR #34 at -`8149a7cf3b52c4f0c7d20b31f14c4d2ddbc52b12`. The latest `origin/main` was -then merged conflict-free into ST-02 at -`f1ad0b9811e9b77dddc933c11df6a6e3fd17cf61`; no source, test, or -documentation conflict required manual resolution. The effective diff against -that updated base remained exactly `SettingsPage.tsx`, its focused regression, -and the two ST-02 evidence files. - -Fresh evidence on the integrated merge passed the focused ST-02 test (1/1), the -formerly blocked recovery target with its canonical temporary path (1/1, 16 -skipped), web typecheck, and the web production build (40 transformed modules). -The required literal `npm run check` then passed without an environment override: -launcher 3/3, server 25 files passed with 2 skipped and 554 tests passed with 2 -skipped, plus web and server production builds. `npm audit --json` reported zero -vulnerabilities across 251 dependencies, and `git diff --check -origin/main...HEAD` passed. - -Terminal Playwright/Chromium repeated the proof against the integrated Vite page. -At both `1280x800` and `1440x900`, stored values remained -`[true, false, true]`; all controls were natively disabled, rejected direct and -sequential focus, and ignored mouse/keyboard activation. Save remained disabled, -zero settings `PATCH` requests occurred, geometry checks reported no horizontal -overflow, clipping, or overlap, and console/page/request error lists were empty. -The visually inspected temporary screenshots remained faithful to `docs/UI.jpeg` -and were not added to the branch diff: - -- `st-02-1280x800.png` — SHA-256 - `8dc439b849eac9aeb84f3353145ff106ff4518f0b007a8fd7c61f5038a2ab22c` -- `st-02-1440x900.png` — SHA-256 - `c6d5c9e0831f9c7cc187827e574f1ca1c98b2fbd322738b96b19e6b45a33d95b` - -## Test-lifecycle stabilization candidate (`#11`) - -**Date:** 2026-08-29 (Asia/Singapore) -**Candidate branch/commits:** `fix/11-shepherd-test-flake-clean` / -`de986b9a3ecdd1e1360050209742497f8c6b2813`, `f2db22c` -**Draft PR:** [#19](https://github.com/kyashp/shepherd/pull/19) - -The generic five-second Vitest budget was exceeded by three real service journeys -and measured Git/recovery integration journeys under full-suite contention. A timed -out background-Mission test could also race fixture cleanup; raw recursive cleanup -could not remove a deliberately read-only trusted-verification snapshot. - -The candidate adds only test lifecycle changes. Service fixtures now require an -exact sentinel, restore write permission only after validating the allocated path, -and skip symlinks. Causal RED checks observed `EACCES` on a `0400` file beneath a -`0500` snapshot and, under a temporary unsafe symlink mutation, an external marker -became unreadable. Restored GREEN checks prove the fixture is removed while the -external marker and permissions survive. Background test Missions cancel and join via -the existing `cancelMission()` behavior before cleanup. Six measured -integration cases declare 15-second budgets; global defaults stay unchanged. - -The contamination route was also causal: `runFixtureGit()` spread `process.env`, so -an inherited `GIT_DIR` could override `git -C` and route a fixture commit elsewhere. -The helper now gives Git a fixed environment (path/locale plus non-interactive, -system/global-config-disabled settings). Its regression creates only disposable -fixture and decoy repositories, poisons `GIT_DIR` with the decoy, and proves the -fixture advances while the decoy's HEAD and tracked file remain unchanged. The RED -against the old inherited environment left the fixture HEAD unchanged; the restored -implementation is GREEN. - -Observed verification: - -```sh -# target-substitution regression: 5 consecutive passes (2.51–3.59 s) -npm run check -# pass twice: 25 files passed, 2 opt-in skipped; 547 tests passed, 2 skipped; -# web and server production builds passed -git diff --check -# passed -``` - -The initial PR #18 was closed as contaminated: the documented defective pre-push hook -created commit `9d252957` and tracked `external-move.txt` before the intended fix. -The clean candidate contains only the causal test files. The demonstrated recovery -fixture route is fixed; the pre-push hook itself remains separate infrastructure work, -so manual verification is required before using `ECC_SKIP_PREPUSH=1` for a scoped -push. - -### Resolved-base verification - -The clean candidate was resolved against current `main` at -`2f7a9fd8122cb62f2f2ed4e2b08cc87f311e8887`. On that exact resolved head, -`npm run check` passed: 25 files passed, 548 tests passed, 2 opt-in tests skipped, -and both production builds completed. A subsequent teardown-only audit identified a -test-lifecycle follow-up; its final commit and verification are recorded separately -once that bounded correction is complete. - -### Teardown follow-up evidence - -Commit `d8c4dff7e6a6c3b1597e56c8b493e436a4f227c2` is test-only. It retains tracked -Missions until cancellation and background-run joining succeed, treats -`attention_required` as cancellable, and releases both blocked promotion checkpoints -in `finally` paths. The promotion verifier release is idempotent. Its causal RED -timed out safely against the prior blocked verifier (the test's `finally` released -the fixture); GREEN focused coverage passed the four promotion/attention teardown -paths, and the full `service.test.ts` file passed 25/25. - -The first repository `npm run check` on `d8c4dff` was **not green**: the unmodified -Git-plane integration test `reports a real textual merge conflict and leaves the -integration Plane clean` timed out at Vitest's five-second default. The observed -test phase had 24 files passed, 1 failed, 2 skipped; 549 tests passed, 1 failed, 2 -skipped. This follow-up did not broaden into that separately owned timeout; its -production builds therefore did not run after the failing test phase. - -That Git-plane test is also an owned #11 real-Git integration case. Commit -`0e0e743` gives only that test a 15-second Vitest budget. It passed five consecutive -focused runs (1.23–1.90 s) and the complete Git-plane integration file passed 19/19. -A subsequent full gate exposed a distinct RED: the background real-Planes service -journey has a 30-second test budget but its shared completion helper stopped at 15 -seconds. Commit `a14c3f7` makes that helper accept an optional timeout and passes -25 seconds only to this measured journey; it does not add another Vitest budget. -The journey passed five consecutive focused runs (4.27–6.33 s) and the complete -service test file passed 25/25. - -On final head `a14c3f71446ff5c46a84db6482fc445e9d1944d9`, `npm run check` passed: -25 files passed, 550 tests passed, 2 opt-in tests skipped, and both production -builds completed. Six measured integration cases now have explicit 15-second -Vitest budgets; the one 25-second internal completion wait remains confined to the -already-30-second background real-Planes test. - -## 2026-08-29 — GC-01 post-#19 current-main browser gate - -[Draft PR #9](https://github.com/kyashp/shepherd/pull/9) was integrated on the -merged [PR #19](https://github.com/kyashp/shepherd/pull/19) `main` commit -`120fff066d962f4f30ed6cd62bc367cc869e02db` in a detached evidence worktree. -The overlay contained exactly the three GC web files, and each blob matched the -PR #9 head: - -```text -apps/web/src/pages/ProjectGroupPage.tsx -apps/web/src/pages/project-group-mention.test.ts -apps/web/src/pages/project-group-mention.ts -``` - -Observed verification on that exact integration: - -```sh -npx vitest run apps/web/src/pages/project-group-mention.test.ts \ - --environment node --no-file-parallelism --maxWorkers=1 -# 1 file passed; 3 tests passed - -npm run check -# exit 0: both workspace typechecks passed -# 25 test files passed, 2 opt-in files skipped -# 550 tests passed, 2 opt-in tests skipped -# web and server production builds passed - -git diff --check -# passed -``` - -A terminal Playwright run exercised the real Vite page with deterministic API -interception in installed headless Chromium. At both exact `1280x800` and -`1440x900` viewports, mouse click, keyboard Enter, and keyboard Space activation -produced `@"Frontend Agent" Keep this draft\nincluding its second line`. After -every activation, `#group-message` was the active element and its collapsed -selection was `59..59` for a 59-character value. Keyboard focus matched -`:focus-visible` with a solid 2 px outline. Both pages reported exact requested -viewport dimensions, no horizontal overflow, no console/page error, and no -unexpected API request. - -The two screenshots were visually inspected against `docs/UI.jpeg`. The dark -sidebar, restrained purple accents, bordered conversation panel, spacing hierarchy, -and bottom composer remained consistent; mention chips and the focused composer had -no clipping or overlap. Screenshots and the one-off Playwright harness remained -temporary and were not committed. - -This evidence closes the scoped `GC-01` interaction uncertainty only. `GC-02..07`, -polling/reconnect and populated-history browser coverage, accessibility, a committed -deterministic E2E harness/screenshot corpus, independent UI review, and post-merge -verification after PR #9 itself lands remain separate. - -### GC-01 final parser-round-trip hardening - -A final review found that a quoted display name could still fail routing when the -server's whole-message normalization changed the decoded lookup target. For example, -`Frontend Agent` was formatted as `@"Frontend Agent"`, then collapsed to one -space before lookup even though the stored Agent name retained two spaces. - -The focused RED failed 2/5 tests: normalization-changing spacing did not fall back -to the Agent ID, and full-width quote characters were not normalized before JSON -escaping. The minimal web-only fix now normalizes safe display-name mentions before -escaping and falls back to the Agent UUID when a parser-valid name cannot survive -the whole-message transformation and the shared ID/name namespace is unambiguous. -The focused GREEN passed 5/5 and -round-tripped those generated mentions through the production -`parseProjectGroupMessage()` implementation. - -A second review found that U+037A gains leading spacing under NFKC and the parser -directory trims after normalization. RED failed 1/6 because the formatter retained -that introduced spacing; the minimal post-NFKC trim is GREEN at 6/6 through the -production parser. No server files, stored records, or public schemas changed. - -The reviews also found two out-of-scope server directory mismatches, now tracked as -`GC-07`: create/update accepts source-short Agent names whose NFKC+trim form exceeds -the parser's 128-character directory-key limit, and names canonically equal to a -different Agent's ID even though IDs/names share one parser lookup namespace. The -parser rejects the first entire directory before resolving an ID and correctly -rejects the second route as ambiguous, so no web fallback can correct either case. -A separate server/schema task must align canonical length and namespace validation -and plan non-destructive repair for existing invalid or colliding stored names. - -On the actual merge-resolved branch: - -```sh -npx vitest run apps/web/src/pages/project-group-mention.test.ts -# 1 file passed; 6 tests passed - -npm run check -# exit 0: both workspace typechecks passed -# 25 test files passed, 2 opt-in files skipped -# 550 tests passed, 2 opt-in tests skipped -# web and server production builds passed -``` - -Terminal Playwright was rerun at exact `1280x800` and `1440x900`. Mouse, Enter, -and Space still inserted the readable `@"Frontend Agent"` form, preserved the -multiline draft, restored focus, and left the collapsed caret at `59..59`. -Keyboard focus remained visibly outlined; both viewports had no overflow, -console/page errors, unexpected API requests, clipping, or overlap. The refreshed -screenshots were visually inspected against `docs/UI.jpeg` and remained temporary. - -## 2026-08-30 — GC-01 current-main integration and default-gate packaging - -PR #9 was merged locally with current `origin/main` at -`d27dea670108e5a06eac20de7df88f756b68e404`, the merge of PR #13. The only -textual conflicts were this build log and `docs/HANDOVER.md`; the product diff -remains limited to the Project Group mention helper and its use in -`ProjectGroupPage.tsx`. - -Review correctly found that the original web-workspace test was not discovered by -the repository's root test command. The pure regression moved to -`apps/server/src/project-group-mention.test.ts`, whose existing Vitest workspace can -import both the web helper and production server parser without new dependencies. -The packaging RED command reported no matching test file before the move. - -Independent review then found an in-flight submission race: the textarea was -disabled during the POST, but a mention button could mutate the retained draft -before the successful request cleared it. The review also found that programmatic -mention insertion could exceed the textarea's 2,000-character limit. The causal RED -failed 2/8 because the submission-locked button and bounded prepend helper did not -exist. The minimal correction gives the mention button native disabled semantics -while sending plus a defensive callback guard, and rejects an over-limit insertion -without changing the draft while showing a composer-scoped status message. GREEN -passes all 8 formatter, parser-round-trip, draft-preservation, submission-lock, and -exact-boundary cases: - -```sh -npm run test -w @launchpad/server -- src/project-group-mention.test.ts -# 1 file passed; 8 tests passed -``` - -The Node 24 Linux verification copy normalized only the checkout's CRLF shell -launcher; repository blobs were not changed. The current-head `npm run check` -completed both workspace typechecks, the 3/3 launcher suite, and all 8 GC-01 tests, -but did **not** complete green. Two unchanged server cases failed under the complete -suite: `recovery.process.test.ts` after `update-ref`, and `service.test.ts` while -rejecting a second Mission after an external protected-head move (24 files passed, -2 failed, 2 skipped; 557 tests passed, 2 failed, 5 skipped). The latter passes 1/1 -alone. The recovery-process file had passed 5/5 in an earlier isolation, then failed -a different `promotion_ready_for_cas` case in a later 4/5 isolation. PR #9 has no -diff in either server path. These rotating failures are recorded as existing -shared-clock/process instability, not as a passing required gate and not as GC-01 -scope. - -Independent production builds passed for web and server, `git diff --check` passed, -and `npm audit --audit-level=high` found 0 vulnerabilities. - -The current integrated browser run used terminal Playwright because the in-app -browser exposed no attachable backend. At exact `1280x800` and `1440x900`, mouse, -Enter, and Space each produced -`@"Frontend Agent" Keep this draft\nincluding its second line`; focus returned to -the composer, the collapsed caret was `59..59`, and keyboard focus had a solid -2 px visible outline. During a deliberately deferred POST, both the mention button -and composer were disabled, programmatic button activation left the submitted draft -unchanged, and the successful response cleared only that submitted content. An -exact 2,000-character mention insertion succeeded; one character over remained at -2,000 and displayed the explicit limit error. Both viewports had no horizontal -overflow, clipping, console or page errors, failed requests, unexpected API writes, -or layout overlap. The temporary screenshots were visually checked against -`docs/UI.jpeg`: - -```text -1280x800 sha256 4d4e35b065f3c530dbb02b5d92e35830490799759b4bac85c855a4a5dd5a0039 -1440x900 sha256 7e09440db22781b45f4c11173580fecfc01d5ef7dcf8792ddaecc255e6c709a1 -``` - -The independent reviewer reported no Critical issue. Its one Important race and -one Minor length-boundary issue are corrected above. The read-only follow-up -reviewed the final staged five-file effective diff, reported no Critical, Important, -or Minor finding, and returned **Ready to merge: Yes**, subject to normal required -checks and integrator disposition of the unrelated suite instability. - -PR #9 remains the bounded `GC-01` correction. The requested no-project composer -behavior is `GC-05`, which issue #5 and this handover explicitly exclude; it needs -its own issue, owner, branch, regression, and review. - -## 2026-08-30 — GC-01 post-merge verification - -PR #9 merged into `main` as `fae0852e284619c2912eeeb8ac3ebe156f45b026`. -GitHub closed issue #5 through the linked merge, and the remote -`fix/5-gc-01-quoted-mentions` branch was removed. - -Fresh Node 24 Linux checks ran against that exact merged-main tree: - -```sh -npm run test -w @launchpad/server -- src/project-group-mention.test.ts -# 1 file passed; 8 tests passed - -npm run typecheck -# web and server workspace typechecks passed - -npm run build -# web Vite production build and server TypeScript build passed -``` - -The in-app browser reported no available backend, so the exact merged-main Vite -page was exercised with the documented terminal Chromium fallback. At both -`1280x800` and `1440x900`, mouse, Enter, and Space produced -`@"Frontend Agent" Keep this draft\nincluding its second line`; focus returned -to the composer with the collapsed caret at `59..59`, and keyboard focus retained -a solid 2 px visible outline. During a deferred POST, both the mention control and -composer were disabled and programmatic activation did not mutate the submitted -draft. Exact 2,000-character insertion succeeded; the over-boundary attempt stayed -at 2,000 and displayed the explicit limit error. Each run issued exactly one -expected group-message POST and had no horizontal overflow, clipping, layout -overlap, console errors, page errors, or failed requests. - -The temporary screenshots were visually inspected and were not committed: - -```text -1280x800 sha256 980854CC1C489C91BE5EBAFD42B940044AEF167FABFE8FF13E2E65D546D7CEC6 -1440x900 sha256 507CC82FE4F8C43E23A72BD022FF7987EAA2EF4518C20AD9007D3C05159363E6 -``` - -The full `npm run check` was not rerun post-merge. Its latest pre-merge attempt -remains the explicitly non-green result recorded above: 557 tests passed, 2 -unchanged server tests failed under suite load, and 5 were skipped. This scoped -post-merge gate does not reclassify that unrelated process/shared-state -instability, and it does not close the separately owned `GC-02..07` work. - -## 2026-08-30 — CI-01 required pull-request checks and merge evidence - -Issue [#36](https://github.com/kyashp/shepherd/issues/36) was implemented from -current `main` on `test/36-ci-01-required-checks`. The branch was published before -edits and owned only `.github/workflows/pull-request-checks.yml`; product code, -assertions, timeouts, dependencies, shared evidence documents, credentials, and -repository rules were excluded from the implementation PR. - -### Workflow contract and local evidence - -The pre-implementation contract probe observed the expected RED because -`.github/workflows/pull-request-checks.yml` did not exist. Commit -`9501b95f952b5ba02d1c5413960999adcde362a3` added the smallest workflow: - -- `pull_request` for `main` plus `merge_group: checks_requested`; -- one deterministic job named `Required checks` on `ubuntu-latest` and Node 22; -- literal `npm ci` followed by literal `npm run check`; -- top-level `contents: read`, superseded-run cancellation, a 30-minute job bound, - no persisted checkout credentials, no package-manager cache, and no secret or - `.env` access; -- `actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1` - (`v7.0.1`) and - `actions/setup-node@820762786026740c76f36085b0efc47a31fe5020` - (`v7.0.0`) pinned to immutable release commits. - -Observed local evidence at the reviewed workflow bytes: - -```text -PowerShell workflow contract -PASS: trigger, permissions, concurrency, runner, timeout, immutable actions, -Node 22, npm ci, npm run check, and forbidden secret/env patterns - -actionlint v1.7.12 .github/workflows/pull-request-checks.yml -PASS; release checksum matched -6e7241b51e6817ea6a047693d8e6fed13b31819c9a0dd6c5a726e1592d22f6e9 - -npm audit --json -PASS: 0 vulnerabilities across 251 dependencies - -git diff --check -PASS - -independent CI/repository-administration review -PASS: no Critical, Important, or Minor finding -``` - -A clean Node 22 Docker execution on both unmodified `main` and the candidate -exposed the same existing Linux absolute-path redaction assertion in -`service.test.ts`; an additional baseline-only timeout did not recur. No test or -timeout was weakened. GitHub's hosted Ubuntu runner subsequently passed the literal -repository command, so the local discrepancy remains recorded rather than treated -as workflow evidence. - -### Hosted positive, controlled-negative, and restored-positive proof - -Draft [PR #37](https://github.com/kyashp/shepherd/pull/37) produced the stable -workflow/job context `Pull request checks / Required checks`: - -1. Representative commit `9501b95` passed hosted run - [33262643612](https://github.com/kyashp/shepherd/actions/runs/33262643612) in - 1m24s, including literal `npm run check`. -2. Temporary workflow-only commit `d9dcea9` appended `exit 1` after the unchanged - repository command. Hosted run - [33262766467](https://github.com/kyashp/shepherd/actions/runs/33262766467) - concluded failure in 1m34s, proving a controlled red candidate cannot satisfy - the same context. -3. Commit `edc240f42ab7398bb710a524859ecdfc816927c5` removed the temporary step and - restored the independently reviewed workflow byte-for-byte. Hosted run - [33262875107](https://github.com/kyashp/shepherd/actions/runs/33262875107) - passed in 1m29s. - -PR #37 merged into `main` as -`1f1fda7782b27e2077a505be5e5be8b413c7f446`. Its closing keyword automatically -closed issue #36; the issue was reopened because repository administration and -post-activation evidence remain. The remote implementation branch was removed. - -The next merged product change, [PR #16](https://github.com/kyashp/shepherd/pull/16), -passed the merged workflow's `Required checks` run -[33266134939](https://github.com/kyashp/shepherd/actions/runs/33266134939) before -merging as `403fc095b07d60e17de1cb3f82b4e16b6a778919`. This is post-workflow proof -that a real product PR can satisfy the context. - -Active draft [PR #25](https://github.com/kyashp/shepherd/pull/25) was briefly -closed and reopened solely to emit the supported `pull_request.reopened` event. -Its draft state, branch, and head `570982dc2766e57f38bb0327f3b906c53b2ed5f2` -were unchanged. The resulting `Required checks` run -[33267807007](https://github.com/kyashp/shepherd/actions/runs/33267807007) -passed in 1m43s, so activating the stable context will not strand that owner. - -### Deliberately pending repository administration - -The repository ruleset query still returns `[]`. After PR #25 passed, an activation -attempt using the narrow default-branch payload reproduced HTTP 404. Read-back of -the effective repository permission identified the cause: authenticated identity -`sanjey99` has `WRITE` but not `ADMIN`, while GitHub requires repository -Administration (write) for ruleset creation. CI-01 therefore remains open for: - -1. a repository admin to activate the default-branch rule requiring exact context - `Required checks` from GitHub Actions integration `15368`, with no bypass actors - and loose freshness; -2. ruleset read-back and a post-activation PR proof that a red required context - cannot merge; and -3. merge-group execution proof only if a merge queue is enabled. - -No repository rule was created or changed by the workflow or this evidence update. - -## 2026-08-30 — E2E-02 Worker candidate - -The Worker added a model/network-free real-browser hero journey on the audited -deterministic verifier fixture. It exercised 13 material stages at `1280x800` and -`1440x900`, from active Contracts through protected promotion and Project Group -summaries, with backend API, Git, persisted-store and bounded verifier-ledger -oracles. Focused Chromium passed twice (4/4 total), the full Chromium suite passed -12/12, and harness unit coverage passed 7/7. All 26 ignored screenshots were -visually inspected; document/body overflow, clipping and theme drift were absent. - -The journey also passed bearer-auth 401, keyboard/focus and evidence-tab controls, -same-base/distinct-branch candidate identity, 11/11/11 verifier -create/complete/remove operations, no-network/read-only verifier constraints, -public DTO/DOM/store/log canary scans, canonical protected output, outside-write -canary, reset restoration and exact port/process/container/root cleanup. It made -zero live/model calls and did not change production code, UI or CSS. E2E-02 remains -at 95% until independent Auditor review and hosted integration evidence; `GC-06` -remains open because lifecycle summaries are truthfully Shepherd-authored. - -## 2026-08-30 — F-01/02 Worker candidate - -The original two-case RED proved that typed Agent Runtime timeout and execution -failures both reached the Mission as `unknown`. The candidate introduces one -bounded typed Runtime error across the container and executor redaction boundary. -A timeout now persists Contract `execution_timed_out` with `agent_timeout`; a -non-timeout execution failure persists `execution_failed` with -`agent_runtime_error`. Both produce the same causal failure on the failed Plane, -logical Agent and failed Mission, release active project/Contract ownership, emit -bounded durable event details, survive store reload and public DTO conversion, and -leave collision/candidate/promotion state empty. Untyped exceptions remain -`unknown`; cancellation, verifier infrastructure and candidate behavior are -unchanged and no message regex was added. - -The RED 2/2 became GREEN 3/3 including the untyped control. Runner/executor/service -focused coverage passed 11/11, adjacent runner/executor/service/API/store coverage -passed 102/102, strict test typecheck passed, and two literal -`npm run check` runs passed server 606/606 with two opt-in skips, Web 17/17, launcher -3/3 and both builds. No live/model call, UI/theme change or schema migration ran. -F-01/02 remains at 95% pending independent Auditor and hosted integration evidence. -## 2026-08-30 — TST-13 bounded Agent Runtime failure candidate - -- **Branch/base:** `fix/f-01-02-runtime-redaction` from Auditor evidence - `b03b17f` (F-01/02 parent `685e4ff`); pushed before implementation. -- **RED:** non-zero Agent Runtime output selected parsed error/raw stderr as - `RuntimeExecutionError.message`. Executor secret/path redaction retained opaque - diagnostics, and Contract/candidate failure paths persisted that message through - Mission, Contract, Plane, Agent, events, state/reload and public DTO. -- **Correction:** `RuntimeExecutionError` constructs fixed bounded text from a - runtime-normalized closed kind and optional positive safe-integer timeout; its - public kind/deadline fields are non-writable. `ContainerCodexRunner.run` - reconstructs cancellation/typed errors and maps every other create/start/child/ - cleanup operational failure to fixed execution text. Executor and service - Contract/candidate boundaries reconstruct again before durable/public use. No raw - stdout/stderr, parsed failure, model output, path, command or cause is retained. -- **Causal evidence:** planted parsed-output, stderr, create-exit, synchronous spawn, - opaque benign, secret, private-path, hostile-kind and invalid-timeout canaries are - absent from Error message/string/stack/inspection/cause and Contract, Plane, - Mission, Agent `lastError`, events, raw store, reload and public mission DTO. - Candidate Runtime failure exhausts in `attention_required`, starts no promotion, - creates no promoted candidate and leaves the protected head at Mission base. -- **Observed checks:** runner 22/22; focused runner/executor/service 75/75; adjacent - service/verifier/model/config 226/226; strict Server test typecheck green; first - literal `npm run check` green (launcher 3/3, Server 607 passed + two explicit - skips, Web 17/17, production builds green). No live/model/network call ran. -- **Security review:** first read-only pass found create/spawn diagnostics and the - candidate path; second found hostile `kind` mutation. Both were corrected with - causal tests. Final read-only follow-up reports no remaining High/Medium finding - and a scoped PASS. Second literal `npm run check` is green (launcher 3/3, - Server 609 passed + two explicit skips, Web 17/17, production builds green). - Auditor U/I remain required. -## 2026-08-30 — TST-14 execution-home cleanup precedence candidate - -- **Branch/base:** `fix/f-01-02-private-home-cleanup` from Auditor evidence - `61b3ced` atop bounded Runtime chain `c7b5175`; pushed before edits. -- **RED:** execution-private-home `rm()` threw its raw opaque/path/OS diagnostic - from `finally`, overriding success, cancellation, typed timeout and typed execution - in all four controlled rows. -- **Correction:** executor records only whether a primary outcome failed, clears its - active/cancellation ownership, and always attempts exact scoped home removal. A - cleanup-only failure becomes fresh fixed typed execution failure; any primary - cancellation/timeout/execution remains authoritative. Raw cleanup error is neither - attached as cause nor persisted. Failed `0700` owner-scoped homes remain eligible - for bounded reconciliation rather than being followed outside their root. -- **Causal evidence:** 4/4 outcome rows exclude opaque, configured-secret, Mac path - and OS-code canaries from Error/string/stack/inspection/cause; inactive cancel - returns false; reconciliation removes exactly the retained home; a later distinct - execution succeeds and cleans. Contract state proves Mission/Contract/Plane/Agent, - event, raw store, reload, public DTO, real `GET /api/shepherd/missions/:id` response - and console error/warn capture are canary-free. Candidate cleanup failure exhausts - to attention, never starts promotion and leaves protected head at Mission base. -- **Observed checks:** executor including OPS-06/preflight 21/21; focused/adjacent - 108/108; strict Server test typecheck; first literal `npm run check` green with - launcher 3/3, Server 615 passed + two explicit skips, Web 17/17 and both builds. - No live/model/UI/network call ran. -- **Security review:** initial read-only review found no High/Medium and requested - explicit inactive-cancel, log-capture, HTTP and OPS-06 evidence; all are now covered. - Final follow-up reports no High/Medium or material evidence gap. A full-suite run - exposed and corrected one test-only overclaim: under contention, an unrelated - candidate can fail before executor cleanup, so the assertion now requires all - candidates terminal/no-promotion, at least one causal fixed cleanup failure and - universal canary absence. No timeout/product change was made. Two post-correction - literal checks pass identically (launcher 3/3, Server 615 + two explicit skips, - Web 17/17, strict types and builds). Auditor U/I remain required. -## 2026-08-30 — TST-15 bounded sentinel/reconciliation filesystem policy - -- **Branch/base:** `fix/f-01-02-sentinel-cleanup` from Auditor evidence `6eb20d0` - atop TST-14 `3afc452`; pushed before edits. -- **RED:** sentinel adoption open attached raw cause; validation/adoption close could - override bounded primary errors; failed unlink was swallowed; interrupted private- - home and preflight-workspace rm escaped raw errno/path/OS diagnostics. Independent - review then identified the adjacent pre-open lstat/chmod/readdir family. -- **Correction:** one internal `BoundedFilesystemError` policy emits only closed - stage/reason text for sentinel validation/adoption and private-home/preflight- - workspace reconciliation. It never retains raw cause/detail. Primary failure wins - over close/unlink double faults, cleanup-only fails closed, and all exact cleanup - attempts still run. Same-process failed sentinel unlink is remembered for exact - retry; rm failures retain the exact contained target. No broad delete, fallback, - symlink relaxation or public error code was added. -- **Causal evidence:** faults cover adoption open; existing-sentinel lstat/chmod; - pre-adoption readdir/chmod; validation close and read+close; adoption close-only and - write+close+unlink; a second failed pending unlink then success; interrupted home - and preflight-workspace rm. Opaque/secret/Mac/Linux/errno/path canaries are absent - from Error/string/stack/inspection/cause and service initialization Error/cause, - store and console logs. Every retained target is observed, retried and removed. -- **Residual:** pending sentinel ownership is process-local. After restart, an - invalid retained sentinel fails closed and may require operator cleanup. This is - intentionally not described as automatic cross-process recovery. -- **Observed checks:** executor 33/33 (also independently rerun); focused/adjacent - 120/120; strict Server test types; two literal `npm run check` passes, each with - launcher 3/3, Server 627 passed + two explicit skips, Web 17/17 and both builds. - No live/model/UI/network call ran. -- **Security review:** first pass found one Medium pre-open family and four evidence - gaps. After correction, final read-only re-review reports PASS with no High, - Medium or material gap; containment and symlink protections remain unchanged. - Auditor U/I remain pending. - -## 2026-08-30 — F-05 Worker candidate - -- **RED/correction:** a real add/add Git conflict was detected and aborted by the - Git boundary, but the service persisted generic `unknown/background_demo` and - left the integration Plane inspecting. The narrow correction maps the existing - typed conflict to fixed `git_conflict/integration_merge`, marks only the - integration Plane failed, and records bounded event evidence. -- **Boundaries:** ten validated repo-relative conflicts prove an exact total count, - an eight-path preview capped at 48 characters, and rejection of absolute, - traversal and control paths (backslashes normalize to `/`). No raw Git output, - host path or cause is persisted or exposed through the public Mission DTO. -- **State/cleanup:** source Contracts remain verified and inspectable; Agents are - released; candidates/collisions remain empty; protected HEAD does not move. Git - merge abort leaves the retained integration worktree clean. Deterministic reset - removes all retained Plane worktrees and branches while preserving repository - HEAD and an outside canary. -- **Observed checks so far:** causal 2/2; adjacent service, Git promotion, recovery, - store and API 110/110; strict production/test types; first literal `npm run check` - passed launcher 3/3, Server 666 passed + two opt-in skips, Web 17/17 and both - builds. After adding explicit reset and unsafe-path boundary proof, the second - literal gate passed launcher 3/3, Server 667 passed + two opt-in skips, Web 17/17 - and both builds. Independent Auditor `I` remains pending; no live, model, network - or UI-design call ran. - -## 2026-08-30 — F-04 Worker candidate - -The causal RED used the existing internal fault checkpoint to place a partial -managed destination immediately before initial Contract Plane creation. Plane -Manager correctly rolled it back, but the owning Contract remained queued and the -Mission persisted generic `unknown/background_demo`. The candidate recognizes the -existing `PlaneCreationError` without exposing its cause, persists fixed bounded -`worktree_creation_failure/plane_creation` evidence on the owning Contract and -Mission, releases the logical Agent/project, and records no Plane for a resource -that never completed creation. Executor and verifier calls remain zero; no -integration, collision, candidate or promotion state exists. - -The original RED became GREEN 1/1. A separate real-Git integration fault after -worktree attachment proves rollback of the partial worktree and `shepherd/` -branch, unchanged protected HEAD/file canary, and a fixed public error message. -Focused coverage passed 2/2; adjacent service/Git/recovery/API/store coverage -passed 107/107; strict test types and two literal `npm run check` runs passed -launcher 3/3, Server 663/663 with two opt-in skips, Web 17/17 and both builds. No -live/model/network/UI/schema change ran. F-04 remains 95% pending independent -Auditor, security and hosted integration evidence. - -## 2026-08-30 — F-06 Worker candidate - -- **Scope:** the representative Mission `running -> verifying` write after two - verified Contracts and before integration now uses `mutateRecoverably`. The - generic store primitive is not claimed as entity-aware recovery for arbitrary - mutations. -- **Journal contract:** the adjacent version-1 sidecar contains only an allowlisted - operation, Mission/two Contract/two Plane IDs, fixed stage, timestamp and SHA-256 - of the exact canonical sanitized bytes written by the shared serializer. It is - capped at 8 KiB, mode/owner checked where supported, opened no-follow, and uses - temp/write/file-sync/close/rename/parent-directory-sync. Unix/macOS directory - sync errors fail bounded; Windows retains file sync, atomic rename and digest - reconciliation but cannot claim the same sudden-power-loss directory guarantee. -- **Recovery:** old digest means the transition did not commit and startup records - exactly one bounded `persistence_error` attention event; changed digest must - match the committed `verifying` state or a prior exact reconciliation. Pending - recovery blocks ordinary mutations and event allocation. Agents are released, - Contracts/Planes remain verified, project attention remains active, and no - integration/candidate/promotion/protected-head mutation occurs. Reset after - cancellation removes the journal and retained Planes. -- **Fault evidence:** all six journal stages, six primary stages and two journal - removal stages are injected. Rename/directory-sync ambiguity, immediate recovery, - two restarts/no duplicate, concurrent mutation denial, corrupt/oversize/symlink, - unknown IDs, stale precondition and digest mismatch pass with bounded errors and - no secret/path/errno canary on public/store/Error/stack surfaces. -- **Observed checks:** store 34/34; focused persistence/recovery 23/23; adjacent - store/service/recovery/API 116/116; first literal `npm run check` passed launcher - 3/3, Server 700 passed + two opt-in skips, Web 17/17, strict types and both builds. - A second literal gate passed with the same counts. Independent - Auditor/security/hosted evidence remains. No live/model/network/UI-design call - ran. - -## 2026-08-30 — CHAT-03 unsafe and underspecified Contract intake - -- **Scope:** issue #81 strengthens the integrated general private-chat Contract - planner without changing the frozen UI theme. A request must end with one direct, - allowlisted action on a quoted authority-contained project artifact, the exact - bounded project-only `Safety:` statement, and one literal-content `Acceptance:` - predicate. Ambiguous, conditional, negated, approval-dependent, credential, - privileged, destructive, external/network and safeguard-bypass wording remains an - inert clarification and creates no Mission, Contract or Plane. -- **Recovery:** unsafe intent is accumulated rather than erased by incremental - follow-ups. Exact `Replace prior request:` starts a clean bounded draft; a complete - follow-up replaces only earlier vague drafts that contained neither an artifact nor - unsafe intent. The Agent remains startable/stoppable/deletable after clarification. -- **Runtime boundary:** the live preflight plants a fake parent credential canary and - scans `/proc/[0-9]*/environ` inside the actual Codex Linux sandbox. The unguarded - control could read the canary; the generated production preflight in the freshly - built Runtime image passed only after the sandboxed child could not recover it. - Visibility maps to fixed `credential_isolation_failed` evidence. -- **Observed deterministic checks:** focused planner/service 27/27; literal - `npm run check` passed launcher 3/3, Server 824 passed + two explicit opt-in skips, - Web 20/20, strict production/test type checks and both builds. Authenticated - Chromium passed 8/8 across exact 1280×800 and 1440×900 projects, covering the auth - collision, clarification/correction, lifecycle recovery, durable human review and - no document overflow. `git diff --check` passed. Independent security and UI - reviews passed with no High/Medium finding. -- **Live evidence and limitation:** the first broad command incorrectly discovered a - stale ignored recording worktree and is not counted. The corrected exact-source, - single-worker live command made the bounded provider attempt, reached Contract - execution, and failed after 35 seconds with `Contract result manifest is missing`. - No retry was made. This is separate Agent-output reliability work and means neither - this candidate nor `LIVE-01` claims an exact-head live Mission pass. - -## 2026-08-30 — PERF-01 Worker candidate - -- **Scope and environment:** this candidate is based on protected-main `baa6b2f`. - macOS `26.5.2` (`arm64`), Node `v26.5.0`, npm `11.17.0`, Playwright `1.62.1`, - and Chromium `151.0.7922.34` ran the deterministic compiled Server and real - Chromium UI. Docker was used only by the separately recorded ContainerVerifier - boundary test below. -- **Bounded RED:** the initial `npm run test:e2e:shepherd-performance` exited 1: - each natural-browser run reported `Expected length: 5; Received length: 2` for - `verification_started`, proving the old count was not the actual Contract - lifecycle. The focused causal test was then deliberately red with - `expected ... length of 3 but got 2` after both real scheduled candidate - executions arrived at its test-owned gate. The green assertion is exactly two; - it releases in `finally`, so the red case cannot strand a Mission. This removed - the non-causal verifier gate rather than adding timeout, retry, product, or UI - behavior. -- **Natural timing, one clean sample per viewport:** the ungated path measured the - earliest of exactly two `contract_started` events, emitted after both initial - `createContractPlane` calls return, as a conservative two-Plane-ready upper - bound; it does not call raw `Plane.createdAt` a worktree-complete boundary. It - also measured earliest `verification_started` to latest `verification_passed` - (exactly two of each), persisted collision → visible, and collision → - `promotion_completed`. At `1280x800`: 339 ms accepted → two-Plane-ready, 230 ms - Mission → two-Plane-ready, 334 ms verification, 391 ms persisted collision → - visible (PRD limit `<=1.5s`), 2,083 ms collision → promotion complete, and - 3,848 ms total. At `1440x900`: 412 ms, 257 ms, 320 ms, 74 ms, 2,187 ms, and - 4,167 ms respectively. -- **Instrumented concurrency proof (not a timing measurement):** the focused - `ShepherdService` test owns a wrapper around the deterministic executor. It - gates only `resolution_candidate` calls, records ISO start/completion times - without prompts, paths, or IDs, waits up to three seconds for exactly two real - scheduler arrivals, asserts no completion before release, then asserts two - parseable completions and `max(start) <= min(complete)`. Its bounded rejection - still enters `finally` to release background work. It passed 1/1 (62 filtered) - after the causal RED. - This test-owned injection is separate from the ungated browser path, so gate - delay cannot enter the natural timing samples. -- **Verifier lifecycle and isolation evidence:** the natural browser run asserts - eleven unique container names, each exact `create → start → complete → remove` - sequence, and an empty fixture container directory. Its run ledger records every - `create` request as `network=none` and `readOnly=true`; those are fixture command - records, not enforcement proof. Enforcement is separately observed with - `npx vitest run --config apps/server/vitest.config.ts apps/server/src/shepherd/verifier.container.test.ts -t "proves cleared secrets, no network, and a read-only candidate mount"`: - 1 passed, 8 skipped. That real ContainerVerifier boundary test rejects network - access and candidate-mount writes and confirms its cleared environment. Neither - check detects package downloads, so none are claimed. -- **Observed GREEN and screenshots:** - `npm run test:e2e:shepherd-performance:evidence` passed build, harness 7/7, and - Chromium 2/2. It intentionally uses the ordinary Playwright config, so this spec - remains included in the full browser harness. The reproducible evidence command - wrote the passing collision-visible and final-promotion screenshots at both - required viewports under `docs/ui-review/perf-01/1280x800/` and - `docs/ui-review/perf-01/1440x900/` (`01-collision-visible.png` and - `02-promotion-completed.png` in each); both required states were visually - inspected. `node --test tests/e2e/harness.test.mjs` also passed 7/7. -- **CI teardown-race RED/GREEN:** hosted Node 22 run `33316746584` exposed a - test-cleanup race after 805 passing tests: a managed temporary disappeared - after `lstat` and before `chmod`, which raised `ENOENT`. A deterministic - regression now removes a fixture at that exact boundary and reproduced the - same failure 1/1 before the fix. Cleanup tolerates only `ENOENT` from that - entry `chmod`; sentinel, containment, symlink, permission, and all other - failures remain strict. The focused regression passed 1/1, the complete - `service.test.ts` file passed 64/64, and a literal `npm run check` passed - launcher 3/3, Server 810 passed plus three opt-in skips, Web 20/20, all - workspace/test-source typechecks, and both builds. -- **Limitations:** local deterministic-fixture evidence is not a live-model - capacity measurement, hosted integrated rerun, package-download proof, or the - three clean rehearsals owned by `DEMO-REHEARSAL`. Gate `I` remains pending an - independent protected-main audit. The prior hosted failure is preserved above; - the corrected commit still requires a fresh hosted run. - -## 2026-08-30 — PERF-01 protected-main integration audit - -- **Integrated identity:** protected `origin/main` - `b193e5745661735c44e581ccdc10f2a1ce4692dc` is PR #77's merge commit; its - direct second parent is the reviewed correction - `332071d37295517721eb1360c501a6746535f5db`. The detached audit worktree was - clean before and after verification. -- **Focused causal checks:** the exact cleanup-race regression passed 1/1 with - 63 filtered tests, and the actual scheduled candidate-executor overlap proof - passed 1/1 with 63 filtered tests. -- **Integrated browser evidence:** the ordinary non-evidence performance command - passed build, harness 7/7, and Chromium 2/2 using the existing pinned read-only - browser cache. It did not download/copy/symlink a browser or set - `E2E_UPDATE_EVIDENCE`; tracked screenshots remained byte-identical. At - `1280x800`: conservative two-Plane-ready 323 ms, verification 303 ms, - persisted event → visible 488 ms, collision → promotion complete 2,073 ms, - and 3,712 ms total. At `1440x900`: 334 ms, 334 ms, 476 ms, 2,044 ms, and - 3,680 ms respectively. Both event-visibility samples satisfy the PRD - `<=1.5s` limit. -- **Full and hosted gates:** a literal `npm run check` passed all production and - test-source typechecks, launcher 3/3, Server 810 passed with three explicit - skips, Web 20/20, and both builds. Hosted exact-main run `33318509842` passed - `Node 22 / npm run check` in 2m54s. -- **Audit result:** independent Auditor returned READY with no Critical or - Important findings. PERF-01 gates `B` and `I` are passed. This remains - deterministic evidence, not a live-model capacity measurement, - package-download proof, or the three clean rehearsals owned by - `DEMO-REHEARSAL`. - -## 2026-08-30 — CHAT-03 protected-main reconciliation - -- The issue #81 candidate was merged locally with protected `origin/main` - `9696c6d`. The only textual conflict was the append-only `BUILD_LOG.md`; both the - CHAT-03 and protected-main PERF-01 histories are retained. Startup-settings, - performance, architecture, fixtures and screenshots from main were accepted - byte-for-byte; product files merged automatically. -- Focused intake/startup/composition coverage passed 33/33. Literal - `npm run check` passed all production/test type checks, launcher 5/5, Server 842 - passed with two explicit live skips, Web 20/20, and both production builds. -- Combined authenticated Chromium passed 10/10 at 1280×800 and 1440×900. The - issue #81 clarification, lifecycle and human-review journeys remained green; - the integrated performance journey completed in 2,343/2,388 ms with persisted - collision visibility in 157/101 ms. -- `git diff --check` and conflict-marker checks passed. No live request was repeated; - the earlier exact live result-manifest failure remains an explicit `LIVE-01` - limitation rather than being hidden by the deterministic integration result. -- Hosted `Pull request checks` run `33319816809` then preserved a causal RED: under - heavy suite contention, PERF-01 spent its three-second candidate-pair deadline on - earlier Mission setup and failed before both candidates arrived, while independent - hosted run `33319816797` passed the same repository head. The test-only correction - gives pre-candidate setup its own bounded 15-second allowance and starts the - unchanged three-second concurrency deadline only when the first real candidate - reaches the executor. Product scheduling, timeouts and retry behavior are - unchanged; a sequential scheduler still fails the pair deadline and releases the - existing gate through `finally`. The preserved row passed 10/10 consecutive - focused repetitions; the post-correction literal gate passed launcher 5/5, - Server 842 passed with two explicit live skips, Web 20/20, all strict typechecks - and both builds. - -## 2026-08-31 — issue #96 exact-main release-readiness remediation - -- **Identity and ownership:** branch `fix/96-release-readiness-audit`, draft PR #97, - protected-main base `f935fdb5581849f8377f20922e254c55d34e5de0`, tested product - commit `223a5fe00f977013d4bf5df6560016a1719c8d11`. Issues #45, #65 and - #89 were explicitly taken over because no other PR or branch was active. This is - candidate evidence; it is not protected-main integration or independent audit. -- **Initial failure evidence:** the exact-main Playwright matrix passed 34/38. - Reproduced causes included a Project Group controlled-input/caret race, Agent edit - hydration/custom-authority data loss, a one-pixel document scroll, and missing - explicit Settings icon names. Release review also confirmed unbounded durable - collections and partial Agent publication, missing tokenless Host/Origin and - public-bind boundaries, a bind-only/non-exact live harness, absent executable - coverage/Terraform gates, and Terraform runtime credentials entering the - plan/state path. -- **Corrections:** `2e7c915` bounds durable collections at 10,000, returns bounded - `507` capacity failures, makes Agent creation atomic, enforces tokenless loopback - Host plus same-origin Origin, and refuses a public bind without a strong token. - `69c12de` fixes the controlled composer and caret, labels Settings controls, - removes the footer overflow pixel, pins direct-Playground behavior, and improves - fake Runtime diagnostics. `223a5fe` fixes Agent edit hydration/rapid-toggle state, - expands functional browser coverage, builds exact-tree live Runtime/controller - images on a named volume with cleanup, adds executable Server/browser coverage, - adds pinned Docker Terraform validation, and transfers runtime credentials only - after apply over SSH into a mode-`0600` environment file. -- **Literal repository gate:** `npm run check` passed root Node tests 26/26, Server - 856 passed with 3 explicit opt-in skips, Web 20/20, every strict production/test - typecheck, and both production builds. No timeout/retry increase, skip, assertion - weakening, design change, or dependency vulnerability was used. -- **Clean coverage gate:** `npm run test:coverage` passed. Server V8 coverage: - statements 86.15% (7543/8755), branches 80.05% (5230/6533), functions 91.46% - (1446/1581), lines 88.03% (7161/8134). Browser Istanbul coverage: statements - 88.50% (924/1044), branches 80.18% (862/1075), functions 87.64% (305/348), - lines 92.37% (788/853). The checker requires every production file and all four - metrics at or above 80%, and restores the ordinary build after instrumentation. -- **Full browser gate:** ordinary one-worker Chromium passed 48/48: 24 functional - flows at both exact `1280x800` and `1440x900`. It covers auth/shell overflow, - Agent create/edit/start/stop/delete/sort, preset compatibility, Settings - persistence/reset/error recovery, direct Playground, Project Group, successful - and denied Shepherd Missions, loading/empty/reconnect/malformed/not-found states, - durable restart, verifier/runtime contracts, accessibility contrast and truthful - promotion evidence. Natural PERF-01 samples were 4,587 ms and 3,457 ms total, - with persisted-event visibility 960 ms and 612 ms respectively. -- **Terraform and live construction:** `npm run test:terraform` initialized and - validated a disposable copy with `hashicorp/terraform:1.9.8` and - `volcengine/volcenginecc` 0.0.58: `Success! The configuration is valid.` - `npm run test:shepherd:live:preflight` built the exact candidate application and - controller, passed both in-image dependency audits, created the named state - volume, and discovered exactly the one bounded live integration test under a - non-root controller. Temporary containers, images and volume were cleaned by the - wrapper. No model request or provider spend occurred. -- **Security and repository hygiene:** `npm audit --json` reported zero - vulnerabilities. `git diff --check`, tracked secret/state/generated-artifact - scans and bounded canary checks passed. No environment value, raw prompt/model - output, session identifier, Terraform state or provider cache was recorded. -- **Hosted candidate checks:** exact candidate/docs head `bb1a1df` passed - `Node 22 / npm run check` run `33389614355` in 2m59s and `Required checks` run - `33389614223` in 3m01s. -- **Explicit remaining evidence:** the external Ark turn was not executed because - it transmits repository-derived prompts and scoped code to the configured - endpoint and the managed executor requires separate informed approval for that - transfer. Independent UI gate `U`, issue #89 part-5 security review, - protected-main integration and the three complete demo rehearsals remain open; - local and hosted candidate success is not substituted for any of them. diff --git a/docs/DEVIATIONS.md b/docs/DEVIATIONS.md deleted file mode 100644 index 57e45ab..0000000 --- a/docs/DEVIATIONS.md +++ /dev/null @@ -1,59 +0,0 @@ -# Shepherd Deviations, Clarifications, and Environment Limits - -This is the hard completion ledger for material interpretations of -[`PRD.md`](PRD.md). It does not narrow the PRD and it does not convert missing -evidence into accepted behavior. Exact implementation status and ownership remain -canonical in [`TASKS.md`](TASKS.md); reproduced defects remain canonical in -[`FIXES.md`](FIXES.md). - -## Status contract - -- **Clarification** resolves an ambiguity without reducing required behavior. -- **Actual deviation** means required behavior or required acceptance evidence is - absent. Every actual deviation must name an open TASKS/FIXES row. -- **Environment limitation** identifies evidence that cannot honestly be claimed in - the current environment. It remains open when the PRD requires that evidence. -- **Permanent scope statement** restates an explicit PRD exclusion and is not work - to “fix.” -- **Resolved** requires implementation and the tests named by the owning task. A - backend-only or hosted-only gate cannot close a browser, live, or second-machine - requirement. - -The project is not complete while any row below is **OPEN** or **PARTIAL**. - -## Product-contract interpretations - -| Topic | Classification | Current status and evidence | Owning task(s) | -|---|---|---|---| -| Manifest ingestion exception | Clarification | **PARTIAL.** The PRD both protects `.shepherd/**` and requires the exact per-Plane `.shepherd/result.json` ingestion channel. Trusted code schema-validates and removes that file before staging; no `.shepherd/**` content may integrate or promote. Valid-path parser/service tests exist, but the required durable missing/malformed/omitted-key failure states and browser evidence remain incomplete. | `FM-01`, `E2E-04/05`, `SEC-REVIEW` | -| Interrupted work | Clarification | **PARTIAL.** The Mission enum remains authoritative. Startup reconciliation maps active work to `attention_required` with `execution_interrupted`; Contracts/candidates may use explicit terminal `interrupted` states. Backend recovery coverage exists, but the required kill/restart-mid-Mission browser journey and full failure-matrix evidence are open. | `E2E-08`, `FM-01`, `SEC-REVIEW` | -| Managed project boundary | Clarification | **PARTIAL.** The demo uses a separately managed Git repository beneath configured application data, never this source repository. Public browser/model input does not accept filesystem paths or shell commands. `E2E-02` now proves its audited hero-path Git/store/API/DOM correlation, but final mutation checks, complete scans across remaining flows, and independent final review remain open. | `SEC-REVIEW`, `DEMO-REHEARSAL` | -| Supported isolation profile | Clarification plus environment limitation | **PARTIAL.** Shepherd's Plane/verifier/no-network guarantees apply only to the local Docker/Colima/Podman path; host-process and ECS starter paths must report unsupported isolation rather than imply parity. Linux Docker gates and bounded stage/reason diagnostics are audited. The affected-host cause is now reproduced and named: a host share reaching the engine through a virtual machine cannot carry Codex's Landlock per-file access rights, so `host-bind` state cannot support the sandbox there and the gate correctly refuses to start. The launcher detects this through its own probes and switches to an engine state volume automatically, which restores the guarantees. | `OPS-06`, `LIVE-01`, `SEC-REVIEW` | -| Control-plane engine socket in container-volume mode | Clarification plus accepted trust decision | **SCOPED.** In `container-volume` mode the control plane runs inside the engine and is given the engine socket so it can start sibling Runtime containers. Socket access is equivalent to control of the engine, so it materially widens the control plane's authority; it does not weaken any Agent boundary, since Runtime and verifier containers keep non-root, read-only, dropped capabilities, no-network verification and the private-home denial. The control plane stays non-root and joins only the socket's group. `host-bind` mode, the default, grants no socket. A scoped socket proxy is the documented hardening if this profile is ever exposed beyond a local operator. | `OPS-06`, `SEC-REVIEW` | -| Completed Plane cleanup | Clarification | **RESOLVED AS POLICY, NOT AS AN IMPLEMENTED CLEANER.** Cleanup is permitted only after evidence capture and must retain persisted Plane metadata, Git lineage, bounded diff/verification evidence, and branch inspection. The current product does not ship automatic completed-Plane cleanup, and this document must not imply it does. The PRD does not require an automatic cleaner; `retainCompletedPlanes` remains the truthful current behavior. | No implementation task unless scope changes; recheck in `SEC-REVIEW`/final docs | -| Visual fidelity | Clarification plus actual evidence deviation | **OPEN.** `UI.jpeg` is a six-surface product reference rather than one literal composite viewport. Human-visible hierarchy, palette, typography, density, spacing and interactions still require the full six-surface/state review. Audited E2E-01, E2E-02, GC-01, and focused UI evidence at 1280x800/1440x900 cover important subsets, not full visual acceptance or “all laptop aspect ratios.” | `UI-GATE`, `E2E-03`–`E2E-08`, `DEMO-REHEARSAL` | - -## Sequencing interpretations - -| Topic | Classification | Current status and evidence | Owning task(s) | -|---|---|---|---| -| Failure matrix sequencing | Clarification | **OPEN.** F-01/02, F-04–06 and TST-13–24 are audited, closing typed Agent runtime/timeout, executor filesystem/config, initial Plane creation, Git-conflict and representative persistence-recovery boundaries. The complete matrix remains open for manifest, candidate timeout/retry, tie, polling, model-degradation and required browser rows. | `F-07`–`F-09`, `FM-01`, `UI-01`, `E2E-04`–`E2E-08`, `SEC-REVIEW` | -| Browser-journey sequencing | Clarification | **OPEN.** Backend paths can precede UI implementation, but no PRD journey is complete without its real browser assertions and screenshots. `E2E-01` and `E2E-02` are audited; harness/shell tests and source inspection do not close `E2E-03`–`E2E-08`. | `E2E-03`–`E2E-08`, `UI-GATE` | - -## Environment and assurance limitations - -| Limitation | Classification | Current status and honest reporting rule | Owning task(s) | -|---|---|---|---| -| Second environment / machine | Environment limitation | **OPEN.** Hosted GitHub Node 22/Docker runs are valid cross-environment evidence only for the exact `npm run check` workflow executed there. They are not a second-machine full demo rehearsal. Claim the latter only after a real second machine/state runs the judge flow. | `DEMO-REHEARSAL`, `DEL-02` | -| Ordinary-container tenancy | Permanent scope statement | **ACCEPTED.** Ordinary containers are not hardened hostile multi-tenant isolation; production OAuth/RBAC/multi-tenancy are explicitly out of scope in PRD 2.2 and 13. Do not market the local PoC as a multi-tenant security boundary. | Final `SEC-REVIEW` wording only | -| Live-model network egress | Clarification plus environment limitation | **PARTIAL.** The bounded reviewer smoke made exactly one external request and passed with `completed findings=2`; deterministic authority, secret scans and cleanup remained green. Current live Shepherd Mission/legacy continuity remain open. Default tests stay model/network-free. | `LIVE-01`, `SEC-REVIEW`, `DEL-02` | -| Secret-scan certainty | Clarification | **OPEN FOR FINAL ASSURANCE.** Scans can prove absence of configured secrets, planted canaries, exact known values, and recognized credential/private-path patterns—not unknowable arbitrary strings. This epistemic limit does not relax the PRD prohibition on secrets in source, store, prompts, logs, events, or DOM. | `SEC-REVIEW`, `DEMO-REHEARSAL`, `DEL-02` | -| Laptop coverage | Environment/evidence limitation and actual deviation | **OPEN.** The two required audit viewports are green only for audited rows; they do not prove all laptop aspect ratios or the full six-surface matrix. “All laptop aspect ratios” is operationalized by a documented representative matrix, which must be defined and executed before final visual claims. | `UI-GATE`, `DEMO-REHEARSAL`, `DEL-02` | - -## Completion rule - -Before submission, the Auditor must reconcile this file against current code, -`TASKS.md`, `FIXES.md`, final browser/live/security evidence, and the generated test -report. No OPEN/PARTIAL row may be silently relabelled as an accepted limitation. -If an actual PRD deviation remains, the project remains incomplete unless the user -explicitly revises the PRD. diff --git a/docs/FIXES.md b/docs/FIXES.md deleted file mode 100644 index ab56ee0..0000000 --- a/docs/FIXES.md +++ /dev/null @@ -1,1278 +0,0 @@ -# Shepherd Defect Queue - -**Current integration branch:** protected `main`. Historical entries retain the -branch/SHA on which their evidence was observed. - -**Reconciled:** 2026-08-31, Asia/Singapore. Individual rows retain their own audit -status; this date does not self-certify candidate fixes. - -**Task ordering and dependencies:** [`TASKS.md`](TASKS.md) - -This file contains only reproduced defects or defects strongly evidenced by the -current source/tests and earlier bounded build-log reproductions. It is the Fixer -queue, not a second PRD. When an observation is only reported from another machine, -that limitation is explicit. - -## Fixer rules - -1. Re-run the exact failure contract before editing. If it does not reproduce, - preserve the report and record the missing condition; do not call it fixed. -2. Make the smallest coherent correction. Do not refactor unrelated code, weaken - schema/lifecycle/security assertions, bypass the sandbox, or change public/UI - contracts unless the supported root cause requires it. -3. Add the causal regression, run targeted and adjacent tests, then literal - `npm run check`. The auditor independently reruns the relevant PRD flow on the - integrated `main` SHA. -4. Preserve the accepted UI exactly as directed in `TASKS.md`. UI design is frozen; - edits are allowed only for indispensable functional clarity/data, causal bugs, or - accessibility, at both required viewports. Minimal fixes must not remove or - weaken intended functionality. -5. Update the defect row with before/after evidence, exact tests, confidence, commit, - and audit status. Anything below scoped 100% remains review-required. - -## Immediate queue - -### `REL-96` — exact-main release audit findings - -- **Evidence class:** issue #96 / draft PR #97, based on protected `main` - `f935fdb`; tested product commit `223a5fe`. -- **Browser failures:** the first full matrix passed 34/38. Project Group's - controlled composer could lose the character committed in the same turn as a - mention action or move its caret; Agent edit could publish a blank/custom draft - before presets and Agent state hydrated, then erase edits on a rapid authority - toggle. A one-pixel shell footer margin created document scroll, Settings icon - buttons lacked explicit accessible names, and the direct Playground choice was - not pinned by the regression suite. -- **Security/durability findings:** durable collections grew without a fixed cap; - Agent creation could publish partial state; a tokenless server trusted arbitrary - Host/Origin values; a public bind could start without a strong application token; - and runtime credentials could enter Terraform variables, cloud-init, plans and - state. -- **Release-harness findings:** the live test forced host bind mounts and could not - cross the documented Docker Desktop sandbox boundary; it did not independently - build the exact candidate tree. Terraform validation was unavailable on hosts - without a local binary, and the repository had no executable coverage provider or - enforceable 80% threshold. -- **Correction/status:** **REMEDIATED CANDIDATE** at `223a5fe` plus the preceding - issue #96 commits. Controlled UI actions synchronously commit the latest draft and - preserve caret/hydration state without changing the accepted design. Durable - publication is capacity-bounded and atomic. Tokenless access is loopback Host plus - same-origin Origin only, public binding requires a strong token, and Terraform - receives runtime credentials only after apply through a mode-`0600` SSH transfer. - The live wrapper builds the exact tree and runs its non-root controller on a named - state volume. Coverage and pinned-container Terraform gates are first-class npm - scripts. -- **Observed closure evidence:** literal `npm run check` passed root 26/26, Server - 856 passed plus 3 opt-in skips, Web 20/20, strict types and both builds. Clean - Server coverage is 86.15/80.05/91.46/88.03%; clean browser coverage is - 88.50/80.18/87.64/92.37% (statements/branches/functions/lines). Full Chromium is - 48/48 at exact `1280x800` and `1440x900`. Pinned Terraform validation and the - exact-tree zero-spend live Docker preflight pass; dependency audit reports zero - vulnerabilities. External Ark inference, independent UI/security review, - hosted CI and protected-main integration remain explicit gates, so this row is - not marked audited or integrated. - -### `TST-30` — Candidate-cleanup fixture races first-use Runtime root adoption - -- **Evidence class:** full pre-push Server gate on issue #48 candidate `f3a9dc0`. - All candidates reached failed/no-promotion state, but none retained the expected - sanitized `Agent Runtime execution failed` cleanup result. -- **Failure contract:** the routed test executor bypasses the production startup - recovery path. Concurrent first-use candidates can therefore race private-root - sentinel adoption and fail before `runner.run` registers their private homes as - cleanup-fault targets. The row then measures setup adoption instead of cleanup. -- **Correction/status:** **RESOLVED + INTEGRATED** at protected-main merge `b05a4aa` - via PR #93; causal correction `69d82b4`. Call the - public executor preflight once and assert it occurred before candidate scheduling; - cleanup injection, timeout, and failure/no-promotion assertions are unchanged. - The exact row passed 10/10, executor file 72/72, full Server 845/3 skipped before - rebase, and the formal current-main campaign passed five literal gates at - `10c95da`. Exact-main local check passed Server 846/3 skipped plus all adjacent - gates, and protected-main workflow `33353622211` passed. Not independently audited. - -### `TST-29` — PERF-01 overlap proof spends its budget on full Mission setup - -- **Evidence class:** formal issue #48 run 4 on `bd77952` timed out at 5.176s - after three complete green gates. A promise start barrier still failed at 6.229s; - an `autoResolution:false` candidate-completion variant failed at 6.038s. -- **Failure contract:** the assertion is about bounded scheduler overlap, but the - five-second row builds a complete Git-backed Mission before reaching that - boundary. Under suite pressure the setup consumes the timing budget even when - candidate scheduling is correct. -- **Correction/status:** **RESOLVED + INTEGRATED** at protected-main merge `b05a4aa` - via PR #93; causal correction `f3a9dc0`. Move the - existing byte-equivalent `allSettledBounded` primitive to the canonical scheduler - module and prove two-start-before-release, completion-after-release, limit-one, - rejection, and input-order behavior directly. Adjacent 30-second real-Plane tests - retain completed-Mission, selection, promotion, and `promotion_completed` - coverage. No product timeout/concurrency/retry changed. Formal campaign 5/5 at - `10c95da`; exact-main local check passed Server 846/3 skipped plus all adjacent - gates, and protected-main workflow `33353622211` passed. Not independently audited. - -### `TST-28` — F-03 snapshot cleanup is observed through OS file watchers - -- **Evidence class:** issue #48 reproduced the previously logged fail-fast sibling - cleanup instability while the test relied on `fs.watch` to notice removal. -- **Failure contract:** the watcher is an extra OS resource and a lossy proxy for a - service-owned lifecycle boundary. Under full-suite contention it can miss the - removal or contribute descriptor pressure even though the snapshot owner's - `finally` is correct. -- **Correction/status:** **RESOLVED + INTEGRATED** at protected-main merge `b05a4aa` - via PR #93; causal correction `682d7d9`. The existing - optional fault-checkpoint seam emits one exact - `contract_verification_snapshot_removed` checkpoint only after owned cleanup - settles; both F-03 variants await the matching Mission/Contract checkpoint and - still require `lstat -> ENOENT`. A failing observer cannot mask the primary - verifier error. Both rows passed five consecutive focused repetitions and the - formal campaign passed 5/5 at `10c95da`. Exact-main local check passed Server - 846/3 skipped plus all adjacent gates, and protected-main workflow `33353622211` - passed. Not independently audited. - -### `TST-27` — Fixture Git inherits outer repository selector variables - -- **Evidence class:** controlled RED on issue #48. With outer `GIT_DIR` and - `GIT_WORK_TREE` set, the general-project fixture helper followed the decoy index; - the surrounding Shepherd repository could receive staged fixture paths. -- **Failure contract:** `git -C` does not override explicit repository selectors. - Raw `execFile("git", ...)` inherited the enclosing hook/session environment, so - a nested test could mutate the wrong index before asserting its repository. -- **Correction/status:** **RESOLVED + INTEGRATED** at protected-main merge `b05a4aa` - via PR #93; causal correction `682d7d9`. Fixture Git - receives only PATH plus fixed locale/noninteractive/no-config values, never ambient - selector variables, and destructive fixture setup first proves the selected - repository's real top level. The hostile-selector/decoy regression passed, the - normal pre-push gate no longer redirected staging, and the formal campaign passed - 5/5 at `10c95da`. Exact-main local check passed Server 846/3 skipped plus all - adjacent gates, and protected-main workflow `33353622211` passed. Not independently - audited. - -### `CRUD-01` — Clarification drafts permanently block Agent deletion - -- **Evidence class:** reproduced on `origin/main` and preserved as a causal service - RED. A ready or stopped Agent with no Contract, Mission, Plane, event, or run still - returned 409 after one or more Shepherd `clarification_required` prompts. -- **Failure contract:** deletion treated every Project Group message as durable - Shepherd history. General intake persists incomplete prompts as unbound human - messages under an inactive `agent-` Project, so an abandoned draft trapped - both the Agent and its workspace even though no execution/evidence existed. -- **Minimal correction:** discard only exact unbound `general-contract` - clarification messages plus their exact inactive managed Project. Keep the 409 - for every Contract, event, Mission, Plane, other message, malformed Project, or - orphaned state. Validate the sentinel, metadata identity, Git worktrees/branches, - and empty private Plane roots before deletion. Journal both managed Project and - workspace intent before database publication; reconcile against on-disk durable - state after restart, and serialize general-project journaling with deletion. - Preserve all UI/CSS. -- **Acceptance:** two clarification turns delete from the existing stopped-Agent UI; - the Agent workspace, exact managed repository/Plane root/metadata and database - draft state disappear; restart is clean. Durable history remains intact with the - specific conflict message. Run targeted/adjacent/full gates, authenticated - Playwright at both viewports, security and UI review, then integrate/recheck main. -- **Status:** **REVIEWED CANDIDATE** on PR #67 / issue #66. Causal lifecycle/project - tests pass 29/29, adjacent API/Shepherd 77/77, literal `npm run check` passes - launcher 3/3, Server 791 plus two opt-in skips, Web 18/18 and both builds, and the - browser journey passes 2/2 with no overflow. UI review reports no High/Medium; - final security review reports PASS/no High or Medium after four causal - persistence/race corrections. Same-OS-user pathname swap and sudden-power-loss - ordering for the Project journal remain Low. Protected-main integration remains. - -### `TST-24` — Persistence-recovery attention is visible before reconciliation quiesces - -- **Evidence class:** exact contention RED on corrected chain - `7d8483a3ef5998002dab6331bd53532640f953ec`. The row passed once and another - 18 consecutive invocations, then failed iteration 19 because the complete Mission - recovery intent remained present; a late queue operation also rejected with fixed - `recovery_pending`. -- **Failure contract:** reconciliation persists visible `attention_required` inside - `mutateForPersistenceReconciliation`, then separately awaits journal unlink, - parent-directory sync and pending-intent clear. The test waits only for visible - Mission state, so its null assertion and subsequent durable/reload/cancel work can - race the owned continuation. This is fixture ordering, not permission to treat - partially reconciled recovery as complete. -- **Minimal correction:** after attention becomes visible, wait for the exact intent - to become null and then await a test-owned no-op mutation sentinel on the original - Store before durable reads, reload, cancellation or teardown. This joins recovery - persistence, intent cleanup and queued background continuation. Use a direct owned - completion signal only if it proves the same ordering. No sleeps, retries, timeout - inflation, assertion weakening, suppression, cleanup catches or product changes. -- **Acceptance:** preserve the RED; exact row passes at least 30/30 with intent null - and no late/unhandled work. Keep one attention event, verified Contracts/Planes, - released Agents, active project, no collision/candidate/promotion/head mutation - and secret/path scans. Run TST-23/TST-22/F-06, strict/full and hosted Node 22. -- **Status:** **CLOSED / AUDITED** at `7d51ec6`. The row now waits on the exact - original Store recovery intent becoming null, then awaits a no-op mutation - sentinel before durable reads and teardown. It passed 30/30; the combined - Store/recovery/service slice passed 138/138, and two literal full checks each - passed launcher 3/3, Server 736 with two opt-in skips, Web 17/17 and both builds. - No product/Store behavior changed; hosted/Auditor integration remains pending. - -### `TST-23` — Plane-unwind reload races the original Store persistence queue - -- **Evidence class:** exact isolated Auditor RED on TST-22 checkpoint - `619e3ddd369d2dd8a0ce3b04134c0064c240142e`. The named TST-17 row's assertions - passed 1/1, but Vitest reported one unhandled `PersistenceBoundaryError` from the - original Store after the test had already observed attention and opened a reload. -- **Failure contract:** the service exposes its in-memory `attention_required` - transition before the queued persistence continuation has settled. The test waits - only for that visible state, then constructs a second `JsonStore` over the same - path. With TST-22's correct fail-closed marker authority, reload can observe the - original writer's active marker; teardown can also remove the case root before - the late rejection is observed, producing `cleanup_pending`, `ENOTEMPTY`, or an - unhandled rejection. This is test lifecycle ownership, not evidence that the - corrected Store protocol should permit concurrent independent writers. -- **Minimal correction:** attach any needed rejection observer immediately, retain - every existing TST-17 state/resource/security assertion, and after attention is - observed await a test-owned no-op mutation sentinel on the original Store before - constructing the reload Store or allowing teardown. Join/release in `finally` if - the row owns another deferred lifecycle. Do not add sleeps, retries, timeout - increases, rejection suppression, cleanup catches, or product/Store changes. -- **Acceptance:** preserve the exact RED; the row passes at least 20 consecutive - invocations with no unhandled rejection or late filesystem work. Prove the sentinel - is queued after every original continuation and before reload/root teardown; keep - Plane-unwind attention, durable reload, protected head/canary and raw-diagnostic - assertions unchanged. Run the combined TST-17/TST-22/F-06 slice, strict/full and - hosted Node 22. -- **Status:** **CLOSED / AUDITED** at `7d51ec6`. The exact test-owned no-op - Store sentinel is placed after attention observation and before reload. The row - passed 20/20; combined Store/recovery/TST-17/TST-20 coverage passed 138/138 with - no late rejection or retained artifact. TST-24 closed the distinct recovery-row - ordering race; full and hosted gates passed. No product or Store change exists. - -### `TST-22` — Cleanup markers do not form a crash-safe retry protocol - -- **Evidence class:** independent causal RED and security re-review of corrected - F-06/TST-21 candidate `f65681aa48a3bfd384d36fc9320ea63e045d3261`. - Reusing the exact double-fault fixture with the same `JsonStore` instance failed - 2/2 (database and journal) with fixed `cleanup_pending` instead of completing - exact cleanup. -- **Failure contract:** after a normal temp-unlink failure records a marker, - same-instance initialization deletes the tracked temp first but leaves its marker; - marker scanning then rejects the missing temp indefinitely. A crash during marker - creation/write/sync/close/directory-sync can leave an unmarked full-database temp - that restart ignores. Temp deletion followed by marker-unlink failure, or a partial - marker, also has no safe completion path. Repetitions can accumulate sensitive - serialized-state temps or permanently block startup. -- **Minimal correction:** implement one idempotent crash-safe state machine for exact - managed temp+marker cleanup. Accept every prefix of marker publication and - temp/marker removal on same-instance retry and restart, preserve the original - primary error, and converge without deleting unrelated files. Add narrow fault - checkpoints for marker open/write/sync/close/publication/directory sync and both - removals; do not weaken containment, no-follow, owner/mode/size, fixed errors, or - the representative F-06 recovery scope. -- **Acceptance:** database and journal matrices cover every cleanup prefix plus - primary double/triple faults, immediate same-instance retry and two restarts. - Exact pairs disappear durably; missing/partial markers, hostile symlinks and - unrelated matching-looking files remain safe and cannot brick recovery. No raw - secret/path/errno reaches startup/log/store/API surfaces; repeated fault/restart - creates no accumulation. Re-run TST-21/F-06, Plane-unwind stress, adjacent/full/ - security and hosted gates. -- **Status:** **CLOSED / AUDITED** at `7d51ec6`. The correction pre-registers - every sensitive temp through an fsynced fixed-schema marker inside an adjacent - owner-validated `0700` private directory. The same marker authority handles - temp-present and temp-missing removal prefixes, same-instance retry and two - restarts without overwriting an earlier intent. The 70-test Store suite covers - 12 publication checkpoints, eight removal checkpoints, double faults, repeated - same-instance writes, strict-schema/UUID ownership, hostile directory/marker/ - publication symlinks and unrelated files. Full/security evidence is recorded in - `BUILD_LOG.md`. TST-23/24 join the fixture-owned queues; local, independent - security and hosted gates pass. - -### `TST-21` — Recovery-journal reads and temp cleanup are not closed boundaries - -- **Evidence class:** independent source/security audit of unintegrated F-06 - candidate `6bc67b3272b530897149aa5a9507e46c2393453a`; focused persistence/journal - tests passed 10/10 repetitions but do not inject either double-fault class. -- **Failure contract:** `readRecoveryIntent()` converts `ENOENT` and symlink - `ELOOP`, but native open/stat/read failures such as `EACCES` or `EIO` escape - initialization with their raw configured path and operating-system diagnostic. - Separately, when a primary database or journal-temp operation has already failed, - a subsequent non-`ENOENT` temp unlink failure is deliberately suppressed. The - database temp contains the complete serialized state, is not journaled or - enumerated on restart, and repeated double faults can retain unbounded sensitive - artifacts. The journal writer has the same untracked-temp structure. -- **Minimal correction:** close every journal open/stat/read failure except the - exact absent-file case into fixed cause-free `PersistenceBoundaryError` evidence. - Preserve the primary write error as causal while explicitly tracking and retrying - cleanup of the exact managed database/journal temp, or otherwise proving bounded - removal without enumerating/deleting unrelated files. Do not expose native - causes/paths, swallow cleanup failure, weaken no-follow/containment/mode/owner - checks, broaden recovery to arbitrary store mutations, or alter the accepted UI. -- **Acceptance:** causal native open/stat/read injections expose no raw error, - `cause`, path or errno through startup/log/Error surfaces. Database and journal - primary+unlink double-fault rows preserve the fixed primary outcome, retain - truthful bounded cleanup evidence, and remove only their exact managed temp on - same-process retry and restart; repeated faults do not accumulate artifacts. - Re-run the complete journal-stage matrix, immediate and two-restart exactly-once - reconciliation, concurrent mutation/event lock, service/API/reload/security, - literal `npm run check`, and hosted Node 22. Unix/macOS errors must not be - swallowed; any Windows exception must remain narrowly platform-gated. -- **Status:** **CLOSED / AUDITED** at `7d51ec6`. Four recovery read-operation - faults return fixed cause-free `recovery_intent_read` evidence. Primary and journal - file-sync plus unlink double faults preserve the primary outcome and retain one - exact UUID temp plus a durable cleanup marker. Restart requires fixed marker - content/name, no-symlink, owner, mode and stage-specific size validation. A hostile - marker symlink fails closed without touching its outside canary; TST-22 completes - the crash-safe cleanup protocol. - -### `TST-20` — Fail-fast verifier sibling persists after test-root teardown - -- **Evidence class:** hosted final-head run `33282108035`, exact annotation at - `store.ts:173`, latest test `does not invoke a sibling verifier after - infrastructure terminalization`. -- **Failure contract:** the Mission promise rejects fail-fast while a backend sibling - remains blocked. The test releases that sibling and waits only one `setImmediate`; - it never joins the sibling's remaining verification/cleanup/store queue. `afterEach` - then removes the exact case root. Hosted Node 22 observed a late atomic-store rename - fail with ENOENT inside that removed root, emitted as an unhandled test error. -- **Minimal correction:** add a deterministic test-owned completion/join signal for - the exact sibling lifecycle and its final awaited store mutation before teardown. - Preserve production fail-fast behavior, typed infrastructure terminalization, - durable interrupted/verification_failed state, no late verifier invocation and - snapshot cleanup. Do not add sleeps, retries, timeout inflation, assertion - suppression, broad root-cleanup catches, or product behavior changes unless a - production lifecycle invariant is independently proven broken. -- **Acceptance:** preserve hosted RED; exact row stress and full suite under - contention; assert no pending sibling/store work before teardown; strict/full and - two exact-head hosted Node 22 gates pass with F-03/TST03/04 unchanged. -- **Status:** **CLOSED / AUDITED** at `cdcfa95`. Auditor exact row 30/30, - service/store 56/56, strict/full local gate and hosted Node 22 run `33282600354` - passed. Production files are unchanged. - -### `TST-19` — Integration identity is checked only after merge mutation - -- **Evidence class:** independent source/security review of corrected F-05/TST-18 - candidate `53c8415`. -- **Failure contract:** `mergeCommit` proves initial status is clean and records the - actual HEAD, but it does not compare the checked-out branch to the persisted Plane - branch or actual HEAD to the persisted Plane head before invoking `git merge`. - A clean integration worktree switched to a sibling branch/head can therefore mutate - or commit that branch before post-conflict inspection detects the mismatch. -- **Minimal correction:** pass the persisted expected head and branch into the Git - boundary and prove both, plus clean status, before any merge command. Use fixed - bounded errors without raw Git output; do not repair or mutate mismatched refs. -- **Acceptance:** real-Git branch-mismatch and head-mismatch REDs fail before mutation; - all managed branches/refs/worktrees, protected HEAD/canary and durable/downstream - state remain byte/identity unchanged; ordinary TST-18 conflict/cleanup/reset, - adjacent/full/security and hosted gates pass. -- **Status:** **CLOSED / AUDITED** at `f8d7f71`. Five identity mismatch rows and - four conflict/cleanup rows passed the real-Git matrix five consecutive times; - adjacent/full/security and hosted run `33281977834` passed. The remaining - multi-command same-host TOCTOU window is Low under the single-process managed-root - threat model and is not claimed eliminated. - -### `TST-18` — Merge-abort cleanup failure masks a detected Git conflict - -- **Evidence class:** independently injected cleanup double-fault on F-05 candidate - `a7b669b`, after a real add/add textual conflict was established. -- **Failure contract:** `GitClient.mergeCommit` enumerates and validates conflict - paths before abort, so enumeration or path-validation failure skips cleanup. If - `git merge --abort` throws, its raw error replaces the conflict; exit 128 is also - accepted without proving cleanup. `mergePlane` then inspects without asserting a - clean worktree/head. The Mission can become `unknown`, planted diagnostics can - cross the boundary, or a dirty/unmerged Plane can be mislabeled as the ordinary - clean conflict outcome. -- **Minimal correction:** preserve the conflict as primary, bound and discard the raw - abort cause, and expose truthful fixed cleanup state. A successful abort may retain - the clean conflict Plane; a failed abort must use explicit bounded attention/ - cleanup evidence and must not claim a clean worktree. Preserve exact Plane/branch - inspection and reset ownership; do not broaden Git cleanup or weaken path gates. -- **Acceptance:** causal real-conflict plus enumeration/path-validation, thrown abort - and accepted-nonzero abort REDs become green; exact clean/head state is checked; - primary Mission/Plane evidence remains `git_conflict/integration_merge`; cleanup - state is truthful; raw Error/cause/store/reload/event/API/log scans are clean; - protected HEAD/canary, verified Contracts, released Agents, no downstream work, - exact reset cleanup, ordinary ten-file/cap/path tests, adjacent/full/security and - hosted gates pass. -- **Status:** **FIXER CANDIDATE / Auditor pending.** The correction always attempts - abort before validating bounded paths, accepts only a successful abort, and proves - quiet `MERGE_HEAD` absence, clean status and unchanged HEAD. Real enumeration, - abort and post-inspection fault rows return a fixed cause-free boundary; the - service retains `git_conflict/integration_cleanup` Plane evidence and transitions - the Mission to `attention_required` without candidates or promotion. Focused - real-Git/service rows pass locally; full gate evidence is in `BUILD_LOG.md`. - -### `TST-17` — Second initial Plane creation failure leaves the first Plane live - -- **Evidence class:** independently reproduced RED and read-only security review of - F-04 candidate `5cc24f5`. -- **Failure contract:** the two initial Contract Planes are created sequentially. If - Plane 1 succeeds and Plane 2 fails, only Contract 2 receives the bounded creation - failure. Plane 1 remains durably `ready`, Contract 1 retains its `planeId`, and its - managed worktree and `shepherd/contract/*` branch remain attached after the Mission - is terminally failed. Executor/verifier/integration/candidates/promotion do not run - and protected HEAD is unchanged, but the no-Plane/resource-cleanup contract fails. -- **Minimal correction:** unwind every previously created Plane in this initial - creation batch, deleting only exact batch-owned durable associations, worktrees and - branches. Preserve the original second-Contract bounded failure and causal - precedence; do not broaden reset/cleanup or alter later lifecycle behavior. -- **Acceptance:** causal second-call RED becomes green; first-call destination and - real partial-Git rollback remain green; zero durable/physical batch Planes after - failure; Contract/Mission/event/API/reload evidence stays bounded; Agent/project - release, protected HEAD/canary, no downstream invocation, artifact cleanliness, - adjacent/full/security and hosted gates pass. -- **Observed correction:** candidate `fix/f04-plane-unwind` tracks only Planes - created by the current initial scheduling batch. A later creation failure destroys - those exact worktrees/branches in reverse order, removes only their durable Plane - rows, clears only their Contract `planeId` associations, and releases their Agents; - the original failed Contract and Mission retain fixed `worktree_creation_failure` - / `plane_creation` evidence. The second-of-two regression proves zero batch Plane, - worktree and branch survivors, unchanged protected HEAD/outside canary, reload - consistency and no executor/verifier/collision/candidate/promotion activity. If an - exact Plane cleanup fails, its record remains discoverable as failed, its Contract - is interrupted, all Agents are released, and the Mission enters existing - `attention_required` with `plane_unwind_failed`; the project remains active as - required by the nonterminal attention invariant. Cleanup evidence uses bounded - `worktree_creation_failure` at `plane_unwind`; F-06 `persistence_error` remains - unclaimed. Planted raw path/OS/secret cleanup diagnostics are absent from durable, - reload and public DTO surfaces. -- **Status:** **CLOSED / AUDITED** at `2cef988`. Auditor focused paths 3/3, real Git - 20/20, adjacent 174/174, literal full gate, independent security and hosted run - `33280187821` passed. A Low evidence limitation remains: the cleanup-double-fault - test mocks the complete destroy operation rather than each partial Git teardown - phase; retained branch metadata remains operator-discoverable and no false cleanup - is claimed. No UI/live/model call ran. - -`TST-13`–`TST-16` are **CLOSED / AUDITED** at `83cc1d0`. The complete -runner→executor→durable/public boundary and all 47 inventoried executor filesystem/ -configuration expressions passed the 31-row injected matrix, focused and full -repository gates, and independent security review. No High/Medium finding remains. -The restart-only invalid retained-sentinel case remains a Low, fail-closed manual -operator-cleanup availability residual; cross-process automatic retry is not claimed. - -### `TST-16` — Executor root/setup/enumeration filesystem failures remain unbounded - -- **Evidence class:** independent full-source security review of unintegrated chain - `8c7cfc1`; source-confirmed outside the corrected TST-15 named edges. -- **Failure contract:** raw native errors still escape from private-root mkdir/lstat/ - realpath and workspace realpath; interrupted-home/workspace readdir/lstat/realpath; - preflight mkdtemp/chmod/config write/root realpath; and execution mkdtemp/chmod/ - realpath/config write. Reconcile/startup can expose them through Error inspection - and `cause`; run failures can persist as arbitrary `unknown` messages through - Contract/candidate/store/event/Agent/API surfaces. -- **Minimal correction:** complete the executor-owned filesystem/config boundary - with closed fixed stages for root preparation, reconciliation enumeration, - preflight setup and execution setup. Preserve existing typed policy errors and - primary-over-cleanup precedence. Add causal mkdir/mkdtemp/lstat/readdir/realpath/ - chmod/config-write fault injection at reconcile/preflight/run and scan Error/cause/ - log/startup plus all durable/public surfaces. Preserve containment, retained- - artifact retry, TST-12–15, OPS-06 and runtime classification. No broad filesystem - refactor or raw cause. -- **Observed correction:** candidate `fix/f-01-02-filesystem-boundary` routes the - remaining root preparation, reconciliation enumeration, preflight setup and run - setup calls through fixed `BoundedFilesystemError` stages. The 31-row injected - operation matrix covers mkdir/mkdtemp/lstat/readdir/realpath/chmod/config write, - exact retained-target cleanup and bounded retry; TST-15 continues to cover open, - handle stat/read/write/sync/truncate/close, unlink and rm. A frozen 47-expression source - inventory detects newly added unreviewed executor filesystem/config call sites. - Planted opaque/secret/path/OS/config canaries are absent from Error/cause/stack/ - inspect, startup/log, Contract/candidate/store/reload/event/Agent/public DTO and - real HTTP response surfaces. Contract and candidate failures do not promote; - containment and symlink policy are unchanged. Focused executor 67/67 (including - independent security re-review), adjacent runtime/service/config/verifier 154/154, - strict test types and two literal checks pass locally; external model/live calls: 0. -- **Acceptance/status:** **FIXER + independent security review VERIFIED candidate / - Auditor integration pending.** The initial review's two Medium evidence gaps were - closed by the expanded call-site matrix and 47-expression inventory; re-review - found no remaining material issue. The existing Low restart-only invalid - sentinel operator-cleanup residual is unchanged; no cross-process retry is claimed. - -### `TST-15` — Sentinel and reconciliation cleanup paths expose raw filesystem errors - -- **Evidence class:** independent exhaustive executor cleanup review of unintegrated - chain `3afc452`; source-confirmed beyond the corrected TST-14 run-finally branch. -- **Failure contract:** sentinel adoption `open` retains raw error as `cause`; - validation/adoption `handle.close()` can override bounded primary errors; failed - adoption `unlink` is silently swallowed; interrupted private-home and preflight- - workspace `rm()` failures escape raw. These paths can expose private path/OS detail, - lose causal precedence or retain an invalid sentinel without an actionable error. -- **Minimal correction:** inject opaque/secret/path faults for sentinel open, - validation close, adoption close+unlink, private-home reconcile rm and preflight- - workspace reconcile rm. Discard raw causes; preserve bounded primary precedence; - emit fixed cleanup/reconciliation diagnostics when cleanup is the only failure; - retain unremoved owned artifacts for safe later retry. Prove String/stack/inspect/ - cause/log/startup surfaces clean. Preserve TST-12/TST-14, OPS-06 and all typed - runtime behavior; no swallowed cleanup or broad filesystem refactor. -- **Observed correction:** candidate `fix/f-01-02-sentinel-cleanup` applies one - internal closed stage/reason filesystem policy across sentinel validation/adoption - and interrupted private-home/preflight-workspace reconciliation. Raw open/lstat/ - chmod/readdir/read/write/close/unlink/rm failures never become a cause or field. - Primary bounded failures win over double cleanup faults; cleanup-only fails closed; - every exact scoped cleanup is attempted. Failed same-process sentinel unlink and - retained reconciliation targets retry exactly; containment, `O_EXCL`/`O_NOFOLLOW`, - direct-child and symlink gates are unchanged. A process restart with an invalid - retained sentinel remains fail-closed and may require operator cleanup; no - cross-process automatic retry is claimed. The matrix covers adoption open, - validation close/body+close, adoption close-only/write+close+unlink, repeated - pending unlink, pre-open lstat/chmod/readdir and both reconciliation rm paths. - Service initialize Error/cause/store/console surfaces are canary-free and retry - succeeds. Executor 33/33, focused/adjacent 120/120, strict types and two literal - checks pass (launcher 3/3, Server 627 + two explicit skips, Web 17/17, builds). - External calls: 0. -- **Acceptance/status:** **AUDITOR VERIFIED locally / integration held by TST-16.** - The named TST-15 five-edge/double-fault matrix passes. Full-source review found a - distinct remaining executor setup/enumeration boundary recorded as TST-16. The - restart-only invalid-sentinel behavior is fail-closed and retained as a documented - Low operator-cleanup/availability residual rather than another correctness task. - -### `TST-14` — Execution-home cleanup leaks and overrides causal failure identity - -- **Evidence class:** independent exhaustive security review of unintegrated - F-01/02 + TST-13 chain `c7b5175`; source-confirmed in executor `run()` finally. -- **Failure contract:** `rm(privateHome)` executes directly in `finally`. A raw - filesystem exception can expose opaque/private path/OS detail through Error - surfaces and override an otherwise bounded timeout, execution or cancellation - failure. Existing fault tests cover preflight home cleanup and runner container - cleanup, not this execution-home path. -- **Minimal correction:** causally inject execution-private-home cleanup failure; - retain every cleanup attempt but bound the emitted error. Define and test - precedence: existing cancellation remains cancellation; existing typed timeout/ - execution identity remains; cleanup-only failure becomes fixed typed execution - failure. Prove raw canaries absent from String/stack/inspect/cause, store/reload, - Contract/Plane/Mission/Agent/event/API/log surfaces and prove a subsequent safe - retry/reconciliation. Preserve TST-12, OPS-06, F-03 and no-promotion behavior. -- **Observed correction:** candidate `fix/f-01-02-private-home-cleanup` records - whether execution already has a primary outcome, always clears active/cancellation - ownership and attempts the exact private-home removal. A cleanup-only fault becomes - a fresh fixed `RuntimeExecutionError("execution")`; cancellation and typed timeout/ - execution remain authoritative, with no raw cleanup cause or field. The four-row - causal matrix proves Error/string/stack/inspection/cause redaction, inactive cancel, - owner-scoped failed-home reconciliation and a clean subsequent execution. Contract - and candidate flows prove fixed durable/event/store/reload/public and real mission - HTTP response output; candidate failures do not promote or move protected head. - Console error/warn capture is canary-free. Executor/OPS-06 slice 21/21, focused and - adjacent 108/108, strict test typecheck and first literal check pass (launcher 3/3, - Server 615 + two explicit skips, Web 17/17, builds). External calls: 0. -- **Acceptance/status:** **AUDITOR VERIFIED locally / integration held by TST-15.** - Auditor passed focused 81/81, adjacent 66/66, literal check and the four execution- - home precedence cases. A distinct sentinel/reconciliation cleanup family remains - open as TST-15, so the chain is not integrated. - -### `TST-13` — Arbitrary Agent Runtime stderr reaches durable/public failures - -- **Evidence class:** independent security review of unintegrated F-01/02 candidate - `685e4ff`; source-confirmed runner → executor → service propagation. -- **Failure contract:** a non-zero Runtime exit builds a typed execution error whose - message includes the last parsed error or raw stderr. Executor redaction removes - configured secrets and common paths but preserves arbitrary opaque content; - service then persists/returns it through Contract, Plane, Mission, Agent - `lastError`, events, state/reload and public mission DTO. Existing tests use clean - synthetic messages and do not plant an opaque stderr canary across these surfaces. -- **Minimal correction:** preserve only typed failure kind across the boundary and - expose fixed bounded public text (`Agent Runtime execution failed`); a timeout may - include only its validated numeric deadline. Add a causal real runner → executor - → service failure with opaque stderr, secret and path canaries absent from Error - message/stack/cause, durable/reloaded state, events, Agent and public DTO. Preserve - cancellation, untyped unknown, verifier/candidate mapping, F-03, OPS-06 and - authority/no-promotion behavior. No regex classification or broad redesign. -- **Observed correction:** candidate `fix/f-01-02-runtime-redaction` replaces every - Runtime diagnostic at the runner boundary with a freshly constructed typed error. - Its kind is normalized to the closed timeout/execution set, timeout text accepts - only a positive safe integer, and its public properties cannot be mutated. The - executor and both Contract/candidate service paths reconstruct the same bounded - failure before any durable/public use. Causal tests plant parsed-output, stderr, - create, spawn, opaque, secret, private-path and invalid-kind/timeout canaries and - scan Error/string/stack/inspection/cause, Contract/Plane/Mission/Agent, event, - store/reload and public DTO surfaces. Candidate failures exhaust without starting - promotion or moving the protected head. Focused 75/75 and adjacent 226/226 pass; - strict test typecheck and the first literal `npm run check` pass (launcher 3/3, - Server 607 with two explicit skips, Web 17/17, build green). External calls: 0. -- **Acceptance/status:** **AUDITOR VERIFIED locally / integration held by TST-14.** - Auditor passed focused 75/75, adjacent 66/66, literal check and this exact - runner-to-durable boundary. A distinct executor execution-home cleanup leak and - precedence defect remains open as TST-14, so the chain is not integrated. - -### `TST-12` — Executor preflight cleanup can expose raw filesystem cause - -- **Evidence class:** independent security review of unintegrated OPS-06 rebased - candidate `34477e8`; source-confirmed at `CodexShepherdExecutor.performPreflight`. -- **Failure contract:** executor mount cleanup throws a fixed message but attaches - raw `cleanupError` as `Error.cause`. An uncaught startup error can render that - cause, including private filesystem paths, planted values and OS diagnostics. - Runner-side typed cleanup diagnostics are bounded; this distinct executor path - is not causally covered, contradicting OPS-06's no-path/raw-detail claim. -- **Minimal correction:** executor/test only. Throw the fixed bounded cleanup - message without a raw cause (or route detail only to a proven redacted internal - sink). Add a causal injected cleanup error containing private path/secret text and - assert rejection/startup-visible output excludes it. Preserve cleanup attempts, - fail-closed startup, runner enums and every sandbox gate. No swallowed failure, - raw logging, broad refactor or compatibility bypass. -- **Observed correction:** executor-only candidate on - `fix/ops-06-preflight-redaction`. Executor mount-cleanup failure now rejects with - fixed `stage=cleanup reason=cleanup_failed` and never attaches the raw failure as - `Error.cause`. The causal test injects planted secret, private-path and OS text - and proves it is absent from message, string, stack, inspection, JSON and cause - surfaces while cleanup remains fail-closed and a bounded retry remains possible. -- **Acceptance/status:** **CLOSED / AUDITED** at integrated `68dbd59`. Focused and - adjacent regressions passed 95 plus one explicit live skip; literal check passed - Server 602 plus two explicit skips, Web 17/17 and launcher 3/3. Independent - security review returned no finding and hosted run `33274769957` passed. The - separate affected-macOS OPS-06 validation remains pending. - -### `TST-11` — E2E-02 candidate-evidence screenshots show metadata only - -- **Evidence class:** independent exhaustive semantic review of all 13 named - stages at both required viewports on unintegrated corrected chain `79da51a`. -- **Failure contract:** `09-selected-candidate-evidence.png` and - `11-rejected-plane-evidence.png` at both 1280x800 and 1440x900 show the selected - or rejected Plane header and metadata, but not the named Candidate verification - tab/evidence. The test asserts text attached below the internally scrolling - drawer, then captures without scrolling or intersection proof. Four of four - stage/viewport pairs therefore fail their visual claim even though hashes are - distinct and functional DOM assertions pass. -- **Manifest result:** the other eleven named stages expose their principal visible - marker in both viewports: Contracts active, Contract verification, collision, - candidates active, candidate outcomes, promotion start, completed overview, - promotion event final evidence, selected final evidence, Project Group lifecycle, - and protected-main promoted state. All 26 files have unique hashes after TST-10. -- **Minimal correction:** test only. For stages 09 and 11, scroll the exact - Candidate verification tab/evidence marker into the drawer and prove positive - intersection with both drawer viewport and browser before capture. Preserve the - already-visible stage-10 final evidence and TST-10 promotion event behavior. No - production UI/CSS/theme, sleep/retry/timing increase, hidden-only assertion, - fake state, or `GC-06`/`UI-02` overclaim. -- **Observed correction:** test-only candidate on `fix/e2e-02-drawer-evidence`. - Before stages 09 and 11, the journey now scrolls the exact selected or rejected - Candidate verification summary inside `.detail-drawer`, proves positive - marker/drawer/browser intersection, and requires that exact marker to be visible. - Stage 10's keyboard-selected final-promotion evidence and TST-10 are unchanged. -- **Acceptance/status:** **CLOSED / AUDITED** at integrated `338f1e4`. Auditor - passed four journeys and all 52 semantic observations: 13/13 named markers were - visible at both viewports and 26/26 hashes were unique. Full harness/check, - independent UI/security review, cleanup scans and hosted run `33273947769` - passed with no production UI/CSS/theme or timing change. - -### `TST-10` — E2E-02 promotion stage screenshot does not show promotion - -- **Evidence class:** independently reproduced from unintegrated candidate - `85550e0a6c6c8f2263375943b22271d72c814c05` after two focused runs at both - required viewports. -- **Failure contract:** `05-candidate-outcomes.png` and - `06-promotion-reverifying.png` are byte-identical at 1280x800 - (`66159d4f...`) and at 1440x900 (`f35e34c3...`). The Playwright assertion finds - “Started final authority and independent verification gate,” but that event is - below the internally scrollable contract pane, so capture 06 does not visibly - evidence its named stage. There are 24 distinct images, not 26. -- **Impact:** functional/API/Git/store/security assertions pass, but the visual - evidence and BUILD_LOG phrase “13 material stages” overclaim the screenshot - corpus. E2E-02 remains unintegrated. -- **Supported cause:** the test captures immediately after a DOM visibility check - without scrolling the promotion event into the visible contract-pane region. -- **Minimal correction:** test only. Scroll the exact promotion event card into - view and assert its rectangle intersects the contract pane before capture 06. - Do not change production UI/CSS/theme, introduce sleeps/retries, weaken the event - assertion, or fake a state. Preserve the truthful `GC-06` and `UI-02` exclusions. -- **Observed correction:** test-only candidate on - `fix/e2e-02-visible-promotion`. The journey now targets the exact persisted - `promotion_started` event, scrolls its card inside `.event-list`, proves positive - card/pane/viewport intersection, and asserts the stage-05 and stage-06 PNG bytes - differ. No production, UI, CSS, timeout, retry or sleep changed. -- **Acceptance/status:** **FIXER VERIFIED / AUDITOR PENDING.** The hero journey - passed twice at both viewports (4/4; 52 capture observations). All 26 final PNGs - were manually reviewed and have 26 distinct hashes; stage 06 visibly contains - the promotion-start card. Harness unit 7/7, full Chromium 12/12, strict test - typecheck and two literal `npm run check` gates passed. Cleanup, ignored-artifact, - diff, dependency, bounded-surface and UI-theme review found no issue. Hosted and - integrated Auditor evidence remain required. - -### `UI-04` — promotion surfaces display candidate verification evidence - -- **Evidence class:** fresh deterministic browser/API reproduction on integrated - `mock-main` `3846591`, using the bounded verifier fixture rebased as `d09e445`. -- **Failure contract:** the selected candidate has distinct non-null - `verificationEvidence.id` and `promotionEvidence.id`. A promotion-completed event - rendered **UI04 VERIFICATION EVIDENCE MARKER** and omitted the distinct promotion - marker. Screenshot: ignored repo-local - `.tmp/playwright-evidence/ui-04/promotion-shows-verification.png`. -- **Supported cause:** `EventEvidence` unconditionally chooses - `candidate.verificationEvidence`, including promotion events, and - `PlaneDetailDrawer` also renders only candidate verification evidence. The API - already supplies both evidence objects; no backend/schema change is required. -- **Minimal correction:** UI data selection only. Promotion-started/completed - events and the appropriate candidate/Plane promotion detail must use - `promotionEvidence`; candidate verification events retain `verificationEvidence`. - Reuse `EvidenceSummary`; do not change layout, styling, theme or backend evidence. -- **Observed correction:** frontend-only. Completed promotion events select and - label only final `promotionEvidence`; candidate events retain candidate evidence, - and promotion-started shows no premature final evidence. Resolution Plane detail - offers both stages in an existing-theme tablist with one/none fallback, safe - reset, full roving keyboard semantics, visible focus, internal scroll and managed - drawer focus/Escape/restoration. `EvidenceSummary` remains the sole renderer and - ignores planted evidence IDs/stdout/stderr/errors/private diagnostics. -- **Acceptance/status:** **RESOLVED + AUDITED** at `412a010`, **100% scoped**, - `T,C,B,U,I` 5/5. - Helper/component 4/4, Web 17/17, harness 7/7, focused browser 2/2 and full - Chromium 10/10 at both required viewports, strict/build and two final literal - checks passed. Screenshots and independent UI/security re-reviews passed with no - remaining finding. Hosted run `33271397185` passed. At this UI-04 checkpoint the - bounded verifier fixture prerequisite was integrated while `E2E-02` remained - incomplete; `E2E-02` was subsequently audited at `338f1e4`. - - -### `MR-02` — Settings implies an unavailable reviewer will run - -- **Evidence class:** reproduced in the real deterministic E2E harness on local - merge `1422fd6` at both 1280x800 and 1440x900; supported by production - composition and an independent security fallback. -- **Failure contract:** with no usable Ark reviewer configuration, - `GET /api/system` reports `arkConfigured=false` while - `GET /api/shepherd/settings` reports the persisted preference - `modelReviewEnabled=true`. The Security tab renders the enabled, checked copy - “Run advisory structured semantic review” with no unavailable/not-configured - capability or operational status. Keyboard toggles false then true and both real - PATCH requests succeed, but `index.ts` deliberately composes no reviewer, so the - enabled preference cannot cause a call or advisory/degraded event. -- **Impact:** the preference is durably correct, and MR-01 remains deterministic - and secure, but the operator-facing control implies behavior the running process - cannot perform. Silence is indistinguishable from “no findings.” -- **Minimal correction:** preserve the stored preference, expose a bounded - server-derived reviewer capability/operational state, and render truthful - unavailable/ready/degraded wording or control state using the existing Settings - visual language. Do not expose credentials, models, prompts, endpoints or probe - the provider from the browser; do not redesign or weaken MR-01's silent - unconfigured production composition. -- **Acceptance:** causal server/API tests for configured/unconfigured readiness and - persisted preference; real browser at both viewports proves unavailable cannot - imply a call, configured enabled/disabled semantics and PATCH persistence, and - advisory/degraded events remain visibly truthful; no X/Y overflow/theme drift; - security/UI fallback, literal check and hosted integrated gate pass. -- **Observed correction:** the candidate exposes only a reviewer-specific boolean - derived from the same fail-closed startup predicate used to compose the reviewer. - Settings preserves the stored preference but uses the existing disabled/locked - visual language and explicit **Unavailable** process-scoped copy when false; it - cannot issue PATCH. Configured mode retains normal mouse/keyboard PATCH behavior. - Server 12/12, Web 5/5, reviewer/API matrix 71/71, harness 6/6, Chromium - 8/8 (dedicated MR-02 2/2 at both viewports), strict test typechecks, two literal - checks, audit 0 vulnerabilities and independent security/UI reviews passed. No live - request ran and no credential/configuration-failure reason is public. -- **Owner/status:** **RESOLVED + AUDITED** at `577255e`; **100% scoped**, - `T,A,C,B,S,U,I` 7/7. Hosted run `33268567614` passed. The UI review noted - only a non-blocking evidence gap: stored-off has component rather than browser - screenshot coverage. - -### `TST-07` — GC-01 test violates strict cross-workspace ownership - -- **Evidence class:** deterministically reproduced on local integration merge - `c834c3907abe84fb0bd79250ac93c2bbf78c87c0`, before any `mock-main` push. -- **Failure contract:** `npm run typecheck:tests -w @launchpad/server` exits 2. - `apps/server/src/project-group-mention.test.ts` imports the Web TSX component and - Web helper. TypeScript reports TS6142 because the Server test config has no JSX - setting and TS6059 because `apps/web/src/pages/project-group-mention.ts` lies - outside Server `rootDir`. Literal `npm run check` therefore cannot pass. -- **Supported cause:** GC-01 moved Web formatter/component coverage under the Server - suite so the default test runner would discover it, but the repository's later - strict test-source gate correctly enforces workspace ownership. This is a test - packaging defect, not evidence of a product parser/UI failure. -- **Minimal correction:** relocate or split the regression into the correct Web and - Server test ownership so both pieces are discovered and strictly typechecked. - Preserve formatter cases, production parser round-trips including exact Agent-ID - fallback, multiline draft preservation, native in-flight disablement, and exact - 2,000/2,001 boundaries. Do not enable JSX or broaden `rootDir` in the Server test - config, add exclusions/suppressions, remove assertions, or change product code. -- **Acceptance:** preserve this RED; focused GC-01 and group-routing tests pass; - strict Server and Web test sources pass; Web type/build and literal - `npm run check` pass; Auditor then performs the full two-viewport Project Group - interaction/parser round-trip and hosted integration gates before GC-01 closes. -- **Observed correction:** exact TS6142/TS6059 RED reproduced. The full eight-case - formatter/parser/component test moved to Web ownership; Web now has explicit - Vitest and strict test-source configs/scripts, and root `test`/`typecheck` execute - both workspaces. Focused Web passed 8/8, adjacent Server routing passed 10/10, - strict Web/Server tests and Web production type/build passed, and literal - `npm run check` passed twice with launcher 3/3, Server 563/563 plus one unchanged - opt-in skip, Web 9/9 and both builds. Lock dry-run and audit reported zero - vulnerabilities. No product, Server JSX/rootDir or assertion change. -- **Audit closeout:** Auditor passed focused Web 8/8, full Web 9/9, Server - routing 10/10, both strict test typechecks, the full deterministic harness - (unit 6/6 and Chromium 6/6), literal `npm run check`, and the complete GC-01 - browser protocol 2/2. Hosted Node 22 run `33266624301` passed on integrated - `de3e631`; no product/UI/Server-config change belongs to this correction. -- **Owner/status:** **RESOLVED + AUDITED** at `de3e631`; **100% scoped**, - `T,C,I` 3/3. - -### `TST-05` — E2E-01 visual evidence is non-reproducible and overclaims the down state - -- **Evidence class:** independently reproduced while auditing unintegrated candidate - `592699d140145165c5ca0d9511478171e5051271`. -- **Failure contract:** a routine `npm run test:e2e:harness` passed its Node 3/3 and - Chromium 6/6 assertions but rewrote 16 of the 18 tracked E2E-01 PNGs plus the - unrelated tracked UI-03 1280 capture. Both `08-server-down.png` files remained - byte-identical, but visual inspection showed blank white canvases. The test only - proves that the original port is closed, catches the failed reload, and captures - the blank page without a DOM or visible-state assertion. The 1280 Create Agent - capture also does not show the primary action within the viewport, and the - journey does not fully prove actual Tab traversal, focus-visible treatment, or - lifecycle-action keyboard activation. -- **Impact:** ordinary successful verification leaves a dirty tree and the checked-in - images cannot be reproduced exactly. The evidence log calls a blank canvas a - visually inspected down state and does not prove that the full Create Agent and - keyboard journey is reachable. -- **Minimal correction:** keep routine generated screenshots under ignored `.tmp` - output, with a separate explicit deterministic review/update path for committed - evidence. Treat port closure as infrastructure evidence; do not invent or fake a - reconnect UI. At both required viewports capture and assert primary-action - reachability, actual Tab/focus-visible behavior, and keyboard activation of the - relevant lifecycle controls. Do not change production UI or its accepted design. -- **Acceptance:** causal regression demonstrates the prior tracked-file mutation; - routine harness unit/browser runs leave an exactly clean tree; an explicit bounded - screenshot-update command is documented and reproducible; the down step is - truthfully recorded as port-down rather than rendered app evidence; Create Agent - completion and keyboard/focus behavior pass at `1280x800` and `1440x900`; full - harness, literal `npm run check`, independent rendered review, and integrated/ - hosted gates pass. -- **Observed correction:** candidate routes default captures to ignored - `.tmp/playwright-evidence` and exposes `test:e2e:starter-kit:evidence` as the - explicit non-default docs update path. It removes the blank down-state canvas, - retaining only the proved closed-port assertion. Create is scrolled within the - existing form at 1280 and 1440, and Create/Stop/Start each passed actual Tab, - visible focus and Enter activation. Harness unit passed 6/6, Chromium passed 6/6, - all 16 journey stages were inspected, tracked screenshot hashes were byte-identical - before/after the ordinary run, and literal check passed twice. No UI/CSS change. -- **Owner/status:** `RESOLVED + AUDITED` at `f6df2d9`, evidence `284994d`; - **100% scoped**, `T,C,B,U,I` 5/5. Auditor passed three ordinary full harness runs, - explicit evidence 2/2, byte-clean tracked-image checks, exact 16-image scope, - rendered review and hosted run `33265640400`. - -### `TST-06` — E2E harness failure paths can retain or disclose sensitive evidence - -- **Evidence class:** independently source-confirmed in unintegrated candidate - `592699d140145165c5ca0d9511478171e5051271`; fault-path regressions are required - before claiming correction. -- **Failure contract:** secret values are passed directly into Playwright matcher - arguments and therefore may be rendered in assertion output. A retained - `runRoot` cannot be removed by a later idempotent `stop()` after a stop/restart - failure. Repository containment checks validate the selected reusable root but - do not canonically reject symlinked managed harness ancestors before `mkdtemp` or - recursive removal. Opt-in live Playwright failure traces/screenshots can retain - prompt or model output. -- **Impact:** a failing CI/local run may disclose a credential or live content and - may leave state/workspace artifacts behind; ancestor indirection weakens the - intended repository-confined cleanup boundary. -- **Minimal correction:** assert only secret-safe booleans or hashes; make stop - idempotence permit a later explicit cleanup of a retained root; validate every - managed ancestor canonically inside the repository before creation/removal; and - suppress, sanitize, or safely isolate live failure artifacts. Add causal unit and - injected-failure coverage. Do not broaden child environment ingress, deletion - scope, filesystem authority, production debug behavior, or live-call count. -- **Acceptance:** fault tests prove redacted matcher failures, retained-root cleanup - after restart failure, ancestor-symlink rejection before write/delete, and no - prompt/output/secret in bounded live failure artifacts. Existing run-root/ - workspace/symlink/outside-canary tests, harness unit/browser suites, literal - `npm run check`, independent security review, and integrated/hosted gates pass. -- **Observed correction:** candidate uses boolean-only sensitive-value assertions, - disables live trace/screenshot/video, and preserves exact live opt-in, no retry, - two-turn cap, loopback binding, bearer auth, environment allowlist and empty live - `SHEPHERD_MODEL`. Repository, `.tmp`, harness and run-root identities are checked - with lstat/realpath before allocation/removal. New fault tests reject a - repo-contained ancestor symlink without following it and prove a retained stopped - root can be removed after restart failure; fresh pre-spawn setup failure also - leaves no allocated root. Harness unit passed 6/6, strict test - typecheck and literal check twice passed, and no run root remained. No live call - was made; the prior separately bounded live evidence remains exactly 2/2 turns. -- **Owner/status:** `RESOLVED + AUDITED` at `f6df2d9`; **100% scoped**, - `T,C,S,U,I` 5/5. Auditor passed the causal 6/6 unit set three times, browser/full/ - strict/hosted gates and artifact/root scans. No High/Medium finding remains. Low - same-user TOCTOU and exceptional spawn/concurrent-mkdir residuals are documented - and do not broaden the local harness threat model. - -### `TST-09` — reviewer-only live gate inherits unrelated hosting validation - -- **Evidence class:** the sole authorized live command failed deterministically at - `loadConfig` before reviewer construction or network egress. -- **Failure contract:** a non-loopback `HOST` plus placeholder/short - `APP_AUTH_TOKEN` from local `.env` triggers production HTTP-server validation. - This isolated reviewer test starts no HTTP server. External reviewer/network - calls are 0; no live root or outcome artifact remained; no retry occurred. -- **Minimal correction:** test/launcher only. Force a safe loopback `HOST` for this - explicit process while still loading real Ark/SHEPHERD key, model, base URL and - the production reviewer configuration predicate/filter. Do not weaken production - non-loopback auth, edit `.env`, hide fatal reviewer configuration/auth, or add an - automatic retry. Add causal environment-precedence coverage if practical. -- **Observed correction:** test-only. The reviewer gate passes `loadConfig` a - cloned environment whose only override is loopback `HOST`; real Ark key/model/ - base URL, SHEPHERD model resolution and all other config remain intact. The - source environment is not mutated. Causal coverage proves production still - rejects the original non-loopback weak-token input and the isolated clone passes - the same reviewer predicate. Package-script gating, one worker, fatal reviewer - handling, retry 0 and the production sensitive-value filter are unchanged. -- **Acceptance/status:** **RESOLVED + AUDITED** at `35ec268`, **100% scoped**, - `T,C,S,L,I` 5/5. - Focused config/default-skip passed 27 plus one skip, TST-08 passed 20/20 and - 40/40, MR-03 matrix 165/165, strict tests and two literal checks passed (Server - 592/592 plus two live skips; Web 13/13). Independent security review passed - with no finding, as did dependency/diff/secret/artifact scans. The single - Auditor's corrected command made external request 1/1 and completed with two - bounded findings; hosted run `33270168480` passed. - -### `TST-08` — returned verifier evidence can race fixture teardown - -- **Evidence class:** literal `npm run check` RED on local MR-03 merge `3c878b3`; - isolated 1/1 and repeated 20/20 GREEN. -- **Failure contract:** Server reported 590 passed, two opt-in skipped and one - failed. `terminalizes returned Contract verification infrastructure evidence` - completed its behavior but `afterEach -> makeDeletable -> realpath` received - `ENOENT` for an exact sibling `.trusted-verification/verify-*` root removed during - traversal. MR-03 changes only the reviewer adapter/tests and is not on this path. -- **Supported cause:** the returned-infrastructure fixture does not block/join the - sibling verification snapshot. Fail-fast Mission rejection therefore permits - the sibling `withVerificationSnapshot` finally to overlap teardown, the same - causal class proven for TST-04 but an uncovered fixture row. -- **Minimal correction:** test fixture only. Reuse or narrowly generalize the - TST-04 two-arrival, early rejection observer and exact snapshot removal join. - Never swallow ENOENT, change the cleanup walker or product, add sleeps/retries/ - timeouts, or weaken state/no-promotion/security assertions. -- **Observed correction:** test fixture only. The returned-evidence verifier now - uses the existing two-arrival barrier, captures the exact sibling - `VerificationRequest.planePath`, and exposes bounded release/return joins. The - row observes rejection immediately, proves the Mission rejects while that exact - contained `verify-*` root still exists, arms the exact-basename removal watcher - before release, then joins Mission, sibling and removal in `finally` before - teardown. Product, cleanup walker and MR-03 code are unchanged. -- **Acceptance/status:** **RESOLVED + AUDITED** at `35ec268`, **100% scoped**, - `T,C,S,I` 4/4. - Exact row passed 20/20, both infrastructure rows 40/40, MR-03 matrix 164/164, - adjacent service/container/API/store/recovery 82/82, strict test typecheck and - two literal checks (Server 591/591 plus two opt-in skips; Web 13/13). Auditor - integrated hosted run `33270168480` passed; no cleanup/product weakening. - -### `TST-04` — F-03 fail-fast verification can race service fixture teardown - -- **Evidence class:** reproduced once inside the literal `npm run check` at - `e88dbef`; the exact isolated row immediately passed 1/1, demonstrating an - order-dependent full-suite condition rather than a deterministic assertion - failure. -- **Failure contract:** after all typechecks passed, Vitest reported 562 passed, - one skipped, and one failed. The failure was - `terminalizes Contract verification infrastructure failures without promotion or - sensitive diagnostics`. Its stack was - `afterEach -> removeServiceCaseRoot -> makeDeletable -> readdir`, where `readdir` - received `ENOENT` for - `.tmp/shepherd-tests/service-*/managed/planes/auth-demo/.trusted-verification/verify-*/src`. - The test's behavioral assertions were not the failing surface. -- **Supported diagnosis:** `runDeterministicDemo()` rejects on the first Contract - verification infrastructure failure. Each concurrent Contract runs inside - `withVerificationSnapshot`, whose `finally` removes its trusted snapshot. The - fail-fast rejection can therefore reach the test and `afterEach` while a sibling - snapshot's `finally` is still deleting the subtree that `makeDeletable` is - traversing. The full-suite RED plus isolated GREEN and the exact disappearing - trusted-snapshot path strongly support this race; the fixer must still capture - the sibling `request.planePath` and establish the removal/quiescence ordering in a - controlled causal test before editing. -- **Minimal correction:** test/fixture only. Record the sibling verification path - and explicitly join the Contract batch/snapshot cleanup before teardown, following - the existing TST-03 release/join pattern. Do not broadly ignore `ENOENT` in the - security-sensitive cleanup walker, add sleeps, extend timeouts, weaken assertions, - or change F-03 production orchestration. -- **Acceptance:** controlled RED proves teardown begins before sibling snapshot - cleanup completes; corrected original row passes repeatedly; entire - `service.test.ts`, strict test-source typecheck, literal `npm run check`, and - independent integrated/hosted gates pass. -- **Observed correction:** test fixture only. A controlled verifier records the - blocked backend `VerificationRequest.planePath` and uses the existing two-arrival - coordination so the frontend typed failure cannot precede that capture. After - the Mission rejects, the test proves the exact owned - `.trusted-verification/verify-` root still exists. It then arms - `fs.promises.watch` on that root's parent, releases and joins the sibling, and - requires an event for the exact basename followed by `lstat -> ENOENT` through - the existing five-second quiescence helper. `finally` joins the Mission, sibling, - and removal outcome before teardown. Exact row passed 20/20 in 28s; full - service/container-verifier slice passed 43/43 in 33.22s; strict test typecheck - passed; and literal `npm run check` passed twice in 39s/39s with launcher 3/3, - server 563/563 plus one opt-in live skip, all typechecks and both builds. The - security-sensitive cleanup walker and production code are unchanged. -- **Owner/status:** `RESOLVED + AUDITED` at integrated implementation `00c81ae`; - **100% scoped**, `T,A,C,I` passed 4/4. Auditor independently passed exact-row - repeats 20/20, adjacent 43/43, strict typecheck, two literal repository gates, - integrated focused 1/1, and hosted Node 22 run `33263688794`. E2E-01 is ready. - -### `TST-02` — deterministic recovery test becomes invalid after its fixed clock - -- **Evidence class:** reproduced twice: once inside `npm run check`, once as the - isolated recovery test. -- **Failure contract:** the post-CAS recovery fixture creates Planes with the real - wall clock, then injects `recoveredAt = 2026-08-29T12:05:00Z`. When run later that - day, reconciliation writes a Plane `updatedAt` earlier than `createdAt`. Observed - bounded values were `createdAt=14:05:54Z`, `updatedAt=12:05:00Z`; `JsonStore` - correctly rejected the invalid lifecycle with `Refusing to persist invalid - database state`. -- **Supported root cause:** the test mixes a fixed recovery clock with an - uninjected PlaneManager clock. This is a deterministic test time-bomb, not - evidence that production recovery should accept backwards timestamps. -- **Minimal correction:** inject the same deterministic clock into this fixture's - PlaneManager (or otherwise derive all fixture times from one injected clock). - Do not loosen `notBefore`, store validation, or recovery lifecycle rules. -- **Acceptance:** original isolated test passes; entire `recovery.test.ts` passes; - literal `npm run check` passes; auditor repeats on integrated `mock-main`. -- **Owner/status:** `RESOLVED + AUDITED` at integrated implementation `0cb431a`; - **100% scoped**, `T,A,C,I` passed 4/4. - -### `TST-03` — F-03 blocked-sibling regression is schedule-sensitive in hosted CI - -- **Evidence class:** reproduced on the required hosted Node 22 gate at exact - head `2ba5cb9`, run [`33261198788`](https://github.com/kyashp/shepherd/actions/runs/33261198788), - job `99123330844`, then reproduced deterministically with a disposable local fault - probe that held only the backend immediately before verifier entry and shortened - only the temporary test budget to one second. The probe produced the same timeout - and unhandled rejection. The unmodified integrated local gate passed 563/563 with - one opt-in skip and five subsequent isolated thrown-verifier runs passed 5/5, - establishing the schedule boundary rather than a UI regression or correction. -- **Failure contract:** the hosted full suite timed out - `atomically interrupts a blocked sibling after 'thrown verifier exception'` at - its explicit 30-second budget. Vitest also reported an unhandled - `ContractVerificationInfrastructureError` from the same Mission. Final hosted - counts were 558 passed, 5 environment-gated skipped, and 1 failed; builds did not - run. The five-skip hosted profile was unchanged. -- **Supported root cause:** the test starts `runDeterministicDemo()`, then awaits - `verifier.siblingEntered` before attaching `expect(run).rejects`. The frontend - fixture may throw and terminalize the Mission before the backend reaches its - verifier under suite contention, leaving `siblingEntered` unresolved and the - already-rejected Mission promise temporarily unhandled. The test also lacks a - `finally` that releases/joins the sibling if an assertion or timeout wins. This is - test orchestration debt; the UI-03 CSS and browser path do not touch it. -- **Minimal correction:** test/fixture only. Establish a deterministic two-arrival - barrier before the selected frontend failure is released, attach rejection - handling immediately, and unconditionally release and join every deferred sibling - in `finally`. Do not add sleeps, merely increase the timeout, swallow unhandled - rejection, weaken durable reload/no-promotion assertions, or change F-03 product - orchestration. -- **Acceptance:** preserve the hosted RED evidence; both parameterized boundary rows - pass causally; the thrown row passes repeatedly alone and under full-suite - contention with zero unhandled errors; literal local `npm run check` passes; the - final `mock-main` hosted `Node 22 / npm run check` passes with the expected - environment-gated skip profile; Auditor integrates and closes UI-03 `C`. -- **Observed correction:** test fixture only. A reusable two-arrival barrier now - holds the selected frontend failure until both Contract verifiers arrive. The - Mission promise gets a success/failure observer immediately before any gate is - awaited, and `finally` idempotently releases both gates and joins the Mission and - sibling. The durable failure/reload/late-return/no-verification-event/no-candidate/ - no-promotion assertions are unchanged. Both rows passed 40/40 across 20 isolated - invocations in 37 seconds; the full service/verifier slice passed 43/43; strict - test-source typecheck passed; and literal `npm run check` passed twice in 39s and - 40s with launcher 3/3, server 563/563 plus one opt-in live skip, and both builds. - No timeout, sleep/retry, suppressed rejection, production/UI edit, or weakened - assertion was introduced. Unmodified hosted run `33261491905` also passed and - corroborates intermittency. Auditor independently repeated both rows 40/40, - passed the 43/43 service/container-verifier slice, strict test-source typecheck, - the literal local repository gate, and integrated focused 2/2. Hosted Node 22 run - [`33262227553`](https://github.com/kyashp/shepherd/actions/runs/33262227553) - passed on integrated implementation `0b1c401`. -- **Owner/status:** `RESOLVED + AUDITED` at integrated implementation `0b1c401`; - **100% scoped**, `T,C,I` passed 3/3. UI-03 hosted closeout is restored and E2E-01 - is ready. - -### `F-03` — Contract verifier infrastructure failure strands active-looking state - -- **Evidence class:** causally reproduced on `fix/mock-main`. The planted verifier - exception surfaced its raw diagnostic while the Mission failed with code - `unknown`; both Contracts remained `verifying`, both Planes `inspecting`, and - both Agents `busy` with Contract ownership retained. A production-shaped returned - mandatory `infrastructure_error` reproduced a second path: both Contracts were - misclassified `failed_independent_acceptance`, Planes remained `inspecting`, - Agents remained owned/busy, and the Mission again failed as `unknown`. -- **Supported root cause:** the Contract verifier await had no infrastructure-error - boundary after durable verification state was entered, and the container verifier - intentionally represents launch/cancel/exit infrastructure failures as returned - evidence. Cancellation was also non-sticky between sequential checks and during - reserved container creation, allowing later work to start after terminalization. -- **Impact:** durable API/UI state lies about ongoing work and blocks safe recovery. -- **Minimal correction implemented:** the existing Contract verification boundary - now maps thrown errors and only returned mandatory `infrastructure_error` checks - to typed, bounded evidence; ordinary mandatory `failed` checks retain acceptance - failure semantics. - One store transaction fails the throwing Contract/Plane, interrupts every active - sibling Contract/Plane, releases all mission Agent/project ownership, and fails - the Mission. The Contract batch fails fast, makes bounded best-effort cancellation - calls, and rejects late sibling completion without allowing integration, - candidate creation, or promotion. Independent verification success remains owned - exclusively by the independent verifier. Target cancellation is sticky across - sequential checks and reserved create-to-start, repeated cancellation cannot - poison bounded ID reuse, and a terminalized sibling cannot invoke the verifier. -- **Observed acceptance:** focused service/verifier tests 8/8; adjacent service/API/ - verifier/executor/store/state-machine/recovery tests 185/185; literal - `npm run check` passed with launcher 3/3 and server 563/563 plus one opt-in live - skip. Fresh store reloads contained no active child ownership; late successful - returns produced no `verification_passed` event. Delayed-create/removal tests - proved no post-cancel container start and safe exact-ID reuse. Planted private - diagnostics were absent from durable state, public DTOs, and the store file. -- **Owner/status:** `RESOLVED + AUDITED` at integrated implementation `dc87553`; - **100% scoped**, `T,A,C,S,I` passed 5/5. Auditor independently observed the - focused 8/8, adjacent 185/185, and literal integrated repository gate; durable - reload/no-promotion, redaction, cancellation isolation, and exact-ID reuse - assertions passed. - -### `UI-03` — invisible authority radios create document-wide horizontal overflow - -- **Evidence class:** reproduced by the E2E-01 real-browser journey at both required - viewports on `ace01ae`; the first Create Agent no-overflow assertion failed before - Agent creation or any Runtime/model turn. -- **Failure contract:** after the authenticated user opens Create Agent and the four - recommended authority presets render, `document.documentElement.scrollWidth` is - `2299` at `1280x800` and `2579` at `1440x900`, rather than remaining within the - viewport. The page looks clipped because `.main-content` hides X overflow, but - the document invariant and keyboard/browser geometry remain incorrect. -- **Supported root cause:** the global `input { width: 100%; min-height: 38px; ... }` - rule also applies to `.preset-grid input`. That narrower rule makes the radios - absolute and transparent but does not reset their size. Browser diagnostics - observed four invisible `INPUT` elements, each exactly one viewport wide, with - right edges at `1589`, `1826`, `2063`, and `2299` in the 1280 case. Their grid - static positions cumulatively expand the root scroll area. -- **Independent audit:** Auditor reproduced the same document widths on integrated - `ace01ae`. At `1440x900`, the radio right edges were `1749`, `2026`, `2303`, and - `2579`; every radio was `1440x38`. Body width/height stayed within the viewport, - isolating the failure to document-root X geometry. Native semantics still work: - the checked Generalist radio is reached as one Tab stop, ArrowLeft moves focus and - selection to Verification, direct focus plus ArrowRight selects the next radio, - and clicking a wrapping label leaves exactly one radio checked. The fix must - preserve these observed behaviors. -- **Minimal correction:** in the existing `.preset-grid input` rule, bound the - visually hidden native radios. Explicitly neutralize the inherited width, - `min-height`, padding, border, and margin so the hidden box is locally bounded, - while preserving the label hit target, native radio semantics, checked selection, - keyboard order, and accepted appearance. Do not hide the symptom by weakening - the document-overflow assertion, clipping another ancestor, or redesigning the - form. -- **Acceptance:** reproduce RED first; then Create Agent at `1280x800` and - `1440x900` has document/body X/Y scroll sizes within client sizes, all four labels - remain clickable, Generalist remains the checked recommended preset, Tab reaches - the radio group as one native stop, arrow keys move focus/selection, screenshots - preserve the current theme, E2E-01 proceeds beyond its first gate, and literal - `npm run check` passes. Independent rendered `ui-reviewer` review and integrated - Auditor rerun remain required. -- **Observed correction:** the hidden native radio alone is now `1x1`, with inherited - `min-height`, margin, padding, and border neutralized. Document scroll/client width - is `1280/1280` and `1440/1440`; document/body Y invariants also pass. The visible - wrapping card receives the existing purple focus treatment through - `:has(input:focus-visible)`, rather than relying on an outline around a transparent - one-pixel control. Causal Playwright passed 2/2 and proves four accessible radios, - Generalist checked, one native Tab stop, arrow focus/selection, visible card focus, - every label click, exactly one checked radio, and bounded computed box styles. - Full browser harness passed 4/4. Literal `npm run check` passed launcher 3/3, - server 563/563 with one opt-in live skip, both typechecks, and both builds. - Screenshots `docs/ui-review/ui-03-create-agent/{1280x800,1440x900}.png` preserve - the accepted theme. No live/model call occurred. -- **Owner/status:** `RESOLVED + AUDITED` at integrated implementation `83954f7`; - **100% scoped**, `T,C,B,U,I` passed 5/5. Focused 2/2 and full 4/4 browser gates plus - harness unit 2/2 passed; screenshots matched and the local strict/full gate - passed. Unrelated TST-03 was corrected test-only at `0b1c401`, and hosted Node 22 - run `33262227553` passed. E2E-01 is ready. - -### `OPS-06` — macOS Docker Desktop live Shepherd preflight fails opaquely - -- **Evidence class:** strong collaborator report from macOS with a complete bounded - stack trace; not reproduced on this Linux audit host. -- **Failure contract:** production builds succeed, server selects live Shepherd, - then `CodexShepherdExecutor.performPreflight()` throws only `Live Shepherd Runtime - preflight failed`; process exits before listening. The no-key preflight failure is - collapsed to a boolean by `ContainerCodexRunner.isEphemeralAvailable()`, so the - failed filesystem/version/socket subprobe is unknown. -- **Impact:** a correctly configured collaborator cannot run the live demo, and the - message is not actionable. This is not evidence of an Ark credential failure. -- **Minimal correction:** first expose only a bounded safe stage/reason code; run - the exact preflight on the affected Mac; correct only the proven compatibility - mismatch. Preserve the non-root/read-only/home-denial/socket-denial/version gates - and fail closed. Never use `danger-full-access` or silently fall back from an - explicit live request. -- **Acceptance:** Linux plus macOS/container-engine regressions, full gate, security - review, and one sparse live startup/Mission smoke on the affected platform. -- **Observed correction:** the runner returns a closed typed availability result - instead of collapsing every failure to false. Safe stage/reason enums cover - container create/start, output validation and cleanup plus bounded probe classes. - Unknown/raw engine errors discard their message and become `engine_error`. - Non-root, read-only/tmpfs, workspace write, private-home denial, listen/connect - denial, exact version, bounded output/marker and owner cleanup remain mandatory; - cleanup failure overrides apparent success. -- **Reproduced cause (affected host, this repository's own preflight):** the - bounded diagnostics did their job. On the affected host `codex sandbox linux - --full-auto` cannot enforce Landlock **per-file** access rights on a host share - that reaches the engine through a virtual machine. Holding image, Codex - configuration and container flags fixed and varying only the workspace - filesystem: ext4 engine volume, image overlayfs and tmpfs all permit writes, - while the host share denies them. Inside the sandbox on that share the split is - parent-inode versus file-inode — `mkdir`, `rmdir` and `unlink` succeed, while - `open()` for read, write, create and truncate all return `EACCES`. The subprobe's - first redirection `: > /workspace/.shepherd-sandbox-probe` is therefore denied, - the sandbox command exits non-zero outside the mapped probe codes, and the runner - reports the catch-all `stage=container_start reason=sandbox_probe_failed`. This - is a compatibility mismatch, not a preflight defect: relaxing the gate would boot - the server and then hand every Plane an Agent unable to read or write its own - workspace. -- **Second, independent defect (both startup probes):** `scripts/start-local-poc.sh` - used `touch` for its bind-mount and Landlock write probes. On exactly the - filesystem where Codex then fails, `touch` exits 0 **and creates the file**, - because Landlock grants `MAKE_REG` while denying `WRITE_FILE`. Both gates were - certifying nothing and handed the failure to the server as an opaque crash. They - now write and read back bytes, and the Landlock probe commits through Git. -- **Observed correction (compatibility):** an opt-in container state volume. - `CONTAINER_STATE_ROOT` and `CONTAINER_STATE_VOLUME` are required together and - address every mounted root as a subpath of one named volume, a native engine - filesystem on every supported host; unset keeps host bind mounts byte-identically. - `volume-nocopy` is mandatory, because without it the engine copies the image's own - directory metadata over an empty subpath, replacing the non-root owner, and the - Runtime loses write access through plain permissions before the sandbox applies. - The independent verifier is translated too: left bind-mounted it would turn every - mandatory check into an infrastructure error and fail the promotion gate. A source - outside the state root throws; it never falls back to a bind mount. Measured on - the affected host, the **unmodified** preflight script then returns - `SHEPHERD_RUNTIME_PREFLIGHT_OK`, and a containerized non-root control plane - creates its workspace, starts the sibling Runtime and reads back what the - sandboxed Agent wrote. -- **Owner/status:** Fixer / `RESOLVED, INTEGRATED at b80af11` (PR #56); `A` and `S` - still open. Cause reproduced and corrected on the affected host. Causal tests cover - volume-mode mount construction, fail-closed containment, the previously - unvalidated shared Agent home, preflight shape, configuration resolution, - verifier translation and the executor canonicality assertion. The - `container-volume` startup smoke and the hosted Linux full gate (run - `33300759535` on exact head `b80af11`) are both recorded. No live/model call has - run. Adjacent `A` coverage is supplied by PR #68 and the independent `S` review - by PR #69; that review returned FAIL against `e6a5878`, which removed the - non-loopback `APP_AUTH_TOKEN` requirement in the same merge with no recorded - review. Its High finding is only partly closed — the guarded deploy script is one - of three documented compose entry points — and the remainder is carried into - `SEC-REVIEW`. - -## Confirmed defect inventory - -| ID | Evidence class and current failure contract | Minimal-fix boundary | Owner/status | -|---|---|---|---| -| `CRUD-01` | Reproduced: clarification-only human drafts created no Contract/Mission/Plane but caused the delete API to return the durable-history 409. Review also reproduced pre-/post-publication cleanup splits, a follow-up policy-journal race, and a direct-run/delete race. | Remove only exact unbound general clarification state; journal Project/workspace cleanup across database publication, reconcile from on-disk truth, serialize project operations, reserve direct-run lifecycle, and retain durable-history denial/accepted UI. | **REVIEWED CANDIDATE** at `171089b` on PR #67; final security PASS, `I` pending | -| `TST-25` | Reproduced on macOS at `b80af11`: `npm run test:e2e:harness:unit` fails 1 of 7 with `fake-codex: workspace identity must be canonical`. `tests/e2e/harness.test.mjs:38` builds its workspace via `mkdtemp(path.join(os.tmpdir(), "shepherd-fake-codex-"))`; on macOS `os.tmpdir()` returns a symlinked `/var/folders/...` path, so the deliberate `realpath` identity assertion at `tests/e2e/fixtures/fake-codex.mjs:69` correctly rejects it. Host-dependent, not intermittent: it passes where `os.tmpdir()` is already canonical, which is why no hosted run catches it — this target is not part of `npm run check`. No safety or data impact; it is a false failure on the presentation host. | Canonicalize the test's own temporary root before `mkdtemp`, matching the existing idiom at `tests/e2e/support/test-app.mjs:93`. Do **not** weaken or remove the fixture assertion: it is the `TST-06` canonical-ancestor hardening. Causal test: assert the harness still rejects a non-canonical workspace while the canonicalized fixture run passes. | **RESOLVED** at `e06357c` (PR #71, issue #70); discovered during `OPS-06` post-merge reconciliation at `b80af11`. The fix canonicalizes the test's own temporary root with `realpath` before `mkdtemp`; the fixture assertion is unchanged. | -| `SEC-01` | Reproduced against the real `createApp` at `bd9b093` with `APP_AUTH_TOKEN` configured and no `Authorization` header: `GET /api/system` returns 401 while `GET /%61pi/system` returns **200** and executes the handler. The `onRequest` hook decided whether to authenticate from `request.url`, the raw request target, while Fastify percent-decodes static path segments before route matching, so any encoded spelling of the `/api/` prefix skipped the hook and the router still resolved the request. Every route was affected including destructive ones (`POST /%61pi/shepherd/demo/reset` removes Plane worktrees and restores protected HEAD; `DELETE /%61pi/agents/` executed). Remotely reachable wherever the token is the only control, because `docker-compose.yml` binds `0.0.0.0` and publishes the port. Not introduced by any recent change; the existing auth tests only ever exercised canonical spellings, so 107 tests passed with the bypass live. | Decide the hook from the decoded target instead of the raw one, treating an undecodable target as protected rather than exempt, and keep the `/api/health` and `/api/auth` exemptions exact-match so a query string still fails closed. Do not widen the exemptions. | **RESOLVED** on `audit/49-sec-review-evidence`; causal test `protects API routes spelled with a percent-encoded prefix`; found by the `SEC-REVIEW` boundary audit | -| `TST-26` | Reproduced at `e552959`: `recovery.process.test.ts` fails 5/5 **in isolation on an idle machine**, 168.75s for 5 tests, each reporting `Timed out waiting for recovered` with empty stderr. Not host speed: raising the message timeout to 400s still timed out, and a direct probe showed the recover child exits **code 0**, sends **zero** IPC messages, and writes nothing to stderr or stdout. Cause is at `test-fixtures/recovery-process.ts`: `send({type:"recovered"...})` is followed immediately by `process.exit(0)`, but `process.send` is asynchronous, so the child can terminate before the IPC frame is flushed. The parent never receives the message, and because the exit code is 0 the harness's exit handler does not reject either, so it waits out the full timeout for a result that was computed correctly and never left the process. Passes on faster hosts and in Linux CI, where the flush wins the race — which is why it was previously recorded as a host-speed timing condition. | Exit from the `process.send` flush callback instead of the next statement. Separately, make the harness reject on a clean exit that never sent the awaited message, so the cause is reported immediately rather than as an anonymous timeout. Do not raise timeouts or add sleeps. | **RESOLVED** on `fix/48-recovery-ipc-flush`; 5/5 pass and the file drops from 168.75s to 52s; reverting the fixture fails 5/5 in 48s with `Fixture exited 0/null without sending recovered` | -| `SEC-02` | Reproduced over a real socket at `0ed41dd`: with `APP_AUTH_TOKEN` configured and no `Authorization` header, `GET /api/system` returns 401 while `GET http://127.0.0.1:PORT/api/system` returns **200 and reaches the handler**. HTTP/1.1 permits an absolute-form request target, and `request.url` is then the whole URI, which does not start with `/api/`, so the hook returned early while the router still matched the path component. Every `/api/` route is affected including the destructive demo reset. This is a sibling of `SEC-01` that the `SEC-01` correction did not close: that fix decoded the raw target but still tested the raw string. Four independent review lenses converged on it. **`app.inject` cannot express this request** — it normalizes the target — so the first regression test written for it reported a false pass. | Derive the decision from the parsed, decoded pathname (`new URL(request.url, base).pathname`), which handles origin-form, absolute-form and protocol-relative targets uniformly; keep the exemptions exact-match on the whole target so a query string or non-origin-form spelling of a public route still fails closed; treat an unparseable or undecodable target as protected. Test over a real socket, not `app.inject`. | **RESOLVED** on `fix/89-absolute-form-auth-bypass`; causal socket test `protects API routes requested in absolute form`; reverting to the raw-target test fails 2 cases, reverting to decoded-but-unparsed fails 1 | -| `SEC-03` | Reproduced at `0ed41dd`: `scripts/check-deploy-auth-token.mjs` gated its CLI entry point on `import.meta.url === \`file://${process.argv[1]}\``. That is not a URL comparison — a space, `#` or any non-ASCII character percent-encodes in `import.meta.url` — and on macOS the filesystem reports names in NFD while an argument is typically NFC, so even a correctly built file URL compares unequal. From a directory named `My Deploy Repo #1 é` the guard body never executed: no output, exit 0, and `deploy-existing-ecs.sh` proceeded to publish the Agent execution API on `0.0.0.0` with an empty token. The existing tests imported the module and never spawned it, so this shipped green through `npm run check`. | Resolve both sides through the filesystem (`realpath` of `import.meta.filename` and of `process.argv[1]`), which removes URL encoding and Unicode normalization from the comparison. Add a test that spawns the CLI from a directory whose name contains a space, a `#` and a non-ASCII character. | **RESOLVED** on `fix/89-absolute-form-auth-bypass`; causal test `the checker CLI refuses an empty token from a directory whose name needs escaping` | -| `SEC-04` | Source-evidenced at `0ed41dd`: `buildCodexArgs` appended the caller-supplied prompt, and on the resume path a stored thread id, as unseparated positional arguments — on the same argv that carries `--sandbox`. A prompt beginning with `-` is therefore parsed by the Codex CLI as an option. Demonstrated argv included `-cmcp_servers.x.command=...` and `-cmodel_providers...base_url=...` reaching the CLI as options. The repository already applies the `--` discipline to every Git invocation and feeds the ephemeral executor's prompt over stdin; the legacy Agent runner was the one path missing it. | Push `--` before the positionals on both the new-session and resume branches. | **RESOLVED** on `fix/89-absolute-form-auth-bypass`; `codex-runner` and `container-codex-runner` assertions updated to pin the separator | -| `SEC-05` | Reproduced at `0ed41dd` with the real `PlaneManager` in the integration fixture: mandatory promotion re-verification ran against the **live Plane worktree**, not the commit being promoted. `withVerificationSnapshot` had a fast path that byte-copied any `refs/heads/shepherd/*` worktree whose HEAD matched and which `git status` called clean — but that cleanliness test, `changedFilesSince`, and every authority check are **ignore-blind** (`--untracked-files=all` without `--ignored`; `ls-files --others --exclude-standard`). An Agent commits a `.gitignore` and writes files under it: they are invisible to the cleanliness test, to `validateChangedPaths` at import, at `commitPlane`, at the candidate authority check and at the gate's final authority recheck — yet they are copied into the verification snapshot, persist in the worktree, and are re-exported into the next execution workspace for that Plane. The tree the mandatory checks execute against was therefore a strict, agent-controlled superset of the tree being promoted. Ignore rules are agent-controlled, so this is a containment failure of the write-authority envelope itself. | Two independent corrections, each of which closes it alone: always materialize the exact commit for the verification snapshot, so the verified tree equals the promoted tree by construction; and make the authority queries ignore-aware (`--ignored=matching`, and drop `--exclude-standard`) so such paths are authority-checked like any other change and a Plane holding them is not reported clean. | **RESOLVED** on `fix/89-absolute-form-auth-bypass`; causal test asserts an ignored file under a committed `.gitignore` is absent from the snapshot; reverting **both** fixes reproduces, reverting either alone does not | -| `SEC-06` | The `OPS-06` `S` review's carried High, confirmed still present at `0ed41dd` and now closed. `docker-compose.yml` published `"${PUBLIC_PORT:-3000}:3000"` with no address prefix, binding every host interface, while `.env.example` ships `APP_AUTH_TOKEN=` empty and the bearer hook short-circuits entirely on an empty token. `README`'s quickstart is `docker compose up --build` against exactly that file, and told the reader that nothing else was needed to start — so the advice to set a token "for any deployment reachable beyond your own machine" never fired, because the reader had no reason to think the quickstart made it reachable. The guard that encodes this knowledge is invoked only from `deploy-existing-ecs.sh`, which the quickstart never runs. Realistic worst case on that profile: unauthenticated prompt-driven command and file execution in the container, read/write to the three bind-mounted host directories, use of whatever credentials `.env` supplies, and the destructive demo reset. On Linux the reachability is wider than operators expect, because Compose port publishing installs DNAT rules evaluated ahead of the filter chains where host firewall rules live. | Default the published address to loopback with an explicit opt-in — `"${PUBLIC_BIND_ADDR:-127.0.0.1}:${PUBLIC_PORT:-3000}:3000"` — mirroring `docker-compose.state-volume.yml`, which already does exactly this. An earlier decision rejected pinning to loopback because it would remove the ECS profile's intended reachability; a defaulted variable keeps that reachability as an explicit opt-in and makes only the default safe. Document it in `.env.example` and in both README paths. | **RESOLVED** on `fix/89-absolute-form-auth-bypass`; causal tests assert the resolved `host_ip` is `127.0.0.1` by default and `0.0.0.0` when opted in; restoring the unprefixed port fails both | -| `F-01` | Source-evidenced: Contract timeout may surface as failure code `unknown` instead of `agent_timeout`. | Typed timeout propagated through Contract/Plane/Agent/Mission/event/API/UI; no message-regex classification. | **RESOLVED + AUDITED** at `83cc1d0`; `T,A,C,S,I` 5/5; 100% scoped | -| `F-02` | Source-evidenced: Contract runtime errors can become generic `unknown`. | Shared typed stage error only; preserve candidate-specific handling. | **RESOLVED + AUDITED** at `83cc1d0`; `T,A,C,S,I` 5/5; 100% scoped | -| `F-04` | Source-evidenced: initial Plane creation can fail before durable stage evidence; later mapper is too late. | Evidence on owning Contract/Mission without inventing a successful Plane. | **AUDITED** at `2cef988`; TST-17 closed | -| `F-05` | Preserved RED proved a real textual conflict became `unknown/background_demo`. | Typed bounded Mission/integration Plane/event mapping; retain clean conflict Plane for inspection and remove it on reset. | **AUDITED** at `f8d7f71`; TST-18/19 closed | -| `F-06` | Preserved RED proved atomic rollback alone cannot leave recovery-visible evidence of the failed transition. | Exact-byte digest + bounded sidecar intent at the representative pre-integration transition; reconcile once without claiming an uncommitted mutation persisted. | **RESOLVED + AUDITED** at `7d51ec6`; TST-21–24 closed | -| `F-07` | Source-evidenced: candidate timeout state mapping is inconsistent and partly regex-based. | One typed timeout class and canonical state mapping. | Worker / ready | -| `F-08` | Source-evidenced: most non-authority candidate exceptions are retryable; second-failure coverage absent. | Retry only typed transient failures, once, from the immutable base. | Worker / ready | -| `GC-01` | Earlier reproduction proved buttons inserted bare `@Name With Spaces`, while the parser requires JSON quoting. | Resolved with parser-safe mention formatting, exact Agent-ID fallback, draft-preservation and two-viewport browser coverage; no parser weakening. | **RESOLVED + AUDITED** at `de3e631`; hosted run `33266624301` | -| `GC-02` | Current service/UI evidence: unmentioned message persists, but no bounded Shepherd action/reply occurs despite UI copy. | Use an existing schema-bounded Shepherd action; no free-form host/model authority. | Worker / ready | -| `GC-03` | Current service path only links an assignment to an already-created active Contract. | Add schema-validated targeted Contract creation under existing authority. | Worker / blocked by GC-02/05 | -| `GC-04` | Earlier reproduction: assignment returns conflict after the fast Mission finishes. | Remove the narrow timing dependency while keeping one mutation owner. | Worker / blocked by GC-03 | -| `GC-05` | Current UI source disables textarea when no project exists; earlier browser observation confirmed it. | Safe read-model initialization or explicit in-panel Mission-start action; preserve composer design. | Worker / ready with GC-02 | -| `GC-06` | Current lifecycle summaries use Shepherd sender; verified manifest-derived Agent summaries are absent. | Server-authored bounded summary only after verification, attributed to the real Agent ID. | Worker / blocked by targeted lifecycle | -| `MR-01` | Full bounded/advisory reviewer, degradation, deterministic independence, truthful capability UI and sparse live smoke passed through `35ec268`. | Keep advisory-only authority and bounded trusted inputs/outputs. | **RESOLVED + AUDITED**; 100% scoped | -| `MR-03` | Valid findings survive invalid peers with bounded dropped count; all-invalid degrades. Deterministic/security/live/hosted gates passed. | Retain per-finding isolation and schema/ref validation. | **RESOLVED + AUDITED** at `35ec268`; 100% scoped | -| `MR-02` | No-Ark browser/API RED showed an enabled “Run” toggle although the process composed no reviewer. The integrated fix publishes one fail-closed capability boolean and renders the preserved preference disabled with explicit **Unavailable** copy; configured PATCH remains functional. | Preserve preference and existing theme; expose no credential/model/endpoint/failure reason. | **RESOLVED + AUDITED** at `577255e`; `T,A,C,B,S,U,I` 7/7 | -| `ST-01` | Current config parses startup auto-resolution/max Planes, but `index.ts` does not pass them into `ShepherdService`. | Explicit initial-settings composition without overwriting later persisted settings. | Worker / ready | -| `ST-02` | Notification toggles persisted although no notification behavior consumed them. | Resolved by preserving stored values behind visibly Reserved/Unavailable native disabled controls; no delivery expansion. | **RESOLVED + AUDITED** at merge `d5df930`; `T,C,B,U,I` 5/5 | -| `SCH-01` | Current service invokes scheduler for one fixed initial batch without real busy/lock/active inputs. | Extend existing scheduler/service boundary for dependency waves; no architecture replacement. | Worker / blocked by SCH-02 | -| `SCH-02` | Cycles are rejected during scheduling rather than before graph persistence. | Call existing DAG validator before durable Contract creation. | Worker / ready | -| `UI-01` | Current detailed failure panel is attention-focused; ordinary failed Missions may hide typed detail. | Reuse existing failure/attention primitives; no visual redesign. | Worker / blocked by typed failures | -| `UI-02` | Current web type has optional `estimatedDurationMs`, but no server/domain producer exists. | Persist and serve trusted estimates, clearly distinct from actuals; preserve timeline design. | Worker / ready | -| `UI-03` | E2E-01 reproduced document widths of 2299/2579 on Create Agent because four transparent absolute preset radios retained global viewport-wide input sizing. | Resolved by bounding only the visually hidden preset-radio dimensions while preserving native semantics, labels, keyboard behavior, and accepted form visuals. | **RESOLVED + AUDITED** at `83954f7`; hosted closeout restored by TST-03 `0b1c401` | -| `TEST-TS` | Server production config deliberately excludes tests, which previously had no separate strict typecheck. | Resolved with a separate no-emit strict test project without changing production emit. | **RESOLVED + AUDITED** at `8995605` | -| `CI-01` | Repository previously had no required hosted repository gate. | Resolved with network/model-free Node 22 install/typecheck/test/build plus Docker verification; preserve protected-main policy. | **RESOLVED + AUDITED** at `cda2446`; hosted `33259565232` | -| `TST-05` | Candidate `592699d` routine harness run passed but modified 16/18 E2E PNGs plus an unrelated UI-03 image; the two stable down captures were unasserted blank canvases. | Resolved with ignored routine output, explicit review-update path, truthful port-down evidence, reachable Create action and real keyboard/focus coverage; no production UI/design change. | **RESOLVED + AUDITED** at `f6df2d9`, evidence `284994d` | -| `TST-06` | Candidate `592699d` passed secrets to matcher output, could not later clean a retained run root, did not canonically reject symlinked managed ancestors, and could retain live prompt/output in failure artifacts. | Resolved with secret-safe assertions, idempotent later cleanup, canonical ancestor confinement, disabled live artifacts and causal fault tests; no authority broadening. | **RESOLVED + AUDITED** at `f6df2d9` | -| `TST-07` | Local GC-01/current-main merge failed strict Server test typecheck with TS6142/TS6059 because a Server test imported Web TS/TSX outside its JSX/rootDir contract. | Resolved by assigning the complete regression to discovered, strictly typed Web ownership; no config weakening, assertion loss or product edit. | **RESOLVED + AUDITED** at `de3e631`; hosted run `33266624301` | - -## Assurance gaps that are not yet defects - -Missing Playwright journeys, screenshots, performance measurements, repeated-run -evidence, final security/UI reviews, sparse live smokes, rehearsals, and Phase 9 -documents remain tasks in `TASKS.md`. They become defects here only when an executed -gate produces a reproducible failure. diff --git a/docs/HACKATHON_EXTENSION_GUIDE.md b/docs/HACKATHON_EXTENSION_GUIDE.md deleted file mode 100644 index e4968c4..0000000 --- a/docs/HACKATHON_EXTENSION_GUIDE.md +++ /dev/null @@ -1,92 +0,0 @@ -# Three-day hackathon guide - -> This is the original Starter Kit extension guide. Shepherd is the selected -> Track 1 implementation. Start with [`TASKS.md`](TASKS.md) for its current -> status and [`PRD.md`](PRD.md) for its requirements. - -Teams receive a working Agent platform and build exactly one middleware track. -Rebuilding the UI, control plane, local Runtime, or ECS setup is out of scope. - -## Provided baseline - -- Browser Agent CRUD and Playground -- Persistent workspaces and Codex sessions -- One-line Docker, Colima, or Podman local Runtime -- Volcengine Ark model connection -- Optional Volcengine ECS deployment - -Local execution is the default judging path. Cloud deployment is optional. - -## Choose one track - -### Glass Box: trace and audit - -Make a Run diagnosable. - -Required demo: - -- Show correlated Run and step events in a timeline or tree. -- Include status, duration, errors, and available model usage. -- Redact secrets. -- Run one successful task and identify the failing step in one failed task. - -### Bouncer: identity and authorization - -Separate the human user from the Agent acting for that user. - -Required demo: - -- Create User A, User B, and an Agent principal owned by User A. -- Allow the Agent to read User A's mock resource. -- Deny access to User B's resource in the backend. -- Record the human, Agent, action, resource, and decision. - -A login screen without server-side authorization does not qualify. - -### Kill Switch: safety and sandboxing - -Contain one explicit dangerous action. - -Required demo: - -- Add a threat-specific policy or a stronger sandbox boundary. -- Block or terminate a malicious Run. -- Keep the protected asset unchanged and show cleanup. -- Run a safe task after containment. - -The Starter Kit's default CPU, memory, PID, and capability limits do not count -as the new control. - -## Three-day plan - -| Day | Goal | -| --- | --- | -| 1 | Start the POC, select one story, define the middleware contract, and complete the backend path. | -| 2 | Finish enforcement or instrumentation, add the minimum UI, and implement positive and negative cases. | -| 3 | Add tests, handle failures, finish the diagram, and rehearse the demo. | - -## Deliverables - -Only three deliverables are required: - -1. **Three-minute live demo:** show a real Agent Run and the middleware result. -2. **One-page architecture diagram:** show the middleware and trust boundary. -3. **Code repository:** include setup, tests, selected track, and limitations. - -## Evaluation - -| Category | Weight | -| --- | ---: | -| End-to-end middleware behavior | 40% | -| Technical design and integration | 25% | -| Verification and robustness | 20% | -| Demo and reproducibility | 15% | - -## Acceptance checklist - -- [ ] The README names one selected track. -- [ ] A reviewer can run the project from the documented command. -- [ ] Middleware executes in the backend or Runtime path, not only in the UI. -- [ ] The demo includes a positive and a failure, denial, or malicious case. -- [ ] Automated evidence covers the core event or policy decision. -- [ ] No secret appears in source, logs, traces, screenshots, or the browser. diff --git a/docs/LOCAL_POC.md b/docs/LOCAL_POC.md deleted file mode 100644 index fed53b3..0000000 --- a/docs/LOCAL_POC.md +++ /dev/null @@ -1,335 +0,0 @@ -# Local POC - -> This is the canonical startup, troubleshooting, and manual verification runbook. -> Current completion status and known gaps are in [`TASKS.md`](TASKS.md); do not -> convert an open task there into a pass based only on manual observation. - -The local profile runs the React/Fastify control plane on macOS or Linux and -starts every Codex turn in a disposable Docker, Colima, or Podman container. -Only the Volcengine Ark model API is remote. - -## Start - -Requirements: - -- Node.js 22+ -- Docker, Colima, or Podman -- An Ark API key and Responses-capable endpoint - -```bash -./scripts/start-local-poc.sh -``` - -The script safely reads the repository's ignored `.env`; configure -`ARK_API_KEY` and `ARK_MODEL` there before starting. It does not source `.env` -as shell code. - -Open . Press `Ctrl+C` to stop the server and remove this -instance's remaining Runtime containers. - -Force an engine by setting `CONTAINER_ENGINE=docker` or -`CONTAINER_ENGINE=podman` in `.env`. Colima uses the Docker CLI. - -### When the host filesystem reaches the engine through a virtual machine - -On a host where the container engine runs inside a virtual machine and shares the -host filesystem into it, that share cannot carry the Codex sandbox's per-file -access rights: directory operations succeed while every attempt to open a file -for reading or writing is denied, so an Agent could not read or write the -workspace it was given. Shepherd does not fall back to `danger-full-access`. - -**You do not need to configure anything for this.** The startup probes detect it -and the script switches to the container state volume by itself: - -``` -[local-poc] The Codex sandbox cannot govern a workspace on /Users/you/.volc-agent-launchpad. -[local-poc] Switching to the launchpad-state container state volume and retrying. -``` - -The volume is a native engine filesystem on every supported host. Set -`LOCAL_POC_STATE_MODE` explicitly to pin one layout and disable the fallback: -`host-bind` to fail loudly on a host that should work, or `container-volume` to -skip the host attempt entirely. - -The fallback builds and starts the control plane inside the engine using -`docker-compose.state-volume.yml`, so it also needs: - -- Access to the engine socket, which the control plane joins as a supplementary - group while remaining non-root. See [`DEVIATIONS.md`](DEVIATIONS.md). - -State lives in the `launchpad-state` volume rather than a host directory, so it -is not browsable from the host file manager; use `docker volume` and -`docker cp`. Switching modes does not migrate existing state: Plane worktrees -record absolute paths, so start the volume empty. - -## Preflight and deterministic demo configuration - -From the repository root: - -```bash -node --version # 22 or newer -npm --version -docker info # or: podman info -npm ci -npm run check -npm run test:coverage -npm run test:terraform -npm run test:shepherd:live:preflight -``` - -`test:coverage` enforces at least 80% statements, branches, functions, and lines for -both the Server and browser-owned Web source, and fails if a production source file -is missing from the report. `test:terraform` uses installed Terraform when available -or the pinned `hashicorp/terraform:1.9.8` image against a disposable module copy. -`test:shepherd:live:preflight` builds the exact working tree, checks the non-root -controller, named state volume, engine socket, Runtime image and live-test discovery, -then cleans up without contacting Ark. - -For the reliable no-model judge flow, keep secrets only in the ignored `.env` and -set: - -```dotenv -HOST=127.0.0.1 -SHEPHERD_EXECUTION_MODE=deterministic -SHEPHERD_DEMO_MODE=true -``` - -`APP_AUTH_TOKEN` is optional and empty by default; the server starts and serves -without one. Set it only if you want the browser unlock screen and a bearer -credential on every API route. - -The launcher parses `.env` as data; never source, print, screenshot, or commit it. -The deterministic Mission does not call Ark. `ARK_API_KEY` and `ARK_MODEL` are used -only by the optional live Agent/Shepherd paths. - -## Manual hackathon flow - -Use a fresh disposable data root for rehearsal. Start with -`./scripts/start-local-poc.sh`, and wait for the loopback URL. The unlock screen -appears only if you set an `APP_AUTH_TOKEN`; enter that same token if so. - -### 1. Positive Shepherd Mission - -1. Open **Settings → General → Reset demo state**. The reset preserves ordinary - Launchpad Agents. -2. Create `Frontend Auth Agent` with role/preset **Frontend**, then create - `Backend Auth Agent` with role/preset **Backend**. Both must be ready. -3. Open `Frontend Auth Agent`, enable **Route through Shepherd**, and send this - private prompt once: - - ```text - Implement the frontend authentication client using an HttpOnly session cookie. - ``` - - Confirm Shepherd says the prompt was captured as - `http-only-session-cookie` and is waiting for the Backend Agent. -4. Open `Backend Auth Agent`, enable **Route through Shepherd**, and send this - private prompt once: - - ```text - Implement the backend authentication service using a bearer JWT. - ``` - - The second compatible-role prompt atomically starts one Mission. Open - **Shepherd**; the former deterministic Agent/transport selectors must not exist. - The small Shepherd composer remains a managed-Agent fallback and is not used in - this primary flow. -5. Wait for `completed`. Verify the visible sequence: the two exact private prompts - become two durable Contracts → - isolated Contract Planes → independent verification → integration → the - `auth.transport` semantic collision → two resolution candidates → independently - passing cookie candidate and rejected bearer candidate → final re-verification → - protected promotion → Mission completion. -6. In the Contract stream, open **View evidence** for both source Contracts. Confirm - the complete bounded definitions show the chosen Agent/ID, objective and exact - transport, Mission/Plane, dependencies, semantic scope and claim, contextual - inputs, readable/writable/forbidden authority, expected artifact, acceptance - check/profile, manifest path, and timestamps alongside existing evidence. -7. Exercise **All**, **Contracts**, **Verification**, **Collisions**, and - **Resolution** filters. No view may expose a secret, absolute host path, raw model - prompt/output, session identifier, or unbounded verifier output. -8. Inspect the timeline, expand the collision, and open each Plane Tree detail. - Confirm short Git evidence, changed files, state, and verification evidence are - visible and that the drawer can be closed. Explain that the source Agent Planes - do not compete: the cookie and bearer **Resolution Planes** compete after both - verified source outputs are combined into the same integration commit. -9. Repeat visual checks at `1280x800` and `1440x900`. The document itself must not - scroll horizontally or vertically; only designated panes may scroll. Compare the - hierarchy and theme with [`UI.jpeg`](UI.jpeg). - -### 2. Settings and human selection - -1. Open **Settings → General → Reset demo state** and confirm the result. -2. Under **Execution**, change one timeout and **Maximum parallel Planes**, save, - refresh, and confirm the values round-trip; then restore them. -3. Disable **Automatic resolution**, save, and repeat the two private Agent prompts - from the positive flow with the preserved user-created Agents. -4. At `attention_required`, confirm the internal human-review ticket shows the full - durable collision/Mission reference. Only an independently passing candidate may offer - **Select verified future**. Select it and confirm completion through the same - promotion gate. Restore **Automatic resolution** afterward. -5. Notification controls must remain visibly **Unavailable/Reserved**, disabled, - unfocusable, and must not send a settings mutation. - -Startup composition for automatic resolution and Plane capacity is still tracked as -`ST-01`; do not claim that open task from a persisted post-start settings round-trip. - -### 3. Cancellation and Project Group - -1. Reset, start a Mission, and immediately choose **Cancel Mission**. Confirm the - durable `cancelled` state, retained evidence, released Agents, and no promotion. - The deterministic flow can finish before the click; if so, record the timing as - inconclusive rather than passing cancellation. -2. Open **Project Group**. Mention controls must preserve the existing draft, - keyboard behavior, focus, quoting, Unicode, and the 2,000-character boundary. -3. Treat unmentioned Shepherd action/reply, targeted Contract creation, and - manifest-derived Agent summaries as open until `GC-02/05`, `GC-03/04`, `GC-06`, - and `E2E-03` are audited. Record behavior that differs from those task rows. - -### 4. Optional bounded live Agent check - -This consumes real `ARK_MODEL` capacity and is not needed for UI inspection: - -1. Create one **Generalist** Agent named `Manual QA Agent`. -2. Send exactly one small task: `Create a dependency-free hello.js that prints - "Hello, Shepherd", add a Node test, run it, and report the exact test result.` -3. Send one follow-up: `Reply with only the exact greeting produced by hello.js.` -4. Confirm queued → running → completed, session continuity, and the expected file. -5. Stop with `Ctrl+C`, restart with the same data root, and confirm the Agent, - messages, Runs, and workspace persist. - -The live Shepherd Mission/reviewer continuity acceptance remains `LIVE-01`; one -legacy Playground run does not close it. - -### 5. Exact-tree live Shepherd gate - -First run the zero-spend preflight above. With the ignored environment file -configured, the bounded external gate is: - -```bash -npm run test:shepherd:live -``` - -This command is opt-in and must remain single-worker/no-retry. It sends -repository-derived Contracts, prompts, and scoped source content to the configured -Ark endpoint, so obtain authorization for that data transfer before running it in a -managed or reviewed environment. A passing preflight proves local construction and -isolation wiring only; it is not a substitute for the provider result. Record only -bounded outcomes and never attach raw prompts, model output, credentials, session -identifiers, or private paths. - -## Recording a defect - -Record the TASKS/PRD ID, exact commit, viewport/runtime, reproduction, expected and -actual behavior, frequency, safety/data impact, redacted evidence, and proposed -causal test. Never attach `.env`, credentials, raw prompts, absolute private paths, -or unbounded logs. - -## Data and Runtime - -Persistent state defaults to: - -- macOS: `~/.volc-agent-launchpad/` -- Linux: `.local/` - -Set `LOCAL_POC_DATA_ROOT` to use another directory, or -`LOCAL_POC_STATE_MODE=container-volume` to force all state into the -`launchpad-state` engine volume instead of on the host. - -Each turn mounts only the selected Agent workspace and Codex session directory. -Default limits are 2 CPUs, 2 GiB memory, 256 processes, dropped capabilities, -and `no-new-privileges`. - -Codex requests `workspace-write`. If the Linux kernel lacks Landlock, startup -warns and disables only the inner Codex sandbox. The outer container limits -remain active, but this fallback is not tenant isolation. - -## Rootless Podman on Linux - -This path requires no Docker or Compose. It supports Ubuntu 22.04/24.04, Debian -12, and veLinux 2. - -Install Podman: - -```bash -sudo apt-get update -sudo apt-get install -y podman uidmap slirp4netns fuse-overlayfs -``` - -Install Node.js 22 if needed. Inspect the downloaded setup script before -running it: - -```bash -curl -fsSL https://deb.nodesource.com/setup_22.x \ - -o /tmp/nodesource_setup_22.sh -less /tmp/nodesource_setup_22.sh -sudo -E bash /tmp/nodesource_setup_22.sh -sudo apt-get install -y nodejs -``` - -Check subordinate UID/GID ranges: - -```bash -grep "^$USER:" /etc/subuid -grep "^$USER:" /etc/subgid -``` - -If both are missing, assign unused ranges and log in again: - -```bash -sudo usermod --add-subuids 100000-165535 "$USER" -sudo usermod --add-subgids 100000-165535 "$USER" -``` - -Verify rootless Podman: - -```bash -podman info -podman run --rm docker.io/library/alpine:3.20 echo PODMAN_OK -``` - -`podman info` must report `rootless: true`. Set `CONTAINER_ENGINE=podman` in -`.env`, then start the POC: - -```bash -./scripts/start-local-poc.sh -``` - -This flow was verified on veLinux 2 with rootless Podman 4.3.1. A `vfs` storage -driver works but needs more disk space; keep at least 5 GiB free for a cold -build. - -## Common options - -Set optional values such as -`CONTAINER_RUNTIME_APT_PACKAGES='ca-certificates git ripgrep python3 build-essential'` -in `.env`, then run `./scripts/start-local-poc.sh`. - -For restricted networks, configure: - -- `CONTAINER_RUNTIME_BASE_IMAGE` -- `CONTAINER_APT_MIRROR` -- `CONTAINER_APT_SECURITY_MIRROR` - -Resource limits are controlled by `CONTAINER_CPU_LIMIT`, -`CONTAINER_MEMORY_LIMIT`, and `CONTAINER_PIDS_LIMIT`. - -## Troubleshooting - -Check Runtime readiness: - -```bash -docker info # Or: podman info -docker image inspect volc-agent-runtime:local -curl http://localhost:3000/api/system -``` - -If a bind mount is rejected, set `LOCAL_POC_DATA_ROOT` to a directory shared -with the container VM. On Linux, the startup script automatically uses the host -UID/GID and validates workspace write access. - -Remove only the default Runtime image: - -```bash -podman image rm volc-agent-runtime:local -``` diff --git a/docs/PRD.md b/docs/PRD.md deleted file mode 100644 index 988d036..0000000 --- a/docs/PRD.md +++ /dev/null @@ -1,441 +0,0 @@ -# Shepherd: Multi-Agent Kernel — Full End-to-End Implementation PRD (No-Compromise Edition) - -**Target executor:** Autonomous coding agent (GPT-5.6 Ultra / Codex or equivalent) -**Hackathon:** TikTok TechJam 2026 — Track 1: Agent Launchpad — Design and Build Lightweight Agent Middleware -**Starter repository:** https://github.com/RrankPyramid/CodeJam -**Document status:** Source of truth. Supersedes all prior Shepherd PRDs. -**Scope directive:** Every capability in this document is required. There is no P1/P2 tiering and no cut line. If a capability cannot be delivered as specified, the executor must stop, document the exact blocker with reproduction evidence, and surface it — never silently narrow scope, never fake behavior, never weaken an assertion to make a test pass. - ---- - -# 0. The Verification Doctrine (READ FIRST — governs every task in this document) - -This PRD imposes a mandatory working discipline on the executing agent. It applies to **every** feature, bug fix, refactor, UI change, and test. - -## 0.1 The Build–Verify–Test–Evidence (BVTE) loop - -No task is "done" when the code compiles or when the agent believes it works. Every task completes only through this loop: - -1. **Build** — implement the smallest coherent change for the task. -2. **Verify** — actually run the system and observe the expected output with your own tool calls: - - Start the real server, hit the real API with `curl` or a script, and inspect the real JSON response. - - For runtime behavior, execute the real container path and inspect real files, real Git state, real persisted JSON. - - For UI behavior, load the real page in a browser automation session (Playwright) and assert on the rendered DOM, and capture a screenshot. - - "It should work" is prohibited. Only "I ran X, observed Y, Y matches the specified expectation Z" is acceptable. -3. **Test** — encode the verified behavior as an automated test at the correct layer (unit, integration, container, or E2E) so it can never silently regress. -4. **Evidence** — append an entry to `docs/BUILD_LOG.md` containing: task, commands run, observed output (bounded/redacted), test file(s) added, and pass status. - -## 0.2 The Problem-Resolution Protocol - -When **any** problem is encountered — a failing command, an unexpected output, a flaky behavior, a UI misrender, a confusing Starter Kit behavior — the agent must: - -1. **Reproduce it deterministically** before attempting a fix. Record the exact reproduction command. -2. **Diagnose the root cause** by reading the actual code path, not by guessing. State the root cause in one sentence in the build log. -3. **Fix the root cause**, not the symptom. Weakening a test, adding a sleep, swallowing an error, or special-casing the demo input are all prohibited fixes unless the root cause genuinely is timing/config, in which case the log must justify it. -4. **Re-run the original reproduction** and confirm the expected output now occurs. Paste the before/after into the build log. -5. **Run the affected test suites** and confirm no regression. -6. **Add a regression test** if one did not already catch the problem. - -## 0.3 Verification asymmetry rule - -The more critical the invariant, the more hostile the verification must be. For the five kernel invariants below, the agent must write **negative tests that actively try to break them**, and those tests must fail if the protection is removed (mutation-check each one at least once by temporarily disabling the guard, observing the test fail, then restoring it — record this in the build log): - -1. An Agent can never self-certify a contract as verified. -2. Changes outside delegated writable scope can never be integrated or promoted. -3. The protected branch can never be updated except through the trusted promotion gate. -4. A resolution winner can never be hard-coded; swapping the fixture's invariant must flip the winner. -5. No secret (Ark key, tokens, `.env` contents) can appear in persisted state, events, prompts to verifiers, or the browser. - -## 0.4 UI/UX verification standard - -UI work is not exempt from verification. Every screen and component in Section 11 must be verified by: - -- **Functional E2E assertions** (Playwright): the specified elements exist, display real backend data, and update on polling. -- **Visual QA screenshots**: capture at 1440×900 and 1280×800, review each against the Visual Acceptance Checklist (11.7), and store screenshots in `docs/ui-review/`. -- **Interaction walkthroughs**: for each user journey in 11.6, drive it end to end in the browser and confirm every intermediate state renders (not just the final state). -- **Empty/loading/error states**: every list, stream, tree, and timeline must be verified in its empty state, loading state, and at least one error state — with screenshots. - -## 0.5 Honesty constraints - -- No hard-coded outcomes anywhere in the product path. -- No static UI standing in for real middleware behavior. -- No fabricated test reports; if something is untestable, it is documented as untested with the reason. -- Every claim in the README must be backed by a named test or a build-log evidence entry. - ---- - -# 1. Executive Summary - -Build **Shepherd: Multi-Agent Kernel** as middleware on top of the supplied Agent Launchpad Starter Kit. - -Shepherd solves one specific multi-agent infrastructure failure: - -> Two coding Agents can independently complete their tasks, pass their own local checks, and produce no Git textual merge conflict, while still making mutually incompatible assumptions about the same system. - -Shepherd delivers three hero primitives, in a causal chain the demo must make undeniable: - -1. **Agent Execution Contracts** — delegation becomes a typed, machine-verifiable contract (objective, dependencies, authority, expected evidence, acceptance criteria). An Agent cannot certify its own success. -2. **Semantic Collision Detection** — Shepherd detects incompatible behavioral/architectural claims between independently successful contracts, including conflicts Git textual merging cannot see. -3. **Speculative Conflict Resolution** — Shepherd forks competing reconciliation strategies into isolated execution Planes, executes and independently verifies each, and promotes only the objectively verified winner. - -Supporting primitives: Task Graph with Live Execution Timeline, Scoped Authority, Planes (Git-worktree-backed isolated worlds run through the existing container runtime), Shepherd Chat, Project Group Chat, and the Plane Tree. - -**The chain: Contract → Execute → Verify → Detect Collision → Fork Futures → Verify Futures → Promote Winner.** All of it real, all of it tested, all of it visible. - ---- - -# 2. Competition Alignment - -The Track 1 brief requires middleware that executes in a backend/Runtime/data/infrastructure path; a defined boundary with failure behavior; demonstrated normal and failure/denial/recovery cases; automated tests; reproducibility; no secrets; and preservation of the Starter Kit baseline (Agent CRUD, lifecycle, Playground, persistence, real model execution). - -| Criterion | Weight | Shepherd delivery | -|---|---:|---| -| End-to-end middleware behavior | 40% | Browser request → real contracts → real isolated Plane execution → real independent verification → real semantic collision evidence → real speculative resolution → protected promotion. Every link verified live and by automated test. | -| Technical design and integration | 25% | Inserted at existing Fastify / AgentService / AgentRunner / JSON-store seams; baseline untouched in behavior; typed domain; explicit trust boundaries. | -| Verification and robustness | 20% | Five mutation-checked kernel invariants; 19-category failure matrix implemented and tested; fail-closed everywhere; redaction verified. | -| Demo and reproducibility | 15% | One-command startup preserved; deterministic fixture; safe reset command; rehearsed 3-minute flow; complete README, architecture doc, and honest test report. | - ---- - -# 3. Product Positioning - -- **Name:** Shepherd: Multi-Agent Kernel -- **Pitch:** Shepherd converts Agent delegation into verifiable execution contracts, detects semantic conflicts between concurrently successful Agents, and resolves those conflicts by executing competing futures before promoting the verified winner. -- **Mental model for judges:** a transactional execution kernel for teams of coding Agents. The UI is mission control for the kernel — never pitch it as a dashboard. -- **Novelty claim:** not worktrees, task graphs, or chat individually — the causal composition **Execution Contract → Semantic Collision → Speculative Reconciliation → Verified Promotion**, integrated into this platform's real lifecycle. - ---- - -# 4. Goals and Non-Goals - -## 4.1 Goals (all required — no tiering) - -Shepherd must: - -1. Let one human coordinate multiple Agent instances through a single Shepherd control surface. -2. Turn assignments into durable typed Execution Contracts. -3. Run contract work in isolated Planes; Agents never directly mutate the protected project. -4. Enforce bounded Agent authority at the trusted control-plane boundary using actual diffs. -5. Independently verify contract outputs; Agent self-reports are informational only. -6. Represent each contract as a node in a live dependency graph with a scheduler. -7. Detect a real semantic conflict requiring no Git textual conflict. -8. Fork at least two distinct reconciliation strategies from the same immutable integration state. -9. Execute and independently evaluate the candidates concurrently. -10. Promote only when deterministic verification and safety checks pass; prefer no promotion over unjustified promotion. -11. Preserve failure evidence and stop safely (`attention_required`) when no candidate is objectively acceptable. -12. Support explicit `@Agent` routing in Project Group chat. -13. Provide a bounded model-assisted semantic reviewer **in addition to** the deterministic detector (never demo-critical; degrades explicitly on failure). -14. Support human selection when candidates are objectively tied. -15. Support Mission cancellation and bounded candidate retry. -16. Show estimated durations in the timeline, clearly labeled as estimates. -17. Expose everything through the UI specified in Section 11. -18. Preserve every Starter Kit baseline behavior. - -## 4.2 Non-Goals - -Production OAuth; multi-tenant identity; Kubernetes; distributed schedulers; multi-region; microVMs; general policy languages; rollback of external side effects; generic semantic-equivalence proofs; workflow editors; vector memory; marketplaces; Git hosting; general CI/CD; production RBAC; autonomous subagent hierarchies; agent social loops; cloud deployment for presentation value. Local Docker/Colima/Podman is the judging path. - ---- - -# 5. Executor Operating Directive - -Before changing code: clone/inspect the repository; read README and `docs/ARCHITECTURE.md`; run the baseline (`npm run poc`) and the full baseline acceptance test from the challenge brief (create agent → hello-world CLI task → follow-up → stop/restart → workspace persists); run `npm run check`; record any pre-existing failures in `docs/BUILD_LOG.md`. - -**Do not begin Shepherd work on a broken baseline.** If the baseline fails, apply the Problem-Resolution Protocol (0.2) to the environment first. - -During implementation: preserve baseline behavior; prefer focused changes; typed TypeScript throughout; validate all untrusted structured input with schemas; enforcement lives in backend/runtime/data paths; deterministic mechanisms preferred; document any material deviation from this PRD in `docs/DEVIATIONS.md` with rationale. - -Continuously: keep `docs/BUILD_LOG.md` current per the BVTE loop; commit in small, coherent, described commits; keep `npm run check` green at the end of every phase. - ---- - -# 6. Architecture Requirements - -## 6.1 Layers - -- **Experience Layer** — existing React app remains the shell; add Shepherd page, Project Group, event stream, timeline, Plane Tree, role/authority config (Section 11). Preserve Agent list, Create/Edit, lifecycle controls, legacy Playground, and existing visual design. -- **Existing Agent Control Plane** — `AgentService` keeps owning Agent CRUD, lifecycle, legacy Playground messages, legacy Runs. Do not turn it into Shepherd. -- **Shepherd Control Plane** — a dedicated `ShepherdService` (or equivalently factored modules) owning Missions, Contracts, the DAG, scheduling, Planes, authority, verification orchestration, claims, collisions, resolutions, winner policy, promotion, events, and interruption state. -- **Agent Runtime Boundary** — reuse `AgentRunner`/container runtime. Shepherd executes a logical Agent against a specific Plane workspace via a distinct **execution identity** (independent session, cancellation, and container per contract/candidate; candidates never resume a shared Codex thread). -- **Verification Boundary** — a separate verification runner: disposable container, candidate Plane mounted, **no Ark key, no Codex session directory, no network**, bounded CPU/memory/PID/time/output, destroyed after use. -- **Git / Plane Boundary** — the protected repository is controlled solely by Shepherd's Git manager. Agents work in worktrees. Only the trusted promotion path updates the protected branch. All Git operations are argv-based `execFile` with sanitized refs, bounded output, and timeouts. - -## 6.2 Trust boundaries - -Untrusted: browser input, model output, Agent-written files, result manifests, semantic-claim content, candidate code, code executed during verification, model-assisted analysis output. - -Trusted: schema validation, contract lifecycle transitions, authority intersection, Git/Plane control, actual changed-file inspection, verification interpretation, deterministic collision rule, deterministic winner policy, promotion, persistence transitions. - -Every trusted decision must be implemented server-side and covered by a test that attempts to subvert it from the untrusted side. - ---- - -# 7. Core Domain Model - -Type names may adapt to repository conventions; semantics are mandatory. All entities persist in the extended JSON store with a versioned migration; existing Agent/message/Run data must survive (verified by a migration test on a captured pre-migration fixture store). - -## 7.1 ShepherdProject -ID, display name, repository location, protected branch, current protected head commit, timestamps, active mutating Mission (nullable). One active project is sufficient; one **mutating Mission at a time** is enforced and tested. - -## 7.2 Mission -ID, project ID, original user intent, base commit, contract IDs, dependency edges, collision IDs, resolution IDs, state, timestamps, attention/failure reason. States: `planning, queued, running, verifying, collision, resolving, completed, failed, cancelled, attention_required`. Every transition emits an event; illegal transitions are rejected and tested. - -## 7.3 AgentRole -Optional persistent Agent metadata: `Frontend | Backend | Verification | Generalist`. Editable via Create/Edit Agent. - -## 7.4 ScopedAuthority -Durable per-Agent envelope over project filesystem scope: readable, writable, forbidden path patterns. Contract authority is intersected: **ContractAuthority ⊆ AgentAuthority** (tested with adversarial patterns). A resolution candidate may receive broader — but still explicit and bounded — authority spanning both original scopes. - -Path engine requirements (all negative-tested): normalization; rejection of traversal (`..`), absolute host paths, and null bytes; forbidden overrides writable; `.shepherd/**`, `.git/**`, and secret paths always protected; matching is deterministic and documented. - -## 7.5 ExecutionContract -contract ID, mission ID, Agent ID, title, objective, contextual inputs, dependency IDs, semantic scopes, authority scope, expected artifacts, acceptance specification (mandatory + optional checks), Plane ID, result-manifest location, lifecycle state, timestamps, error info. - -Lifecycle: `created → queued/blocked → running → agent_completed → authority_validation → verifying → verified` with explicit failure states at each step. **No path exists from `agent_completed` to `verified` that skips authority validation and independent verification** — enforced structurally and mutation-tested (0.3 invariant 1). - -## 7.6 ContractResultManifest (`.shepherd/result.json` inside the Plane) -schema version, contract ID, summary, changed/produced artifacts, semantic claims, evidence references, Agent-declared test outcomes (informational), notes. Schema-validated on ingestion; malformed/missing manifests are explicit failure states with preserved evidence. - -## 7.7 SemanticClaim -canonical key, value, scope, mode (at minimum `exclusive`), evidence references into real project artifacts. - -**Robustness requirement (demo-critical):** claim keys and values pass through a server-side normalization table (trim, lowercase, canonical aliases — e.g., `jwt`/`bearer`/`bearer-jwt` → `bearer-jwt`) so trivially different spellings of the same claim still collide. The contract prompt envelope additionally pre-declares the expected canonical claim key(s) for the contract, and Shepherd cross-checks manifest claims against the declared keys; a contract whose manifest omits its declared key enters `attention_required` rather than silently passing. Both behaviors are tested. - -Evidence validation before a claim may participate in a collision: referenced files exist inside the Plane; paths remain inside the project boundary; no secret/control-plane paths; bounded description length; where practical, confirmation that referenced files were changed by or are materially relevant to the contract. Invalid evidence → explicit rejected-claim state, never silent acceptance. - -## 7.8 Plane -Git branch + worktree + base commit + purpose + execution identity + authority envelope + persisted state + verification evidence. Kinds: `contract`, `integration`, `resolution`. Worktree lifecycle (create/inspect/diff/destroy) is wrapped in a tested `PlaneManager`; leaked worktrees are detected and cleaned by reset. - -## 7.9 SemanticCollision -collision ID, mission ID, semantic key/scope, left/right contract IDs, left/right claims, per-side evidence, human-readable reason, detection mechanism (`deterministic` | `model_assisted`), resolution strategy IDs, state, timestamps. - -## 7.10 ResolutionCandidate -candidate ID, collision ID, strategy description (exact canonical value it makes true), Plane ID, state, independent verification evidence, changed-file/diff summary, result, selection/rejection status, retry count. - -## 7.11 ShepherdEvent -timestamp, type, summary, actor, correlation IDs (mission/contract/agent/plane/collision/candidate), bounded safe details. Event types cover at minimum: mission created; contract created/blocked/started; agent completed; authority accepted/denied; verification started/passed/failed; claims loaded; claim rejected; collision detected; resolution started; candidate created/passed/failed/retried; candidate selected; tie escalated; promotion started/completed; mission completed/failed/cancelled; execution interrupted; model-review degraded. Events never contain secrets, raw prompts, or unbounded output (redaction tested). - ---- - -# 8. Kernel Behavior Requirements - -## 8.1 Contract creation -Contracts originate from: Shepherd chat Mission decomposition (constrained, reliable parser — if free-form planning proves unreliable during verification, the structured assignment path is the primary path and the planner degrades to suggesting a structured plan the user confirms); explicit `@Agent` assignment in Project Group; and the deterministic demo Mission definition. All three paths are implemented and E2E-tested. - -## 8.2 Contract prompt envelope -The runtime prompt for a Shepherd-managed execution contains: logical Agent identity and role; contract ID; exact objective; supplied context and dependency outputs; readable/writable/forbidden scope; expected outputs; the declared semantic claim key(s); the result-manifest schema and requirement to write it; instructions to make the smallest coherent change, not to claim unverified success, and not to modify `.shepherd/**` or other protected metadata. Never include Ark keys or control-plane secrets (asserted by a test that scans generated prompts against known secret values). - -## 8.3 Scheduler and Task Graph -Contracts form a DAG. A contract runs only when: mission active; dependencies satisfied; the Agent's execution identity is free; the project mutation lock permits; Plane concurrency limit not exceeded. Failed required dependencies block downstream contracts with a visible, evidenced `blocked` reason. Cycle detection rejects cyclic dependency definitions at creation. All scheduler rules unit-tested; concurrency verified with a real two-contract parallel run. - -## 8.4 Integration stage -When a compatible verified group exists: create an integration Plane from the Mission base; merge verified contract branches with argv Git; record textual conflicts if any (explicit `git_conflict` state — implemented and tested even though the demo avoids it); load manifests; run collision detection; freeze the integration commit as the immutable base for resolution. - -## 8.5 Deterministic collision rule (demo-critical) -A collision exists iff: same Mission; both contracts independently `verified`; both contain a claim with the same canonical (normalized) key; both marked `exclusive`; normalized values differ; both claims carry valid evidence; dependency semantics do not establish supersession. Exhaustively unit-tested including near-miss cases (same values, non-exclusive mode, invalid evidence, superseding dependency). - -## 8.6 Model-assisted semantic reviewer (required, never demo-critical) -A bounded structured model review compares objectives, manifests, claims, changed files, and diff summaries to flag equivalent keys with different naming or likely incompatibilities. Output is schema-validated; on any failure it produces an explicit `degraded_analysis` event — never a fake "safe". The deterministic detector alone must carry the live demo; a test verifies collision detection succeeds with the model reviewer disabled. - -## 8.7 Speculative resolution -On a validated collision: generate two explicit strategies (reconcile to left value; reconcile to right value — each states the exact canonical value it makes true); fork two resolution Planes from the same immutable integration commit (verified: identical base SHA, no shared mutable state, independent sessions); execute both through the real runtime, concurrently; independently verify each against the project acceptance criteria plus all relevant original contract criteria. - -## 8.8 Winner policy (deterministic, mutation-tested) -- Exactly one candidate passes all mandatory checks → select it. -- Both fail → select none; `attention_required`; evidence preserved. -- Both pass → apply predeclared objective tie-breakers only; if still tied → human selection UI (Goal 14); an LLM opinion is never the sole tie-breaker. -- Prefer no promotion over unjustified promotion. - -**No hard-coded winner:** a dedicated test modifies the fixture invariant so the opposite candidate passes and asserts the selection flips (0.3 invariant 4). - -## 8.9 Final promotion gate -Immediately before promotion: re-check candidate authority against actual diff; re-run mandatory acceptance checks; confirm protected branch head equals expected head (if moved → stop, preserve evidence, `attention_required`); confirm the selected candidate matches the persisted decision; promote via the trusted Git path only; persist the promotion event. The losing Plane remains inspectable. Every sub-check has a negative test. - -## 8.10 Independent verification runner -Disposable container; candidate Plane mounted; no Ark key; no Codex session dir; no network for the deterministic fixture; bounded CPU/memory/PID/time/stdout; clear exit code/duration; destroyed after use. A test asserts the verifier environment contains no secret variables and no network reachability (attempt an outbound request from inside; expect failure). All mandatory checks must pass for `verified`; optional checks add evidence only. - -## 8.11 Cancellation and retry -Mission cancellation stops scheduled/running work safely, cancels only the targeted execution identities, preserves evidence, and lands in `cancelled`. A failed candidate may retry once (bounded) with a fresh Plane from the same integration commit; retries are evidenced. Both are E2E-tested. - ---- - -# 9. Persistence, Events, and API - -## 9.1 Persistence -Extend the JSON store with a versioned migration; pre-existing data survives (fixture-based migration test). Mutations remain serialized/atomic at store level. Interrupted in-flight work never becomes `completed` after restart: startup reconciliation marks it `interrupted/attention_required` (tested by killing the server mid-Mission at multiple points and restarting). No secrets persisted (scanning test over the store after a full demo run). - -## 9.2 API (adapt names to Fastify conventions; all schema-validated; all covered by API tests) -Read: Shepherd state, Mission detail, event polling (since-cursor), Project Group messages, Plane/collision/candidate detail. Write: send Shepherd message / create Mission, send Project Group message, cancel Mission, human tie-break selection, demo reset (explicit dev/demo mode only). The browser can never submit arbitrary server filesystem paths (negative-tested). Reuse the starter's existing auth/demo-token boundary. Polling (~1s) preferred over WebSockets. - ---- - -# 10. Demo Fixture (deterministic, network-free) - -A tiny dependency-light authentication project using Node built-ins: - -- Frontend contract → bearer-JWT client auth; claim `auth.transport = bearer-jwt`. -- Backend contract → HttpOnly session-cookie auth; claim `auth.transport = http-only-session-cookie`. -- The contracts modify **different files**, so Git merges without textual conflict (asserted by a test). -- Each side passes its own local acceptance checks (asserted). -- A project-level security invariant (e.g., token/credential must not be readable by client script) objectively distinguishes the two reconciliation candidates. The verification result — not a strategy name — determines the winner; flipping the invariant flips the winner (8.8 test). -- No package installation or network during the fixture run; runtime image pre-built. - -**Demo reset command:** resets only Shepherd demo state; recreates the fixture repo at its known initial commit; removes stale demo worktrees/branches safely; never deletes arbitrary user paths (guard-tested with a hostile path config); leaves unrelated Launchpad data alone. - ---- - -# 11. UI/UX Specification (every item verified per 0.4) - -## 11.1 Sidebar -Retain the dark sidebar and `Create Agent` button. Above `YOUR AGENTS`, add in order: **SHEPHERD** → Shepherd; **GROUP CHAT** → Project Group; then existing Agent cards. - -## 11.2 Shepherd page — Left column: Execution Contract Stream -Real polled events with contract IDs, Agent names, timestamps, state pills, collision alerts, candidate results, promotion events, compact evidence expanders. Filters: All / Contracts / Verification / Collisions / Resolution. Shepherd message composer at the bottom. New events visible within ~1–1.5s of persistence (measured in an E2E test). - -## 11.3 Shepherd page — Right column top: Live Execution Timeline -Minimal Gantt: rows per Agent/contract; dependency order; queued/blocked/running/verifying segments; collision marker; candidate resolution segments; completed/failed states; actual start/end times; estimates clearly labeled "est.". Driven by real Mission/contract state only. - -## 11.4 Shepherd page — Right column bottom: Plane Tree -Renders real persisted Plane/Git lineage (main → contract Planes → collision → integration → Resolution A/B with verified/failed/selected/promoted badges). Hover/click details: purpose, branch, short base/head SHA, assigned Agent or strategy, changed-file count, diff summary, verification result, status. A test asserts the tree matches `git worktree list` / branch reality. - -## 11.5 Project Group, Agent page, Create/Edit -Project Group: human + Shepherd + Agents; unmentioned messages route to Shepherd; `@AgentName` creates/targets a contract; Shepherd posts lifecycle summaries; Agents post concise real completion summaries from their manifests. No uncontrolled agent chatter. Agent page: preserve legacy Playground; add current-contract badge, Plane link, role display. Create/Edit: role selector + authority presets with an advanced section; the demo never requires typing glob rules live. - -## 11.6 User journeys (each driven end-to-end in Playwright with screenshots at every stage) -1. Baseline journey: create Agent → Playground task → follow-up → stop/restart (regression). -2. Mission journey: submit Mission → contracts appear → Planes appear → both verify → integration → collision → resolution planes → winner → promotion → final state. -3. `@Agent` journey: targeted contract from Project Group. -4. Failure journey: contract with unauthorized change → authority denial visible with evidence. -5. Attention journey: both candidates fail → `attention_required` with preserved evidence. -6. Tie journey: objective tie → human selection UI → promotion of chosen candidate. -7. Cancellation journey: cancel mid-Mission → safe durable `cancelled` state. -8. Restart journey: kill server mid-Mission → restart → interrupted state visible, nothing falsely green. - -## 11.7 Visual Acceptance Checklist (applied to every screenshot in `docs/ui-review/`) -Cream/off-white surface, dark sidebar, purple primary accent, green success, red failure/collision; restrained borders/shadows; starter typography; consistent spacing rhythm; no neon/gradients/particles/3D/excess animation; no truncated or overlapping text at 1280×800; loading, empty, and error states styled (never raw/unstyled); state pills readable; long IDs truncated with full value on hover; the judge should recognize the starter kit immediately. Any checklist failure is a defect and enters the Problem-Resolution Protocol. - ---- - -# 12. Failure and Recovery Matrix (all implemented, all tested) - -Each category must produce a durable, visible, evidenced state — never a generic error, never a falsely green UI: - -Agent timeout; Agent runtime error; missing result manifest; malformed manifest; invalid semantic evidence; omitted declared claim key; unauthorized file change; failed independent acceptance; worktree creation failure; Git textual merge conflict; semantic collision; candidate timeout; single-candidate failure; all-candidate failure; objective tie; final re-verification failure; protected branch moved unexpectedly; verification infrastructure error; server restart mid-Mission; persistence error; UI polling interruption (UI reconnects and reconciles); model-reviewer failure (degraded state). - -For each: an automated test triggers the condition (fault injection where needed) and asserts the resulting state, event, and UI representation. `attention_required` is preferred over unsafe automatic recovery. - ---- - -# 13. Security Requirements - -- Never expose/persist: Ark API key, AK/SK, bearer tokens, Codex credentials, `.env` contents, unrelated host env values. A repository-wide and store-wide secret scan runs in CI/check and after the full demo run. -- Redact sensitive verification/log output before storing/displaying (tested with planted canary secrets that must not survive into events, store, or DOM). -- Semantic evidence may not reference secret/control-plane paths (negative-tested). -- No model-generated host shell execution; Git via argv `execFile`; acceptance commands run only inside the bounded disposable verifier. -- Sanitize branch names/IDs; bound all subprocess output and time. - ---- - -# 14. Performance and Demo-Time Targets (measured, not assumed) - -- Event persistence → UI visibility ≤ 1.5s (measured in E2E). -- Plane creation near-instant for the fixture (measured; log the number). -- Fixture verification completes in seconds (measured). -- Candidates execute concurrently (verified by overlapping timestamps). -- Zero network/package downloads during the fixture run (verified by the no-network verifier and a run log check). -- Collision → resolution → promotion well under two minutes; the full judge narrative fits comfortably in three (rehearsed and timed at least three times; timings recorded in the test report). - ---- - -# 15. Judge-Facing Demo Flow (the system must support this exact story) - -1. **Mission** — human asks Shepherd to implement the demo auth flow; two contracts appear, assigned to different Agents; Mission/contracts/Planes/timeline visible immediately. -2. **Independent work** — both Agents run in different Planes, make real changes, write manifests, pass local acceptance; both show locally verified. -3. **No Git conflict** — branches integrate textually clean; visibly explainable. -4. **Semantic collision** — `bearer-jwt` vs `http-only-session-cookie`; high-salience stream event; Plane Tree shows the integration point. -5. **Speculation** — two resolution Planes fork from the same commit; both visibly execute. -6. **Objective verification** — one candidate passes all mandatory checks; the other fails a real security/integration condition; evidence shown. -7. **Promotion** — deterministic selection, re-verification, head-consistency check, promotion; loser remains inspectable. -8. **Proof** — final protected state, green verification, event trail, and the legacy Agent page still works. - -Closing line: “Shepherd turns multi-Agent concurrency from a group chat into a controlled execution kernel: contract, detect, speculate, verify, promote.” - -Timing plan: 0:00–0:25 problem; 0:25–0:55 Mission + contracts; 0:55–1:20 independent verification; 1:20–1:40 no-Git-conflict → collision; 1:40–2:25 speculative candidates; 2:25–2:45 winner + promotion; 2:45–3:00 proof + summary. - ---- - -# 16. Implementation Plan (dependency order, with mandatory verification gates) - -Every phase ends with a **Gate**: the listed verifications performed and logged, phase tests green, `npm run check` green, and a build-log entry. Do not proceed through a failed gate. - -## Phase 0 — Baseline Lock -Run baseline + full acceptance flow + `npm run check`; record environment and pre-existing issues. -**Gate:** baseline evidence in build log; zero product changes. - -## Phase 1 — Walking Skeleton of the Hero Chain (fake agents, real kernel) -Before any live-model work, implement the entire kernel chain driven by deterministic fake agent executors that write real files/manifests into real worktrees: contracts → real Planes → real diff/authority checks → real verification containers → real collision detection → real candidate forking → real verification → real winner policy → real promotion into a real protected branch. -**Purpose:** the hero property is proven end to end with zero model variance before model integration multiplies risk. -**Gate:** an automated end-to-end kernel test passes using fake executors; the 8.8 winner-flip test passes; all five kernel invariants have their mutation checks recorded. - -## Phase 2 — Domain + Persistence Hardening -Full domain model, versioned migration, restart reconciliation, event stream. -**Gate:** migration test on captured fixture store; kill-and-restart tests at ≥3 mid-Mission points; secret-scan of store. - -## Phase 3 — Live Agent Runtime Integration -Replace fake executors with real Codex-in-container execution per Plane with distinct execution identities; prompt envelope; manifest ingestion; claim normalization + declared-key cross-check. -**Gate:** a real two-Agent Mission produces a real collision from real model executions at least twice consecutively; prompt secret-scan test; independent-session verification (candidates provably do not share threads). - -## Phase 4 — Scheduler, Integration Stage, Failure Matrix -DAG, concurrency, blocking, integration Plane, and every Section 12 category with fault-injection tests. -**Gate:** full failure-matrix suite green; parallel execution demonstrated with overlapping timestamps. - -## Phase 5 — Resolution Live + Cancellation/Retry/Tie -Live speculative resolution, concurrent candidates, retry, tie → human selection, cancellation. -**Gate:** journeys 5–7 (Section 11.6) pass headlessly; winner-flip test re-run against live path. - -## Phase 6 — API + UI Complete -All Section 11 surfaces on real data; polling; filters; Plane Tree from real Git state. -**Gate:** all eight Playwright journeys green with screenshots; Visual Acceptance Checklist applied to every screenshot; empty/loading/error states captured. - -## Phase 7 — Model-Assisted Reviewer + Group Chat polish -Bounded structured reviewer with degraded-state handling; `@Agent` routing; Agent summaries. -**Gate:** reviewer-disabled collision test still green; degraded-state test green. - -## Phase 8 — Demo Hardening -Reset command with hostile-path guard tests; pre-built image; timing measurements; three full timed rehearsals from a clean reset, including one on a machine/state other than the primary dev environment if available. -**Gate:** three consecutive clean full-demo runs logged with timings; reset-safety tests green. - -## Phase 9 — Feature Freeze + Post-Build Deliverables -No feature work past this point. Then, from the as-built system: - -- **A. `docs/SHEPHERD_ARCHITECTURE.md`** — Mermaid diagrams generated from real code: system/component view; Launchpad integration; labeled trust boundaries; browser→runtime flow; Mission/Contract lifecycle; Plane lifecycle; scheduling; collision path; resolution sequence; verification boundary; winner+promotion; persistence relationships; failure handling. One diagram explicitly optimized as the hackathon one-page diagram. Mermaid syntax validated with local tooling; regenerate if code changes later. -- **B. Final generated test suite** — after a testing-gap analysis of the as-built system, covering: starter regression; domain/state; persistence/migration; authority; path safety; task graph; Plane isolation; protected-branch invariants; contract execution; manifest validation; independent verification; claim validation; deterministic collision; candidate independence; winner policy; promotion; no-winner; interruption/restart; API; UI; fault injection; secret/redaction; reset safety; complete E2E demo flow. Run → inspect every failure → fix product defects (never weaken assertions) → rerun until stable → run the complete suite ≥5 consecutive times to detect flakiness → remove/fix flaky tests by root cause. Default suite requires no live Ark calls; a separate live-runtime smoke path covers what inherently needs it. -- **C. `docs/SHEPHERD_TEST_REPORT.md`** — exact commands, environment, categories, pass/fail, failure modes exercised, container/browser coverage, repeated-run results, known untested limitations with reasons, credential-requiring checks, final `npm run check` status, demo rehearsal timings. Nothing fabricated. -- **D. README update** — name, track, problem/rationale, one-sentence design, three primitives, architecture summary, setup, run commands, demo reset, exact demo steps, validation/test commands, links to A and C, security notes, honest limitations, future work. Preserve starter setup instructions. -- **E. Final audit** — no hard-coded winner; no static/fake evidence; no secrets in source/store/browser; no large stray artifacts; no broken starter behavior; no dead debug endpoints; no duplicate abandoned implementations; no stale docs; no failing tests; no reset hazards; no promotion bypass; no code change after reports without revalidation. - -**Gate:** all five deliverables exist, are consistent with the code, and the full suite + `npm run check` + one final clean demo run are green on the final commit. - ---- - -# 17. Definition of Done - -Complete only when **all** are true: - -**Baseline** — starter launches; Agent CRUD, legacy Playground, real execution, session continuity, workspace persistence all work; `npm run check` passes. - -**Kernel** — real Mission/contracts/Planes; real Agents execute in Planes; manifests required; authority checked against actual diffs; independent verification decides success; two locally-verified Agents expose a semantic collision with no textual Git conflict; evidence references real artifacts; two strategies fork from one immutable base; candidates execute and verify independently; no hard-coded winner (flip-test proven); failed/ambiguous resolution never promotes; winner re-verifies; head consistency checked; only the verified selected candidate reaches protected state. - -**UI** — all Section 11 surfaces exist on real data; collision, speculation, and promotion are visually obvious; all eight journeys pass; visual checklist clean. - -**Robustness** — every Section 12 category tested; interruption durable; unsafe scope cannot promote; secrets clean; reset safe; no falsely green UI; five kernel invariants mutation-checked. - -**Discipline** — `docs/BUILD_LOG.md` reflects the BVTE loop throughout; `docs/DEVIATIONS.md` lists any deviations with rationale; all Phase 9 deliverables complete and truthful. - -**Honest limitations to document** — one project / one mutating Mission; single-process JSON store; ordinary containers are not hardened multi-tenant isolation; semantic detection guarantees the implemented structured-claim protocol (normalized keys + declared-key cross-check), not universal program-semantic conflict detection; model-assisted analysis is best-effort; scoped authority guarantees unauthorized changes cannot be promoted, not that an Agent cannot physically write inside its disposable Plane; external side effects are outside the transaction model; candidate verification depends on declared acceptance-criteria quality; local PoC is the judging path. - ---- - -# 18. Final Executor Instruction - -Implement the complete chain — **Contract → Execute → Verify → Detect Collision → Fork Futures → Verify Futures → Promote Winner** — with the walking skeleton first, live integration second, and verification woven through every step per Section 0. Never mark anything done that you have not personally run and observed producing the specified output. Never fake, never weaken, never skip a gate. When blocked, reproduce, diagnose, fix the root cause, prove the fix, and log it. The finished system must be demonstrable from a clean reset, three times in a row, inside three minutes. diff --git a/docs/SHEPHERD.md b/docs/SHEPHERD.md deleted file mode 100644 index 3747a2e..0000000 --- a/docs/SHEPHERD.md +++ /dev/null @@ -1,357 +0,0 @@ -# Shepherd: Multi-Agent Kernel - -This document describes Shepherd's as-built design and trust boundaries. - -For current implementation status, defects, confidence, pending tests, task IDs, -and agent workflow, use [`docs/TASKS.md`](TASKS.md). For run instructions, use -[`docs/LOCAL_POC.md`](LOCAL_POC.md). If a status statement here conflicts with the -task ledger, the task ledger wins. The product requirements remain authoritative in -[`docs/PRD.md`](PRD.md), while -[`docs/BUILD_LOG.md`](BUILD_LOG.md) is immutable historical evidence for the commit -and phase named in each entry. - -## Current release-readiness snapshot - -Protected `main` is currently `f935fdb`. Issue #96 / draft PR #97 is an -exact-main release-remediation candidate; its tested product commit is `223a5fe`. -The candidate passes the literal repository check, an enforced 80% coverage gate, -48/48 functional browser flows across exact `1280x800` and `1440x900` viewports, -pinned Docker Terraform validation, dependency audit, the exact-tree zero-spend -live Runtime preflight, and both hosted PR workflows at `bb1a1df`. Exact commands, -counts, coverage, failures, and limitations are in -[`SHEPHERD_TEST_REPORT.md`](SHEPHERD_TEST_REPORT.md). - -The candidate removes the previously documented macOS host-share blocker from the -live test harness by using a named state volume and a non-root controller that -builds the current tree. The external Ark inference itself has not been executed in -this audit because it sends repository-derived prompts and code to the configured -provider and requires separate informed approval in the execution environment. -Independent UI review (#45), independent security review (#89), protected-main -integration, and three complete demo rehearsals also remain explicit evidence gaps; -none is inferred from the local or hosted candidate matrix. - -### Historical 2026-08-30 snapshot (retained) - -The estimates and candidate identities below record the earlier campaign state for -historical context. They are not the current release verdict; `TASKS.md` and the -test report above are authoritative. - -The canonical delivery branch is protected `main`. PR #53 promoted the verified -campaign through protected review at merge `5ccd0f1`; that exact merge passed the -post-integration repository gate recorded in `BUILD_LOG.md`. The latest product -feature in the campaign is PR #40 source `3d1a041`. The deterministic kernel, strict -persistence/API boundaries, live isolated Runtime adapter, Agent roles and scoped -authority, cancellation/retry/selection/reset controls, Project Group lifecycle -storage, and all six requested UI surfaces are implemented. - -Reviewed candidate PR #57 (`e1fe067`) improves the primary deterministic demo -without claiming protected-main integration: users create Frontend and Backend -Agents, opt each private chat into **Route through Shepherd**, and describe the two -incompatible transports in their own words. The exact bounded prompts become two -durable Execution Contract objectives and feed the existing verified -Plane/collision/resolution/promotion kernel. The former Shepherd Agent/transport -selectors are removed. Literal checks, the two-viewport browser journey, and -independent security/UI re-reviews pass; `TASKS.md` records the remaining integration -gate and keeps the separate Project Group journey open. - -Stacked candidate PR #59 extends that private-chat route beyond the fixed auth -phrasing. Shepherd is now the default for every Agent role, while a visible toggle -retains direct Playground chat. Incomplete requests are stored only as clarification -drafts; no executable entity exists until the user supplies a concrete change, -writable project-relative artifacts, and explicit `Acceptance:` evidence. Confirmed -requests run as one authority-bounded Contract through an isolated Plane, strict -manifest ingestion, independent verification, integration, final re-verification, -protected-head compare-and-swap promotion, and exact verified-artifact sync to the -Agent workspace. This does not claim free-form DAG decomposition or complete the -separate Project Group issue #41. - -This is a strong Track 1 proof of concept, not a full-PRD completion claim. Current -hackathon-submission completion is **82%**. The core middleware demonstration itself -is **90% demo-ready** because the primary deterministic journey is functional and -browser-verified; the remaining percentage is concentrated in Project Group's full -work path, one judge-visible denial, final live/stability/security gates, rehearsal, -and submission artifacts. The broader PRD intentionally retains additional work -after the hackathon cut. `TASKS.md` remains authoritative when status changes. -The 82% figure is a dependency- and rubric-weighted estimate of the required -hackathon work packages; it is not the raw ratio of audited full-PRD ledger rows. - -| Hackathon completion dimension | Weight | Evidence completion | Contribution | -|---|---:|---:|---:| -| Core trusted middleware and preserved starter behavior | 50% | 96% | 48% | -| Judge-visible normal, collision, human, and denial journeys | 20% | 80% | 16% | -| Integrated live, security, stability, performance, and rehearsal gates | 20% | 65% | 13% | -| Architecture, test report, README, and final evidence reconciliation | 10% | 50% | 5% | -| **Current minimum-cut completion** | **100%** | | **82%** | - -The evidence-completion values are rounded judgments against the acceptance gates -listed in `TASKS.md`; future updates must change the underlying gate evidence, not -just the percentage. - -### Implemented and demonstrable Track 1 features - -| Capability | Backend behavior and evidence | Current confidence | -|---|---|---:| -| Preserved starter platform | Agent create/edit/start/stop/delete, Playground messages, Runs, workspaces, session continuity, persistence, and local container execution remain functional. | 95% | -| One-command local PoC | The launcher reads `.env`, localizes Docker-default paths, builds the Runtime and application, performs mount/startup checks, and serves the authenticated local UI. | 95% | -| User-selected specialists | Reviewed candidate PR #57 lets a user prompt Frontend and Backend Agents separately in private chat. Server-side bounded transport parsing, restart-safe prompt records and serialized intake bind both exact prompts to one Mission; role, readiness, authority, idempotency and deletion races are revalidated before execution. | 98% candidate; integration pending | -| General private-chat Contract intake | PR #59 is integrated and makes Shepherd routing the default for all roles. Issue #81's integration-verified correction additionally fails closed on unsafe, ambiguous, negated, conditional, privileged, credential, external/network and destructive wording; it requires an exact project-only safety boundary, a direct quoted artifact, and literal acceptance evidence. Clarifications create no executable entity, unsafe intent remains sticky, and explicit replacement permits safe recovery. Confirmed work continues through scoped authority, isolated Git, strict manifests, independent verification, final CAS promotion and exact artifact sync. | 100% scoped deterministic integration | -| Execution Contracts | Shepherd persists and displays Agent, Mission, Plane, objective, dependencies, semantic scope/claims, contextual inputs, scoped authority, artifacts, acceptance profile/checks, manifest path, and timestamps. | 96% | -| Isolated Planes | Each Contract and candidate executes in its own Git worktree from a trusted immutable base; Agents receive Git-free authority-filtered exports rather than protected repository access. | 94% | -| Independent verification | Registry-owned, credential-free, no-network checks inspect the exact committed output. Agent-authored manifests cannot self-certify acceptance. | 95% | -| Semantic collision detection | Independently valid frontend cookie and backend bearer outputs yield an `auth.transport` collision even when ordinary Git integration is clean. | 98% | -| Competing resolution futures | Cookie and bearer Resolution Planes fork from the same immutable integration commit, execute independently, and must pass the same project invariant. | 96% | -| Evidence-derived promotion | Deterministic selection uses persisted verification evidence; the winner receives final authority inspection, independent re-verification, expected-HEAD comparison, and compare-and-swap promotion. The loser remains inspectable. | 95% | -| Human escalation | Disabled/non-unique automatic resolution produces durable `attention_required` evidence and an internal human-review ticket. Only independently passing candidates can be selected manually and promoted through the same gate. | 92% | -| Durable audit and recovery | Typed lifecycle events, redaction, request idempotency, serialized schema-validated persistence, cancellation/reset, restart classification, Plane cleanup, and representative crash recovery are implemented. | 93% | -| Bounded model assistance | `SHEPHERD_MODEL` may perform one validated advisory semantic review. It cannot verify, choose, execute arbitrary commands, or promote; deterministic logic remains authoritative and degrades explicitly when review fails. | 90% | -| Middleware observability UI | Contract stream, execution timeline, Plane tree, collision/candidate evidence, Project Group lifecycle, Settings, and private Agent chat expose real backend state rather than static success screens. | 90% | -| Automated assurance | Exact issue #81 integration evidence includes launcher 5/5, Server 842 passed plus two explicit live skips, Web 20/20, strict production/test type checks, both builds, and ten combined browser journeys across both required viewports. Independent UI/security review passed with no High/Medium finding. The separately attempted exact live Mission failed because the Agent result manifest was missing, so this evidence does not claim live end-to-end completion. | 98% deterministic; live gate open | - -Confidence is scoped to the recorded deterministic/local evidence. It is not a claim -that the open exact-head live, final security, stability, and rehearsal gates passed. - -### Pending but feasible before the end of today - -These are the minimum remaining submission items, not every optional PRD extension. -They are feasible today with three to four non-overlapping owners, prompt review, -stable CI, and a working live provider/Runtime. Exact ownership and acceptance gates -are in the linked issues and `TASKS.md`. - -| Work package | Required outcome | Estimate | -|---|---|---:| -| [Project Group journey #41](https://github.com/kyashp/shepherd/issues/41) | Bounded unmentioned Shepherd reply, click/type targeted Contract creation, verified manifest-derived Agent summary, and the full two-viewport E2E journey. | 2–4 h | -| [Failure matrix #42](https://github.com/kyashp/shepherd/issues/42) and [visible denial #43](https://github.com/kyashp/shepherd/issues/43) | Complete the demo-critical typed failure proofs, then visibly deny an unauthorized diff with retained evidence and no promotion. | 2–4 h | -| [Startup composition #44](https://github.com/kyashp/shepherd/issues/44) | Make automatic resolution and maximum Plane concurrency startup settings causally control `ShepherdService` while preserving later persisted choices. | 0.5–1 h | -| [UI gate #45](https://github.com/kyashp/shepherd/issues/45) and [performance #46](https://github.com/kyashp/shepherd/issues/46) | Verify—not redesign—all required surfaces/states at both viewports and record judge-path latency/overlap. | 2–3 h | -| [Live/host gate #47](https://github.com/kyashp/shepherd/issues/47) | One bounded exact-head live Shepherd Mission, legacy continuity, and presentation-host compatibility when applicable. | 1–2 h plus provider latency | -| [Stability #48](https://github.com/kyashp/shepherd/issues/48) and [security #49](https://github.com/kyashp/shepherd/issues/49) | Five consecutive literal gates, final trust-boundary/canary review, and causal fixes for any High/Medium finding. | 2–4 h plus fixes | -| [Demo rehearsal #50](https://github.com/kyashp/shepherd/issues/50) | Three clean reset-to-completion runs under three minutes with the normal and human/denial story. | 1–2 h | -| [Submission package #51](https://github.com/kyashp/shepherd/issues/51) | One-page architecture, exact test report, final README, reconciled docs, and dead/debug/artifact review. | 2–3 h | - -Serial execution is approximately **13–23 hours**. With dependency-aware parallel -work, the realistic elapsed estimate is **6–10 hours**, with **8–12 hours** reserved -for CI, live-provider, or integration corrections. This is feasible today but not -guaranteed; feature work must freeze early enough for security, stability, and three -actual rehearsals. - -Additional PRD work such as arbitrary dependency-wave scheduling, extended failure -journeys, duration estimates, mid-Mission restart UI reconciliation, and broader -retry/cancellation matrices is valuable but not required for the minimum Track 1 -submission cut. - -### Track 1 rubric assessment - -This grading uses the weights in `TECHJAM.md`, observed repository/browser evidence, -and the no-middleware starter behavior as the baseline. It is a dated internal -assessment, not an official judge score. - -| Track 1 category | Weight | Current score | Evidence and deductions | -|---|---:|---:|---| -| End-to-end middleware behavior | 40 | **34/40** | The complete deterministic Contract → Plane → verification → semantic collision → competing futures → re-verification → promotion/human-review path is real backend behavior and browser-visible. Deducted for unfinished full Project Group action/reply, judge-visible unauthorized denial, and current exact-head live Mission. | -| Technical design and integration | 25 | **23/25** | Strong trusted-kernel placement, typed contracts/state, authority intersection, Git/workspace isolation, credential-free verifier, deterministic model containment, persistence and CAS promotion. Deducted for fixed hero scheduling and startup-setting composition gap. | -| Verification and robustness | 20 | **18/20** | Large causal suite, strict types/builds, real Git/container boundaries, recovery/security tests, two-viewport journeys, independent reviews, hosted CI. Deducted until the final integrated security review and five consecutive stability runs pass. | -| Demo and reproducibility | 15 | **10/15** | One-command launcher, runbook, polished evidence UI, reset/manual selection, and verified browser hero exist. Deducted for missing three rehearsals, final live/host gate, architecture page, exact test report, and final README freeze. | -| **Weighted total** | **100** | **85/100** | Strong competitive prototype with concentrated, actionable submission gaps. | - -**Current confidence of winning: 74/100.** The solution is unusually deep and -defensible for Track 1: the Agent cannot self-certify, semantic conflicts are -resolved through evidence-backed parallel futures, and protected promotion is owned -by trusted middleware. Winning confidence is below the rubric score because judging -also depends on competitor quality, clarity, timing, and live-demo reliability. - -If issues #41–#51 pass exactly as written, projected rubric performance is -**92–95/100** and projected winning confidence is **84/100**. Novelty confidence is -**91/100**: the combination of typed Agent Contracts, independently verified -semantic claims, same-base competing resolution Planes, and final CAS promotion is -materially more distinctive than ordinary multi-Agent chat or task routing. - -## Accepted design contract - -Shepherd is a trusted execution kernel placed beside—not inside—the starter `AgentService`. - -```text -Human / UI - ↓ validated plan or trusted demo definition -Shepherd control plane - ↓ typed Execution Contracts -isolated contract Planes - ↓ actual-diff authority validation -credential-free independent verification - ↓ normalized, evidence-backed claims -deterministic collision detection - ↓ competing resolution Planes from one immutable SHA -credential-free independent candidate verification - ↓ deterministic winner policy or human tie decision -final re-verification + expected-HEAD promotion gate - ↓ -managed protected branch -``` - -### Model responsibilities - -- `ARK_MODEL` runs logical coding Agents in their isolated contract/candidate Plane. -- `SHEPHERD_MODEL` is reserved for bounded structured planning and best-effort semantic review. When configured, Mission orchestration calls the bounded reviewer once after verified Contract integration and before deterministic collision detection. -- Model output is always untrusted. It cannot certify verification, choose a winner by opinion, submit shell commands, mutate the protected branch, or bypass authority. -- Deterministic collision detection carries the demo-critical guarantee. Model-assisted review may raise advisory findings and emits an explicit degraded event on failure. - -The deterministic executor remains available as an explicit, labelled mode and proves -the kernel independently of model variance. In live mode, each Contract and resolution -candidate uses a fresh `ARK_MODEL` Codex turn. Historical Phase 3 opt-in evidence -records two live Missions, each containing two Contract and two candidate turns; see -the exact scoped entries in `BUILD_LOG.md`. This does not replace the open exact-head -continuity gate in `LIVE-01`. The composed -`SHEPHERD_MODEL` reviewer smoke made exactly one external request, completed with two -validated findings, and preserved the deterministic outcome. Adapter normalization -and reviewer authority containment are audited. The separate current live Shepherd -Mission and legacy-continuity gate remains open as `LIVE-01`. - -Recovery remains deterministic across the Phase 2 and Phase 3 boundaries. No LLM is -called during startup classification, evidence validation, interruption mapping, -cleanup, or trust adoption, and no model opinion can turn interrupted work green. - -### Deterministic responsibilities - -Trusted server code owns schemas, state transitions, scope intersection, actual Git-diff inspection, manifest ingestion, evidence validation, acceptance-profile lookup, no-network verification, collision predicates, candidate base equality, winner rules, final re-verification, protected-head comparison-and-swap, persistence, redaction, and event ordering. - -### Security boundary - -- Agents receive only generated execution identities and authority-filtered, Git-free - exports; they never receive a trusted linked Plane worktree or protected Git - metadata. -- A live Codex control process necessarily receives the scoped Ark credential and - bridge access to call the configured provider. Its generated shell policy inherits - no credential, and startup proves sandboxed spawned code cannot listen or connect. -- The verifier receives no model/API key, application token, Codex session, Docker socket, unrelated host environment, or network. -- In `container-volume` mode the control plane itself is given the container engine - socket, which is equivalent to control of the engine; the verifier boundary above - is unchanged. Every Agent and verifier mount becomes a subpath of one named - volume, containment is asserted against the canonical path so a symlink cannot - redirect it, and an escaping source throws instead of reverting to a bind mount. - Recorded as an accepted deviation in `docs/DEVIATIONS.md`. -- Browser and model inputs select trusted identifiers; neither can provide host paths or executable commands. -- `.shepherd/result.json` is the sole Agent-written control artifact exception and is never promoted. -- Unsafe or ambiguous outcomes stop in an evidenced non-green state. - -## Deterministic Mission flow (Phase 1) - -1. Shepherd creates or reuses only its sentinel-marked managed fixture repository and records the immutable protected-branch base SHA. -2. Two Contracts receive intersected Agent/Contract authority and separate trusted Git worktrees. Each executor receives a separate authority-filtered, Git-free export with an opaque execution identity; the executors run concurrently and write project files plus a result manifest. -3. Trusted code imports the export into its Plane only after rejecting unsafe file types/metadata and proving the actual imported diff stays within authority. It then validates the manifest, removes the control artifact, and creates a trusted commit. -4. The independent verifier materializes a fresh read-only snapshot of that exact commit and runs only registry-owned commands in disposable containers. Passing mandatory evidence—not the Agent report—moves each Contract to `verified`; independently observed project facts must also corroborate semantic claim values before collision detection. -5. A clean integration worktree merges both commits. Normalized exclusive claims for `auth.transport` conflict despite no textual Git conflict. -6. Cookie and bearer reconciliation Planes fork from the same integration SHA and execute concurrently. Project-level verification objectively distinguishes them. -7. The deterministic policy selects from persisted evidence. The chosen Plane is re-checked for authority, re-verified, compared with the persisted decision and expected protected HEAD, then promoted through one trusted compare-and-swap path. -8. The loser remains inspectable, every transition is persisted as a bounded event, and any unsafe/ambiguous result stops without promotion. - -The public API returns logical IDs, short Git evidence, and domain state, but strips host repository/worktree/workspace paths. The approved `.shepherd/result.json` relative control path may appear as declared evidence; it is not a host path and is absent from every promoted commit. - -## Live Plane execution (Phase 3) - -At startup, `auto` resolves to live only when the container Runtime and usable Ark -Agent configuration are both present. `live` is an explicit fail-closed request; -`deterministic` remains the stable no-model kernel/demo mode. The resolved mode is -reported by the application. - -Before accepting live work, Shepherd reconciles only exact installation-owned -Runtime containers and private artifacts, then runs a credential-free preflight. The -preflight requires `codex-cli 0.111.0`, a non-root read-only-root container, and the -inner `workspace-write` sandbox. Inside that sandbox it proves `/workspace` is -writable, `/codex-home` is not, and TCP listen/connect operations are denied. A failed -or partially cleaned preflight prevents startup. The issue #81 candidate also plants -a parent-only fake credential canary and scans readable process environments from -inside the real Codex sandbox; visibility fails startup with bounded -`credential_isolation_failed` evidence. - -For each Contract or resolution candidate: - -1. Trusted code creates a new authority-filtered, Git-free execution export and a - versioned bounded prompt envelope. -2. Shepherd creates a unique private `CODEX_HOME` below its sentinel-guarded root and - writes a minimal secret-free Codex config with a key-free shell environment. -3. A disposable container is created with only that export and private home mounted. - The prompt is absent from argv and is sent on standard input to - `codex exec --ephemeral --json --sandbox workspace-write - --skip-git-repo-check -C /workspace -` after attaching by immutable container ID. -4. Exactly one fresh thread-start event is required. No prior session is resumed or - shared. The raw thread ID is hashed, checked for reuse, discarded, and only the - SHA-256 fingerprint is persisted privately. -5. The ordinary trusted import, actual-diff authority, independent verification, - collision, candidate, re-verification, and protected-head CAS gates remain - authoritative. Candidate verification must also corroborate the implemented - semantic target against its persisted strategy. -6. The private home, execution export, and exact-owner container are removed on - success, failure, timeout, cancellation, and restart reconciliation. - -The Codex control process needs bridge networking to reach Ark. Model-authored shell -processes remain inside the preflight-proven inner sandbox. The acceptance verifier is -a different credential-free, session-free, no-network container and never relies on -the Agent's own report. - -## Durable recovery model (Phase 2) - -The JSON store is a single-server-per-data-root design. Within that process, mutations -are serialized and each publish is schema-validated, scrubbed, written through a -unique exclusive temporary file, synced, and atomically renamed. Running multiple -servers against one data root is unsupported and must be prevented operationally; it -is not presented as distributed durability. - -On startup Shepherd first validates its installation nonce/marker, managed-root and -project sentinels, canonical Agent workspaces, Plane roots, Git registration, protected -ref, checked-out branch, index, and worktree. It never selects a repository or Plane -from persisted path text. Any ambiguity is made durable and startup aborts rather than -silently adopting state. - -The only recoverable promotion gap is represented by a durable `promoting` Candidate -with passing promotion evidence linked to its verified resolution Plane. That evidence -must repeat exactly the candidate's trusted mandatory suite. The observed protected -HEAD must be that Plane's immutable HEAD and a descendant of the persisted expected -HEAD; the server-derived resolution branch/worktree must be registered, clean, and -exactly checked out. All other movement is untrusted and leaves the Project fenced for -explicit reset/recovery. - -Verifier cleanup uses a persisted installation nonce plus configured Runtime identity. -The separate establishment marker makes a missing nonce after first boot a hard error, -while a first upgrade can establish both records once. These files and all Shepherd -identity metadata are bounded regular files opened with no-follow and non-blocking -semantics. - -## Configuration - -Real secrets belong only in ignored `.env`. - -| Variable | Purpose | -| --- | --- | -| `ARK_API_KEY` | Credential for the configured OpenAI-compatible Responses API. | -| `ARK_MODEL` | Coding Agent model. | -| `SHEPHERD_MODEL` | Bounded planning/advisory-review model; defaults to `ARK_MODEL` when empty. When its configuration passes the adapter-aligned readiness gate, Mission orchestration injects one advisory review after verified Contract integration. | -| `ARK_BASE_URL` | Responses-compatible API root. | -| `APP_AUTH_TOKEN` | Optional shared bearer boundary for loopback-only development. Empty permits only loopback Host values, no cross-origin browser Origin, and CLI-style no-Origin loopback requests. A public bind fails startup without a 24+ non-placeholder URL-safe token. Any configured token is enforced on every protected `/api/` route with a length-checked constant-time comparison. | -| `PUBLIC_BIND_ADDR` | Optional explicit public listener address used by Compose/deployment profiles. It participates in the same fail-closed public-bind/token check as `HOST`; it cannot be used to publish a tokenless service. | -| `RUNTIME_PROVIDER` | Starter Agent runtime (`local-process` or `container`); Shepherd verification always uses its independent container boundary. | -| `CONTAINER_STATE_ROOT` | Optional. With `CONTAINER_STATE_VOLUME`, addresses every mounted state root as a subpath of one named volume instead of a host bind mount, so the Agent sandbox can govern its workspace on a host whose filesystem reaches the engine through a virtual machine. Required together; a half-configured pair fails at startup, and a source outside the root throws rather than falling back to a bind mount. | -| `CONTAINER_STATE_VOLUME` | Optional. Name of that volume. Mounts are emitted with `volume-nocopy=true`, without which the engine serves an empty subpath using the image's own `/workspace` ownership and the Runtime loses write access before the sandbox is applied. | -| `SHEPHERD_ROOT` | Sentinel-guarded managed fixture repositories and Plane worktrees; defaults below `APP_DATA_DIR`. | -| `SHEPHERD_CODEX_HOME_ROOT` | Sentinel-guarded parent for one private, ephemeral live-Plane `CODEX_HOME` per execution; must be inside `APP_DATA_DIR` and separate from shared Agent and managed Shepherd roots. | -| `SHEPHERD_EXECUTION_MODE` | `auto`, `live`, or `deterministic`. `auto` selects live only with usable Ark configuration plus the container Runtime; explicit live fails closed otherwise. | -| `SHEPHERD_DEMO_MODE` | Enables the fixed, path-free demo Mission and reset controls. | -| `SHEPHERD_AUTO_RESOLUTION` | Startup default for evidence-derived automatic selection, composed into `ShepherdService`. Seeds a pristine store only while the persisted value is still the factory default, so a later Settings update stays authoritative. | -| `SHEPHERD_DELETE_COMPLETED_PLANES` | Retention startup control. The current UI/service keeps completed Planes inspectable; final cleanup behavior remains subject to evidence-retention requirements. | -| `SHEPHERD_MAX_PARALLEL_PLANES` | Startup Plane-capacity setting, composed into `ShepherdService`. Minimum 2, matching the persisted schema, `updateSettings` and the API; defaults to the persisted default. Seeds a pristine store only while the persisted value is still the factory default, so a later Settings update stays authoritative. | -| `SHEPHERD_CONTRACT_TIMEOUT_MS` | Maximum contract execution duration. | -| `SHEPHERD_CANDIDATE_TIMEOUT_MS` | Maximum candidate execution duration. | -| `SHEPHERD_VERIFICATION_TIMEOUT_MS` | Maximum duration accepted by the independent verifier. | -| `SHEPHERD_VERIFIER_IMAGE` | Pre-built no-network verification image; defaults to `CONTAINER_RUNTIME_IMAGE`. | -| `CODEX_SANDBOX_MODE` | Must resolve to `workspace-write` for live Shepherd execution; startup preflight proves its filesystem and socket restrictions. | - -No configured secret value is documented, persisted into Shepherd state, sent to the verifier, or rendered in the browser. - -## Evidence and further documentation - -- `docs/BUILD_LOG.md` — executed commands and bounded observations. -- `docs/DEVIATIONS.md` — accepted clarifications and material deviations. -- `docs/TASKS.md` — authoritative current status, completion cut, tasks, and agent workflow. -- `docs/LOCAL_POC.md` — startup, troubleshooting, and exact manual demo runbook. -- `docs/TECHJAM.md` — Track 1 competition context, judging, and deliverables. -- `docs/ui-review/` — inspected UI evidence by viewport and journey. -- `docs/ARCHITECTURE.md` — integrated as-built component/trust-boundary diagram. -- `docs/SHEPHERD_TEST_REPORT.md` — exact candidate commands, failures, results, and limitations. diff --git a/docs/SHEPHERD_TEST_REPORT.md b/docs/SHEPHERD_TEST_REPORT.md deleted file mode 100644 index 6ab1474..0000000 --- a/docs/SHEPHERD_TEST_REPORT.md +++ /dev/null @@ -1,102 +0,0 @@ -# Shepherd release test report - -**Observed:** 2026-08-31, Asia/Singapore - -**Protected-main base:** `f935fdb5581849f8377f20922e254c55d34e5de0` - -**Tested product commit:** `223a5fe00f977013d4bf5df6560016a1719c8d11` - -**Candidate:** [issue #96](https://github.com/kyashp/shepherd/issues/96) / -[draft PR #97](https://github.com/kyashp/shepherd/pull/97) - -This report records commands actually observed on the named candidate. It does not -claim protected-main integration, independent security/UI review, a paid provider -request, or a complete demo rehearsal. - -## Environment - -| Component | Observed version | -|---|---| -| macOS host | `26.5.2` / `arm64` | -| Node.js | `v26.5.0` | -| npm | `11.17.0` | -| Playwright | `1.62.1` | -| Docker client/server | `29.6.1` / `29.6.1` | -| Terraform validator | pinned `hashicorp/terraform:1.9.8` container | -| Volcengine provider | `volcengine/volcenginecc` `0.0.58` | - -## Final observed matrix - -| Gate | Result | Scope | -|---|---:|---| -| `npm run check` | Pass | root Node tests 26/26; Server 856 passed and 3 explicit opt-in skips; Web 20/20; strict production/test typechecks; Web and Server production builds | -| `npm run test:coverage` | Pass | Server: 86.15% statements, 80.05% branches, 91.46% functions, 88.03% lines. Browser: 88.50% statements, 80.18% branches, 87.64% functions, 92.37% lines. Every production source file is required; all four thresholds are 80%. | -| full Playwright matrix | Pass, 48/48 | 24 functional flows at both `1280x800` and `1440x900`, one worker, normal non-instrumented production build | -| `npm run test:terraform` | Pass | formats, initializes, and validates a disposable module copy with the pinned Terraform image; working tree is not populated with provider state | -| `npm run test:shepherd:live:preflight` | Pass | builds the exact candidate Runtime and non-root controller images, uses a named state volume and engine socket, discovers exactly one live test, and cleans temporary resources; no model request | -| `npm audit --json` | Pass | 0 vulnerabilities | -| `git diff --check` and bounded secret scan | Pass | no whitespace error, tracked credential, state, or generated Terraform artifact found | -| hosted PR workflows at `bb1a1df` | Pass | `Node 22 / npm run check` run `33389614355` in 2m59s; `Required checks` run `33389614223` in 3m01s | - -The clean coverage run executes the complete Server suite first, then rebuilds the -Web app with browser instrumentation and runs 24 Chromium flows. It restores the -ordinary production build before exit. The browser release matrix was then run -separately at both required viewports, so the 48/48 result is not an -instrumentation-only observation. - -## Failures found and corrected - -The first exact-main browser matrix passed 34/38. The audit then reproduced and -fixed the underlying defects rather than weakening assertions: - -- Project Group could lose a fast typed character or move the caret because a - controlled input update raced the mention action. -- Agent edit could render before authority presets and Agent state had hydrated; - a rapid custom-authority toggle could then erase edited values. -- the accepted shell could acquire a one-pixel document scroll, and Settings icon - buttons lacked explicit accessible names. -- durable collections were unbounded and Agent creation could partially publish; - capacity now fails with a bounded `507` and creation is atomic. -- a tokenless server had no loopback Host/same-origin Origin boundary, and public - binds could start without a token. -- the live gate forced host bind mounts, did not build the exact working tree, and - could not cross the documented macOS Docker Desktop sandbox boundary. -- no executable coverage provider/threshold or reproducible Terraform validator - existed. -- runtime credentials could enter Terraform input, cloud-init, plan, and state. - -Causal regression coverage was added for each corrected behavior. The accepted UI -theme and layout were preserved. - -## Explicitly incomplete evidence - -- **External Ark inference:** not executed in this audit. The live command sends - repository-derived prompts and code to the configured Ark endpoint. The local - execution environment requires a separate informed approval for that data - transfer. The zero-spend exact-tree Docker preflight passes, so the earlier - host-share sandbox-probe blocker is no longer the current blocker. -- **Independent review:** issue #45's read-only UI review and issue #89's required - independent security review cannot be self-certified by the author of this - remediation. The deterministic UI and security regressions pass locally. -- **Integration:** both hosted candidate workflows pass, but this remains candidate - evidence until an integrator merges it and the protected-main rerun passes. -- **Rehearsal/delivery:** three clean timed demo rehearsals and any genuinely - available second-machine run remain separate evidence work. This report does not - infer them from automated tests. - -## Reproduction - -```bash -npm ci -npm run check -npm run test:coverage -PLAYWRIGHT_BROWSERS_PATH=/path/to/browser-cache \ - ./node_modules/.bin/playwright test --config=playwright.config.ts -npm run test:terraform -npm run test:shepherd:live:preflight -npm audit --json -``` - -The live provider gate is intentionally omitted from the default sequence. Run it -only with the documented opt-in, configured ignored environment file, bounded test -scope, and authorization to send repository-derived payloads externally. diff --git a/docs/TASKS.md b/docs/TASKS.md deleted file mode 100644 index e785d69..0000000 --- a/docs/TASKS.md +++ /dev/null @@ -1,317 +0,0 @@ -# Shepherd Completion Task Ledger - -**Canonical implementation branch:** protected `main`. - -**Latest protected-main integration:** `f935fdb` (PR #95), including the issue #48 -stability campaign and issue #89 High remediations. Issue #96 / draft PR #97 is an -exact-main release-readiness candidate based on that SHA; its tested product head is -`223a5fe`. Candidate evidence is not an `I` claim until protected-main integration -and the hosted rerun complete. Exact observations are in `BUILD_LOG.md` and -`SHEPHERD_TEST_REPORT.md`. - -**Reconciled:** 2026-08-31, Asia/Singapore - -**Requirement authority:** [`PRD.md`](PRD.md) - -**Runbook:** [`LOCAL_POC.md`](LOCAL_POC.md) - -**As-built design:** [`SHEPHERD.md`](SHEPHERD.md) - -**Track 1 brief:** [`TECHJAM.md`](TECHJAM.md) - -**Reproduced defects:** [`FIXES.md`](FIXES.md) - -This is the canonical entry point and work queue for the protected-`main` completion -campaign. The PRD still defines the required scope; this ledger does not narrow it. -`DEVIATIONS.md` records interpretations and environment limits, `FIXES.md` records -reproduced defects, and `BUILD_LOG.md` preserves exact historical evidence. - -## Working contract - -- `READY` means an owner may begin now. `BLOCKED` names the dependency. - `HELD_EXTERNAL` means an open external PR/branch already owns the work and the - worker/fixer must not edit it. `AUDITED` requires independent end-to-end evidence - on the exact integrated `main` SHA. -- The worker implements the smallest coherent task, adds causal tests, records - exact evidence in `BUILD_LOG.md`, then updates completion confidence and test - counts. The auditor independently reruns the task and adjacent PRD flow before - setting `AUDITED`. The fixer takes only entries in `FIXES.md` and preserves the - named failure contract. -- No product task is complete at confidence below 100. Scoped 100 means every - listed acceptance gate for that row passed; it does not claim unknown defects are - impossible. -- Do not call a branch implementation integrated until its commit is an ancestor of - `origin/main` and the post-integration gate passes. -- Default tests are model/network-free. Use live Ark capacity only for the two - explicitly labelled sparse live gates. - -Before editing, follow the ownership workflow in the root `AGENTS.md`: check issues, -PRs, remote branches, and worktrees; claim one task; immediately push its narrow -branch; record owned files and exclusions; then open a linked draft PR when there is -a comparable commit. The integrator alone merges sibling work. True stacks must name -their parent and merge order. - -A task is ready only when its issue names the ID, PRD references, current and -expected behavior, acceptance gates, owned files, exclusions, dependencies, and test -plan. It is done only after the smallest coherent implementation, causal tests, -targeted and adjacent checks, the applicable `C/B/S/U/L` gates, independent review, -integration into `origin/main`, and an exact integrated rerun are recorded. - -Use this intake shape for a newly discovered defect: - -```text -TASKS/PRD ID; assessed commit; viewport/runtime; reproduction; -expected; actual; frequency; safety/data impact; redacted evidence; -proposed causal acceptance test; known ID or NEW -``` - -## Hackathon-ready completion cut - -All incomplete rows remain PRD work. The following subset is the minimum required to -call the repository presentation-ready; “additional” below means optional only for -the hackathon cut, not removed from the PRD. - -### Required before submission - -- **Exposed product flow ([issue #41](https://github.com/kyashp/shepherd/issues/41)):** - `GC-02/05`, `GC-03/04`, `GC-06`, and `E2E-03` so the - visible Project Group surface performs real bounded work rather than dead-end chat. -- **Truthful failure story:** `FM-01` - ([#42](https://github.com/kyashp/shepherd/issues/42)), then `UI-01` and `E2E-04` - ([#43](https://github.com/kyashp/shepherd/issues/43)), - denial journey, while preserving every broader failure row for full PRD follow-up. -- **Advertised controls ([issue #44](https://github.com/kyashp/shepherd/issues/44)):** - `ST-01`; settings shown in the demo must causally compose. -- **Baseline Agent lifecycle ([issue #66](https://github.com/kyashp/shepherd/issues/66)):** - integrate `CRUD-01` so an abandoned clarification draft does not permanently - trap its Agent while durable Shepherd evidence remains protected. -- **Judge evidence:** `UI-GATE` ([#45](https://github.com/kyashp/shepherd/issues/45)), - `PERF-01` ([#46](https://github.com/kyashp/shepherd/issues/46)), the remaining - `OPS-06` host gate ([#47](https://github.com/kyashp/shepherd/issues/47)) and - `LIVE-01` ([#65](https://github.com/kyashp/shepherd/issues/65), split out of #47 - because it cannot run on the affected host), - `STABILITY` ([#48](https://github.com/kyashp/shepherd/issues/48)), `SEC-REVIEW` - parts 4-5 ([#89](https://github.com/kyashp/shepherd/issues/89), successor to the - closed [#49](https://github.com/kyashp/shepherd/issues/49)), and `DEMO-REHEARSAL` - ([#50](https://github.com/kyashp/shepherd/issues/50)). `OPS-06` also requires a - passing rerun on the actual presentation - host when that host is the affected macOS environment. -- **Submission package ([issue #51](https://github.com/kyashp/shepherd/issues/51)):** - `DEL-01`–`DEL-05`, including the one-page architecture, - exact test report, final README, reconciled documents, and final cleanup review. - -### Additional full-PRD work after the hackathon cut - -- `F-07/08`, `F-09`, the remaining `FM-01` failure variants, and `E2E-05`–`E2E-08`. -- `SCH-02` and `SCH-01` for arbitrary validated DAG waves beyond the fixed hero flow. -- `UI-02` for trusted duration estimates distinct from actual timing. -- A second-machine rehearsal when it is genuinely available and is not the selected - presentation host. - -## Requirement and code navigation - -| Need | Start here | -|---|---| -| Workflow, status, and evidence discipline | PRD 0; this working contract; `BUILD_LOG.md` | -| Goals, architecture, domain, kernel, API, persistence | PRD 4–10; `SHEPHERD.md`; P0 rows below | -| UI surfaces and journeys | PRD 11; required-product and P1 rows; `UI.jpeg` | -| Failures and recovery | PRD 12; failure/recovery rows; `FIXES.md`; `DEVIATIONS.md` | -| Security | PRD 13; `SEC-REVIEW`; `SECURITY.md` | -| Performance and judge flow | PRD 14–15; `PERF-01`; `DEMO-REHEARSAL`; `LOCAL_POC.md` | -| Final gates and deliverables | PRD 16–17; `STABILITY`, `LIVE-01`, and `DEL-01`–`DEL-05` | - -Primary implementation areas: - -- Mission scheduling/state/resolution/promotion: `apps/server/src/shepherd/{service,state-machine,scheduler,resolution,promotion-gate}.ts` -- Runtime, manifest, authority, and verification boundaries: - `apps/server/src/shepherd/{codex-executor,prompt,manifest,authority,verifier,model-reviewer}.ts` -- Git/demo/recovery: `apps/server/src/shepherd/{git-client,plane-manager,demo-project,recovery}.ts` -- Persistence/API/composition: `apps/server/src/{database-schema,database,store,agent-service,app,index,config}.ts` -- UI: `apps/web/src/{App,Shell,api,types,shepherd-hooks}.ts` and - `apps/web/src/pages/`; shared styling is `apps/web/src/styles.css`. - -## UI freeze - -The current UI theme and layout are accepted. Preserve the charcoal sidebar, -cream/off-white surfaces, restrained purple accent, green/red semantic colors, -typography, spacing, borders, and interaction patterns. UI edits are allowed only -to add required clarity/data or fix causal behavior. Reuse existing components and -CSS. Do not redesign. Every material UI correction must be browser-checked at -`1280x800` and `1440x900` against [`UI.jpeg`](UI.jpeg), with no document-level X/Y -scrolling. - -## Baseline at this snapshot - -| Check | Observed result | Verdict | -|---|---|---| -| Environment | Node `26.5.0`; npm `11.17.0`; Playwright `1.62.1`; Docker client/server `29.6.1` | Recorded for issue #96 candidate | -| Workspace typecheck | Both server and web passed during `npm run check` | Pass | -| Root script/deploy tests | 26/26 passed | Pass | -| Server suite | Candidate `223a5fe`: 856 passed, 3 explicit opt-in skips | Pass candidate | -| Web unit suite | 20/20 passed | Pass candidate | -| Persistence/recovery closeout | `TST-23` 20/20; `TST-24` 30/30; Store 70/70; combined boundary 133/133 | Pass | -| Production build | Web and server production builds passed | Pass | -| Coverage | Server 86.15/80.05/91.46/88.03%; browser 88.50/80.18/87.64/92.37% (statements/branches/functions/lines) | Pass; all four metrics >=80% and every production file required | -| Dependency audit | `npm audit --json`: 0 vulnerabilities | Pass | -| Script syntax | `bash -n` launcher and Node launcher syntax passed | Pass | -| Full browser matrix | 48/48: 24 functional flows at both `1280x800` and `1440x900` | Pass candidate; independent `U` remains | -| Terraform | Pinned Terraform `1.9.8` plus Volcengine provider `0.0.58` initialized and validated a disposable copy | Pass candidate | -| Live Runtime preflight | Exact-tree Runtime/controller build, non-root controller, named volume/socket, one test discovered, cleanup | Pass candidate; zero model requests | -| Hosted candidate gate | PR #97 at `bb1a1df`: `Node 22 / npm run check` run `33389614355` passed in 2m59s; `Required checks` run `33389614223` passed in 3m01s | Pass candidate; protected-main `I` pending | -| External live/model gate | Requires explicit informed approval to send repository-derived prompts/code to configured Ark | Not run | - -No model request was made during the issue #96 release audit. Earlier bounded live -evidence remains attached to its exact task rows; it is not generalized to the open -external portion of `LIVE-01`. - -## Integration and external ownership holds — do not assign - -| ID | PRD | Status / owner | Current external work | Integration requirement | -|---|---|---|---|---| -| `MR-03` | 8.6, 12 | **AUDITED** at `35ec268` | Invalid findings are dropped individually with bounded count while valid peers survive; all-invalid degrades. Auditor passed MR matrix 165/165, TST-08 stress, full harness/check/security, exactly one external reviewer request (`completed findings=2`), deterministic outcome/advisory assertions, cleanup, and hosted run `33270168480`. | **100% scoped**; `T,A,C,S,L,I` 6/6; audited | - -No product-code workstream is externally held. `MR-01` is integrated and -independently audited for its full bounded reviewer scope after MR-03 and the sparse live gate. -Historical -`feature/shepherd-phase-*`, merged startup/reset/UI branches, and remote branches -without an open issue/PR are not active ownership claims. - -## Acceptance gate codes - -| Gate | Required evidence | -|---|---| -| `T` | Causal targeted test(s), including the original RED reproduction where applicable. | -| `A` | Adjacent service/API/persistence/recovery tests. | -| `C` | Literal `npm run check` passes without weakened assertions or hidden worker overrides. | -| `B` | Real Playwright/DOM journey at both required viewports with screenshots and intermediate states. | -| `S` | Secret/store/API/DOM scan and read-only security review where trust boundaries change. | -| `U` | Read-only UI review after rendered evidence; all high/medium findings resolved. | -| `L` | Explicit opt-in sparse live Runtime/model smoke; credentials and raw prompts remain undisclosed. | -| `I` | Integrated `origin/main` SHA rerun by the auditor, with task row and build log updated. | - -## P0 — restore a trustworthy green baseline - -| ID | PRD ref | Status / owner / dependencies | Evidence and required acceptance | Confidence; gates passed; audit | -|---|---|---|---|---| -| `TST-02` | 0.2, 16 Phase 9B, 17 | **AUDITED** at integrated implementation `0cb431a`; test fixture only | Worker and Auditor reproduced the fixed-clock cause. Auditor verified candidate and integrated trees: isolated test 1/1, full recovery 17/17, literal `npm run check` with launcher 3/3, server 555/555 plus one opt-in skip, and both production builds. Exact diff is one test clock injection plus evidence docs; production/UI/security files and lifecycle validation are unchanged. | **100% scoped**; `T,A,C,I` passed (4/4); audited | -| `TST-03` | 0.2, 12, 16 Phase 9B, 17 | **AUDITED** at integrated implementation `0b1c401`; test fixture only | Hosted RED run `33261198788` and a controlled pre-verifier hold proved the scheduling race. The two-arrival barrier, early rejection observer, and unconditional release/join preserve the typed failure and durable reload/late-return/no-promotion assertions. Auditor independently passed both rows 40/40, the service/container-verifier slice 43/43, strict test typecheck, the literal local gate (launcher 3/3, server 563/563 plus one opt-in skip, both builds), and integrated focused 2/2. Hosted Node 22 run `33262227553` passed the final implementation gate. No timeout, sleep/retry, assertion weakening, rejection suppression, or product/UI change. | **100% scoped**; `T,C,I` passed (3/3); audited | -| `TST-04` | 0.2, 12, 16 Phase 9B, 17 | **AUDITED** at integrated implementation `00c81ae`; test fixture only | Preserved full-suite RED: `afterEach -> makeDeletable -> readdir` received `ENOENT` beneath a sibling `.trusted-verification/verify-*/src`. The correction records the exact blocked backend snapshot, proves Mission rejection precedes its removal, arms an exact-basename watcher before release, requires `lstat -> ENOENT`, and unconditionally joins Mission/sibling/removal before teardown. Auditor independently passed the exact row 20/20, service/container-verifier slice 43/43, strict test typecheck, literal `npm run check` twice (563/563 plus one opt-in skip and both builds), and integrated focused 1/1. Hosted Node 22 run `33263688794` passed. No cleanup suppression, sleep/retry/timeout increase, assertion/sentinel/path/symlink weakening, or product/UI change. | **100% scoped**; `T,A,C,I` passed (4/4); audited | -| `TST-08` | 0.2, 12, 16 Phase 9B, 17 | **AUDITED** at `35ec268`; test fixture only | Exact returned row passed 20/20 and paired infrastructure rows 40/40 independently. The exact contained snapshot is joined through removal without cleanup suppression, timing inflation, assertion weakening or product change; full/hosted gates passed. | **100% scoped**; `T,C,S,I` 4/4; audited | -| `TST-09` | 0.2, 16 live gate, 17 | **AUDITED** at `35ec268`; test-only env clone | Only reviewer-test `HOST` is cloned to loopback; real provider configuration, predicate/filter and fatal handling remain. Config 27/27, MR 165/165, full/security/hosted passed. Command attempt two made external request 1/1 and completed with two bounded findings; no retry/artifact/root leak. | **100% scoped**; `T,C,S,L,I` 5/5; audited | -| `TST-07` | 0.2, 16 Phase 9B, 17 | **AUDITED** at integrated implementation `de3e631`; test packaging only | Exact TS6142/TS6059 RED was preserved. The complete eight-case file moved from Server to Web; explicit Web Vitest and strict test-source configs/scripts make both workspaces execute and typecheck under the root gate. Auditor independently passed focused Web 8/8, full Web 9/9, adjacent Server routing 10/10, both strict test projects, lock-backed clean install with zero vulnerabilities, literal `npm run check` (launcher 3/3, Server 563/563 plus one opt-in skip, Web 9/9 and both builds), and hosted Node 22 run `33266624301`. Server JSX/rootDir, product code and assertions are unchanged. | **100% scoped**; `T,C,I` passed (3/3); audited | - -## P0 — failure and recovery correctness - -| ID | PRD ref | Status / owner / dependencies | Evidence and required acceptance | Confidence; gates passed; audit | -|---|---|---|---|---| -| `F-01/02` | 12: Agent timeout/runtime | **AUDITED** at `83cc1d0` | Typed timeout/execution identity, fixed public messages, complete cleanup precedence and the executor filesystem/config boundary pass durable Contract/candidate/API/store/reload/log and no-promotion checks. No model/UI call was required. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `TST-13` | 0.3, 12, 13 | **AUDITED** at `83cc1d0` | The closed runner→executor→durable/public boundary rejects parsed output, stderr, container, hostile typed, secret and path diagnostics while preserving fixed execution/validated timeout identity. | **100% scoped**; `T,C,S,I` 4/4; audited | -| `TST-14` | 0.3, 12, 13 | **AUDITED** at `83cc1d0` | Execution-home cleanup preserves cancellation/timeout/execution primary outcomes; cleanup-only is fixed typed failure, exact retained-home retry succeeds, and public/durable surfaces remain bounded. | **100% scoped**; `T,C,S,I` 4/4; audited | -| `TST-15` | 0.3, 6.1, 12, 13 | **AUDITED** at `83cc1d0` | Sentinel and reconciliation open/handle/unlink/rm edges are cause-free and bounded with exact same-process retry. Restart with an invalid retained sentinel remains a documented Low fail-closed/manual-cleanup availability residual. | **100% scoped**; `T,C,S,I` 4/4; audited | -| `TST-16` | 0.3, 6.1, 12, 13 | **AUDITED** at `83cc1d0` | All 47 executor-owned filesystem/config expressions were manually inventoried; the 31-row injected matrix plus Contract/candidate public/durable proof passed. Independent security review found no High/Medium issue. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `F-03` | 12: verifier infrastructure | **AUDITED** at integrated implementation `dc87553` | Preserved REDs cover thrown diagnostics, returned mandatory `infrastructure_error` misclassification, sequential-check cancellation, and reserved create→start/repeated-cancel ID poisoning. The integrated correction atomically terminalizes the batch for thrown or returned mandatory infrastructure failure, preserves ordinary acceptance failure, releases ownership, blocks late invocation/integration, and makes exact-target cancellation sticky with bounded cleanup/reuse. Auditor independently passed the corrected regressions 8/8, adjacent service/API/recovery/store/state-machine/verifier coverage 185/185, and the literal integrated gate with launcher 3/3 plus server 563/563 and one opt-in live skip; both builds passed. Durable reload/no-promotion, exact target isolation, same-ID cleanup, bounded public/store output, and unchanged UI/workflow/dependency scope were inspected. | **100% scoped**; `T,A,C,S,I` passed (5/5); audited | -| `F-04` | 12: worktree creation | **AUDITED** at `2cef988` | First/second initial Plane creation failures persist bounded owning Contract/Mission evidence. Successful unwind removes only current-batch durable/physical resources; cleanup failure retains truthful failed Plane/interrupted Contract evidence under attention without masking the primary failure. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `TST-17` | 0.3, 6.1, 12 | **AUDITED** at `2cef988` | Second-of-two failure leaves zero durable/physical batch Planes, planeIds, worktrees or branches. Cleanup double-fault retains bounded exact recovery evidence, releases Agents, preserves active-project attention invariant and protected HEAD, and emits no raw cause or false cleanup claim. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `F-05` | 8.4, 12: Git conflict | **AUDITED** at `f8d7f71`; final stability restored by `cdcfa95` | Real conflict, cleanup attention, pre-merge identity and reset contracts passed local, security and both hosted gates. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `TST-18` | 0.3, 8.4, 12 | **AUDITED** at `f8d7f71` | Mandatory abort and truthful bounded cleanup evidence pass. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `TST-19` | 0.3, 8.4, 12 | **AUDITED** at `f8d7f71` | Five pre-mutation identity mismatch rows preserve all target/source state. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `TST-20` | 0.2, 12, 16 Phase 9B, 17 | **AUDITED** at `cdcfa95`; test-only | Immediate rejection observation, unconditional release, exact backend lifecycle join and queued store sentinel prevent teardown with pending persistence while preserving fail-fast and durable assertions. | **100% scoped**; `T,C,I` 3/3; audited | -| `F-06` | 9.1, 12: persistence error | **AUDITED** at `7d51ec6` with TST-21–24 | Representative running→verifying recovery uses exact-byte digest and bounded journal; uncommitted/ambiguous writes reconcile once, pending recovery locks unrelated mutations/events, and no downstream promotion occurs. Crash-safe temp authority and deterministic fixture joins passed local, security and hosted gates. No arbitrary-mutation recovery is claimed. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `TST-21` | 0.3, 9.1, 12, 13 | **AUDITED** at `7d51ec6` | Journal read faults are fixed/cause-free; database/journal double faults converge without raw detail or unrelated deletion. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `TST-22` | 0.3, 9.1, 12, 13 | **AUDITED** at `7d51ec6` | Owner-validated `0700` private namespace plus pre-published fixed-schema marker makes tested publication/removal prefixes idempotent across same-instance and two restarts. Store 70/70, combined 133/133, security 0 High/Medium and hosted `33286090602` passed. | **100% scoped**; `T,A,C,S,I` 5/5; audited | -| `TST-23` | 0.2, 9.1, 12, 16 Phase 9B | **AUDITED** at `7d51ec6`; test-only | A no-op original-Store sentinel joins Plane-unwind persistence before reload/teardown; Auditor passed 20/20 without late work. | **100% scoped**; `T,C,I` 3/3; audited | -| `TST-24` | 0.2, 9.1, 12, 16 Phase 9B | **AUDITED** at `7d51ec6`; test-only | Exact intent clearance plus a no-op original-Store sentinel joins reconciliation before durable evidence/teardown; Auditor passed 30/30. | **100% scoped**; `T,C,I` 3/3; audited | -| `F-07/08` | 8.11, 12: candidate timeout/retry | `READY`; Worker | Timeout mapping is inconsistent and retry eligibility is too broad. Retry only typed transient failures, exactly once, from the immutable base; cover second failure/no second retry; `T,A,C,I`. | **55%**; 0/4; not audited | -| `F-09` | 8.11, 12: repeated cancellation | `READY`; Worker | Promotion race coverage exists; explicit repeated service/API cancellation idempotence is absent. Preserve evidence and exact cancellation identities; `T,A,C,I`. | **70%**; 0/4; not audited | -| `FM-01` | 7.6–7.7, 8.9, 12 | **AUDITED FOLLOW-UP CANDIDATE** at `471f5e8` on [PR #74](https://github.com/kyashp/shepherd/pull/74), after [PR #72](https://github.com/kyashp/shepherd/pull/72) merged as `2e40581`; [issue #42](https://github.com/kyashp/shepherd/issues/42) | The merged six-case matrix preserves exact bounded Mission/Contract-or-Candidate/Plane/event evidence through service, API and reload, plus stored and actual Git protected-head immutability. Integrated scoped coverage passed 187/187 and literal `npm run check` passed launcher 3/3, Server 808/808 plus three skips, Web 19/19, all types and builds. Independent audit then found final re-verification asserted only `promotion_started`, not its causal attention event. Follow-up RED was 5 pass/1 fail; `471f5e8` adds fixed event code/stage and exact durable/API transition assertions, passes matrix 6/6, adjacent 187/187, the same literal gate, and independent fix-round audit with no remaining blocker. UI remains E2E scope. | **99% scoped**; `T,A,C` passed (3/4), `I` pending PR #74 integration; independently reviewed | - -## P0 — required composed product behavior - -| ID | PRD ref | Status / owner / dependencies | Evidence and required acceptance | Confidence; gates passed; audit | -|---|---|---|---|---| -| `CRUD-01` | 4.1.2, 11.1, Track 1 Agent CRUD | **REVIEWED CANDIDATE** at `171089b` on [PR #67](https://github.com/kyashp/shepherd/pull/67), [issue #66](https://github.com/kyashp/shepherd/issues/66) | The reproduced delete conflict classified unbound `general-contract` clarification drafts as durable history. The candidate permits only exact inactive `agent-` Projects whose references are human-authored, unbound clarification messages; Contracts, events, Missions, Planes, other messages, and malformed/orphaned state still return the specific 409. Exact Project and workspace cleanup is identity-validated and journaled across the database boundary. Injected pre-publication and post-rename durability-unknown failures converge on restart from on-disk Agent/Project state; racing Shepherd follow-up and direct-run requests cannot strand journals or launch work after deletion reserves the lifecycle, and an active run is cancelled/joined before success. RED plus four security counterexamples became green; lifecycle/project 29/29, adjacent API/Shepherd 77/77, literal check (launcher 3/3, Server 791 passed + two opt-in skips, Web 18/18, strict types/builds), and authenticated Chromium 2/2 at 1280x800 and 1440x900 pass. Independent UI and final security reviews passed with no High/Medium finding; no Web/CSS delta. Two documented Low same-host/power-loss residuals remain. Protected-main integration rerun remains. `T,A,C,B,S,U,I`. | **98% scoped**; `T,A,C,B,S,U` passed (6/7), `I` pending; not audited | -| `GC-01` | 4.1.12, 11.5–11.6.3 | **AUDITED** at merge/fix `de3e631`; source `main` `662a7e7` | Parser-safe buttons preserve the draft and exact Agent routing for simple, spaced, escaped quote/backslash, Unicode, NFKC and unsafe-name ID-fallback cases. Auditor passed focused Web 8/8, full Web 9/9, Server routing 10/10, clean install/audit, both strict test typechecks, and a real-browser 2/2 protocol at 1280x800 and 1440x900 covering mouse/Tab/Enter/Space, focus-visible, caret, multiline draft, exact 2,000/2,001 boundaries, in-flight disable/no duplicate, parser ID round-trip, no document/body X/Y overflow, and no private output. Full harness passed unit 6/6 plus Chromium 6/6; literal check passed launcher 3/3, Server 563/563 plus one opt-in skip, Web 9/9 and both builds; hosted Node 22 run `33266624301` passed. Independent UI fallback found no GC-01 theme or accessibility regression; the accepted internally scrollable page requires scrolling the composer into view when the runtime banner is present, and disabled-button visual distinction remains a Low `UI-GATE` review item. This row does not claim `GC-03/04` lifecycle behavior. | **100% scoped**; `T,A,C,B,U,I` passed (6/6); audited | -| `ST-02` | 11.5, 12 | **AUDITED** at integrated merge `d5df930` | PR #13 was merged to `main` as `d27dea6` and then merged into `mock-main` without product-code conflict. Notifications remain deliberately undelivered; the Settings surface now labels the capability **Unavailable** and every preserved preference **Reserved**, with three native disabled controls. Auditor passed focused rendering 1/1, web type/build, two-viewport real-browser semantics/no-PATCH/no-overflow, full harness unit 2/2 plus Chromium 4/4, and literal `npm run check` with launcher 3/3, server 563/563 plus one opt-in skip, strict typechecks and both builds. Independent rendered fallback review returned READY/no scoped findings; the configured `ui-reviewer` role was unavailable. No notification integration, public API/schema, persistence, or theme change. | **100% scoped**; `T,C,B,U,I` passed (5/5); audited | -| `MR-01` | 4.1.13, 8.6, 12 | **AUDITED** through `35ec268` | Bounded reviewer consumes trusted verified summaries/refs, validates output, remains advisory-only, degrades truthfully and cannot alter deterministic authority. Provider-free, MR-03 partial, browser/security, one-request live and hosted gates passed. | **100% scoped**; `T,A,C,B,S,U,L,I` 8/8; audited | -| `MR-02` | 4.1.13, 8.6, 11.5, 12 | **AUDITED** at `577255e` | The server exposes only `shepherdModelReviewConfigured`, derived from the same fail-closed startup predicate used to compose the reviewer. Settings preserves the stored preference but renders a native disabled control plus explicit **Unavailable** process-scoped copy when false; it issues no PATCH. Configured mode retains normal mouse/keyboard PATCH behavior. Auditor passed reviewer/config/service 173/173, Settings 5/5, adjacency 100/100, harness unit 6/6 and Chromium 8/8, literal check (launcher 3/3, Server 588/588 plus two opt-in skips, Web 13/13), audit/scans and hosted run `33268567614`; no live call. | **100% scoped**; `T,A,C,B,S,U,I` passed (7/7); audited | -| `OPS-06` | 6.1, 8.10, 17 baseline | **COMPATIBILITY INTEGRATED** at `b80af11` ([PR #56](https://github.com/kyashp/shepherd/pull/56)); diagnostics audited earlier at `68dbd59` | The bounded stage/reason diagnostics did their job and the affected-host cause is now reproduced: `codex sandbox linux --full-auto` cannot enforce Landlock per-file access rights on a host share reaching the engine through a virtual machine, so the sandbox subprobe's first redirection is denied and the runner reports the catch-all `sandbox_probe_failed`. Both startup probes were also certifying nothing, because `touch` succeeds on exactly that filesystem. Correction adds the opt-in container state volume (`CONTAINER_STATE_ROOT` plus `CONTAINER_STATE_VOLUME`, required together, `volume-nocopy` mandatory), translates the independent verifier, and makes both probes write and read back bytes; unset keeps host bind mounts byte-identically. On the affected host the unmodified preflight now returns `SHEPHERD_RUNTIME_PREFLIGHT_OK` and a containerized non-root control plane completes the sibling-Runtime loop; the `container-volume` startup smoke is recorded in `BUILD_LOG.md`. The green Linux full gate now exists: hosted run `33300759535` ran literal `npm run check` on exact head `b80af11` and succeeded. `ba1ee77` additionally defaulted `LOCAL_POC_STATE_MODE` to `auto`, so the launcher selects the volume layout from its own probes; an explicit `host-bind` or `container-volume` still disables the fallback. Local serial rerun on `b80af11`: 745 passed / 6 failed / 6 skipped, every failure a host-speed timeout (`recovery.process` 5, plus the recorded `resolving`/`attention_required` flake). Adjacent `A` coverage is supplied by [PR #68](https://github.com/kyashp/shepherd/pull/68): eight causal tests for the verifier fail-closed branch, the three executor state-root guards, the `index.ts` verifier composition and the launcher probe/fallback selection, each proven by mutating its guard. An independent `S` review of the merged range returned **FAIL** with one High and two Medium findings, all against `e6a5878`, which removed the non-loopback `APP_AUTH_TOKEN` requirement in the same merge with no recorded review. [PR #69](https://github.com/kyashp/shepherd/pull/69) restores the deploy-path guard and the configured-token floor, documents the state volume and the control-plane engine socket, and gates its own regression test. Adversarial re-review then reproduced two bypasses of that first guard and a bypass of the composition test; both are corrected and re-verified against the reproductions. See `docs/BUILD_LOG.md`. | **100% scoped**; `T,A,C,S,I` passed. `A` integrated at `6137f36` (PR #68) and `S` at `3087b69` (PR #69); both are ancestors of `origin/main`, and the hosted exact-head gate on `3087b69` is run `33322423938`. Scoped 100 means every listed gate for this row passed; the `S` review's High finding is **carried, not closed** — see below — and `L` is `LIVE-01` ([#65](https://github.com/kyashp/shepherd/issues/65)). The High finding is only partly closed: the guarded deploy script is one of three documented compose entry points, and `README` still documents `docker compose up --build` and `docker compose --env-file .env.production up -d` against the same unguarded `docker-compose.yml`, which binds `0.0.0.0` with an unprefixed port. That remainder is owned by [issue #89](https://github.com/kyashp/shepherd/issues/89), successor to `SEC-REVIEW` `#49`. `I` rerun performed on integrated `a62e29b`: hosted exact-head gate run `33324819058` succeeded, and the OPS-06 surfaces passed locally. **The rerun was SELF-PERFORMED by the author of the implementation, not by an independent auditor**, so this row is explicitly NOT `AUDITED`. An independent rerun is still owed, and it matters here: the `SEC-REVIEW` boundary audit found `SEC-01`, an authentication bypass on the same `APP_AUTH_TOKEN` boundary this row's `S` gate covers, which the author had not noticed. | -| `TST-12` | 0.3, 6.1, 13 | **AUDITED** at `68dbd59` | Executor correction discards raw mount-cleanup cause and throws fixed bounded cleanup stage/reason. A planted failure proves message/String/stack/inspect/JSON/cause surfaces contain no secret/private-path/OS detail; cleanup continuation, fail-closed cache reset/retry and primary typed diagnostic remain. Focused/adjacent, strict/literal, independent security review and hosted run `33274769957` passed. | **100% scoped**; `T,C,S,I` 4/4; audited | -| `GC-02/05` | 8.1, 11.5–11.6.3 | **AUDITED CANDIDATE** on [PR #64](https://github.com/kyashp/shepherd/pull/64), [issue #41](https://github.com/kyashp/shepherd/issues/41) | Explicit initialization creates only the fixed idle auth-demo Project: no Mission, Contract, Plane, shell, model or executor run. Unmentioned bounded text persists with a bounded Shepherd reply. Duplicate/replayed IDs are deterministic, including cross-route concurrency. Focused and full checks, security/DB hostile-state coverage, two-viewport browser evidence and independent review passed; protected-main integration remains. `T,A,C,B,S,U,I`. | **100% scoped**; 7/7 passed; audited candidate | -| `CHAT-01` | 4.1.2, 6.1, 11.5, 11.6.2 | **INTEGRATED** at `cd82ec4`, reviewed at `e1fe067`; [PR #57](https://github.com/kyashp/shepherd/pull/57), [issue #55](https://github.com/kyashp/shepherd/issues/55) | A user creates Frontend/Backend Agents and sends each exact assignment in its private chat with **Route through Shepherd**. Server-side bounded parsing accepts one HttpOnly-cookie and one bearer-JWT assignment, persists both restart-safely, atomically/idempotently binds them to one Mission and two authority-intersected Contracts, and reuses the verified Plane/collision/resolution/promotion pipeline. Agent deletion/intake races serialize without archive/state drift. Legacy Playground remains available; route mode cannot leak across Agents; old Shepherd Agent/transport selectors and CSS are removed; the fallback composer remains visible without page overflow. Literal check passed with Server 742 plus two opt-in skips and Web 18/18; focused authenticated Chromium passed 4/4 at both viewports, including keyboard route opt-in, Frontend→Generalist isolation, Backend verified status, exact Contract objectives, full evidence and container/document overflow gates. Independent security and UI re-reviews passed with no blocker. Protected-main integration is done at `cd82ec4`; the exact post-merge `I` rerun remains before issue #55 can close. `T,C,B,S,U,I`. | **98% scoped**; `T,C,B,S,U` passed (5/6), `I` pending; not audited | -| `CHAT-02` | 4.1.2, 8.1, 11.5–11.6.3 | **INTEGRATED** by [PR #59](https://github.com/kyashp/shepherd/pull/59), [issue #58](https://github.com/kyashp/shepherd/issues/58) | Every Agent role defaults to Shepherd-managed chat with a visible direct-Playground opt-out. A bounded deterministic planner requires a concrete objective, writable project-relative artifacts and an enforceable whole-statement `Acceptance:` predicate. Missing or unenforceable fields remain an inert clarification draft; sufficient input enters the scoped Contract, isolated Plane, independent verification and CAS-promotion pipeline. Issue #81 below hardens this already-integrated intake against unsafe and adversarial wording. | **100% integrated baseline**; superseded for intake-security evidence by `CHAT-03` | -| `CHAT-03` | 4.1.2, 8.1, 11.5–11.6.3, 13 | **INTEGRATION-VERIFIED** for [issue #81](https://github.com/kyashp/shepherd/issues/81) on branch `fix/81-contract-intake-clarification` | Private-chat intake now fails closed unless the terminal request has one direct, allowlisted action on a quoted authority-contained artifact, the exact bounded project-only `Safety:` statement, and one literal-content `Acceptance:` predicate. Secret/credential, external/production/network, privileged, destructive, safeguard-bypass, conditional, negated, approval-dependent and ambiguous requests stay clarification-only and create no Mission, Contract or Plane. Earlier unsafe intent remains sticky until exact `Replace prior request:` recovery; a complete follow-up may supersede only earlier vague drafts that named no artifact and had no unsafe intent. The UI gives exact corrective syntax without design changes. Live Runtime preflight also proves a parent-only credential canary cannot be recovered from `/proc/*/environ` inside the actual Codex sandbox. After reconciliation with protected `main` `9696c6d`, focused intake/startup/composition passed 33/33; literal `npm run check` passed launcher 5/5, Server 842 passed + two opt-in skips, Web 20/20, strict types and both builds; combined authenticated Chromium passed 10/10 at 1280×800 and 1440×900, including the integrated performance journey. Independent security and UI reviews passed with no High/Medium finding. An explicitly constrained live Mission reached execution but failed its separate result-manifest contract; this row therefore does not close `LIVE-01`. `T,A,C,B,S,U,I`. | **100% scoped deterministic integration**; 7/7 gates passed; live end-to-end remains open | -| `GC-03/04` | 8.1, 11.5–11.6.3 | **AUDITED CANDIDATE** on [PR #64](https://github.com/kyashp/shepherd/pull/64), [issue #41](https://github.com/kyashp/shepherd/issues/41) | A leading mention of a ready Frontend or Backend Agent captures exactly one fixed authentication transport. A complementary opposite-role request creates the existing deterministic two-Contract Mission with server-owned objectives and authority; cross-intake pairing is rejected. The real mention-button → request → Contract → evidence browser journey passed at both required viewports without adding shell/model authority or changing the frozen design. `T,A,C,B,S,U,I`. | **100% scoped**; 7/7 passed; audited candidate | -| `GC-06` | 11.5 | **AUDITED CANDIDATE** on [PR #64](https://github.com/kyashp/shepherd/pull/64), [issue #41](https://github.com/kyashp/shepherd/issues/41) | Project Group Agent messages are appended only after the bound Contract is verified and use the exact persisted manifest summary. V2 validation rejects wrong sender, target, Contract, summary, non-verified state or absent manifest; causal nonterminal fixtures and legacy pre-summary compatibility pass. `T,A,C,B,S,U,I`. | **100% scoped**; 7/7 passed; audited candidate | -| `ST-01` | 6 configuration, 11.5 | **INTEGRATED** at `a8d2266` (PR #73), [issue #44](https://github.com/kyashp/shepherd/issues/44) | `SHEPHERD_AUTO_RESOLUTION` and `SHEPHERD_MAX_PARALLEL_PLANES` were parsed and then discarded: `ShepherdServiceOptions` had no field for either and the only production construction passed neither, so both advertised controls were inert. The gap was masked in E2E because the harness sets values equal to the persisted defaults. The candidate adds both options, passes them from resolved configuration, and extends the pristine-store seeding block so a later operator change stays authoritative across restarts — seeding applies only while the persisted value is still the factory default, and the residual case (an operator explicitly choosing the factory default is indistinguishable from one who never chose) is documented on the predicates rather than hidden. It also closes a real boundary contradiction: the env schema accepted `min(1)` while the persisted schema, `updateSettings` and the API all require 2, and its default of 4 made the persisted default of 2 unreachable. Eight causal tests, each verified by mutating the guard it covers; evidence in `BUILD_LOG.md`. Stated behaviour change: `SHEPHERD_MAX_PARALLEL_PLANES=1` previously booted because the value was discarded and now fails at `loadConfig`, and a host that never set the variable moves from a nominal 4 to the 2 it actually ran with. Integrated at `a8d2266`; hosted exact-head gate on `3087b69` is run `33322423938`. `T,A,C,I`. | **100% scoped**; `T,A,C,I` passed. `I` rerun performed on integrated `a62e29b`: hosted exact-head gate run `33324819058` succeeded, and the ST-01 surfaces passed locally. **The rerun was SELF-PERFORMED by the author of the implementation, not by an independent auditor**, so this row is explicitly NOT `AUDITED`: this ledger reserves that for independent end-to-end evidence. An independent rerun is still owed. | -| `SCH-02` | 8.3 | `READY`; Worker | Reject DAG cycles before Contract graph persistence using the existing validator; `T,A,C,I`. | **50%**; 0/4; not audited | -| `SCH-01` | 4.1.6, 8.3 | `BLOCKED` by `SCH-02`; Worker | Service schedules only one fixed initial batch. Implement dependency waves using real Agent occupancy, mutation lock, active Plane count/capacity, failure blocking and downstream re-evaluation; prove overlap. `T,A,C,S,I`. | **35%**; 0/5; not audited | -| `UI-01` | 11.2, 12 | **AUDITED** at merged `fbc937f` via [PR #75](https://github.com/kyashp/shepherd/pull/75); [issue #43](https://github.com/kyashp/shepherd/issues/43) closed | Ordinary failed Missions reuse the frozen attention panel to expose the precise denied Contract code/stage, durable state, full-ID affordance and explicit no-promotion outcome. The merged tree matches the independently reviewed candidate bytes; fresh integrated literal check, Web 20/20 and the required two-viewport journey passed with no CSS/layout change. `T,C,B,U,I`. | **100% scoped**; `T,C,B,U,I` passed (5/5); audited | -| `UI-04` | 11.1–11.3, 12 | **AUDITED** at `412a010` | Promotion-completed events select/label `promotionEvidence`; candidate events retain candidate verification and promotion-started claims none. Drawer exposes both safe stages with complete roving/focus lifecycle and internal scroll. Auditor passed fixture 7/7, Web 17/17, focused browser 2/2 twice, full Chromium 10/10, literal check, private-field/security/UI review and hosted run `33271397185`. Frontend/CSS/tests only; no backend/schema/live change. | **100% scoped**; `T,C,B,U,I` 5/5; audited. The fixture prerequisite integrated here; `E2E-02` was subsequently audited at `338f1e4`. | -| `UI-02` | 4.1.16, 11.3, 14 | `READY`; Worker | UI has an optional estimate renderer but backend produces no `estimatedDurationMs`. Persist/serve a trusted clearly labelled estimate distinct from actual timing. `T,A,C,B,U,I`. | **20%**; 0/6; not audited | - -## P1 — browser, cross-surface and assurance gates - -**Issue #96 candidate overlay (not yet integrated):** PR #97 extends the existing -rows without rewriting their protected-main audit history. `UI-GATE` passes an -expanded 48/48 matrix at both required viewports, including Agent edit hydration, -Settings recovery, full CRUD/lifecycle, runtime-contract and error-state coverage; -independent `U` remains. `SEC-REVIEW` candidate fixes bound durable retention, -make Agent creation atomic, protect tokenless loopback/same-origin access, refuse a -public bind without a token, and remove runtime credentials from Terraform -input/cloud-init/state; the required independent part-5 review remains. `LIVE-01` -now has a passing exact-tree named-volume Docker preflight on the affected host; the -external provider turn remains unexecuted pending informed approval for sending -repository-derived payloads to Ark. `I` remains pending for every candidate claim. - -| ID | PRD ref | Status / dependencies | Required acceptance | Confidence; gates passed; audit | -|---|---|---|---|---| -| `UI-03` | 0.4, 11.1–11.2, 11.7 | **AUDITED** at integrated implementation `83954f7`; hosted closeout restored by `TST-03` at `0b1c401` | Create Agent's transparent preset radios inherited global viewport-wide input sizing, expanding document width to 2299/1280 and 2579/1440. The integrated correction bounds only the hidden radio box and adds a theme-matched visible card focus outline. Auditor independently passed focused Chromium 2/2, full browser 4/4 and harness unit 2/2 at both required viewports; document/body X/Y, exact neutralized 1x1 boxes, accessible group/names, Generalist default, one Tab stop, arrow focus/selection, visible 2px outline, all label clicks and exactly one checked radio passed. Regenerated screenshot hashes matched the committed images; visual review preserved layout/theme. Integrated local check passed. Hosted run `33262227553` passed after the unrelated schedule-sensitive TST-03 fixture was corrected without touching UI code. | **100% scoped**; `T,C,B,U,I` passed (5/5); audited | -| `E2E-HARNESS` | 0.4, 16 Phase 6 | **AUDITED** at integrated implementation `5b152a0` | Auditor independently verified the candidate and integrated SHA: allowlisted child environment with no `.env` or ambient Ark/model ingress; required bearer auth; bounded fake Codex/container fixtures, readiness, logs, termination, port and run-root cleanup; ignored artifacts; no production debug route or UI/runtime change. Node harness passed 2/2 and Chromium passed 2/2 at exact `1280x800` and `1440x900`; regenerated screenshot hashes matched, document/body X/Y overflow was absent, and both images preserved the accepted clean-shell UI. Literal `npm run check` passed launcher 3/3, server 555/555 with one opt-in live skip, typechecks and both builds. This foundation does not satisfy `E2E-01`–`08`, populated/composer states, accessibility, or `UI-GATE`. `T,C,B,S,I`. | **100% scoped**; `T,C,B,S,I` passed (5/5); audited | -| `E2E-01` | 11.6.1, 17 baseline | **AUDITED** at integrated implementation `f6df2d9`; evidence `284994d` | Auditor independently passed harness unit 18/18 and Chromium 18/18 across three runs at both required viewports, plus the explicit evidence path 2/2. The authenticated create → exact artifact/test 2/2 → two-turn same fake session → port-down → restart-continuity journey passed with 401/auth, disabled active composer, exact persisted/API/DOM/log/path checks and actual Tab/focus-visible/Enter Create/Stop/Start. All 20 ephemeral images and the 16 committed journey images were reviewed with no clipping, overflow or theme drift. Strict test typecheck and literal check passed; ordinary runs left tracked evidence byte-identical. The prior bounded live gate remains exactly two ARK turns, no retry, one real Codex thread, artifact test 2/2, restart/security/cleanup pass and no Shepherd call; it was not repeated. Hosted run `33265640400` passed. `C,B,L,S,U,I`. | **100% scoped**; 6/6 gates passed; audited | -| `TST-05` | 0.4, 11.6.1, 11.7 | **AUDITED** at `f6df2d9`; evidence `284994d` | Default screenshots route only to ignored `.tmp/playwright-evidence`; explicit `test:e2e:starter-kit:evidence` wrote exactly the intended 16 E2E-01 files and no blank-down or unrelated evidence. Port closure is infrastructure evidence only. Three ordinary harness runs left tracked screenshot hashes unchanged. Both viewports proved inner-scroll Create reachability plus actual visible keyboard focus and Enter activation for Create/Stop/Start. Independent rendered fallback returned READY with no findings; configured `ui-reviewer` was unavailable. No production UI/CSS/theme change. `T,C,B,U,I`. | **100% scoped**; 5/5 passed; audited | -| `TST-06` | 0.3, 11.6.1, 13 | **AUDITED** at `f6df2d9` | Boolean-only secret assertions, live trace/screenshot/video off, exact live opt-in/two-turn/no-retry cap, loopback/auth/allowlisted environment and empty live `SHEPHERD_MODEL` passed review. Managed repository/`.tmp`/harness/run-root identities are lstat/realpath checked before allocation/removal. Causal tests reject a repo-contained ancestor symlink, prove later cleanup of a retained stopped root after restart failure, prove fresh setup failure leaves no root, and preserve reusable-root rejection. Harness unit 18/18, strict typecheck, literal check and hosted run `33265640400` passed; no run roots, credentials, private paths or live artifacts remained. Configured `security-reviewer` was unavailable; Auditor review found no High/Medium issue. `T,C,S,U,I`. | **100% scoped**; 5/5 passed; audited; documented Low local TOCTOU/exceptional-concurrency residuals remain outside the harness threat model | -| `E2E-02` | 11.6.2, 15 | **AUDITED** at integrated chain `338f1e4` | Authenticated real-server deterministic hero proves Contracts/isolated Planes, independent verification, exact semantic collision, concurrent candidates from one immutable base, cookie pass/bearer fail, objective selection, distinct final re-verification, protected promotion, retained loser, Project Group lifecycle and reset/cleanup. Auditor ran four journeys and inspected all 52 stage/viewport observations: 13/13 named claims are visible at both viewports and 26/26 final hashes are unique. Full harness passed unit 7/7 plus Chromium 12/12; literal check passed launcher 3/3, Server 592 plus two explicit skips, Web 17/17, strict types and builds. Independent UI/security fallback returned READY; hosted run `33273947769` passed. Shepherd summaries remain truthful (`GC-06` open); no `UI-02` estimate or live/model behavior is claimed. `C,B,S,U,I`. | **100% scoped**; 5/5 gates passed; audited | -| `TST-10` | 11.6.2, 15 | **AUDITED** at `338f1e4` | Exact `promotion_started` is scrolled into `.event-list`, positively intersects pane/browser and differs bytewise from stage 05. Auditor verified it in all four focused journeys, full harness/check, independent review and hosted run `33273947769`. | **100% scoped**; `T,C,B,U,I` 5/5; audited | -| `TST-11` | 11.6.2, 15 | **AUDITED** at `338f1e4` | Exact selected/rejected Candidate summaries are scrolled into the drawer and positively intersect drawer/browser before capture. Auditor verified stages 09/11 in all four journeys while stage 10 final evidence, TST-10, keyboard/focus and security assertions remained intact. The 52/52 semantic manifest, 26/26 unique hashes, full harness/check, independent review and hosted run `33273947769` passed; no product/UI/theme/timing change. | **100% scoped**; `T,C,B,U,I` 5/5; audited | -| `E2E-03` | 11.6.3 | **AUDITED CANDIDATE** on [PR #64](https://github.com/kyashp/shepherd/pull/64), [issue #41](https://github.com/kyashp/shepherd/issues/41) | Authenticated Chromium passed the real Project Group initialization and mention-button → typed request → targeted Contract → verified Agent summary → Contract evidence journey 2/2 at `1280x800` and `1440x900`, including server-owned objective, `src/frontend/**` authority and document/body overflow checks. Focused UI/security review passed; protected-main integration remains. `C,B,S,U,I`. | **100% scoped**; 5/5 passed; audited candidate | -| `E2E-04` | 11.6.4, 12 | **AUDITED** at merged `fbc937f` via [PR #75](https://github.com/kyashp/shepherd/pull/75); [issue #43](https://github.com/kyashp/shepherd/issues/43) closed | The integrated real compiled service attempts an out-of-scope `policy.json` change, rejects it at Contract authority, reloads through the production server, and proves typed visible denial, unchanged stored/actual protected heads, zero Candidates/integration/promotion, keyboard/focus, bounded evidence and no overflow. Fresh integrated Chromium passed 2/2 at both required viewports; literal check and independent UI/security review passed. The two isolated candidate-time starter-kit harness failures remain unrelated and documented. `C,B,S,U,I`. | **100% scoped**; `C,B,S,U,I` passed (5/5); audited | -| `E2E-05` | 11.6.5, 12 | `READY`; Worker; failure UI prerequisite completed by `UI-01` at `fbc937f` | Both candidates fail → durable `attention_required`, preserved evidence, no promotion; `C,B,S,U,I`. | **55%**; 0/5; not audited | -| `E2E-06` | 11.6.6 | `BLOCKED` by `FM-01` | Real service tie → human verified choice → trusted promotion; `C,B,S,U,I`. | **40%**; 0/5; not audited | -| `E2E-07` | 11.6.7 | `BLOCKED` by `F-09` product behavior | Cancel mid-Mission → durable cancelled, released Agents, no promotion; `C,B,S,U,I`. | **55%**; 0/5; not audited | -| `E2E-08` | 11.6.8, 12 | `BLOCKED` by restart/reconnect product composition | Kill/restart mid-Mission → reconnect/cursor reconciliation, interrupted visible, no false green/duplicates; `C,B,S,U,I`. | **50%**; 0/5; not audited | -| `UI-GATE` | 0.4, 11.1–11.7 | **INTEGRATED CANDIDATE** at protected-main merge `cf4dd0fa` via [PR #87](https://github.com/kyashp/shepherd/pull/87), [issue #45](https://github.com/kyashp/shepherd/issues/45); causal UI fixes `bbc7c81`; independent `U` remains | One real-server Playwright matrix covers the six PRD surfaces plus adjacent auth/Agents/Settings/not-found states at both exact viewports. Final candidate `adbb7aa` passed hosted runs `33329742705` and `33329742709`. The exact merge tree is identical to that candidate; its one-worker integration rerun passed 12/12, regenerated 36 reviewed PNGs (18 per viewport, 3,225,044 bytes), and exact-main hosted run `33329997913` passed literal `npm run check`. Keyboard/focus/roles/state/contrast/long-ID/named-scroll/no-document-overflow and bounded canary assertions pass. The local Node harness remains honestly limited by Windows `spawn EFTYPE` at 15/19; hosted Linux supplies the complete gate. `docs/ui-review/ui-gate/AUDIT.md` records the compact-chip exception, no connected in-app browser, and no manual screen-reader claim. `C,B,U,I`. | **95% scoped**; `C,B,I` passed (3/4), independent `U` pending; not audited | -| `PERF-01` | 14 | **AUDITED** at integrated implementation `b193e57` via [PR #77](https://github.com/kyashp/shepherd/pull/77); [issue #46](https://github.com/kyashp/shepherd/issues/46) | The independent protected-main audit passed the deterministic compiled-service/real-Chromium journey 2/2 at `1280x800` and `1440x900`: conservative two-Plane-ready 323/334 ms, exact verification 303/334 ms, persisted event → visible 488/476 ms (limit `<=1.5s`), collision → `promotion_completed` 2,073/2,044 ms, and 3,712/3,680 ms total. The actual candidate-executor overlap proof and cleanup-race regression passed 1/1 each; harness passed 7/7; literal `npm run check` passed launcher 3/3, Server 810 with three explicit skips, Web 20/20, all typechecks and builds. Hosted exact-main run `33318509842` passed. Tracked screenshots remained unchanged. The evidence is deterministic, not a live-model capacity, package-download, or three-rehearsal claim. `B,I`. | **100% scoped**; `B,I` passed (2/2); audited | -| `TEST-TS` | 16 Phase 9B | **AUDITED** at integrated implementation `8995605` | Separate strict no-emit server test-source config is enforced by root `typecheck`/`check`; production emit config is unchanged. RED evidence covers 14 errors across 4 test files (4 implicit callback types, 5 invalid Vitest matcher generics, 4 stale promotion fixtures, 1 stale verifier fixture), then 2 nullable fixture values exposed after matcher typing was restored. Auditor confirmed no suppression, broad exclusion, compiler weakening, blanket `any`, assertion weakening, product/UI change, or dependency churn. Candidate and integrated strict test-source checks passed; both production typechecks/builds passed; affected suites passed 73/73; literal candidate and integrated gates passed with launcher 3/3, server 563/563 and one unchanged opt-in live skip, plus both production builds. | **100% scoped**; `T,C,I` passed (3/3); audited | -| `CI-01` | 0.1, 16, 17 | **AUDITED** at workflow `cda2446`; hosted run `33259565232` succeeded | `required-checks.yml` uses supported official checkout/setup-node actions, Node 22, lockfile-backed npm cache, `npm ci`, Docker availability, and literal `npm run check`; it triggers every PR, pushes to protected `main`, and merge-queue `checks_requested`. Token permission is only `contents: read`; checkout credentials are not persisted; no `.env`, secrets, artifacts, privileged actions, or live/model path is configured. Independent local validation passed Docker 29.7.2 and launcher 3/3 plus server 555/555 with one opt-in skip. Hosted Node 22.23.2/npm 10.9.8 and Docker client/server 28.0.4 passed locked install, launcher 3/3, server 551 passed/5 environment-gated skips, typechecks, 40-module web build and server build. Stable job check: `Node 22 / npm run check`. Administrator must require that check on protected `main`; this external rule change is not performed by agents. `C,I`. | **100% scoped**; `C,I` passed (2/2); audited | -| `SEC-REVIEW` | 0.3, 13, 17 | `PARTIAL`; parts 4-5 tracked in [issue #89](https://github.com/kyashp/shepherd/issues/89), successor to [#49](https://github.com/kyashp/shepherd/issues/49) | Parts 1-3 are evidenced at `bd9b093`. **Canary scan:** exactly two credentials exist, both threaded as `sensitiveValues`; no path found by which either reaches `state.json`, a model prompt, a 4xx/5xx body, the DOM, browser storage, a URL, the logger or a tracked file. The Ark key is never in argv and never in the generated Codex config. Two low observations: `/api/system` has no redaction pass, and `ARK_API_KEY` has no minimum length against a 4-character redaction floor. **Five invariant mutations, each caught by an existing test:** bearer auth rejection (2 tests), promotion refusal on failed final re-verification (`failure-matrix`), fast-forward-only protected-ref CAS, contract-cannot-broaden-authority intersection, and verifier Plane containment. **Boundary audit: FAIL.** Route inventory, traversal, identity, authority and promotion boundaries hold, but the bearer hook was bypassable by percent-encoding the `/api/` prefix — filed and fixed as `SEC-01`. **Parts 4 and 5 are tracked in [#89](https://github.com/kyashp/shepherd/issues/89), successor to `#49` after that issue was closed three times with its scope unsatisfied:** the independent read-only review must not be done by the author of `config.ts`'s token floor, `check-deploy-auth-token.mjs`, the deploy guard, the `A`-gate tests or the `SEC-01` fix. This row also owns the carried `OPS-06` High finding: `docker-compose.yml` binds `0.0.0.0` with an unprefixed port while `README` documents two entry points a deploy-script guard cannot reach. `C,S,I`. | **85%**; parts 1-3 evidenced; a seven-lens adversarial review ran for part 4 and returned 19 confirmed findings with 0 refuted, of which five Highs are fixed; part 5 incomplete and four findings remain open; whether that review satisfies "by someone other than the author" is the maintainer's call; not audited | -| `STABILITY` | 16 Phase 9B | **INTEGRATED** at protected-main merge `b05a4aa` via [PR #93](https://github.com/kyashp/shepherd/pull/93), [issue #48](https://github.com/kyashp/shepherd/issues/48); immutable campaign candidate `10c95da` | The first `bd77952` sequence was truthfully reset after run 4 exposed PERF-01's full-Mission timing harness. Four causal corrections isolate inherited Git selectors, post-cleanup F-03 observation, scheduler overlap, and candidate-cleanup preflight without sleeps, timeout/retry increases, hidden workers, suppression, skips, or weakened assertions. Candidate `10c95da` passed five separate literal `npm run check` gates: launcher/deploy 12/12, Server 846 passed / 3 documented skips, Web 20/20, all typechecks and both builds on every run; Server durations were 149.16, 145.77, 144.00, 145.19, and 137.87 seconds. A fresh literal exact-main check at `b05a4aa` passed the same counts with Server duration 140.70s; protected-main workflow `33353622211` also passed. `C,I`. | **100% scoped**; `C,I` passed (2/2); integration verified, not independently audited | -| `LIVE-01` | 16 Phase 3/7/8 | `BLOCKED` by host capability, not by code; [issue #65](https://github.com/kyashp/shepherd/issues/65), split out of #47 | Reviewer sub-gate is satisfied: command attempt two made exactly one external request and completed with two bounded findings while deterministic outcome/security/cleanup stayed green. Current live Shepherd Mission and legacy continuity remain required. Reproduced on the affected host at `b80af11`: a plain write to a host-share bind mount inside the Runtime succeeds while the identical write under `codex sandbox linux --full-auto` is denied, so `test:shepherd:live` — which pins `CONTAINER_STATE_ROOT`/`CONTAINER_STATE_VOLUME` to `undefined` and bind-mounts `.tmp/shepherd-live-gate` — would fail at `stage=container_start reason=sandbox_probe_failed` and consume the no-retry allowance for no evidence. The gate needs a Linux host, or a code change making it volume-aware, which is outside an `L` run. `L,S,I`. | **55%**; 1/3; not audited | -| `DEMO-REHEARSAL` | 14–15, 16 Phase 8 | `BLOCKED` by all demo-critical rows; [issue #50](https://github.com/kyashp/shepherd/issues/50) | Three clean reset-to-completion judge flows under three minutes, including clean no-op reset and initialized reset; second machine/state if genuinely available. `B,S,I`. | **0%**; 0/3; not audited | - -## P2 — feature freeze deliverables - -| ID | PRD ref | Status / dependencies | Required acceptance | Confidence; gates passed; audit | -|---|---|---|---|---| -| `DEL-01` | 16 Phase 9A | **INTEGRATED** as [`ARCHITECTURE.md`](ARCHITECTURE.md) at `39cd800` via PR #60; [issue #51](https://github.com/kyashp/shepherd/issues/51) was prematurely closed after this one deliverable | As-built one-page architecture and judge-facing Mermaid were rendered and validated. The filename differs from the older prospective name, but all current links use the integrated path. | **100% implementation/integration**; independent final package review not claimed | -| `DEL-02` | 16 Phase 9C | **CANDIDATE** on [PR #97](https://github.com/kyashp/shepherd/pull/97) | [`SHEPHERD_TEST_REPORT.md`](SHEPHERD_TEST_REPORT.md) records the exact base/product head, commands, failures, counts, coverage, browser/container/Terraform scope, and explicit live/review/integration limitations. | **95%**; `C` and hosted candidate checks passed, protected-main `I` pending; not audited | -| `DEL-03` | 16 Phase 9D | **CANDIDATE** on [PR #97](https://github.com/kyashp/shepherd/pull/97) | README now documents reproducible coverage/Terraform validation, credential-safe Terraform deployment, and links the exact report without removing starter setup. | **75%**; final frozen-state/independent review pending | -| `DEL-04` | 0.1, 16 Phase 9E | **RECONCILIATION CANDIDATE** on [PR #97](https://github.com/kyashp/shepherd/pull/97); prior consolidation audited at `5a38d37` | `TASKS.md`, `SHEPHERD.md`, `LOCAL_POC.md`, `FIXES.md`, `BUILD_LOG.md`, README and the test report distinguish protected-main, candidate, live-external, independent-review and rehearsal evidence. | **95% overall**; hosted candidate checks passed, final protected-main/independent audit pending | -| `DEL-05` | 16 Phase 9E, 17 | **PARTIAL CANDIDATE** on [PR #97](https://github.com/kyashp/shepherd/pull/97) | Dependency, tracked-secret, generated-artifact, exact-tree Docker, Terraform, coverage and complete browser checks pass. External live inference, independent security/UI review, hosted integration, demo rehearsals and broader optional PRD rows remain. | **60%**; `C,B,S` candidate evidence, `L,U,I` pending; not audited | - -## Count and current verdict - -- **71 tracked work items:** 40 fully audited and 31 not fully audited; no external - hold items across P0/P1/P2. -- **Ready non-overlapping assignments:** `F-07/08`, `F-09`, `FM-01`, `GC-02/05`, - `ST-01`, `SCH-02`, and `UI-02`, subject to the ownership check above. `PERF-01` - remains blocked by the completed Project Group and visible-denial journeys. -- **Presentation-host caveat:** protected `main` still has the historical - bind-mounted `LIVE-01` blocker. PR #97 makes the gate volume-aware and its - exact-tree zero-spend preflight passes on the affected host. The external Ark - request remains a separate consent and evidence boundary. -- **Current completion verdict:** incomplete. The exact-main candidate closes the - deterministic browser, coverage, Terraform, release-harness, identified security - and documentation gaps, but independent `U`, protected-main `I`, external `L`, - and three rehearsals remain explicit. The older 82% estimate is retained only - in `SHEPHERD.md`'s labelled historical snapshot and is not reused as a current - metric. diff --git a/docs/TECHJAM.md b/docs/TECHJAM.md deleted file mode 100644 index 6a25058..0000000 --- a/docs/TECHJAM.md +++ /dev/null @@ -1,157 +0,0 @@ -# TikTok TechJam 2026 — Track 1 Brief - -> Source: [TikTok TechJam 2026 Tracks & Problem Statements](https://bytedance.larkoffice.com/wiki/DNtSwxgeciCS2nkiUefc5qqtnkf) -> Source page last updated: 25 August 2026; retrieved 25 August 2026, -> Singapore time. The source password is intentionally not stored here. - -This repository targets **Track 1 — Agent Launchpad: Design and Build Lightweight -Agent Middleware**. [`PRD.md`](PRD.md) is Shepherd's implementation contract; -[`TASKS.md`](TASKS.md) is the current completion ledger. - -## Workshop - -The Track 1 workshop and Q&A was scheduled for Friday, 28 August 2026, -1:00–1:45 p.m. Singapore time (GMT+8), in -[Lark Meeting 484622806](https://vc-my.larkoffice.com/j/484622806). - -## Goal - -Teams receive a functioning platform where users can create, run, stop, edit, test, -and delete AI agents. The challenge is to add one meaningful infrastructure -capability between its existing components—not rebuild the product. - -Useful middleware can control what an Agent may do, record what it did, recover from -failure, manage cost, coordinate multiple Agents, or strengthen isolation and -safety. Depth, architecture, integration, and evidence matter more than feature -count. - -The extension must remain functional and testable without breaking Agent CRUD, -lifecycle controls, Playground chat, persistence, or model execution. - -## Starter Kit and extension boundary - -The starter repository is [RrankPyramid/CodeJam](https://github.com/RrankPyramid/CodeJam). - -| Area | Provided | Team responsibility | -|---|---|---| -| Product | React UI, Agent list/forms, lifecycle controls, Playground, run status | Preserve the baseline; add only enough UI to reveal middleware behavior. | -| Control plane | Fastify API, validation, asynchronous Runs, `AgentService`, JSON persistence | Integrate the real middleware decision into a trusted backend path. | -| Runtime | Codex CLI, persistent sessions/workspaces, disposable local containers | Insert middleware at the execution boundary that owns the decision. | -| Infrastructure | Docker, Colima, Podman, Compose, optional ECS/Terraform | Use the smallest path that proves the idea; cloud is optional. | - -Valid seams include the Fastify boundary, `AgentService`, `AgentRunner`, execution -data model, persistence layer, and Runtime. Teams may add events, principals, -policies, lifecycle behavior, provider adapters, memory controls, reliability -mechanisms, or coherent coordination behavior. - -The starter remains a single-user proof of concept. Its optional bearer token is -not user identity or authorization, its JSON store is single-process, and ordinary -containers are not hardened multi-tenant isolation. - -## Required engineering qualities - -- Preserve Agent CRUD, lifecycle actions, Playground chat, persistence, and model - execution. -- Execute the middleware in a trusted backend, Runtime, data, or infrastructure - path. Static screens and hard-coded success responses do not qualify. -- Explain which component owns each decision or event, what crosses each boundary, - and how failures are handled. -- Demonstrate normal behavior and one relevant failure, denial, degradation, abuse, - or recovery case. -- Add automated tests for the middleware itself, not only its UI. -- Never commit or display API keys, Volcengine AK/SK values, passwords, bearer - tokens, or unredacted sensitive payloads. -- Prefer the local Docker/Colima/Podman judging path. ECS is optional and does not - increase the score by itself. - -In scope are a focused middleware story, its supporting backend capabilities, -minimal UI, schemas, protected fixtures, controlled failures, policy decisions, -reliability mechanisms, and contract-focused refactors. Rebuilding the whole -product, production OAuth, a commercial cloud platform, a general policy engine, -microVM infrastructure, or multi-region deployment is unnecessary unless central -to the selected idea. - -## Representative middleware directions - -- Identity, scoped delegation, authorization, approvals, and attributable policy - decisions enforced by the server. -- Correlated traces, audit history, timing/status, failure diagnosis, redaction, - resource signals, and visual timelines or trees. -- Explicit layered architecture with replaceable provider/runtime contracts. -- Threat modeling, least privilege, redaction, allowlists, typed schemas, target - scoping, timeouts, limits, containment, and residual-risk reporting. -- Multi-Agent coordination with shared state, routing or turn rules, attributable - history, and timeout/recovery behavior. -- Lifecycle reconciliation, failure recovery, human approval, budget control, - provider abstraction, versioning, rollback, or another coherent middleware story. - -Shepherd selects the multi-Agent coordination and reliability direction: trusted -Execution Contracts, isolated Git Planes, credential-free independent verification, -deterministic semantic collision detection, parallel resolution futures, and a -protected evidence-derived promotion gate. - -## Baseline and validation - -The supported local baseline requires macOS or Linux, Node.js 22+, npm 10+, one of -Docker/Colima/Podman, an Ark model API key, and a Responses-capable endpoint. -Shepherd's current command is documented in [`LOCAL_POC.md`](LOCAL_POC.md). - -The baseline acceptance flow is: create an Agent; submit a real small coding task; -verify its completed response and artifacts; send a follow-up and verify session -continuity; stop/restart; and verify workspace persistence. - -The required repository validation command is: - -```bash -npm run check -``` - -## Demo and deliverables - -The live demonstration must create or select a runnable Agent, execute a real task, -show at least one real model/file/tool/sandbox/data/infrastructure action, expose the -middleware behavior and evidence, demonstrate a relevant failure or recovery, and -leave the platform understandable and controllable. Mock external services are -acceptable; a static UI is not. - -| Deliverable | Requirement | -|---|---| -| Three-minute live demo | One real Agent run, normal middleware behavior, and one failure, denial, degradation, abuse, or recovery case. | -| One-page architecture diagram | Middleware, data flow, trust boundary, and enforcement/instrumentation/recovery point. | -| Code repository | Setup, problem/rationale, design, automated tests, demo steps, limitations, and no secrets. | - -## Judging - -| Track 1 category | Weight | -|---|---:| -| End-to-end middleware behavior | 40% | -| Technical design and integration | 25% | -| Verification and robustness | 20% | -| Demo and reproducibility | 15% | - -## Submission checklist - -- A reviewer can start the repository from the documented command. -- Agent creation, a real task, follow-up continuity, and restart persistence work. -- Middleware executes outside the UI and exposes evidence through the product. -- The demo includes a normal path and a relevant failure/recovery path. -- `npm run check` passes and core middleware behavior has automated evidence. -- The architecture diagram identifies the trusted decision and promotion boundary. -- The demo completes within three minutes and has been rehearsed from clean state. -- No secret appears in source, Git history, logs, traces, screenshots, browser - storage, or the presentation. - -## Simple-to-technical bridge - -Track 1 asks for the missing rules and control system around an AI Agent. In -technical terms, the solution intercepts requests or execution events at a trusted -boundary, applies an operational mechanism, persists correlated evidence, exposes -minimal APIs/UI, and tests an allowed path plus a denial, failure, or recovery path. -The central architecture question is: **which trusted component must own this -decision so that an Agent cannot bypass it?** - -## Track 1 links - -- [Official problem statement](https://bytedance.larkoffice.com/wiki/DNtSwxgeciCS2nkiUefc5qqtnkf) -- [Workshop meeting](https://vc-my.larkoffice.com/j/484622806) -- [Starter repository](https://github.com/RrankPyramid/CodeJam) diff --git a/docs/assets/Shepherd_TechJam_Track1_Architecture.drawio b/docs/assets/Shepherd_TechJam_Track1_Architecture.drawio new file mode 100644 index 0000000..dbc6161 --- /dev/null +++ b/docs/assets/Shepherd_TechJam_Track1_Architecture.drawio @@ -0,0 +1,474 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/Shepherd_TechJam_Track1_Architecture.png b/docs/assets/Shepherd_TechJam_Track1_Architecture.png new file mode 100644 index 0000000..c891cb7 Binary files /dev/null and b/docs/assets/Shepherd_TechJam_Track1_Architecture.png differ diff --git a/docs/superpowers/plans/2026-08-30-ui-gate.md b/docs/superpowers/plans/2026-08-30-ui-gate.md deleted file mode 100644 index b5a1479..0000000 --- a/docs/superpowers/plans/2026-08-30-ui-gate.md +++ /dev/null @@ -1,420 +0,0 @@ -# UI-GATE Audit and Evidence Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:test-driven-development` for every behavior change and `superpowers:verification-before-completion` before reporting completion. Execute each task in order and stop if an ownership recheck finds overlapping active work. - -**Goal:** Add a reproducible, accessibility-aware UI quality gate for issue #45 that exercises all six PRD surfaces at 1280×800 and 1440×900, records reviewable evidence, and fixes only causal gaps discovered by the gate. - -**Architecture:** Add one Playwright journey spec plus a small test-only audit helper module. The journeys use the real local server and database for positive product claims; route interception is limited to delaying or failing real reads so loading and recovery states are deterministic. Product changes remain narrow and are made only after a failing assertion demonstrates the gap. - -**Tech stack:** Node.js 24, Vitest/Node test runner already used by the repository, Playwright, React, TypeScript, CSS, GitHub Actions. - -**Approved spec:** `docs/superpowers/specs/2026-08-30-ui-gate-design.md` - -## Global constraints - -- Work only in `C:\Users\sanje\shepherd\.tmp\worktrees\ui-gate-45` on `test/45-ui-gate`. -- Before every product edit, fetch/prune and confirm that no active PR owns the target file. -- Do not edit `apps/web/src/pages/AgentPage.tsx` while issue #78 owns it. If the gate exposes an Agent-page defect there, preserve the failing evidence and coordinate instead. -- Do not edit backend startup, auth-boundary, recording, or contract-intake files owned by issues #44, #47, or #81. -- Do not edit `package.json`. Register the new spec in the existing Playwright configuration only. -- Keep default tests network- and model-free. Use the deterministic local Shepherd API. -- Store ordinary run output under `.tmp/playwright-evidence/ui-gate/`. Commit only bounded review evidence under `docs/ui-review/ui-gate/`. -- Treat the candidate UI gate as complete only after the exact branch is green in hosted CI. Keep the final integration gate and independent usability review pending until their owners complete them. - -## Task 1: Add reusable audit helpers with unit coverage - -**Files:** - -- Create: `tests/e2e/support/ui-gate.mjs` -- Modify: `tests/e2e/harness.test.mjs` - -### Step 1: Write failing pure-helper tests - -Import the proposed helpers from `./support/ui-gate.mjs` in `tests/e2e/harness.test.mjs` and add Node tests for: - -- `contrastRatio('#ffffff', '#111827')` returning a value greater than 15. -- `contrastRatio('#8773e8', '#0b1020')` meeting the 3:1 non-text threshold. -- `normalizeEvidenceStage('08 Shepherd / loading')` returning `08-shepherd-loading`. -- `uiGateEvidencePath('1440x900', '08 Shepherd / loading')` ending in `.tmp/playwright-evidence/ui-gate/1440x900/08-shepherd-loading.png`. -- Rejection of a stage containing only punctuation so accidental path traversal or empty names cannot create evidence files. - -Run: - -```powershell -node --test tests/e2e/harness.test.mjs -``` - -Expected RED: the module or exports do not exist. - -### Step 2: Add minimal exported stubs - -Create `tests/e2e/support/ui-gate.mjs` with these exports and no unused abstraction: - -```js -export function contrastRatio(foreground, background) {} -export function normalizeEvidenceStage(stage) {} -export function uiGateEvidencePath(viewportName, stage) {} -export async function assertNoDocumentOverflow(page) {} -export async function assertScrollOwner(locator) {} -export async function assertMinimumContrast(locator, minimum) {} -export async function assertVisibleFocus(page, locator) {} -export async function assertSafeUiGateSurface(locator) {} -export async function assertNoSensitiveCanaries({ page, responses, logs }) {} -export async function captureUiGate(page, viewportName, stage) {} -``` - -Re-run the focused Node test and confirm it now fails on behavior, not import resolution. - -### Step 3: Implement the pure functions - -- Parse three- and six-digit hex colors and `rgb()`/`rgba()` computed colors. -- Convert sRGB channels to relative luminance and compute `(lighter + 0.05) / (darker + 0.05)`. -- Normalize evidence stages to lowercase ASCII kebab-case and throw when normalization is empty. -- Resolve evidence paths from the repository root exported by `tests/e2e/support/test-app.mjs`; validate viewport names against `1280x800` and `1440x900`. - -Run the Node test until it is green. - -### Step 4: Implement the Playwright assertions - -- `assertNoDocumentOverflow`: compare document and body scroll width/height with the viewport, allowing at most one CSS pixel for rounding; all intentional overflow must belong to a named internal pane. -- `assertScrollOwner`: verify a designated region is actually scrollable when its content exceeds its box and that the document width does not change after setting `scrollTop`/`scrollLeft`. -- `assertMinimumContrast`: read computed foreground/background colors, walk through transparent ancestors, calculate the ratio, and include the selector plus observed colors in failures. -- `assertVisibleFocus`: focus the locator and require either a non-zero outline or box shadow plus an accessible name. -- `assertSafeUiGateSurface`: reject executable descendants and inline event attributes in user-controlled content, matching the existing safe-DOM audit style. -- `assertNoSensitiveCanaries`: inspect public DOM text/attributes plus bounded captured API responses and browser/server logs for auth tokens, raw prompts, private filesystem paths, and seeded secret canaries. Never print a matched secret in the failure message. -- `captureUiGate`: create the output directory and save a full-page PNG using the normalized path. - -Add focused unit coverage for color parsing and path validation where it remains pure. Avoid duplicating Playwright behavior in mocks. - -### Step 5: Verify and commit - -Run: - -```powershell -node --test tests/e2e/harness.test.mjs -npm run typecheck -w @launchpad/web -git diff --check -``` - -Commit subject: `test(45): add bounded UI gate audit helpers` - -The commit body must record the helper boundary and the exact observed checks. - -## Task 2: Cover the shell, authentication, Agents, Settings, and not-found states - -**Files:** - -- Create: `tests/e2e/ui-gate.spec.mjs` -- Modify: `playwright.config.ts` -- Potentially modify after a demonstrated failure: `apps/web/src/pages/SettingsPage.tsx` - -### Step 1: Register one dedicated project spec - -Add `ui-gate.spec.mjs` to the existing `testMatch` array in `playwright.config.ts`. Do not add a script or dependency. - -In the spec, reuse `prepareHarnessRoot`, `startTestApp`, `isPortOpen`, and `AUTH_TOKEN` from `tests/e2e/support/test-app.mjs`. Start one deterministic app per worker, create isolated browser contexts for both required viewports, and remove only the temporary harness root owned by this spec. - -### Step 2: Write the clean-shell journey before product edits - -For each viewport, assert this sequence: - -1. Hold the first real `/api/auth` request, navigate to `/`, and capture `01-auth-loading`. -2. Release it and submit without a token; assert the required-token instruction remains associated with the input. -3. Enter an invalid token and assert the visible server-backed `Authentication required` error; capture `02-auth-error`. -4. Unlock with `AUTH_TOKEN`; assert the sidebar landmarks, current-route state, keyboard focus, and no document overflow. -5. Open Agents with an empty database; assert the empty state and capture `03-agents-empty`. -6. Open Create Agent; assert the initial disabled primary action and capture `04-agent-create-disabled`. -7. Create a real Agent with an 80-character name, verify text wrapping and no horizontal document overflow, then capture `05-agent-long-content`. -8. Visit its Agent page, exercise Edit Agent and the real stopped/started lifecycle controls using the existing public flow, and assert visible state changes. Treat existing lifecycle/denial specs as the deeper business source of truth. -9. Open Settings; assert every reserved/unavailable control plus save/discard actions are visibly and semantically disabled when unavailable, and capture `06-settings-disabled`. -10. Navigate to an unknown route; assert the not-found recovery link and capture `07-not-found`. - -Use role/name selectors. Apply `assertMinimumContrast` to representative primary text, muted text, active navigation, errors, and disabled controls. Apply `assertVisibleFocus` to navigation, form controls, and recovery actions. - -### Step 3: Add a failing Settings tab keyboard assertion - -Assert that the Settings tablist: - -- has exactly one tab with `tabindex="0"`; -- moves selection and focus with ArrowLeft/ArrowRight; -- supports Home/End; -- relates each tab to a `tabpanel` through `aria-controls`/`aria-labelledby`. - -Expected RED on current main: tabs expose `role="tab"` and `aria-selected`, but do not implement roving focus or tabpanel relationships. - -Do not fix it yet; preserve the focused failure for Task 5. - -### Step 4: Verify the test boundary and commit - -Run the focused spec at both configured viewports. The journey should pass until the intentional Settings assertion and should produce bounded diagnostics. Confirm no assertion requires an edit to `AgentPage.tsx`; if one does, document and coordinate it instead of editing the file. - -Commit subject: `test(45): cover clean shell and Agent UI states` - -## Task 3: Exercise every Shepherd surface and recovery state - -**Files:** - -- Modify: `tests/e2e/ui-gate.spec.mjs` -- Potentially modify after a demonstrated failure: `apps/web/src/pages/ShepherdPage.tsx` - -### Step 1: Add deterministic loading, empty, and reconnect coverage - -For each viewport: - -1. Hold the initial real `/api/shepherd/state` response, open Shepherd, assert `Connecting to the Shepherd kernel…`, and capture `08-shepherd-loading`. -2. Release the response; assert `No execution events yet`, `Timeline waiting`, and `No Planes yet`, then capture `09-shepherd-empty`. -3. Allow a confirmed state, fail exactly one subsequent state read with HTTP 503, and assert `Showing the last confirmed state · reconnecting automatically` while the prior state remains visible; capture `10-shepherd-reconnecting`. -4. Release interception and assert `Kernel online` returns without a reload. - -Interception may delay or fail the real read only. It must not fabricate a successful state payload. - -### Step 2: Create a real Mission and inspect the six Shepherd surfaces - -Start the repository's deterministic demo Mission through the real API/UI path already used by `tests/e2e/shepherd-hero.spec.mjs`. Wait for real persisted state that includes the collision, candidates, promotion/evidence, and retained-loser state required by the PRD, then assert: - -- sidebar/navigation remains usable; -- contract stream events render and filter controls change the visible subset; -- the timeline has a bounded `.timeline-scroll` owner; -- the Plane tree renders nested `button.tree-node` controls and retains usable focus; -- opening a Plane produces a named `dialog` drawer; -- drawer evidence tabs are keyboard-operable and content is safe DOM; -- Escape closes the drawer and restores focus to the activating tree node without trapping the keyboard; -- Project Group entry points remain discoverable. - -Capture `11-shepherd-active`, `12-shepherd-filtered`, and `13-plane-drawer`. - -### Step 3: Add the failing full-identifier assertion - -Locate a visibly shortened Plane ID and require its full identifier to be programmatically available through an accessible description or `title` attribute. - -Expected RED on current main: the shortened `` text has no full-value affordance. - -Preserve this failure for Task 5. - -### Step 4: Verify and commit - -Run the focused Shepherd journey at both viewports and the adjacent existing Shepherd specs to confirm the new gate reuses, rather than replaces, their deeper behavioral coverage. - -Commit subject: `test(45): exercise every Shepherd UI surface` - -## Task 4: Cover Project Group initialization, recovery, and message states - -**Files:** - -- Modify: `tests/e2e/ui-gate.spec.mjs` -- Potentially modify after a demonstrated failure: `apps/web/src/pages/ProjectGroupPage.tsx` -- Potentially modify after a demonstrated failure: `apps/web/src/styles.css` - -### Step 1: Write the uninitialized and loading assertions - -Using the real Agent created in Task 2: - -1. Open Project Group before initialization and assert `No Shepherd project yet`. -2. Assert the composer and member mention controls are semantically disabled and visually distinguishable from enabled controls; capture `14-group-uninitialized`. -3. Initialize the Project Group through the existing real flow. -4. Hold the first real `/api/shepherd/projects/:id/group-messages` read, assert `Loading real group messages…`, and capture `15-group-loading`. -5. Release the read, assert `The Project Group is quiet`, and capture `16-group-empty`. - -### Step 2: Write recovery and sending assertions - -1. Fail exactly one subsequent group-message GET with HTTP 503. -2. Assert the reconnect banner contains the returned error plus `retrying automatically`, and that last confirmed content remains visible. -3. Let polling recover and assert the banner disappears without a reload. -4. Hold a real group-message POST after submission. While it is pending, assert the composer, send action, and mention controls cannot produce a second action. -5. Release the POST and require the persisted message to appear after the real read path. -6. Submit long unbroken content within the public limit and verify wrapping plus internal scrolling without document overflow. -7. After recovery and another poll, assert the persisted message is neither duplicated nor replaced by stale content. -8. Assert a Project Group message does not silently create a Mission. - -Capture `17-group-reconnecting` and `18-group-message`. - -### Step 3: Add failing compact-control and identifier assertions - -- Compare enabled and disabled member-mention button styles and require a non-color-only disabled distinction. -- If the real message includes a shortened Contract ID, require the full identifier to be available through `title` or an accessible description. - -Expected RED on current main: disabled mention buttons lack a distinct visual treatment; shortened Contract links may also lack a full-value affordance. - -### Step 4: Verify and commit - -Run the focused Project Group journey at both viewports plus `tests/e2e/project-group-contract-flow.spec.mjs`. - -Commit subject: `test(45): cover Project Group recovery states` - -## Task 5: Make only the causal product fixes demonstrated by the gate - -**Files:** - -- Modify: `apps/web/src/pages/SettingsPage.tsx` -- Modify: `apps/web/src/pages/ShepherdPage.tsx` -- Modify if the failing assertion requires it: `apps/web/src/pages/ProjectGroupPage.tsx` -- Modify: `apps/web/src/styles.css` -- Modify tests only to correct an invalid assumption, never to weaken the acceptance criteria. - -### Step 1: Recheck ownership - -Fetch/prune and inspect open PR files. Stop if any active owner now includes one of the four product files. Record the overlap in issue #45 rather than editing through it. - -### Step 2: Implement Settings roving tabs - -Keep the visible Settings design unchanged. Add stable tab and panel IDs plus a small local keyboard handler: - -```ts -function selectAdjacentTab( - current: SettingsSection, - key: 'ArrowLeft' | 'ArrowRight' | 'Home' | 'End', -): SettingsSection -``` - -- Set the active tab to `tabIndex={0}` and inactive tabs to `-1`. -- On ArrowLeft/ArrowRight, wrap through the ordered tabs; Home selects the first and End the last. -- Update selection and move DOM focus to the new active tab. -- Add `aria-controls` to tabs and `role="tabpanel"`, `id`, and `aria-labelledby` to the active panel. -- Do not change click behavior, labels, or visual hierarchy. - -Run the Settings slice of the UI gate. Expected GREEN: the preserved keyboard assertions now pass. - -### Step 3: Expose full values for shortened identifiers - -- In `ShepherdPage.tsx`, add the full Plane ID to the existing shortened ID element, preferring `title={plane.id}` unless an accessible description is clearer in context. -- In `ProjectGroupPage.tsx`, if the gate found a shortened Contract link, add `title={message.contractId}` without changing the visible compact label. -- Do not add copy buttons or redesign the rows in this issue. - -Run the corresponding focused slices. Expected GREEN: full-value assertions pass. - -### Step 4: Distinguish disabled compact mention buttons - -Add a scoped rule for `.group-members button:disabled` that changes opacity and cursor while retaining readable contrast. Do not increase the existing compact chip size or globally restyle disabled buttons. - -Run the Project Group slice. Expected GREEN: semantic disabled state and non-color visual distinction both pass. - -### Step 5: Run adjacent verification - -Run: - -```powershell -npm run test -w @launchpad/web -npm run typecheck -w @launchpad/web -npm run build -w @launchpad/web -npm run build -w @launchpad/server -npx playwright test tests/e2e/ui-gate.spec.mjs -npx playwright test tests/e2e/settings-model-review.spec.mjs tests/e2e/ui04-audit.spec.mjs tests/e2e/shepherd-hero.spec.mjs tests/e2e/project-group-contract-flow.spec.mjs -git diff --check -``` - -If a Playwright command does not select the intended tests through the repository config, run the exact configured project names shown by `npx playwright test --list` and record the corrected command. - -Commit subject: `fix(45): close UI gate accessibility gaps` - -## Task 6: Produce bounded evidence and the audit record - -**Files:** - -- Create: `docs/ui-review/ui-gate/AUDIT.md` -- Create: `docs/ui-review/ui-gate/1280x800/*.png` -- Create: `docs/ui-review/ui-gate/1440x900/*.png` -- Conditionally modify after an ownership recheck: `docs/BUILD_LOG.md` -- Conditionally modify after an ownership recheck: `docs/TASKS.md` - -### Step 1: Generate the evidence set - -Delete or replace only files under the branch-owned `docs/ui-review/ui-gate/` directory. Run the dedicated gate with `E2E_UPDATE_EVIDENCE=true` so its 18 named stages are copied from temporary output into both committed viewport directories. Ordinary runs must continue writing only to `.tmp/playwright-evidence/ui-gate/`. - -Verify: - -- every expected stage exists at both sizes; -- PNGs are non-empty and have the declared pixel dimensions; -- no trace, video, server log, auth token, private path, or raw prompt is included; -- bounded DOM/API/log canary scans passed without echoing sensitive matches; -- the total evidence set is bounded and reviewable. - -### Step 2: Inspect the rendered UI - -Use the in-app browser workflow to open the local app at 1280×800 and 1440×900. Inspect representative loading, empty, error, long-content, disabled, active, drawer, and reconnect states. Confirm screenshots agree with the live DOM assertions and with `docs/UI.jpeg`. - -Record visual findings in `AUDIT.md`; do not infer visual quality from selectors alone. - -### Step 3: Write the WCAG and design audit - -`AUDIT.md` must include: - -- branch commit, test command, date, Node/browser versions, and viewport matrix; -- a table mapping all six PRD surfaces to evidence filenames and assertions; -- keyboard results for global navigation, Settings tabs, filters, Plane tree, drawer tabs/close, Project Group composer, and recovery links; -- focus visibility and logical-order observations; -- accessible names, roles, selected/expanded/disabled state, landmarks, dialogs, and live status/error findings; -- measured contrast pairs and thresholds, including disabled and error treatments; -- overflow/scroll-owner checks and long unbroken content results; -- loading, empty, error/reconnect, disabled, and not-found state results; -- the compact mention-chip target exception and its rationale; -- screen-reader testing limitations stated explicitly—DOM semantics are not a substitute for manual assistive-technology validation; -- design critique for hierarchy, consistency, density, and fidelity to the current Launchpad UI; -- candidate gate status, independent usability review status, and final integration status as separate fields. - -### Step 4: Run candidate gates - -With Node 24 active, run: - -```powershell -node --test tests/e2e/harness.test.mjs -npm run test -w @launchpad/web -npm run typecheck -w @launchpad/web -npm run build -w @launchpad/web -npm run build -w @launchpad/server -npx playwright test tests/e2e/ui-gate.spec.mjs -npm run check -git diff --check -git status --short -``` - -The known Windows launcher limitation may still prevent the local aggregate `npm run check`; if so, preserve the exact failure, confirm the individual substantive gates locally, and require hosted CI on the exact commit before calling the candidate green. - -### Step 5: Update shared ledgers only when safe - -Recheck open PRs immediately before touching `docs/BUILD_LOG.md` or `docs/TASKS.md`. - -- If another active task owns either file, leave it untouched and state the deferred ledger update in the PR. -- Otherwise add a concise issue #45 candidate-evidence entry, without marking independent usability or final integration complete. - -Commit subject: `docs(45): record UI gate candidate evidence` - -## Task 7: Open the draft PR and request independent gates - -**Files:** No code changes expected. - -### Step 1: Final branch verification - -Use `superpowers:verification-before-completion`. Review the exact diff from `origin/main`, check for unrelated files, run the focused/adjacent gates again if any code changed after Task 6, and confirm the worktree is clean. - -### Step 2: Push and open the linked draft PR - -Push every commit to `origin/test/45-ui-gate`. Use the repository PR-description skill and open a draft PR targeting `main` with: - -- `Closes #45` only if repository convention allows a draft to carry the closing keyword; otherwise `Relates to #45` until ready; -- HANDOVER replacement reference: `docs/TASKS.md` issue `UI-GATE`; -- approved design and implementation-plan links; -- owned files and explicit exclusions; -- six-surface acceptance matrix; -- exact tests and whether each was local or hosted; -- links to both viewport evidence directories; -- known limitations and deferred shared-ledger edits; -- separate `C/B/U/I` statuses, with only directly observed candidate/browser gates claimed and independent usability/final integration left pending. - -### Step 3: Verify hosted CI on the exact commit - -Wait for the draft PR's hosted checks. If they fail, use `superpowers:systematic-debugging`, reproduce the smallest failure, add a causal regression where applicable, and repeat the relevant local and hosted gates. - -### Step 4: Request independent review - -Request a reviewer who did not implement the change to perform the usability gate against the evidence and live flow. Do not self-approve that gate. Keep final integration pending until issues #44 and the E2E/integration owners have landed and the gate has been rerun on updated `main`. - -### Step 5: Report the candidate outcome - -Report: - -- PR URL and exact head commit; -- candidate UI gate result; -- local and hosted verification evidence; -- causal fixes made; -- any findings deferred due to file ownership; -- independent review and final integration status. diff --git a/docs/superpowers/plans/2026-08-31-issue-48-stability.md b/docs/superpowers/plans/2026-08-31-issue-48-stability.md deleted file mode 100644 index e215258..0000000 --- a/docs/superpowers/plans/2026-08-31-issue-48-stability.md +++ /dev/null @@ -1,387 +0,0 @@ -# Issue 48 Stability Campaign Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:test-driven-development` for each behavior change and `superpowers:verification-before-completion` before commits, pushes, pull-request updates, or completion claims. Execute the tasks in order and keep every observed command result in the issue evidence packet. - -**Goal:** Remove the reproduced sources of suite instability, recheck the previously recorded service rows without weakening them, and produce a trustworthy five-run `npm run check` campaign for GitHub issue #48. - -**Architecture:** Keep the fixes at their causal boundaries. Fixture Git commands receive a deliberately curated child-process environment so an enclosing hook cannot redirect them. Verification-snapshot tests synchronize through the service's existing fault-checkpoint seam after the owned snapshot has been removed, rather than consuming OS file watchers. Scheduler overlap is proven directly at the shared bounded-batch primitive instead of through a full Git-backed Mission. The candidate-cleanup fixture establishes the executor's shared private root through its public preflight before concurrent runs, isolating the cleanup phase that the test claims to exercise. No product behavior, public API, UI, dependency, retry count, assertion strength, or timeout changes. - -**Tech stack:** TypeScript, Node.js, npm workspaces, Vitest 4, Git, GitHub Actions. - -**Spec:** GitHub issue #48; `docs/PRD.md` section 16, Phase 9B; `docs/TASKS.md` row `STABILITY`. - -## Progress - -- [x] Task 1: Isolate fixture Git commands from enclosing hook state. -- [x] Task 2: Replace snapshot-removal file watchers with a lifecycle checkpoint. -- [x] Task 3: Recheck and causally isolate the historically sensitive service rows. -- [x] Task 4: Run adjacent and full server verification on the revised candidate. -- [x] Task 5: Commit the causal fixes and open the linked draft pull request. -- [x] Task 6: Run the formal five-consecutive-check campaign. -- [ ] Task 7: Independent readiness review. - -## Global constraints - -- Work only in `/Users/sanje/code/shepherd/.tmp/worktrees/issue-48-stability` on `test/48-stability-campaign`, based on `origin/main@a2a464d6be697ab949b254944b81c355a9be5403` after PR #94 integrated. -- The issue is assigned to `sanjey99`; ownership is recorded in issue comment `#issuecomment-5472521900`; the branch is already published to `origin`. -- Recheck issue #48, open pull requests, remote branches, and worktrees before each new file-ownership expansion. Stop if another active owner claims an overlapping file. -- Keep the accepted UI frozen. This plan does not modify web code or visual evidence. -- Do not alter production timeouts, Vitest timeouts, retry counts, suite concurrency, assertions, or skip lists. A green result obtained through those mechanisms is invalid for #48. -- Keep default tests network- and model-free. Never print credentials, prompts, session identifiers, private environment values, or unbounded logs. -- Preserve the current `test.each` coverage for both policy values and both F-03 failure variants. -- Treat the five-run sequence as formal evidence only when every run uses the same commit and current `origin/main`. If either SHA changes, restart the sequence from run 1. -- Do not merge the branch. Integration and the post-merge gate belong to the integrator. - ---- - -## Task 1: Isolate fixture Git commands from enclosing hook state - -**Files:** - -- Modify: `apps/server/src/shepherd/general-project.test.ts` -- Reference only: `apps/server/src/shepherd/recovery.test.ts` - -### Step 1: Preserve the deterministic RED evidence - -The pre-implementation reproduction has already been observed on the unchanged branch: - -- `general-project.test.ts` alone: 8/8 passed. -- Full server suite in a normal shell: 843 passed, 3 skipped. -- The same policy-interruption row under inherited outer `GIT_DIR` and `GIT_WORK_TREE`: 1/1 failed and staged `policy.json` in the enclosing Shepherd repository. - -Record this exact contrast in `docs/BUILD_LOG.md`; do not manufacture a second enclosing repository mutation merely to repeat RED. - -### Step 2: Add a hostile-environment regression test first - -Import `vi` from Vitest and add `vi.unstubAllEnvs()` to the existing teardown path. Add one focused test modeled on the poisoned-Git-selector regression in `recovery.test.ts`: - -1. Create a managed project fixture and a separate decoy Git repository inside the test-owned temporary directory. -2. Point inherited `GIT_DIR` and `GIT_WORK_TREE` at the decoy with `vi.stubEnv`. -3. Ask the fixture helper for the managed repository's top level and stage a fixture-owned file. -4. Assert that the returned top level is the real path of the selected managed repository. -5. Assert that the selected repository contains the expected staged path and the decoy repository remains clean. - -Run: - -```bash -npx vitest run apps/server/src/shepherd/general-project.test.ts -``` - -Expected RED: the current raw `execFile("git", ...)` helper follows the inherited selector variables, so repository identity or staging ownership is wrong. - -### Step 3: Add one curated fixture Git helper - -Replace direct uses of the promisified raw Git executor with a local helper whose public shape is: - -```ts -async function runFixtureGit( - repositoryPath: string, - args: readonly string[], -): Promise -``` - -Invoke Git as `git -C ...args` with a bounded buffer and timeout. Pass a new environment object containing only the process values the child needs: - -- `PATH` -- `HOME=/nonexistent` -- `LANG=C` -- `LC_ALL=C` -- `GIT_CONFIG_NOSYSTEM=1` -- `GIT_CONFIG_GLOBAL=/dev/null` -- `GIT_TERMINAL_PROMPT=0` - -Do not spread `process.env`; omitting `GIT_DIR`, `GIT_WORK_TREE`, `GIT_INDEX_FILE`, and related selector state is the security and isolation boundary. Return trimmed stdout and allow command failures to retain their normal diagnostics. - -### Step 4: Assert nested repository identity before destructive fixture operations - -Add a small assertion helper that compares: - -```ts -await realpath(repositoryPath) -``` - -with the resolved result of: - -```bash -git -C rev-parse --show-toplevel -``` - -Call it before the policy interruption tests stage or commit fixture paths. A mismatch must fail before Git mutates any index. Keep the existing assertions that prove the interrupted write is cleaned before its commit. - -### Step 5: Turn the focused test GREEN - -Run: - -```bash -npx vitest run apps/server/src/shepherd/general-project.test.ts -npm run typecheck -w @launchpad/server -git diff --check -``` - -Expected GREEN: all general-project rows pass, including the hostile-selector regression, and the enclosing Shepherd repository remains clean. - ---- - -## Task 2: Replace snapshot-removal file watchers with a lifecycle checkpoint - -**Files:** - -- Modify: `apps/server/src/shepherd/service.ts` -- Modify: `apps/server/src/shepherd/service.test.ts` - -### Step 1: Write checkpoint-driven F-03 tests before production code - -Remove `watch` from the `node:fs/promises` imports and remove `waitForOwnedPathRemoval`. Extend the two test verifiers' sibling-capture promise values from a bare path to: - -```ts -{ - contractId: string; - snapshotPath: string; -} -``` - -For each F-03 test, create one promise before constructing the service. Its `faultCheckpoint` observer resolves only when all three conditions hold: - -- the checkpoint is `contract_verification_snapshot_removed`; -- the checkpoint context belongs to the current Mission; -- the checkpoint context contract ID equals the captured sibling contract ID. - -Keep the existing sequence: observe the primary failure, capture the blocked sibling, release the sibling verifier, await its return, await the exact cleanup checkpoint, then assert the sibling snapshot path returns `ENOENT`. The promise replaces only watcher-based observation; it does not replace the filesystem assertion. - -Run: - -```bash -npx vitest run apps/server/src/shepherd/service.test.ts -t "removes the sibling verification snapshot after F-03" -npm run typecheck -w @launchpad/server -``` - -Expected RED: the new checkpoint literal is not yet part of the service contract and no production path emits it. - -### Step 2: Extend the existing checkpoint type - -In `service.ts`, add: - -```ts -"contract_verification_snapshot_removed" -``` - -to `ShepherdFaultCheckpoint`. Do not add a new event bus, public response field, or runtime dependency; the existing optional `faultCheckpoint` test seam is sufficient. - -### Step 3: Emit the checkpoint only after owned cleanup settles - -Wrap the existing `planeManager.withVerificationSnapshot(...)` call in a local async function with `try/finally`. In the `finally` block, await: - -```ts -this.checkpoint("contract_verification_snapshot_removed", { - missionId: mission.id, - contractId: contract.id, -}); -``` - -The checkpoint belongs after `withVerificationSnapshot` settles because `PlaneManager` removes the snapshot in its own `finally`. Preserve the verifier result and exception unchanged. Use the same scoped IDs already passed to `contract_verification_snapshot_ready`. - -If the optional checkpoint observer itself throws while a verifier exception is already active, preserve the verifier exception as the primary failure and attach the observer failure only through the repository's existing diagnostic mechanism; a test seam must not mask product behavior. - -### Step 4: Turn the F-03 tests GREEN without watchers - -Run the focused command five separate times, followed by adjacent verification tests: - -```bash -npx vitest run apps/server/src/shepherd/service.test.ts -t "removes the sibling verification snapshot after F-03" -npx vitest run apps/server/src/shepherd/service.test.ts -t "contract verification snapshot" -npm run typecheck -w @launchpad/server -git diff --check -``` - -Expected GREEN: both F-03 variants pass without `fs.watch`, the snapshot-removal assertions remain intact, and no `EMFILE` or unhandled-rejection warning appears. - ---- - -## Task 3: Recheck the two historically sensitive service rows - -**Files:** - -- Inspect first: `apps/server/src/shepherd/service.test.ts` -- Modify only after a deterministic RED demonstrates a causal defect: `apps/server/src/shepherd/service.test.ts`, `apps/server/src/shepherd/service.ts` - -### Step 1: Run each row repeatedly on the fixed branch - -Run the PERF-01 overlap row and attention-required fixture-cleanup row five separate times each: - -```bash -npx vitest run apps/server/src/shepherd/service.test.ts -t "PERF-01 proves real scheduled candidate executor intervals overlap before release" -npx vitest run apps/server/src/shepherd/service.test.ts -t "cancels tracked attention-required Missions before fixture cleanup" -``` - -Record every result. Passing repeated focused runs establishes that the previously logged failures do not currently justify unrelated edits. - -### Step 2: Apply only a demonstrated causal synchronization fix - -PERF-01 did fail during formal campaign run 4 after five focused passes and three complete green campaign runs. The service row timed out at 5.176 seconds while 843 peer server tests passed. A deferred start barrier alone retained the original full-Mission completion assertions but still timed out under a fresh full-suite run at 6.229 seconds. Disabling auto-resolution and awaiting exact candidate completion/attention also remained over budget at 6.038 seconds. These RED results prove that a Git-backed Mission lifecycle cannot be the timing harness for a five-second scheduler-overlap assertion under representative suite pressure. - -Move the existing production `allSettledBounded` primitive from `service.ts` to the canonical `scheduler.ts` module without changing its implementation or callers. Replace the expensive service-level PERF row with a scheduler-boundary test in `scheduler.test.ts` that: - -1. passes two distinct candidate IDs to the same exported bounded batch primitive used by `ShepherdService`; -2. dispatches each item through a test executor with promise barriers for both-started, release, and both-completed; -3. asserts two start timestamps exist while completion remains empty before release; -4. releases both operations, awaits the real batch result, and asserts two fulfilled results plus two completion timestamps; -5. proves the latest start timestamp is no later than the earliest completion timestamp; -6. retains a separate limit-one assertion so the moved primitive still enforces its concurrency cap and input-order result contract. - -Remove the service-test-only `CandidateExecutionIntervalExecutor` and its full-Mission PERF row after the scheduler-boundary RED/GREEN test exists. This isolates the performance contract rather than reducing it: the exact start-before-release/completion-after-release assertions move intact to the production scheduling primitive, while the adjacent 30-second real-Planes tests continue to prove completed Mission, selected/promoted candidate, and `promotion_completed` behavior. Do not extend any timeout or change suite concurrency. - -If attention-required cleanup fails, add a test-owned lifecycle barrier at the exact point the tracked Mission finishes cancellation and await that barrier before fixture removal. Preserve the terminal-state and cleanup assertions; do not add retries or sleeps. - -After either demonstrated fix, rerun the failing row five separate times and run all adjacent lifecycle tests. If neither row fails, leave their code unchanged. - ---- - -## Task 4: Run adjacent and full server verification - -**Files:** none unless a new deterministic defect is exposed. - -### Step 1: Verify the complete server suite - -Run: - -```bash -npm test -w @launchpad/server -npm run typecheck -w @launchpad/server -git diff --check -git status --short -``` - -Expected GREEN: 843 or more passing server tests, only the three documented skips, zero unhandled-rejection warnings, and no unowned files or staged fixture artifacts. - -### Step 2: Review the causal diff - -Inspect the complete diff and confirm: - -- no timeout, retry, concurrency, skip, or assertion weakening; -- no UI or dependency changes; -- fixture Git selectors cannot escape the fixture repository; -- the removal checkpoint is emitted after cleanup and cannot alter normal production behavior; -- all temporary repositories and snapshots remain test-owned. - -Run `npm audit` and record the observed result before committing. - -### Step 3: Isolate candidate cleanup from first-use root adoption - -The normal pre-push server gate exposed one more representative-load failure in -`keeps candidate cleanup failures bounded and prevents promotion`: all candidates -were failed and promotion remained blocked, but none retained the expected -sanitized Runtime cleanup message. The row passed alone, indicating a scheduling -race rather than a deterministic assertion mismatch. - -The live executor prepares and validates one shared private-home root inside every -candidate `run()`. This routed fixture bypassed the production executor recovery / -startup path, so concurrent first-use candidates could race sentinel adoption and -fail before `runner.run` registered their private homes as cleanup-fault targets. -Initialize that shared boundary through the executor's public `preflight()` before -candidate scheduling and assert exactly one preflight occurred. Do not change -sentinel production code, cleanup injection, failure assertions, or the test -timeout. - -Preserve the observed RED/GREEN evidence: - -- RED: the new preflight-count invariant observed `0` before fixture initialization. -- GREEN: the exact row 10/10, the executor file 72/72, production and test - typechecks, and the full server suite with 845 passed / 3 skipped. - ---- - -## Task 5: Commit the causal fixes and open the linked draft pull request - -**Files:** the Task 1 and Task 2 files plus this plan. - -### Step 1: Commit the implementation packet - -Use the repository commit format with subject: - -```text -test: harden stability campaign fixtures -``` - -The body must summarize both root causes and list the focused checks actually observed. Push without bypassing hooks. The normal pre-push hook must pass with the new Git-environment isolation; do not use `--no-verify` for this implementation push. - -### Step 2: Open a draft PR against `main` - -The draft PR must include: - -- `Relates #48` and TASKS ID `STABILITY`; -- PRD section 16 / Phase 9B; -- owned files and explicit exclusion of UI/product feature work; -- base `main` and exact branch SHA; -- the two root causes and why the fixes are causal; -- acceptance criteria and the five-run test plan; -- current focused/full checks, with the formal five-run campaign still pending. - -Post the PR URL and current SHA to issue #48. Do not mark the issue complete at this stage. - ---- - -## Task 6: Run the formal five-consecutive-check campaign - -**Files:** - -- Modify after the campaign: `docs/BUILD_LOG.md` -- Modify after the campaign: `docs/FIXES.md` -- Modify after the campaign: `docs/TASKS.md` - -### Step 1: Freeze and record the candidate identity - -Fetch and prune. Record: - -```bash -git rev-parse HEAD -git rev-parse origin/main -git status --short -``` - -Confirm the worktree is clean and no overlapping PR has appeared. The branch SHA and `origin/main` SHA become the campaign identity. - -### Step 2: Run the exact full gate five times - -Run this command five separate times, without edits, commits, dependency changes, Docker state changes, or branch changes between runs: - -```bash -npm run check -``` - -For each run, record start/end time, duration, server pass/skip counts, web pass count, build result, warnings, branch SHA, and `origin/main` SHA. Any failure or SHA change resets the count to zero after the causal issue is resolved. - -### Step 3: Record bounded evidence - -Add `FIXES` entries for: - -- fixture Git environment isolation under enclosing hooks; -- deterministic verification-snapshot cleanup observation without OS watchers. - -Add a bounded `BUILD_LOG` campaign table for runs 1–5. Update the `STABILITY` row in `TASKS` with branch evidence and distinguish candidate coverage from post-integration status. Do not claim the issue integrated or closeable until the branch is merged and the required updated-`main` gate is observed. - -### Step 4: Commit and push the evidence packet - -Use subject: - -```text -docs: record issue 48 stability evidence -``` - -Run `git diff --check`, the relevant documentation checks, and the normal pre-push hook. Update the draft PR with the exact run table and candidate SHA. - ---- - -## Task 7: Independent readiness review - -**Files:** review-only unless a finding requires a causal correction. - -Ask the selected quality specialist for a critical review of the final branch against issue #48 and Phase 9B. The review must check: - -- correctness and failure preservation in both fixes; -- absence of masking tactics; -- adequacy of regression coverage; -- exact-SHA integrity of the five-run campaign; -- accuracy of `TASKS`, `FIXES`, `BUILD_LOG`, the draft PR, and issue evidence; -- remaining integration and post-merge gates. - -Address every critical/high finding with TDD, rerun the affected gates, and restart the five-run sequence if the candidate SHA changes. Leave the draft PR ready for integrator review; do not merge it or close #48 yourself. diff --git a/docs/superpowers/plans/2026-08-31-issue-96-release-readiness.md b/docs/superpowers/plans/2026-08-31-issue-96-release-readiness.md deleted file mode 100644 index c38ea24..0000000 --- a/docs/superpowers/plans/2026-08-31-issue-96-release-readiness.md +++ /dev/null @@ -1,189 +0,0 @@ -# Issue 96 Release Readiness Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Resolve every concrete product, security, test-harness, infrastructure-validation, and documentation defect reproduced by the exact-main audit. - -**Architecture:** Preserve the frozen UI and existing public contracts. Add fail-closed capacity and request-boundary helpers, constrain live gates structurally, move cloud secrets to a post-provision SSH bootstrap outside Terraform, and make every correction observable through causal tests before implementation. - -**Tech Stack:** Node.js 22+, TypeScript, Fastify, React, Vitest, Playwright, Docker, Terraform 1.6+. - -**Spec:** `docs/PRD.md` sections 0.3–0.4 and 11–17; umbrella issue #96 with linked issues #45, #65, and #89. - -## Global Constraints - -- Preserve the accepted UI theme and layout; only minimal functional/accessibility corrections are allowed. -- Default tests must remain network- and model-free. -- Live gates stay opt-in, single-worker, retry-free, bounded, redacted, and current-tree-only. -- No credential may enter Terraform state, cloud-init user data, process arguments, persisted state, DOM, or logs. -- Every production behavior change starts with a failing regression test. -- `npm run check`, the two-viewport Playwright matrix, coverage, audit, and Terraform validation must pass before push. - ---- - -### Task 1: Durable collection admission - -**Files:** -- Create: `apps/server/src/collection-capacity.ts` -- Modify: `apps/server/src/database-schema.ts` -- Modify: `apps/server/src/agent-service.ts` -- Modify: `apps/server/src/shepherd/service.ts` -- Test: `apps/server/src/collection-capacity.test.ts` -- Test: `apps/server/src/agent-service.test.ts` - -**Interfaces:** -- Produces `appendWithinCapacity(collection, values, label)` and `DurableCapacityError` with HTTP status `507`. -- Consumers use the helper before every top-level durable append; no existing evidence is evicted. - -- [ ] Write boundary tests proving an append at 9,999 succeeds, an append past 10,000 fails without mutation, and an Agent capacity failure creates no workspace. -- [ ] Run the focused tests and observe the expected RED at the real append paths. -- [ ] Implement bounded admission and replace top-level durable `push` calls. -- [ ] Run focused Store, Agent, Shepherd service, API, and schema tests GREEN. - -### Task 2: Tokenless request and public-bind boundary - -**Files:** -- Modify: `apps/server/src/config.ts` -- Modify: `apps/server/src/config.test.ts` -- Modify: `apps/server/src/app.ts` -- Modify: `apps/server/src/app.test.ts` -- Modify: `docker-compose.yml` -- Modify: `scripts/deploy-existing-ecs.test.mjs` - -**Interfaces:** -- Tokenless mode is valid only for a loopback external bind. -- Tokenless API requests require a loopback `Host`; requests carrying `Origin` require an exact same-origin loopback origin. - -- [ ] Add failing config tests for a direct non-loopback bind and Compose public bind without a token. -- [ ] Add failing real-app tests for hostile `Host`, hostile `Origin`, `Origin: null`, and allowed same-origin/no-Origin loopback requests. -- [ ] Implement external-bind validation and the tokenless request hook before route handling. -- [ ] Run focused config, app, and Compose behavior tests GREEN. - -### Task 3: UI interaction and accessibility regressions - -**Files:** -- Modify: `apps/web/src/pages/ProjectGroupPage.tsx` -- Modify: `apps/web/src/pages/SettingsPage.tsx` -- Modify: `apps/web/src/styles.css` -- Modify: `tests/e2e/ui-gate.spec.mjs` -- Modify: `tests/e2e/starter-kit.spec.mjs` -- Modify: `tests/e2e/starter-kit.live.spec.mjs` - -**Interfaces:** -- Mention insertion commits text and caret synchronously before subsequent keyboard input. -- Settings numeric inputs expose exact accessible names. -- The direct Playground tests explicitly select direct mode without changing the product default. - -- [ ] Add/retain failing Playwright assertions for exact mention content, numeric-control roles/names, direct-mode routing, and Create Agent viewport containment. -- [ ] Run focused tests at both viewports and observe the four audit failures. -- [ ] Use synchronous React state flush for mention insertion, add explicit numeric labels, select direct mode in legacy tests, and add the minimum scroll clearance needed for the Create action. -- [ ] Run focused browser tests GREEN at `1280x800` and `1440x900`. - -### Task 4: Current-tree-only live gates - -**Files:** -- Modify: `package.json` -- Modify: `apps/server/vitest.config.ts` -- Modify: `tests/e2e/starter-kit.live.spec.mjs` -- Modify: `tests/e2e/support/test-app.mjs` -- Test: `tests/e2e/harness.test.mjs` - -**Interfaces:** -- Vitest live commands run with `--root apps/server` and paths relative to that root. -- The legacy harness resolves a bare Codex executable through the allowlisted `PATH`, while an explicit path remains exact. - -- [ ] Run the existing model-review list command and capture duplicate worktree discovery as RED. -- [ ] Add a failing executable-resolution harness test and a list assertion that exactly one live file is selected. -- [ ] Constrain both package scripts/config and implement bounded executable resolution. -- [ ] Verify one listed model-review test and one listed runtime test without making a live request. - -### Task 5: Volume-aware live Runtime gate - -**Files:** -- Create: `Dockerfile.live-test` -- Create: `scripts/run-live-runtime-gate.mjs` -- Create: `scripts/run-live-runtime-gate.test.mjs` -- Modify: `apps/server/src/shepherd/live-runtime.integration.test.ts` -- Modify: `package.json` - -**Interfaces:** -- The host wrapper runs the test control plane in a disposable test image with a named state volume and the container-engine socket. -- `liveConfig()` accepts only the wrapper-provided canonical state root/volume and places all mounted roots beneath it. - -- [ ] Add wrapper argument/environment tests that fail until the named-volume, cleanup, env-name-only, one-attempt contract exists. -- [ ] Add a config-focused RED proving the live test no longer clears valid volume settings. -- [ ] Implement the disposable runner image/wrapper and volume-root layout. -- [ ] Run the zero-spend preflight, then the single authorized live Runtime gate once with no retry. - -### Task 6: Enforced 80 percent coverage - -**Files:** -- Modify: `package.json` -- Modify: `package-lock.json` -- Modify: `apps/server/vitest.config.ts` -- Modify: `apps/web/vitest.config.ts` - -**Interfaces:** -- `npm run test:coverage` produces bounded text/JSON reports and enforces at least 80 percent statements, branches, functions, and lines for covered production modules. - -- [ ] Run `npm run test:coverage` and observe the missing-script RED. -- [ ] Add pinned `@vitest/coverage-v8` and workspace coverage commands with explicit source inclusion and live-test exclusions. -- [ ] Run coverage, add causal unit tests for uncovered behavior rather than exclusions, and repeat until all thresholds pass. - -### Task 7: Secret-free Terraform provisioning - -**Files:** -- Modify: `deploy/volcengine/main.tf` -- Modify: `deploy/volcengine/variables.tf` -- Modify: `deploy/volcengine/cloud-init.yaml.tftpl` -- Modify: `scripts/deploy-volcengine.sh` -- Create: `scripts/deploy-volcengine.test.mjs` -- Modify: `package.json` -- Modify: `README.md` - -**Interfaces:** -- Terraform provisions only infrastructure and public repository metadata. -- The deploy script transfers `.env.production` over SSH after cloud-init and installs it mode `0600`; secret values never become Terraform inputs or command arguments. - -- [ ] Add a behavior test with fake Terraform/SSH/SCP commands proving secrets are absent from Terraform environment, generated plan inputs, and command arguments. -- [ ] Run the test RED against the current `TF_VAR_ark_api_key` and cloud-init path. -- [ ] Remove secret Terraform variables/user data and implement post-provision SSH bootstrap with strict key-file validation. -- [ ] Run script tests, shell syntax checks, and credential canary scans GREEN. - -### Task 8: Pinned Terraform validation - -**Files:** -- Modify: `package.json` -- Create: `scripts/validate-terraform.mjs` -- Test: `scripts/validate-terraform.test.mjs` - -**Interfaces:** -- `npm run test:terraform` uses local Terraform when compatible, otherwise pinned `hashicorp/terraform:1.9.8` through Docker with no credentials. - -- [ ] Run the missing validation command RED. -- [ ] Implement version selection, read-only repository mount, isolated plugin cache, `fmt -check`, `init -backend=false`, and `validate`. -- [ ] Run the pinned validation command GREEN. - -### Task 9: Complete browser, security, and repository verification - -**Files:** all changed files. - -- [ ] Run focused RED/GREEN tests for every task. -- [ ] Run `npm audit --json` and inspect zero High/Critical results. -- [ ] Run `npm run test:coverage`, `npm run test:terraform`, full `npm run test:e2e:harness`, and `npm run check`. -- [ ] Inspect both viewport screenshots, console errors, accessibility names, and document/body overflow. -- [ ] Run `git diff --check` and a tracked secret scan. - -### Task 10: Truthful evidence and delivery - -**Files:** -- Modify: `docs/TASKS.md` -- Modify: `docs/SHEPHERD.md` -- Modify: `docs/LOCAL_POC.md` -- Modify: `docs/FIXES.md` -- Modify: `docs/BUILD_LOG.md` -- Create or modify: `docs/SHEPHERD_TEST_REPORT.md` - -- [ ] Update only statuses supported by the fresh commands from Task 9; keep independent `U`/`S` and second-machine evidence open when not independently observed. -- [ ] Commit using the repository conventional format with Summary, Root cause, Fix, and Testing evidence. -- [ ] Push the branch, open a draft linked PR for #96/#45/#65/#89, inspect CI, and update the PR/issue evidence. diff --git a/docs/superpowers/specs/2026-08-30-ui-gate-design.md b/docs/superpowers/specs/2026-08-30-ui-gate-design.md deleted file mode 100644 index 3f09f2d..0000000 --- a/docs/superpowers/specs/2026-08-30-ui-gate-design.md +++ /dev/null @@ -1,200 +0,0 @@ -# UI-GATE Audit and Evidence Design - -## Context - -Issue #45 is the final global UI gate for PRD sections 0.4 and 11.1–11.7. It is -not a redesign. The accepted Launchpad theme and layout are frozen, and existing -journey suites already prove several narrow flows. The missing deliverable is one -auditable matrix showing that the complete PRD UI remains functional, accessible, -truthful, responsive, and visually coherent across the two required viewports and -the required non-happy-path states. - -This branch is an audit-first candidate. Final completion remains blocked until -issue #44 and the remaining prerequisite E2E work are integrated. Evidence produced -before then is candidate evidence and must be regenerated on the exact integrated -head before the `I` gate can pass. - -## Goals - -- Verify the six PRD UI surfaces at `1280x800` and `1440x900`. -- Exercise real empty and populated product states plus loading, error, disabled, - and reconnect behavior where those states apply. -- Prove keyboard reachability, focus visibility and restoration, accessible names, - roles and state, required text/non-text contrast, long-identifier handling, - designated-pane scrolling, and zero document/body X/Y overflow. -- Generate a deterministic, opt-in screenshot corpus under - `docs/ui-review/ui-gate/` without changing evidence during ordinary test runs. -- Turn every product defect found by the audit into a causal failing assertion - before applying the smallest coherent correction. -- Preserve the existing UI design and every security, persistence, API, and - deterministic behavior boundary. - -## Surface Inventory - -The six surfaces follow PRD section 11 rather than the number of application -routes: - -1. Sidebar and primary navigation. -2. Shepherd Execution Contract Stream. -3. Shepherd Live Execution Timeline. -4. Shepherd Plane Tree and its detail drawer. -5. Project Group conversation and composer. -6. The Agent experience: Agent page plus Create/Edit configuration. - -Authentication, Agents-list, Settings, and not-found views are adjacent starter-kit -regression surfaces. They will be exercised where they provide a required state -(for example authentication loading/error or Settings disabled controls), but they -do not replace any of the six PRD surfaces. - -## Recommended Architecture - -Add one dedicated Playwright UI-gate suite and a small test-only support module. -Register the suite in the existing `playwright.config.ts`; do not add a dependency, -new production endpoint, debug route, or package script while active branches own -`package.json`. - -The support module owns repeated audit mechanics only: - -- exact viewport and document/body overflow checks; -- designated-scroll-owner checks; -- keyboard traversal and visible-focus checks; -- accessible name, role, state, and relationship assertions; -- computed color parsing and WCAG contrast calculations; -- safe screenshot routing and evidence naming; -- public DOM/API/log secret and private-path canary scans. - -The spec owns user journeys and expected product behavior. It starts the existing -compiled application with `startTestApp()`, uses authenticated public APIs to -create genuine product state, and drives the UI with role/name locators. Real -backend state is required for all positive product claims. Request interception is -permitted only to hold or fail an actual polling/bootstrap request so that loading, -error, and reconnect UI can be observed deterministically; it must not fabricate a -successful Mission, Contract, verification, candidate, or promotion result. - -## State and Evidence Matrix - -The suite will divide coverage into independently reviewable journeys: - -### Clean shell and Agent configuration - -- Authentication connecting, required-token, invalid-token error, and successful - unlock states. -- Empty Agents list, Create Agent, validation-disabled submit, populated Agent - page, Edit Agent, stopped/started Agent controls, and long-name/ID behavior. -- Sidebar navigation, current-route state, keyboard activation, and focus-visible - styling throughout. - -### Shepherd surfaces - -- Empty/loading/error/retry states before any Mission exists. -- A real deterministic Mission furnishing populated Contract Stream, Timeline, - Plane Tree, collision, candidate, promotion, evidence, and retained loser state. -- Contract filters, evidence disclosure, tree-node activation, drawer focus trap or - contained tab order, Escape close, and focus restoration. -- Internal scrolling belongs to the stream, timeline/tree region, or drawer; the - page itself must not acquire X or Y overflow. - -### Project Group and disabled/reconnect states - -- Empty/uninitialized Project Group, initialized group, disabled composer or - mention target, real bounded request lifecycle, and long content. -- A polling request is deliberately held to expose loading/reconnecting copy, then - released to prove reconciliation without duplicate messages or stale state. -- A polling request is deliberately failed to expose a bounded user-facing error, - followed by successful retry/recovery against the real server. - -### Adjacent regression states - -- Settings tabs, locked/unavailable controls, save/discard disabled states, labels, - and visible focus. -- Not-found recovery navigation. -- Existing Agent lifecycle and denial journeys remain the causal source of truth; - the UI gate may call them as adjacent gates but will not copy their business - assertions into a second divergent implementation. - -Every evidence stage is captured at both viewports. Ordinary runs write only below -`.tmp/playwright-evidence/ui-gate/`; setting `E2E_UPDATE_EVIDENCE=true` writes the -reviewed corpus below `docs/ui-review/ui-gate//`. - -## Accessibility and Visual Review - -The automated audit targets WCAG 2.1 AA: - -- `1.3.1`, `4.1.2`: semantic headings, landmarks, labels, roles, names, values, - selected/expanded/disabled state, and dialog/tab relationships. -- `1.4.3`: at least `4.5:1` for normal text and `3:1` for large text. -- `1.4.11`: at least `3:1` for meaningful UI component boundaries and focus - indicators. -- `2.1.1`, `2.4.3`, `2.4.7`: keyboard operation, logical order, visible focus, - drawer close/restoration, and no keyboard trap. -- `2.5.5`: `44x44` CSS-pixel targets where the product presents touch-oriented - controls; compact desktop-only controls require a documented exception rather - than a fabricated pass. -- `3.2.1`, `3.3.1`, `3.3.2`: predictable focus behavior, identified errors, and - input instructions. - -Headless semantics are not a substitute for an actual screen-reader pass. The -candidate report will state that limitation and request an independent read-only -UI/accessibility review on the final screenshots and latest reviewable commit. -No `U` claim is made by the implementation owner. - -Visual review compares every committed screenshot with `docs/UI.jpeg` and the -frozen design contract: charcoal sidebar, cream surfaces, restrained purple -primary accent, green/red semantic colors, existing typography/spacing, restrained -borders and shadows, readable pills, no unstyled states, and no overlap or -truncation without a title/accessible full value. - -## Test-First Correction Policy - -The initial audit may fail. For each failure: - -1. Reduce it to one causal Playwright or component assertion and observe the - expected RED result. -2. Confirm the production change that would make the assertion green. -3. Apply the smallest correction in the existing component or CSS primitive. -4. Re-run the focused assertion, its adjacent journey, both viewports, and relevant - Web tests. -5. Preserve the accepted layout and avoid unrelated cleanup. - -If a required correction touches a file owned by issue #78 or another active task, -stop and coordinate; do not expand ownership. The initial excluded files are -`apps/web/src/pages/AgentPage.tsx`, `apps/web/src/types.ts`, the deterministic/live -recording specs and configs, `package.json`, issue #44 startup/settings backend, -issue #47 authentication/OPS files, and issue #81 Contract-intake files. - -## Planned Files - -- Create `tests/e2e/support/ui-gate.mjs` for reusable audit mechanics. -- Create `tests/e2e/ui-gate.spec.mjs` for the state/evidence journeys. -- Modify `playwright.config.ts` only to register the new spec. -- Add reviewed PNG files below `docs/ui-review/ui-gate/` only during the explicit - evidence run. -- Modify production UI or CSS files only after a causal RED finding and only when - no active owner holds them. -- Defer shared `docs/TASKS.md` and `docs/BUILD_LOG.md` edits until current active PR - ownership clears or coordination is recorded. - -## Verification and Completion - -Candidate verification consists of: - -- focused support-module unit tests; -- the dedicated Playwright suite at both exact viewports; -- relevant Web component tests and strict test typecheck; -- Web and Server production builds required by the real compiled harness; -- public DOM/API/log and screenshot safety checks; -- an explicit evidence run and screenshot-by-screenshot accessibility/design - review; -- the literal repository `npm run check` in hosted Node 22 CI. - -The Windows worktree cannot establish a literal local baseline because Node cannot -spawn the npm/shell shims used by the launcher tests (`ENOENT`/`EFTYPE`) and Docker -is currently offline. This is recorded as environment evidence, not treated as a -product pass. The exact base commit `b193e57` has a successful hosted -`Node 22 / npm run check` job. The candidate must obtain its own hosted green job. - -Issue #45 can close only after its blockers integrate, the branch is updated from -current `origin/main`, all evidence is regenerated on that exact head, an -independent reviewer resolves every High/Medium finding, protected integration -passes, and the integrated SHA is rerun. Until then the branch and draft PR must -say `C/B/U/I pending` or claim only the gates actually observed. diff --git a/docs/ui-review/baseline/1280x800.png b/docs/ui-review/baseline/1280x800.png deleted file mode 100644 index 05851a7..0000000 Binary files a/docs/ui-review/baseline/1280x800.png and /dev/null differ diff --git a/docs/ui-review/baseline/1440x900.png b/docs/ui-review/baseline/1440x900.png deleted file mode 100644 index cf3e1b2..0000000 Binary files a/docs/ui-review/baseline/1440x900.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1280x800/01-create-agent.png b/docs/ui-review/e2e-01/1280x800/01-create-agent.png deleted file mode 100644 index db3195e..0000000 Binary files a/docs/ui-review/e2e-01/1280x800/01-create-agent.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1280x800/02-empty-agent.png b/docs/ui-review/e2e-01/1280x800/02-empty-agent.png deleted file mode 100644 index 1e6d802..0000000 Binary files a/docs/ui-review/e2e-01/1280x800/02-empty-agent.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1280x800/03-first-turn-active.png b/docs/ui-review/e2e-01/1280x800/03-first-turn-active.png deleted file mode 100644 index 286b13c..0000000 Binary files a/docs/ui-review/e2e-01/1280x800/03-first-turn-active.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1280x800/03-first-turn-completed.png b/docs/ui-review/e2e-01/1280x800/03-first-turn-completed.png deleted file mode 100644 index ab91635..0000000 Binary files a/docs/ui-review/e2e-01/1280x800/03-first-turn-completed.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1280x800/05-follow-up-active.png b/docs/ui-review/e2e-01/1280x800/05-follow-up-active.png deleted file mode 100644 index 4b520e4..0000000 Binary files a/docs/ui-review/e2e-01/1280x800/05-follow-up-active.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1280x800/05-follow-up-completed.png b/docs/ui-review/e2e-01/1280x800/05-follow-up-completed.png deleted file mode 100644 index b5df9ad..0000000 Binary files a/docs/ui-review/e2e-01/1280x800/05-follow-up-completed.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1280x800/07-agent-stopped.png b/docs/ui-review/e2e-01/1280x800/07-agent-stopped.png deleted file mode 100644 index f464fc7..0000000 Binary files a/docs/ui-review/e2e-01/1280x800/07-agent-stopped.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1280x800/09-server-restarted.png b/docs/ui-review/e2e-01/1280x800/09-server-restarted.png deleted file mode 100644 index 19691be..0000000 Binary files a/docs/ui-review/e2e-01/1280x800/09-server-restarted.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1440x900/01-create-agent.png b/docs/ui-review/e2e-01/1440x900/01-create-agent.png deleted file mode 100644 index 2876880..0000000 Binary files a/docs/ui-review/e2e-01/1440x900/01-create-agent.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1440x900/02-empty-agent.png b/docs/ui-review/e2e-01/1440x900/02-empty-agent.png deleted file mode 100644 index 4a0ccbd..0000000 Binary files a/docs/ui-review/e2e-01/1440x900/02-empty-agent.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1440x900/03-first-turn-active.png b/docs/ui-review/e2e-01/1440x900/03-first-turn-active.png deleted file mode 100644 index 92010b5..0000000 Binary files a/docs/ui-review/e2e-01/1440x900/03-first-turn-active.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1440x900/03-first-turn-completed.png b/docs/ui-review/e2e-01/1440x900/03-first-turn-completed.png deleted file mode 100644 index f17b4ee..0000000 Binary files a/docs/ui-review/e2e-01/1440x900/03-first-turn-completed.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1440x900/05-follow-up-active.png b/docs/ui-review/e2e-01/1440x900/05-follow-up-active.png deleted file mode 100644 index e814344..0000000 Binary files a/docs/ui-review/e2e-01/1440x900/05-follow-up-active.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1440x900/05-follow-up-completed.png b/docs/ui-review/e2e-01/1440x900/05-follow-up-completed.png deleted file mode 100644 index e9d045f..0000000 Binary files a/docs/ui-review/e2e-01/1440x900/05-follow-up-completed.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1440x900/07-agent-stopped.png b/docs/ui-review/e2e-01/1440x900/07-agent-stopped.png deleted file mode 100644 index d0f8821..0000000 Binary files a/docs/ui-review/e2e-01/1440x900/07-agent-stopped.png and /dev/null differ diff --git a/docs/ui-review/e2e-01/1440x900/09-server-restarted.png b/docs/ui-review/e2e-01/1440x900/09-server-restarted.png deleted file mode 100644 index 4173dad..0000000 Binary files a/docs/ui-review/e2e-01/1440x900/09-server-restarted.png and /dev/null differ diff --git a/docs/ui-review/e2e-04/1280x800/01-authority-denied.png b/docs/ui-review/e2e-04/1280x800/01-authority-denied.png deleted file mode 100644 index f814712..0000000 Binary files a/docs/ui-review/e2e-04/1280x800/01-authority-denied.png and /dev/null differ diff --git a/docs/ui-review/e2e-04/1280x800/02-denial-evidence.png b/docs/ui-review/e2e-04/1280x800/02-denial-evidence.png deleted file mode 100644 index 13a526e..0000000 Binary files a/docs/ui-review/e2e-04/1280x800/02-denial-evidence.png and /dev/null differ diff --git a/docs/ui-review/e2e-04/1440x900/01-authority-denied.png b/docs/ui-review/e2e-04/1440x900/01-authority-denied.png deleted file mode 100644 index 4758b3c..0000000 Binary files a/docs/ui-review/e2e-04/1440x900/01-authority-denied.png and /dev/null differ diff --git a/docs/ui-review/e2e-04/1440x900/02-denial-evidence.png b/docs/ui-review/e2e-04/1440x900/02-denial-evidence.png deleted file mode 100644 index c2f88dd..0000000 Binary files a/docs/ui-review/e2e-04/1440x900/02-denial-evidence.png and /dev/null differ diff --git a/docs/ui-review/e2e-harness/1280x800.png b/docs/ui-review/e2e-harness/1280x800.png deleted file mode 100644 index 4e28631..0000000 Binary files a/docs/ui-review/e2e-harness/1280x800.png and /dev/null differ diff --git a/docs/ui-review/e2e-harness/1440x900.png b/docs/ui-review/e2e-harness/1440x900.png deleted file mode 100644 index 6b22d77..0000000 Binary files a/docs/ui-review/e2e-harness/1440x900.png and /dev/null differ diff --git a/docs/ui-review/perf-01/1280x800/01-collision-visible.png b/docs/ui-review/perf-01/1280x800/01-collision-visible.png deleted file mode 100644 index 17e1abe..0000000 Binary files a/docs/ui-review/perf-01/1280x800/01-collision-visible.png and /dev/null differ diff --git a/docs/ui-review/perf-01/1280x800/02-promotion-completed.png b/docs/ui-review/perf-01/1280x800/02-promotion-completed.png deleted file mode 100644 index 33f0ed0..0000000 Binary files a/docs/ui-review/perf-01/1280x800/02-promotion-completed.png and /dev/null differ diff --git a/docs/ui-review/perf-01/1440x900/01-collision-visible.png b/docs/ui-review/perf-01/1440x900/01-collision-visible.png deleted file mode 100644 index 475ddfd..0000000 Binary files a/docs/ui-review/perf-01/1440x900/01-collision-visible.png and /dev/null differ diff --git a/docs/ui-review/perf-01/1440x900/02-promotion-completed.png b/docs/ui-review/perf-01/1440x900/02-promotion-completed.png deleted file mode 100644 index 7aef15e..0000000 Binary files a/docs/ui-review/perf-01/1440x900/02-promotion-completed.png and /dev/null differ diff --git a/docs/ui-review/st-02-settings/1280x800.png b/docs/ui-review/st-02-settings/1280x800.png deleted file mode 100644 index 0288b95..0000000 Binary files a/docs/ui-review/st-02-settings/1280x800.png and /dev/null differ diff --git a/docs/ui-review/st-02-settings/1440x900.png b/docs/ui-review/st-02-settings/1440x900.png deleted file mode 100644 index 004cf05..0000000 Binary files a/docs/ui-review/st-02-settings/1440x900.png and /dev/null differ diff --git a/docs/ui-review/ui-03-create-agent/1280x800.png b/docs/ui-review/ui-03-create-agent/1280x800.png deleted file mode 100644 index a747280..0000000 Binary files a/docs/ui-review/ui-03-create-agent/1280x800.png and /dev/null differ diff --git a/docs/ui-review/ui-03-create-agent/1440x900.png b/docs/ui-review/ui-03-create-agent/1440x900.png deleted file mode 100644 index 9d313fe..0000000 Binary files a/docs/ui-review/ui-03-create-agent/1440x900.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/01-auth-loading.png b/docs/ui-review/ui-gate/1280x800/01-auth-loading.png deleted file mode 100644 index a1edf88..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/01-auth-loading.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/02-auth-error.png b/docs/ui-review/ui-gate/1280x800/02-auth-error.png deleted file mode 100644 index 63a4b2d..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/02-auth-error.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/03-agents-empty.png b/docs/ui-review/ui-gate/1280x800/03-agents-empty.png deleted file mode 100644 index 1009df4..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/03-agents-empty.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/04-agent-create-disabled.png b/docs/ui-review/ui-gate/1280x800/04-agent-create-disabled.png deleted file mode 100644 index 8f2e3f4..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/04-agent-create-disabled.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/05-agent-long-content.png b/docs/ui-review/ui-gate/1280x800/05-agent-long-content.png deleted file mode 100644 index 5f6acea..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/05-agent-long-content.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/06-settings-disabled.png b/docs/ui-review/ui-gate/1280x800/06-settings-disabled.png deleted file mode 100644 index b7a0c9f..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/06-settings-disabled.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/07-not-found.png b/docs/ui-review/ui-gate/1280x800/07-not-found.png deleted file mode 100644 index 460f19f..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/07-not-found.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/08-shepherd-loading.png b/docs/ui-review/ui-gate/1280x800/08-shepherd-loading.png deleted file mode 100644 index bdb89be..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/08-shepherd-loading.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/09-shepherd-empty.png b/docs/ui-review/ui-gate/1280x800/09-shepherd-empty.png deleted file mode 100644 index c88ffac..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/09-shepherd-empty.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/10-shepherd-reconnecting.png b/docs/ui-review/ui-gate/1280x800/10-shepherd-reconnecting.png deleted file mode 100644 index 26bf8ed..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/10-shepherd-reconnecting.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/11-shepherd-active.png b/docs/ui-review/ui-gate/1280x800/11-shepherd-active.png deleted file mode 100644 index 8321d70..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/11-shepherd-active.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/12-shepherd-filtered.png b/docs/ui-review/ui-gate/1280x800/12-shepherd-filtered.png deleted file mode 100644 index 4d59012..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/12-shepherd-filtered.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/13-plane-drawer.png b/docs/ui-review/ui-gate/1280x800/13-plane-drawer.png deleted file mode 100644 index aea2ff7..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/13-plane-drawer.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/14-group-uninitialized.png b/docs/ui-review/ui-gate/1280x800/14-group-uninitialized.png deleted file mode 100644 index a23122e..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/14-group-uninitialized.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/15-group-loading.png b/docs/ui-review/ui-gate/1280x800/15-group-loading.png deleted file mode 100644 index e25edc4..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/15-group-loading.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/16-group-empty.png b/docs/ui-review/ui-gate/1280x800/16-group-empty.png deleted file mode 100644 index 40de49a..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/16-group-empty.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/17-group-reconnecting.png b/docs/ui-review/ui-gate/1280x800/17-group-reconnecting.png deleted file mode 100644 index dc86010..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/17-group-reconnecting.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1280x800/18-group-message.png b/docs/ui-review/ui-gate/1280x800/18-group-message.png deleted file mode 100644 index 0dbef5b..0000000 Binary files a/docs/ui-review/ui-gate/1280x800/18-group-message.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/01-auth-loading.png b/docs/ui-review/ui-gate/1440x900/01-auth-loading.png deleted file mode 100644 index e18483c..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/01-auth-loading.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/02-auth-error.png b/docs/ui-review/ui-gate/1440x900/02-auth-error.png deleted file mode 100644 index 03a93e9..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/02-auth-error.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/03-agents-empty.png b/docs/ui-review/ui-gate/1440x900/03-agents-empty.png deleted file mode 100644 index b45d3a0..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/03-agents-empty.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/04-agent-create-disabled.png b/docs/ui-review/ui-gate/1440x900/04-agent-create-disabled.png deleted file mode 100644 index 4933cd0..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/04-agent-create-disabled.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/05-agent-long-content.png b/docs/ui-review/ui-gate/1440x900/05-agent-long-content.png deleted file mode 100644 index 88e8214..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/05-agent-long-content.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/06-settings-disabled.png b/docs/ui-review/ui-gate/1440x900/06-settings-disabled.png deleted file mode 100644 index 04f05c8..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/06-settings-disabled.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/07-not-found.png b/docs/ui-review/ui-gate/1440x900/07-not-found.png deleted file mode 100644 index 02d29b6..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/07-not-found.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/08-shepherd-loading.png b/docs/ui-review/ui-gate/1440x900/08-shepherd-loading.png deleted file mode 100644 index 1114a3c..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/08-shepherd-loading.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/09-shepherd-empty.png b/docs/ui-review/ui-gate/1440x900/09-shepherd-empty.png deleted file mode 100644 index 73148ab..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/09-shepherd-empty.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/10-shepherd-reconnecting.png b/docs/ui-review/ui-gate/1440x900/10-shepherd-reconnecting.png deleted file mode 100644 index c0b69ac..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/10-shepherd-reconnecting.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/11-shepherd-active.png b/docs/ui-review/ui-gate/1440x900/11-shepherd-active.png deleted file mode 100644 index ca04ee9..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/11-shepherd-active.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/12-shepherd-filtered.png b/docs/ui-review/ui-gate/1440x900/12-shepherd-filtered.png deleted file mode 100644 index de17b3c..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/12-shepherd-filtered.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/13-plane-drawer.png b/docs/ui-review/ui-gate/1440x900/13-plane-drawer.png deleted file mode 100644 index c4513b4..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/13-plane-drawer.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/14-group-uninitialized.png b/docs/ui-review/ui-gate/1440x900/14-group-uninitialized.png deleted file mode 100644 index 8992f58..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/14-group-uninitialized.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/15-group-loading.png b/docs/ui-review/ui-gate/1440x900/15-group-loading.png deleted file mode 100644 index 2f463fd..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/15-group-loading.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/16-group-empty.png b/docs/ui-review/ui-gate/1440x900/16-group-empty.png deleted file mode 100644 index 59b33c5..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/16-group-empty.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/17-group-reconnecting.png b/docs/ui-review/ui-gate/1440x900/17-group-reconnecting.png deleted file mode 100644 index e9a04ee..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/17-group-reconnecting.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/1440x900/18-group-message.png b/docs/ui-review/ui-gate/1440x900/18-group-message.png deleted file mode 100644 index be07902..0000000 Binary files a/docs/ui-review/ui-gate/1440x900/18-group-message.png and /dev/null differ diff --git a/docs/ui-review/ui-gate/AUDIT.md b/docs/ui-review/ui-gate/AUDIT.md deleted file mode 100644 index 589b184..0000000 --- a/docs/ui-review/ui-gate/AUDIT.md +++ /dev/null @@ -1,117 +0,0 @@ -# UI-GATE Integrated Candidate Accessibility and Design Audit - -## Audit identity - -- Issue: [#45](https://github.com/kyashp/shepherd/issues/45), `UI-GATE` -- Source: merged [PR #87](https://github.com/kyashp/shepherd/pull/87), branch `test/45-ui-gate` -- Rendered protected-main integration: `cf4dd0fa5886979f2af823efa65fd028dbb03334` (direct second parent/final candidate `adbb7aa25ed464c3c7080bc6c9c29690ce20d18e`; causal UI fixes at `bbc7c81`) -- Audit date: 2026-08-31 -- Runtime: Node.js 24.16.0 -- Browser: Google Chrome for Testing 151.0.7922.34, Playwright, one worker -- Viewports: 1280x800 and 1440x900 -- Reviewed corpus: 36 PNGs, 18 named stages per viewport, 3,225,044 bytes total -- Post-merge evidence command: exact `cf4dd0fa` archive plus `node node_modules/@playwright/test/cli.js test tests/e2e/ui-gate.spec.mjs --workers=1` -- Harness ordinary-run boundary: screenshots remain under `.tmp/playwright-evidence/ui-gate/`; only the explicit environment value `true` makes the harness copy them into this reviewed directory. This post-merge follow-up promoted the separately validated exact-main manifest after the run. - -The protected-main evidence run passed 12/12 tests with one Chromium worker. Every PNG is non-empty, has its declared dimensions, and belongs to the expected 18-file manifest for its viewport; there are no extra or non-PNG artifacts in the corpus. The 18 captures whose bytes changed from the candidate corpus were visually re-inspected before this exact-main corpus was published. The positive journeys use the real compiled local server and deterministic public APIs. Request interception is limited to holding or failing real reads to expose loading and reconnect states. - -## Gate status - -| Gate | Status | What is and is not claimed | -| --- | --- | --- | -| `C` candidate checks | Passed. Local UI-gate, adjacent Web tests, strict Web production/test typechecks, and Web/Server builds passed. Final candidate `adbb7aa` passed hosted runs `33329742705` and `33329742709`. | The four local Windows process-spawn harness cases remain honestly excluded by `spawn EFTYPE`; the full Linux gate is the hosted evidence. | -| `B` browser evidence | Automated Chromium journeys passed at both exact viewports and all 36 images were inspected against `docs/UI.jpeg`. | The product browser path is directly observed. A separate live inspection through the in-app browser was unavailable because no browser session was connected. | -| `U` independent usability | Pending. | This implementation-owner review is not an independent approval. | -| `I` final integration | Passed at protected-main merge `cf4dd0fa`. | The exact merge archive passed the two-viewport UI gate 12/12, regenerated this 36-image corpus, and passed hosted `npm run check` in run `33329997913`. The merge tree is byte-identical to final candidate `adbb7aa`. | - -## Six-surface matrix - -Each filename below exists beneath both `1280x800/` and `1440x900/`. - -| PRD surface | Evidence | Direct assertions | -| --- | --- | --- | -| Sidebar and primary navigation | `03-agents-empty.png`, `07-not-found.png`, `11-shepherd-active.png`, `18-group-message.png` | Complementary, main, and three named navigation landmarks are present; current-route styling is exposed; named links receive visible focus; sidebar navigation and recovery are activated with Enter; long Agent labels truncate only in the sidebar while the page exposes the full value. | -| Shepherd Execution Contract Stream | `09-shepherd-empty.png`, `10-shepherd-reconnecting.png`, `11-shepherd-active.png`, `12-shepherd-filtered.png` | Empty, stale/reconnecting, populated, and filtered states are visible; real Mission state produces 33 bounded events; filters activate by keyboard and expose `aria-pressed`; the event list owns its overflow. | -| Shepherd Live Execution Timeline | `09-shepherd-empty.png`, `11-shepherd-active.png`, `12-shepherd-filtered.png` | Waiting and completed states render from real state; Agent and Resolution rows remain readable; the timeline pane owns any overflow and does not widen the document. | -| Shepherd Plane Tree and detail drawer | `09-shepherd-empty.png`, `11-shepherd-active.png`, `13-plane-drawer.png` | Empty and five-Plane populated states render; a tree-node button opens with Enter; shortened Plane IDs expose the full ID through `title`; the labelled non-modal dialog focuses Close on open; evidence tabs use roving keyboard selection; Escape closes and restores focus to the opener; the tree and drawer own their scroll. | -| Project Group conversation and composer | `14-group-uninitialized.png` through `18-group-message.png` | Uninitialized, loading, empty, reconnect, pending-send, and persisted-message states are covered; composer/send/mention controls are disabled when unavailable; Enter submits exactly once; the real targeted message persists without creating a Mission; 1,900-character unbroken messages wrap and remain singular after polling; the message pane owns vertical scroll. | -| Agent experience and Create/Edit configuration | `03-agents-empty.png`, `04-agent-create-disabled.png`, `05-agent-long-content.png` | Empty list and Create flow render; required submit is visibly and semantically disabled; initial focus is on the labelled name input; an 80-character unbroken name wraps without document overflow; Edit preserves the full name, Save persists the description, and Stop/Start return the Agent to a ready route. | - -Adjacent evidence is `01-auth-loading.png` and `02-auth-error.png` for authentication, `06-settings-disabled.png` for Settings, and `07-not-found.png` for route recovery. - -## Keyboard and focus results - -| Interaction | Observed result | -| --- | --- | -| Global navigation | Native named links receive the shared 2px visible focus outline. The Your Agents link and not-found Open Shepherd recovery link activate with Enter and land on the expected headings. | -| Settings tabs | Exactly one tab has `tabindex=0`. ArrowRight selects/focuses Execution; End selects/focuses Notifications; Home returns to General; ArrowLeft wraps to Notifications. Every tab has an ID and `aria-controls`; the one rendered tabpanel has the reciprocal ID and `aria-labelledby`. | -| Contract filters | Each named filter receives visible focus, activates with Enter, sets `aria-pressed=true`, and leaves a visible filtered event. | -| Plane tree | The selected Plane button receives visible focus and opens the detail dialog with Enter. The current tree is a static hierarchy of named buttons, not a collapsible ARIA tree, so no unsupported expanded state is claimed. | -| Drawer | Close receives initial focus. ArrowRight moves selection from Candidate verification to Final promotion re-verification. Escape closes the non-modal dialog and restores focus to the exact Plane opener; no trap was observed. | -| Project Group composer | The labelled textarea submits on Enter, is disabled before initialization and during the held POST, and produces exactly one request/message. Mention insertion preserves the draft and becomes disabled with a non-color cursor/opacity cue while unavailable. | -| Recovery | The labelled Open Shepherd link has the expected `/shepherd` destination, a visible focus indicator, and works with Enter. Authentication required-value feedback is native and the invalid-token error is announced as an alert. | - -Focus order followed the visual order in the exercised flows. Focus never disappeared behind an overlay, and drawer close/restoration was deterministic. Programmatic focus assertions verify a non-zero outline or box shadow and an accessible name; they do not substitute for assistive-technology observation. - -## Semantics, status, and input feedback - -- The shell exposes complementary and main landmarks plus separately named Shepherd, Project Group, and Agents navigation landmarks. -- Primary regions and panel headings are associated through native headings and `aria-labelledby`. -- Authentication failure uses `role=alert`; reconnecting and retry copy uses status semantics while preserving the last confirmed content. -- Settings and drawer evidence controls use tabs, selected state, roving tab stops, and reciprocal tab/tabpanel relationships. -- Filters expose pressed state. Native disabled state is present on unavailable buttons, checkboxes, composer, send, and mention controls; disabled appearance also changes opacity/cursor rather than relying on color alone. -- The Plane detail is a labelled `role=dialog` with `aria-modal=false`, matching its non-blocking drawer behavior. -- Required Access token input has an associated label and native `valueMissing` feedback. Invalid credentials produce bounded, actionable copy without exposing the token. -- User-controlled Project Group content contains no executable descendant or inline event attribute. Bounded public DOM/API/log canary scans passed without exposing tokens, raw prompts, private paths, or seeded private markers. - -## Contrast and target sizing - -Ratios use the WCAG relative-luminance formula implemented by the gate and the computed CSS pairs exercised by the screenshots. - -| Treatment | Pair | Ratio | Result | -| --- | --- | --- | --- | -| Muted authentication copy | `#6f7069` on `#fbfaf7` | 4.79:1 | Passes 4.5:1 normal-text threshold. | -| Muted empty-state copy | `#6f7069` on white | 5.00:1 | Passes 4.5:1 normal-text threshold. | -| Authentication error | `#9e4141` on `#fae8e6` | 5.40:1 | Passes 4.5:1 and is also identified by alert text/border. | -| Primary button text | white on `#6954d9` | 5.43:1 | Passes 4.5:1 before any disabled opacity treatment. | -| Focus outline on paper | `#8773e8` on `#fbfaf7` | 3.56:1 | Passes 3:1 non-text threshold. | -| Focus outline on sidebar | `#8773e8` on `#242421` | 4.19:1 | Passes 3:1 non-text threshold. | -| Mention-chip text | `#5e4ab7` on `#f0edfa` | 5.80:1 | Passes 4.5:1. | -| Disabled send glyph/text | `#9c9b95` on `#d8d6cf` | 1.92:1 | Disabled controls are exempt from 1.4.3/1.4.11; native disabled state, reduced opacity, and `not-allowed` cursor provide the unavailable cue. No enabled-state pass is inferred from this pair. | - -The Project Group mention chips are 25 CSS pixels high, below the preferred 44x44 touch target. This is a documented WCAG 2.5.5 exception for compact, repeated, desktop-only routing chips in a horizontally scrollable member rail. The primary actions and touch-oriented controls retain the larger control treatment. This exception is not a general target-size pass. - -## Overflow and responsive behavior - -- Both document and body remained at the viewport width and height within the one-pixel rounding tolerance at both sizes. -- The event list, timeline, Plane tree, detail drawer, Project Group member rail, and message history are the named internal scroll owners. Programmatic one-pixel scroll probes confirm that an overflowing pane can actually scroll without changing document width. -- The 80-character Agent name wraps across lines, remains fully available in its heading, and no longer creates the former 5px document Y overflow at 1280x800. -- Two 1,900-character unbroken Project Group messages use `overflow-wrap:anywhere`, stay within the message bubble, and make only the message history scroll. -- The Create Agent form is intentionally dense and requires vertical scrolling at 1280x800; the same action footer is visible without scrolling at 1440x900. A future design pass could consider a sticky action footer, but this is not an obstruction or document-overflow defect. -- The focused drawer screenshot is scrolled to the resolution-evidence tabs, so its header is outside that image's visible drawer segment. Separate DOM assertions cover the labelled dialog, Close control, focus entry, Escape close, and restoration. A final independent live review should inspect the complete drawer sequence. - -## State coverage - -| State | Result | -| --- | --- | -| Loading | Authentication, Shepherd, and Project Group loading copy and spinners are visible without layout shift or a false ready state. | -| Empty | Agents, Contract Stream, Timeline, Plane Tree, and initialized Project Group provide specific next-step copy rather than blank panels. | -| Error and reconnect | Invalid auth is bounded and actionable. Shepherd and Project Group preserve last-confirmed content, identify reconnection, recover automatically after the real read succeeds, and remove the stale status. | -| Disabled | Create, Settings, unavailable notification/model toggles, Project Group composer/send, and mention controls expose native disabled state plus visible treatment. No-op Settings Discard is disabled. | -| Not found | A centered, named recovery action returns to Shepherd by keyboard. | -| Active and long content | Real Mission/collision/candidate/promotion state and persisted Project Group messages remain legible, internally scrollable, and canary-free. | - -## Design critique - -The candidate is faithful to the accepted Launchpad reference: the charcoal sidebar, cream paper surfaces, restrained purple accent, compact rounded panels, green/red semantic colors, typography, spacing, borders, and shadows remain consistent across happy and non-happy paths. Headings and primary actions establish a clear hierarchy; reconnect banners and state pills add meaning without overpowering the work surfaces. Empty states use one icon, one short heading, and actionable copy, and dense Shepherd data remains divided into three stable regions. - -No High or Medium visual/accessibility defect was found in the reviewed corpus. The remaining Low observations are the 1280x800 Create Agent scroll depth, the intentionally compact mention-chip target exception, and the drawer evidence image's focused scroll position. These are recorded for independent review rather than hidden or promoted to a fabricated pass. - -## Limitations and required follow-up - -- No manual screen-reader session was run. Names, roles, relationships, focus, and live-state assertions are DOM evidence, not a substitute for NVDA, JAWS, VoiceOver, or another assistive technology. -- The product was exercised in Playwright Chromium, but the in-app browser connector reported no available browser session. No separate in-app live visual claim is made. -- The literal local Node harness reproduced the documented Windows `spawn EFTYPE` boundary: 15/19 passed and the four process-spawn cases failed. This is not recorded as a harness pass; hosted Linux CI supplied the complete exact-final and exact-integration checks. -- This is an implementation-owner candidate audit. An independent reviewer must perform and record the `U` gate. -- Final candidate and exact protected-main hosted CI passed; the exact integration corpus was regenerated and re-inspected. Gates `C`, `B`, and `I` are complete. -- Independent usability gate `U` remains required before this row can be called audited.