# BuildMender 0.2: detailed run and testing guide

**Updated:** 4 November 2026
**Application:** BuildMender 0.2.0 (existing package: `ci-resolve`)
**Workspace path:** `/Users/subashthiruppathy/Documents/projects/ci-resolve`
**Product name:** **BuildMender**; see [naming notes](PRODUCT_NAMING.md). The website and dashboard use BuildMender. The application directory, package, environment variables, repair branches and commands still use `ci-resolve` for compatibility.

**Product website:** `/` includes interactive platform and workflow sections. Browser-readable guides are under `/guides/`; the application remains at `/app`. See [website deployment and testing](WEBSITE_GUIDE.md) for the standalone static build.

This guide covers one-time installation, running the dashboard, running automated tests, connecting unattended operation, testing a real repair, observing results, troubleshooting, and maintaining a background service.

**Normal operation after setup:** collect → reproduce → repair → verify → publish → observe CI/merge → resolve. Manual log uploads and per-failure commands are optional diagnostic tools, not requirements for the automated path.

## Contents

1. [Choose what you want to run](#1-choose-what-you-want-to-run)
2. [Prerequisites](#2-prerequisites)
3. [Open the project and check the installation](#3-open-the-project-and-check-the-installation)
4. [Run a preview without live automation](#4-run-a-preview-without-live-automation)
5. [Run the automated test suite](#5-run-the-automated-test-suite)
6. [Enable browser tests](#6-enable-browser-tests)
7. [Run selected tests](#7-run-selected-tests)
8. [Understand what the tests prove](#8-understand-what-the-tests-prove)
9. [Connect a target repository once](#9-connect-a-target-repository-once)
10. [Configure credentials once](#10-configure-credentials-once)
11. [Configure the execution policy](#11-configure-the-execution-policy)
12. [Start unattended operation](#12-start-unattended-operation)
13. [Perform a real GitHub canary test](#13-perform-a-real-github-canary-test)
14. [Read the dashboard and API](#14-read-the-dashboard-and-api)
15. [Interpret workflow states](#15-interpret-workflow-states)
16. [Test rejection and recovery behavior](#16-test-rejection-and-recovery-behavior)
17. [Optional manual diagnostic commands](#17-optional-manual-diagnostic-commands)
18. [Run automatically after macOS login](#18-run-automatically-after-macos-login)
19. [Stop, restart, and change configuration](#19-stop-restart-and-change-configuration)
20. [Back up and restore local state](#20-back-up-and-restore-local-state)
21. [Troubleshoot common problems](#21-troubleshoot-common-problems)
22. [Current support limits](#22-current-support-limits)
23. [Acceptance checklist](#23-acceptance-checklist)
24. [Quick command reference](#24-quick-command-reference)
25. [References](#25-references)

## 1. Choose what you want to run

| Goal | GitHub/model credentials | Docker | Browser dependency | Starting section |
| --- | --- | --- | --- | --- |
| View the dashboard and labeled sample | No | No | Your normal browser | Section 4 |
| Run core, API, CLI and automation tests | No | No | No | Section 5 |
| Include automated desktop/mobile browser tests | No | No | Python Playwright + Chromium | Section 6 |
| Run unattended repairs against GitHub | Yes | Yes for default backend | Optional | Sections 9–13 |
| Run a trusted-local controlled pilot | Yes for live services | No | Optional | Section 11 |

The test suite uses temporary local repositories and simulated external responses. It does not need access to your GitHub repositories, a paid model account, or a running Docker daemon.

Live automation can create repair branches, PRs and merges in the repositories you configure. Use a dedicated canary repository for the first live test.

## 2. Prerequisites

### Required for the application and core tests

- Node.js **24 or newer** with npm.
- Git available in `PATH`.
- A terminal with permission to create local files and localhost listeners.
- This application source directory.

There are no npm runtime dependencies. SQLite is provided through Node's built-in `node:sqlite` module.

### Additional requirements for live automation

- Docker installed and running for the default execution backend.
- A checked-out target repository with a standard `github.com` origin.
- A Node.js target with an `npm test` script and supported TAP/Node spec results.
- GitHub credentials with access to that target repository.
- A repair-model API key and an available model ID.
- Network access to GitHub, its log-storage destinations, the model API, and any permitted dependency registry.
- CI configured to run on repair PRs and the resulting merged commits.

### Additional requirement for browser tests

A supported Python 3 installation, the Python `playwright` package, and its Chromium browser. These are development-test dependencies, not application runtime dependencies.

The command examples use macOS/Linux shell syntax. Native Windows service installation and Windows execution recipes are not covered.

## 3. Open the project and check the installation

Open Terminal and run:

```sh
cd /Users/subashthiruppathy/Documents/projects/ci-resolve
export CI_GUIDE_APP="$PWD"
node --version
npm --version
git --version
```

Expected: Node reports `v24.x` or newer; npm and Git print their versions.

The variables above belong to that terminal session. In a new terminal, rerun the absolute `cd` command and `export CI_GUIDE_APP="$PWD"` before using the variable-based examples.

Check JavaScript syntax:

```sh
npm run check
```

Expected: exit status zero with no syntax errors.

A dependency installation is not required to start this version. If you want npm to verify the lockfile state, run:

```sh
npm ci --ignore-scripts
```

Run commands from the application directory unless a section explicitly switches to the target repository. The **application directory** and the **repository being repaired** are different concepts.

## 4. Run a preview without live automation

### 4.1 Create isolated preview state

This makes the preview independent of any existing live policy or database:

```sh
cd "$CI_GUIDE_APP"
CI_GUIDE_PREVIEW="$(mktemp -d)"
CI_RESOLVE_CONFIG="$CI_GUIDE_PREVIEW/no-automation.json" \
CI_RESOLVE_DB="$CI_GUIDE_PREVIEW/preview.sqlite" \
npm start
```

Do not create `no-automation.json`; its absence intentionally disables the worker for this preview. These environment assignments apply only to this command.

Expected terminal message:

```text
CI Resolve: http://127.0.0.1:4310/app
```

### 4.2 Open the application

- Workbench: `http://127.0.0.1:4310/app`
- Product website: `http://127.0.0.1:4310/`
- Health API: `http://127.0.0.1:4310/api/health`

On macOS, from a second terminal:

```sh
open http://127.0.0.1:4310/app
```

Expected dashboard: empty investigation inbox and **Connect once. Resolve automatically.**

### 4.3 Explore the labeled sample

Click **Explore a sample run**. Inspect Diagnosis, Occurrences, Verification and Activity. You can assign an owner, add a note, start an investigation and use the filters.

The sample is fictional. It is explicitly labeled, cannot receive real verification evidence and cannot demonstrate live repair or merge.

### 4.4 Check HTTP responses

While the preview is running, use another terminal:

```sh
curl --fail --silent --show-error http://127.0.0.1:4310/api/health
curl --fail --silent --show-error http://127.0.0.1:4310/api/automation
```

Expected health fields include `ok: true`, `version: "0.2.0"`, and `mode: "local"`. Automation reports `configured: false` for this preview.

### 4.5 Stop the preview

Press **Control-C** in its terminal. The preview database remains in the temporary directory; it does not replace `.data/ci-resolve.sqlite`.

If port 4310 is occupied, choose another port:

```sh
PORT=4311 npm start
```

Use `http://127.0.0.1:4311/app` for that process. A bare `npm start` uses the normal default policy/database, so keep the isolated assignments from step 4.1 if you still want preview-only mode.

## 5. Run the automated test suite

From the application folder:

```sh
cd "$CI_GUIDE_APP"
npm test
```

The current version defines **56 tests**, including two optional browser tests:

| Browser configuration | Expected result for the current source |
| --- | --- |
| No configured Python Playwright interpreter | 54 pass, 2 explicitly skipped, 0 failures |
| Working configured Python Playwright + Chromium | 56 pass, 0 skipped, 0 failures |
| Interpreter configured but package/browser missing | Browser tests fail; fix that dependency |

The count may change with future code updates. The decisive result is zero unexpected failures and successful execution of the test groups you intended to run.

The suite starts its own temporary HTTP servers on available ports. You do not need to leave the app running. It also creates and removes temporary Git fixtures; it does not intentionally patch your registered repository.

The existing `.private/browser-python` file can enable browser tests even when you did not set an environment variable in this shell.

## 6. Enable browser tests

### 6.1 Create a Python environment

```sh
cd "$CI_GUIDE_APP"
python3 -m venv .private/browser-venv
.private/browser-venv/bin/python -m pip install playwright
.private/browser-venv/bin/python -m playwright install chromium
```

On Linux, Playwright may also require OS browser dependencies; follow its official installation guidance. Network access is required to install the package/browser. The current test scripts use the Playwright Python library directly, not pytest.

### 6.2 Run all tests with this interpreter

```sh
CI_RESOLVE_BROWSER_PYTHON="$PWD/.private/browser-venv/bin/python" npm test
```

Expected: all 56 tests pass, including:

- `browser workflows, website and mobile layout`
- `automatic workflow browser experience`

### 6.3 Persist the interpreter choice locally

Optional one-time convenience:

```sh
printf '%s\n' "$PWD/.private/browser-venv/bin/python" > .private/browser-python
npm test
```

`.private/` is Git-ignored. The environment variable takes precedence over the local file.

### 6.4 View generated screenshots

Browser tests write these files under `artifacts/`:

- `workbench-empty.png`
- `workbench-desktop.png`
- `workbench-mobile.png`
- `import-mobile.png`
- `website-desktop.png`
- `website-mobile.png`
- `autopilot-desktop.png`
- `autopilot-mobile.png`

For example, on macOS:

```sh
open artifacts/autopilot-desktop.png
open artifacts/autopilot-mobile.png
```

Screenshots are local test artifacts and are not committed by default.

## 7. Run selected tests

Use the Node test runner directly when selecting files or names. Put runner options before file paths.

### Core diagnostic and persistence tests

```sh
node --test test/core.test.js
```

### HTTP/API tests

```sh
node --test test/server.test.js
```

### CLI and local command verification

```sh
node --test test/cli.test.js test/verify.test.js
```

### Full unattended automation tests

```sh
node --test test/automation.test.js
```

### Provider, model-contract and policy tests

```sh
node --test test/providers.test.js
```

### Browser tests only

```sh
CI_RESOLVE_BROWSER_PYTHON="$PWD/.private/browser-venv/bin/python" \
node --test test/browser.test.js
```

### One complete unattended-flow test

```sh
node --test \
  --test-name-pattern='unattended failure collection' \
  test/automation.test.js
```

Expected: the matching test passes; nonmatching tests may be omitted or reported skipped depending on runner output.

## 8. Understand what the tests prove

| Stage | What runs for real in the test suite | What is simulated |
| --- | --- | --- |
| Source fixture | Temporary Git repository and committed failing source | No customer repository |
| Reproduction | Real Node process executes a failing test | Remote CI acquisition responses |
| Repair proposal | Patch contract, path restrictions and exact edit application | The model's generated response |
| Verification | Real test execution against candidate source; original tests preserved | No live model quality claim |
| PR publication | Client request shape and ambiguous-response recovery | GitHub remote state/network responses |
| Merge and final CI | State machine evaluates required checks and merge identity | GitHub merge/check responses |
| Browser | Real Chromium on desktop/mobile viewports | Fixture account/repository data |
| Docker | Execution command/policy code exists | Real Docker runtime is not exercised by the current suite |

A green suite validates implemented behavior under these conditions. It does not establish live credentials, Docker readiness, a production deployment, or the model's repair success rate on your repositories.

During development, 56 tests passed with Chromium enabled. Live GitHub/model/Docker validation remains a separate acceptance step.

## 9. Connect a target repository once

Use an existing supported repository, or first create the disposable canary from section 13.

In your terminal:

```sh
export CI_GUIDE_TARGET=/absolute/path/to/your/repository

git -C "$CI_GUIDE_TARGET" remote get-url origin
```

Supported origins look like:

```text
https://github.com/your-org/your-repo.git
git@github.com:your-org/your-repo.git
```

GitHub Enterprise hosts, custom SSH aliases and a checkout without an origin are not supported by this version.

Check the target's test command:

```sh
cd "$CI_GUIDE_TARGET"
npm test
cd "$CI_GUIDE_APP"
```

Start Docker Desktop or the Docker service, then verify:

```sh
docker version
docker info
```

Expected: both client and server details are available. A client binary alone is insufficient.

Generate the policy:

```sh
node bin/ci-resolve.js setup --cwd "$CI_GUIDE_TARGET"
```

Setup pulls `node:24`, resolves an immutable image digest, detects npm scripts and writes `.private/automation.json`. It does **not** create GitHub/model credentials or change repository review rules.

Expected output contains `configured: true`, the target repository and the policy filename. This means the local policy was generated, not that live authentication has passed.

If you already have an appropriate pinned image:

```sh
CI_GUIDE_IMAGE="$(docker image inspect node:24 --format '{{index .RepoDigests 0}}')"
node bin/ci-resolve.js setup --cwd "$CI_GUIDE_TARGET" --image "$CI_GUIDE_IMAGE"
```

Setup refuses to overwrite an existing policy. For additional repositories, edit its `repositories` array once; do not repeatedly run setup against the same policy file.

## 10. Configure credentials once

### 10.1 Create a private environment file

```sh
cd "$CI_GUIDE_APP"
mkdir -p .private
chmod 700 .private
touch .private/automation.env
chmod 600 .private/automation.env
```

Edit `.private/automation.env` using your editor. Put real values into that private file, not into a tracked document or a pasted terminal command. Do not overwrite an existing credential file while following this guide.

### 10.2 GitHub token option

The application reads this exact variable:

```dotenv
CI_RESOLVE_GITHUB_TOKEN=YOUR_SCOPED_GITHUB_TOKEN
```

Choose only the intended repository access. Permissions needed by the implemented flow include Actions read, Checks read, Commit statuses read, Contents read/write, Pull requests read/write and Metadata read. Organization policies or App installation settings may further restrict access.

`gh auth login` configures GitHub CLI; it does **not** automatically populate `CI_RESOLVE_GITHUB_TOKEN` for this application.

### 10.3 GitHub App option

Instead of a token, configure:

```dotenv
CI_RESOLVE_GITHUB_APP_ID=YOUR_NUMERIC_APP_ID
CI_RESOLVE_GITHUB_INSTALLATION_ID=YOUR_NUMERIC_INSTALLATION_ID
CI_RESOLVE_GITHUB_PRIVATE_KEY_FILE=/absolute/private/path/to/app-key.pem
```

Install the App on the chosen repositories and grant the required permissions. The private key remains on the service host; the client obtains and refreshes installation tokens.

If both options are set, `CI_RESOLVE_GITHUB_TOKEN` takes precedence. Use the option you intend rather than leaving an old token configured accidentally.

### 10.4 Repair model

```dotenv
CI_RESOLVE_ANTHROPIC_KEY=YOUR_MODEL_API_KEY
CI_RESOLVE_ANTHROPIC_MODEL=YOUR_AVAILABLE_MODEL_ID
```

Use a model available to your API account. The adapter uses the Claude Messages API, requires a structured JSON repair response, and has a bounded context/output budget.

Model calls send bounded source excerpts, protected test context and redacted diagnostic evidence. GitHub/model credentials are not passed into worker subprocess environments. Redaction is best effort; avoid placing secrets in source and logs.

### 10.5 Check presence without printing values

```sh
node --env-file-if-exists=.private/automation.env --input-type=module <<'JS'
console.log({
  githubToken: Boolean(process.env.CI_RESOLVE_GITHUB_TOKEN),
  githubApp: Boolean(
    process.env.CI_RESOLVE_GITHUB_APP_ID &&
    process.env.CI_RESOLVE_GITHUB_INSTALLATION_ID &&
    process.env.CI_RESOLVE_GITHUB_PRIVATE_KEY_FILE
  ),
  modelKey: Boolean(process.env.CI_RESOLVE_ANTHROPIC_KEY),
  modelId: Boolean(process.env.CI_RESOLVE_ANTHROPIC_MODEL)
});
JS
```

Expected: at least one GitHub option and both model fields are `true`. Presence is not proof that the credentials have valid permissions or billing.

## 11. Configure the execution policy

Inspect the generated policy locally:

```sh
node --input-type=module <<'JS'
import { loadConfig } from './src/automation/config.js';
const config = loadConfig();
console.log(config ? {
  repositories: config.repositories.map(r => ({
    repository: r.repository,
    backend: r.backend,
    commands: r.commands,
    allowPaths: r.allowPaths,
    autoMerge: r.autoMerge
  })),
  pollIntervalMs: config.pollIntervalMs,
  concurrency: config.concurrency
} : { configured: false });
JS
```

### Important fields

| Field | Current behavior |
| --- | --- |
| `version` | Must be `1` |
| `pollIntervalMs` | Default 60,000; allowed 1,000–3,600,000 |
| `concurrency` | Default 2; allowed 1–8 |
| `repository` | Exact GitHub `owner/name` |
| `checkout` | Absolute local source-cache checkout |
| `backend` | `docker`, or explicitly opted-in `trusted-local` |
| `image` | Required Docker image digest; mutable tags rejected |
| `install` | Preparation commands as arrays, not shell strings |
| `installNetwork` | `none` or `bridge`; setup initially chooses `bridge` |
| `commands` | First command reproduces/tests; all commands verify candidates |
| `allowPaths` | Editable source globs; protected paths stay prohibited |
| `jobs` | Optional exact job-name allowlist |
| `requiredChecks` | Additional exact check names alongside the failed source job |
| `autoMerge` | Defaults true; requests a native merge where permitted |
| `timeoutMs` | Default 120,000; allowed 100–600,000 |

A command is represented as `["npm", "test"]`, not `"npm test"`. Shell operators such as `&&` are not parsed in an argument array.

Setup's initial editable patterns are `src/**/*.js`, `src/**/*.ts`, and `lib/**/*.js`. If your source uses `.cjs`, `.mjs`, `.tsx` or `app/`, add the appropriate bounded source patterns during setup. This does not allow modifications to tests, fixtures, snapshots or package configuration.

The first command must expose the supported test inventory and the failing behavior. A build-only command or a test command that always exits zero will not satisfy the normal reproduction contract.

### Fully unattended merge prerequisites

The service can merge a ready repair via GitHub's merge endpoint or request native auto-merge while waiting for repository policy. It does not disable review requirements or required checks.

For a completely unattended canary, its repository policies must permit the scoped service identity to merge verified repairs without an additional human review. Keep your real repository's desired governance rules; configure the intended policy once rather than treating a blocked review as an application test failure.

CI must produce the required check names on both the repair head and the merged commit. Otherwise the task remains in `observe` and cannot claim resolution.

### Trusted-local alternative

For code you already trust to execute as your local user, an explicitly configured policy can use:

```json
{
  "backend": "trusted-local",
  "trustedLocalExecution": true
}
```

These are fields within a complete repository policy, not a complete configuration file. This backend does not provide Docker/network/OS isolation. It is useful for controlled local environments; the automatic test fixture uses it.

Restart the service after policy or environment changes. Existing tasks retain their original policy digest. A changed policy is not silently applied to already queued work.

## 12. Start unattended operation

### Dashboard and workers together

```sh
cd "$CI_GUIDE_APP"
npm start
```

When `.private/automation.json` exists, this loads `.private/automation.env` and starts the collector/workers with the server.

### Worker without a dashboard

```sh
npm run automate
```

### One collection/processing cycle

```sh
node --env-file-if-exists=.private/automation.env \
  bin/ci-resolve.js automate --mode once
```

A single cycle may leave a PR waiting for CI/merge. It is not a promise that an asynchronous remote repair completes in one invocation. The continuous service performs later reconciliation.

Also, exit code zero alone does not mean live readiness: collector errors can be represented in the returned `health` data. Inspect that output or the dashboard.

### Use explicit state paths for a service

```sh
CI_RESOLVE_CONFIG="$PWD/.private/automation.json" \
CI_RESOLVE_DB="$PWD/.data/ci-resolve.sqlite" \
PORT=4310 npm start
```

All processes sharing work should use the same absolute database path **and the same application working directory**. The execution work root is `.data/automation` relative to that working directory, not relative to the database filename.

The default reconciliation interval is 60 seconds; the browser refreshes approximately every eight seconds when you are not editing a form. Collection, execution and remote CI add their own time. Use section 18 for automatic launch after login.

## 13. Perform a real GitHub canary test

This is an optional **live acceptance test** in a dedicated disposable repository. It creates actual remote commits and can create/merge an automatic repair. Do not introduce the intentional defect into a production repository.

### 13.1 Prepare an empty canary repository

Create a private test repository on GitHub and clone it into a separate directory. Set `CI_GUIDE_TARGET` to that checkout. Keep `CI_GUIDE_APP` pointing to the CI Resolve application.

Create these files in the canary checkout:

**`package.json`**

```json
{
  "name": "ci-resolve-canary",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --test --test-reporter=tap"
  }
}
```

**`src/add.js`**

```js
export function add(a, b) {
  return a + b;
}
```

**`test/add.test.js`**

```js
import test from 'node:test';
import assert from 'node:assert/strict';
import { add } from '../src/add.js';

test('adds two positive numbers', () => {
  assert.equal(add(2, 3), 5);
});
```

**`.github/workflows/ci.yml`**

```yaml
name: Canary CI
on:
  push:
  pull_request:
permissions:
  contents: read
jobs:
  test:
    name: Unit tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: '24'
          package-manager-cache: false
      - run: npm test
```

The action versions follow the official repositories' examples checked on the guide date. Follow your organization's action-version pinning policy for a production workflow.

There are no package dependencies, so this fixture does not require a lockfile or dependency-install step.

### 13.2 Establish a passing baseline

In the canary checkout:

```sh
cd "$CI_GUIDE_TARGET"
npm test
git add package.json src/add.js test/add.test.js .github/workflows/ci.yml
git commit -m "test(canary): add passing automation fixture"
git push
```

Confirm that GitHub Actions reports **Unit tests** passing. Ensure the checkout is on a normal branch name, such as `main`, rather than `ci-resolve/...`; the collector intentionally excludes its own repair branches.

Register this repository using sections 9–11, configure its credential access and start the unattended service. If a different repository policy already exists, add this canary as a separate policy entry rather than overwriting the existing file.

### 13.3 Introduce one source defect

Change only the source implementation:

```js
export function add(a, b) {
  return a - b;
}
```

Confirm the local test fails, then create the intentionally failing canary commit:

```sh
cd "$CI_GUIDE_TARGET"
npm test
git add src/add.js
git commit -m "test(canary): introduce intentional addition regression"
git push
```

Do not edit the expected assertion. Leave the remote source branch at this commit while the automation investigates it; an additional push can supersede that evidence.

### 13.4 Observe the automatic repair

The configured service should:

1. Discover the failed **Unit tests** job.
2. Reproduce `adds two positive numbers` failing in a disposable workspace.
3. Request a source repair from the configured model.
4. Reject any proposed test modification.
5. Verify the candidate against the original test inventory.
6. Publish a `ci-resolve/<task-id>` branch and repair PR targeting the failing branch.
7. Confirm original CI checks on the repair head.
8. Merge/request auto-merge if native policy permits.
9. Observe **Unit tests** on the merged commit.
10. Mark the investigation resolved automatically.

A model may abstain or produce an invalid candidate; the expected correct behavior then is a recorded stop/exhaustion, not fabricated success. The acceptance test demonstrates live success only when an actual correct repair completes.

### 13.5 Record acceptance evidence

Retain the source workflow/run/attempt/job IDs, source commit, task ID, repair PR/head SHA, verification results, merged SHA and resulting CI result. The original tests must remain unchanged.

The service does not patch the registered checkout's working files. After remote merge, refresh your checkout through your normal Git workflow if you want to inspect the merged repair locally.

A failing check on a merged commit is recorded as blocked; version 0.2 does **not** implement automatic rollback. Do not infer rollback from the presence of merge reconciliation.

## 14. Read the dashboard and API

### Dashboard

- **Automation status:** configured policies, connection errors and active/stopped workflows.
- **Inbox:** grouped failure investigations and occurrences.
- **Automatic workflow:** reproduction/repair/verification/publication/observation stages.
- **Workflow evidence & decisions:** captured transition evidence and stop reasons.
- **Verification:** real configured command results and the source/patch identity.
- **Activity:** assignments, transitions, notes and errors.

For automated cases, resolution is owned by the worker. The legacy **Mark resolved** action is not the normal automated path.

### Read-only API inspection

While the server is running:

```sh
curl --fail --silent --show-error http://127.0.0.1:4310/api/automation
curl --fail --silent --show-error http://127.0.0.1:4310/api/cases
```

To pretty-print without installing another tool:

```sh
curl --fail --silent --show-error http://127.0.0.1:4310/api/automation \
  | python3 -m json.tool
```

Use an actual case ID for details:

```sh
curl --fail --silent --show-error \
  http://127.0.0.1:4310/api/cases/REPLACE_WITH_CASE_ID
```

`configured: true` means a policy was loaded. Read `health` and task `error`/`phase` to determine actual progress. The overview lists the newest 200 tasks; per-case details retain that case's workflow evidence.

## 15. Interpret workflow states

| Task phase | Meaning | Normal next behavior |
| --- | --- | --- |
| `queued` | Imported failed job has a durable task | Source revision check |
| `prepare` | Disposable checkout/environment preparation | Reproduction |
| `reproduce` | Run the first configured command | Require a comparable failing symptom/test inventory |
| `repair` | Request/validate a structured source proposal | Candidate verification or bounded retry |
| `verify` | Run protected tests and all configured checks | Publish only if verification succeeds |
| `publish` | Create/reconcile deterministic repair branch and PR | Remote CI observation |
| `observe` | Wait for checks, native merge and merged-commit checks | Automatic resolution when all required evidence exists |
| `resolved` | Required evidence and merge checks accepted | Terminal success |
| `unreproduced` | Original supported failure not reproduced | Terminal; no repair claimed |
| `superseded` | Source, repair head or newer occurrence invalidated work | Terminal obsolete task |
| `blocked` | Explicit unsupported condition, rejected remote CI or unavailable policy | Terminal recorded stop |
| `failed` | Generic retry budget exhausted | Terminal error |
| `exhausted` | Candidate or lifetime budget exhausted | Terminal; no repair claimed |

An investigation's legacy `status` is separate from its task `phase`. For example, `investigating` can accompany a stopped automatic task; inspect the task's exact phase and evidence.

Transient errors use bounded retries. Missing repair-model setup parks the current phase for a later retry. The service must be restarted to load edited environment-file values. Terminal tasks are not automatically reset by editing SQL or restarting; create fresh provider evidence after correcting setup rather than altering recorded evidence by hand.

## 16. Test rejection and recovery behavior

The following automated tests already cover negative paths without modifying a real repository:

```sh
node --test test/automation.test.js test/providers.test.js
```

Important cases include:

| Test scenario | Expected result |
| --- | --- |
| Proposal edits a protected test | Rejected; no publication |
| Source patch still fails tests | Another bounded candidate or exhausted outcome |
| Model returns no changes | Recorded abstention/blocked outcome |
| Reproduced failure differs from imported symptom | Unreproduced outcome |
| Source branch advances | Old task superseded |
| Repair head changes | Old evidence rejected; obsolete observed PR closed where possible |
| Original CI rejects repair | No successful resolution |
| Merged-commit checks are missing | Stay in observation |
| Response is lost after PR creation | Reconcile existing PR instead of blindly duplicating it |
| Worker lease expires | Stale worker cannot commit a checkpoint |
| Model setup is temporarily missing | Retry later without inventing repair evidence |

For a restart experiment in a live canary, stop the service with Control-C during observation and restart it using the same policy, database and application directory. It should resume reconciliation rather than generate another repair simply because the process restarted. A workspace lost before verification requires reproduction/re-verification, which is intentional.

## 17. Optional manual diagnostic commands

These help with ad hoc inspection and backward compatibility. They are not required for daily unattended operation.

```sh
cd "$CI_GUIDE_APP"
node bin/ci-resolve.js --help
node bin/ci-resolve.js list
node bin/ci-resolve.js show --case REPLACE_WITH_CASE_ID
```

Import the fictional fixture into a separate diagnostic database:

```sh
CI_RESOLVE_DB="$PWD/.private/manual-demo.sqlite" \
node bin/ci-resolve.js import --file examples/failed-run.json
```

Use that same database setting for subsequent `list`/`show` commands if inspecting the fixture. A manual import does not automatically become provider-authenticated evidence or enqueue a live repair task.

For a real **manual** investigation, an explicitly chosen local command can be recorded:

```sh
node bin/ci-resolve.js verify \
  --case REPLACE_WITH_CASE_ID \
  --cwd "$CI_GUIDE_TARGET" \
  -- npm test
```

Sample cases reject real verification. The local command runs with your user permissions; it is not the Docker automation path. A passing manual command is not full CI-equivalence proof.

## 18. Run automatically after macOS login

This optional one-time setup keeps the dashboard and workers running without opening Terminal each day. It is for a local macOS installation, not a production hosting deployment.

First complete a foreground live canary. Stop any foreground CI Resolve process before installing the login service so the two do not fight for port 4310. Docker Desktop must also be available after login if the policy uses Docker.

The following command creates a **user LaunchAgent** under your home folder and points it at this application. It does not change repository code or install a system-wide daemon.

```sh
cd "$CI_GUIDE_APP"
export CI_GUIDE_APP="$PWD"
python3 <<'PY'
import os
import pathlib
import plistlib
import shutil

app = pathlib.Path(os.environ['CI_GUIDE_APP']).resolve()
node = shutil.which('node')
if not node:
    raise SystemExit('Node is not available in PATH.')
node = pathlib.Path(node).resolve()
private = app / '.private'
private.mkdir(exist_ok=True)
agent = pathlib.Path.home() / 'Library/LaunchAgents/in.spekra.ci-resolve.plist'
agent.parent.mkdir(parents=True, exist_ok=True)
if agent.exists():
    raise SystemExit('LaunchAgent already exists; inspect it instead of overwriting.')
path = ':'.join([str(node.parent), '/opt/homebrew/bin', '/usr/local/bin', '/usr/bin', '/bin'])
payload = {
    'Label': 'in.spekra.ci-resolve',
    'ProgramArguments': [
        str(node),
        '--env-file-if-exists=' + str(private / 'automation.env'),
        str(app / 'src/server.js'),
    ],
    'WorkingDirectory': str(app),
    'EnvironmentVariables': {'PATH': path},
    'RunAtLoad': True,
    'KeepAlive': True,
    'StandardOutPath': str(private / 'service.stdout.log'),
    'StandardErrorPath': str(private / 'service.stderr.log'),
}
with agent.open('wb') as stream:
    plistlib.dump(payload, stream)
print(agent)
PY
```

Register it:

```sh
launchctl bootstrap "gui/$(id -u)" \
  "$HOME/Library/LaunchAgents/in.spekra.ci-resolve.plist"
```

Check it:

```sh
launchctl print "gui/$(id -u)/in.spekra.ci-resolve"
curl --fail --silent --show-error http://127.0.0.1:4310/api/health
```

The service loads credentials from `.private/automation.env`; it does not inherit arbitrary exports from your current Terminal. The resolved Node executable must remain installed at that path. Regenerate the service definition deliberately if its Node installation is removed or relocated.

The LaunchAgent example is an operator setup recipe, not a service installed or validated by this development session. On Linux, use your normal user/system service manager with the same working directory, Node executable and environment-file arguments.

## 19. Stop, restart, and change configuration

### Foreground process

Press Control-C, then use `npm start` again. Let the shutdown finish before starting another process against the same state.

### macOS LaunchAgent

Restart after editing a one-time environment/policy setting:

```sh
launchctl kickstart -k "gui/$(id -u)/in.spekra.ci-resolve"
```

Remove the running registration:

```sh
launchctl bootout "gui/$(id -u)" \
  "$HOME/Library/LaunchAgents/in.spekra.ci-resolve.plist"
```

The plist remains on disk. If you intend to disable launch after future logins, move that specific plist out of `~/Library/LaunchAgents` as well. Do not delete application evidence to stop a service.

### Change policy carefully

Stop/restart to load the edited policy. Existing tasks are bound to their previous digest and can stop with a policy-changed result. After correcting a recipe, rerun the canary workflow to produce a fresh provider attempt or create a new canary commit. Restarting alone does not re-enqueue an already terminal task.

## 20. Back up and restore local state

Application state includes `.data/ci-resolve.sqlite`, SQLite companion/WAL files where present, and any retained execution workspaces under `.data/automation/`. Configuration and credentials are separate in `.private/`.

For a simple filesystem backup, first stop **all** app/worker instances, including any LaunchAgent. Then:

```sh
cd "$CI_GUIDE_APP"
CI_GUIDE_BACKUP="$PWD/.private/backups/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$CI_GUIDE_BACKUP"
cp -R .data "$CI_GUIDE_BACKUP/data"
cp .private/automation.json "$CI_GUIDE_BACKUP/automation.json"
```

The policy copy assumes live setup exists. Back up credential material separately using your chosen secret-management procedure; do not add it to a shared support archive.

To restore, keep every instance stopped, preserve the existing `.data` directory under another name, and restore the selected backup to the original state path. Confirm the policy checkout paths still exist before restarting. Do not copy only the main SQLite file from an actively writing process and assume its WAL-backed state was captured.

Execution workspaces can contain private source. Treat backups and evidence as sensitive application data.

## 21. Troubleshoot common problems

| Symptom | Likely cause | What to check/do |
| --- | --- | --- |
| `node:sqlite` unavailable | Wrong Node version | Run Node 24+ from the same shell/service PATH |
| `EADDRINUSE` | Another process owns the port | Stop the intended previous service or choose another `PORT` |
| `listen EPERM` | Terminal/agent socket restriction | Use a normal terminal that permits localhost listeners |
| Docker client exists, server missing/denied | Docker daemon or socket unavailable | Start Docker and run `docker info` as the service user |
| Setup says configuration exists | Overwrite protection | Inspect/edit the existing policy; do not discard it blindly |
| Setup rejects origin | Missing/custom/enterprise origin | Use a supported standard github.com checkout |
| GitHub 401/403/404 | Invalid token, wrong installation, insufficient access, policy, or unavailable resource | Check selected repositories, permissions and organization requirements |
| Dashboard says setup required despite `gh auth login` | App-specific variables absent | Configure the exact CI Resolve credential variables |
| API shows `configured: true` but no tasks | No eligible failure, filters, or connection error | Inspect `health`, job allowlist and provider run age/conclusion |
| Browser tests skip | No configured interpreter | Set `CI_RESOLVE_BROWSER_PYTHON` or `.private/browser-python` |
| Browser tests fail on import | Wrong Python environment | Install Playwright into the exact configured interpreter |
| Browser executable missing | Chromium not installed for that environment | Run that interpreter's `-m playwright install chromium` |
| `unreproduced` | Different symptom, missing environment, empty inventory or skipped tests | Inspect baseline output and verify the supported recipe |
| Preparation modifies tracked inputs | Install/build step changes protected files | Prepare the appropriate image/recipe; do not bypass the integrity check |
| Repair rejected for path | Source extension outside allowlist or protected file | Review one-time bounded source patterns; tests/config remain protected |
| Model credentials missing | Key/model unset or wrong environment file | Set both model fields and restart; parked tasks can retry |
| Model HTTP error/incomplete JSON | Account/model/API issue or truncated response | Inspect task error and model access; no patch should be accepted |
| PR exists but task stays in `observe` | Missing checks, policy requirements or merge waiting | Inspect exact required names and PR/merged-commit checks |
| Merged PR never resolves | No matching CI on the merged commit | Configure CI to run the required jobs on pushes/merged revisions |
| Source/repair head changed | Evidence became stale | Expected superseded behavior; inspect the newer revision/task |
| More than 1000 provider list records | Current reconciliation list budget exceeded | This workload needs narrower collection/product support; changing the job allowlist alone does not reduce the run-list query |
| Tasks appear in one process but not another | Different DB or working directory | Use the same absolute DB/config paths and application directory |
| Terminal task does not resume | Terminal outcome is retained | Correct setup, then produce fresh provider evidence; do not rewrite recorded results |
| GitHub push fails DNS/authentication | Publication environment unavailable | Restore network and configured GitHub authentication; local commits remain available |

The collector looks at failed workflows **created in the preceding 24 hours**, not every historical failure or every recently rerun old workflow. Workflows created earlier may be excluded even if retried recently.

Forks, `ci-resolve/...` repair branches and merge-group source events are excluded intentionally. The original failed job's name is always required during reconciliation; `requiredChecks` adds checks rather than replacing it.

## 22. Current support limits

- Local single-user service; no hosted tenant/login boundary.
- GitHub Actions only; no live GitLab/CircleCI connector in version 0.2.
- Node test inventory required; general Jest/Pytest/JUnit support is not implied.
- No tracked symlinks/submodules or arbitrary service-topology reconstruction.
- Generated default policy requires review for nondefault source extensions.
- Two repair candidates and a 24-hour task lifetime.
- No universal functional-correctness proof, automatic rollback or guarantee that a model can repair every failure.
- Actual external GitHub/model/Docker success was not demonstrated in the development environment.
- No automatic OS-service installation; section 18 is optional one-time operator setup.

These limits do not require per-failure manual action for the supported happy path. They define when automation should stop with evidence instead of claiming success.

## 23. Acceptance checklist

### Local application/test readiness

- [ ] Node, npm and Git report valid versions.
- [ ] `npm run check` succeeds.
- [ ] Core/API/CLI/automation tests pass.
- [ ] Both browser tests pass when browser coverage is required.
- [ ] Preview and website open without horizontal overflow.
- [ ] Optional sample remains labeled and cannot be mistaken for live evidence.

### Live unattended readiness

- [ ] Registered repository, origin and execution recipe match.
- [ ] GitHub and model credentials are valid, not merely present.
- [ ] Docker/default image or explicitly permitted trusted-local backend works.
- [ ] CI reports the required job names on repair and merged commits.
- [ ] Repository policy permits the intended automatic merge behavior.
- [ ] A canary failure reproduces, receives a source repair, passes protected tests, merges and resolves automatically.
- [ ] Restarting during observation does not duplicate the repair PR.
- [ ] Rejected/unsupported cases show a stop reason rather than resolution.
- [ ] Persistent service, logs and backup ownership are configured once.

Only a completed live canary establishes live readiness; green simulated-service tests alone do not.

## 24. Quick command reference

| Task | Command from the application directory |
| --- | --- |
| Syntax checks | `npm run check` |
| Full suite | `npm test` |
| Unattended-flow tests | `node --test test/automation.test.js` |
| Provider/policy tests | `node --test test/providers.test.js` |
| Browser tests | `node --test test/browser.test.js` with a configured interpreter |
| One-time target setup | `node bin/ci-resolve.js setup --cwd /absolute/target/path` |
| Dashboard + configured workers | `npm start` |
| Worker-only service | `npm run automate` |
| One live cycle | `node --env-file-if-exists=.private/automation.env bin/ci-resolve.js automate --mode once` |
| CLI help | `node bin/ci-resolve.js --help` |
| List investigations | `node bin/ci-resolve.js list` |
| Inspect case | `node bin/ci-resolve.js show --case ACTUAL_CASE_ID` |
| Health | `curl --fail http://127.0.0.1:4310/api/health` |
| Automation status | `curl --fail http://127.0.0.1:4310/api/automation` |

## 25. References

- [Current application README](../README.md)
- [Implemented architecture](ARCHITECTURE.md)
- [Validation status](VALIDATION.md)
- [Enterprise target research](ENTERPRISE_RESEARCH.md)
- [Product naming recommendations](PRODUCT_NAMING.md)
- [Playwright Python installation](https://playwright.dev/python/docs/intro)
- [Official checkout action](https://github.com/actions/checkout)
- [Official setup-node action](https://github.com/actions/setup-node)
- [GitHub App installation authentication](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation)
- [Claude Messages API](https://platform.claude.com/docs/en/api/messages/create)

Commands were checked against version 0.2 source and local tests. External dependency installation, the live canary, the LaunchAgent recipe and remote credentials require their respective environments and have not been executed as part of writing this guide.

**Guide validation:** the 25 sections and contents anchors, relative links, tables, JSON examples and all 46 shell examples were checked. The documented local canary passed with correct source and failed after introducing the source defect. The full 56-test application suite also passed, including both Chromium workflows. Live account, Docker and LaunchAgent setup remain environment-dependent steps.
