# Objective Guard in TODO_HARNESS

TODO one or two sentences: which harness this covers and which edit tool it gates. Point to [../getting-started.md](../getting-started.md) for first-run setup instead of repeating it. Spanish counterpart: [_template.es.md](_template.es.md).

Before you fill this in, read the harness's own hook script under `src/` and the tests that cover it. Replace every `TODO`. If a capability is not implemented or not covered by a test, delete the claim or say so explicitly — do not invent flags, paths, or configuration keys. Keep the seven H2 headings below, in order.

## What this integration gives you

Three to six bullets. Each states a concrete capability and what it does not prove.

- **A pre-edit preflight gate.** TODO which harness event runs `src/pre-edit-gate.mjs`, and what a denial looks like in this harness. It proves the agent read the contract before mutating; it proves nothing about whether the edit is correct.
- **Edit-time detectors.** TODO which event runs the harness hook, how the edited file is extracted from the payload, and which detectors apply (`weak-test`, `stub-prod`, `new-dep` on `package.json` alone, JS syntax on `.js`/`.mjs`/`.cjs` alone). Silence means those four found nothing on that file.
- **Prompt injection of the current phase.** TODO which script and event, and what it tells the agent to run next. It is advice injected as context; it enforces nothing.
- **Round evidence.** `oguard align` measures the changed surface against the declared scope and key results; `oguard round-end` runs the declared checks and preserves an append-only record. A `pass` means the checks in scope found no violation.
- **Sanitized telemetry.** Each decision appends harness, repository hash, result, reason code and duration to the global inventory. No paths, no prompt, no file content.

## Requirements

- Node 20 or newer (`package.json#engines` declares `"node": ">=20"`), and `node` resolvable on `PATH` — hook commands invoke `node` directly.
- A Git repository. Every command resolves its root with `git rev-parse --show-toplevel`.
- TODO the harness capabilities the code actually depends on: which hook events, whether it honours a deny decision, and which payload fields the hook reads. State that no harness version is pinned unless the code pins one.

## Install

TODO whether the package can be installed from a registry. As of today `package.json` sets `"private": true`, so guides describe a checkout.

```bash
git clone <repository-url> objective-guard
cd objective-guard
node --version            # must be >= 20
node src/cli.mjs --help   # prints the command surface on stderr and exits 2
```

Inside this checkout, call the CLI as `node src/cli.mjs <cmd>`. `package.json#bin` maps `oguard` to `./src/cli.mjs`, so `npm link` puts `oguard` on your `PATH`; no test covers the linking step.

Hook configuration is TODO **user-level** or **project-level**, in `TODO/path/the/harness/reads`. Paths in `command` must be absolute.

```json
{
  "TODO": "the real configuration block this harness reads, with the pre-edit gate, the post-edit hook, and the prompt script"
}
```

TODO explain any environment variable the hook needs (`OGUARD_HARNESS=<name>` labels telemetry; `OGUARD_HOOK_EXECUTE=1` forces the hook's `main()` when invoked through a wrapper) and any matcher subtlety.

Then, per repository:

```bash
oguard init   # creates oguard.contract.json only
```

`oguard init` installs no hooks and touches no harness configuration — it writes a placeholder contract with `objective.id = "O-UNSPECIFIED"` and refuses to overwrite an existing one (`test/init-cli.test.mjs`). Hook installation is the manual step above.

## Verify the integration

```bash
# 1. Preflight. Prints status ready or action-required; action-required exits 1.
node src/cli.mjs task-flow --json

# 2. Feed the gate the payload shape this harness sends, with isolated telemetry.
export OGUARD_INVENTORY_DIR=/tmp/oguard-verify
printf '{"cwd":"%s","tool_name":"TODO","tool_input":{"file_path":"%s/README.md"}}' "$PWD" "$PWD" \
  | OGUARD_HARNESS=TODO node src/pre-edit-gate.mjs
echo "exit=$?"

# 3. Read the decision that was recorded.
tail -1 "$OGUARD_INVENTORY_DIR/events.jsonl"
```

An authorized repository produces no stdout and `exit=0` with `"preflight_reason":"fresh-preflight"`. An unauthorized one prints the `permissionDecision: deny` JSON, exits 2, and records `"preflight_reason":"missing-or-expired-preflight"`. Both transitions are asserted in `test/pre-edit-gate.test.mjs`.

```bash
node --test test/pre-edit-gate.test.mjs test/hooks-e2e.test.mjs test/claude-hook.test.mjs
```

TODO name the test that covers this harness's own wiring and what it asserts. If no test covers it, say so plainly.

## The loop in practice

```bash
oguard init
oguard intent --objective-id O-1 --objective "TODO objective" --task-type bugfix --scope "src/**,test/**"
oguard intent-scan
oguard start --from-intent --round-id R-1 --round "TODO round" --kr-id KR-1 --kr "TODO key result"
git add oguard.contract.json && git commit -m "open round R-1"
oguard task-flow --json
# ... edits, each gated and inspected by the hooks above
oguard check --file TODO/path.mjs
oguard align --json
oguard round-end --mode final
```

`init` writes the placeholder contract once per repository. `intent` records a local, revisable draft objective, task type and candidate scope under `.oguard/intent.json`; nothing is frozen yet. `intent-scan` resolves only Git-observable files matching those globs — structural evidence, never semantic proof. `start --from-intent` copies the reviewed draft into the frozen contract and anchors the baseline; after this, changing direction requires a successor round. Commit `oguard.contract.json` so the frozen contract is versioned with the work. `task-flow --json` must return `ready` before the first material edit; it is what grants the authorization the gate looks for. Each edit is then gated and inspected automatically. `check --file` runs the same four detectors on demand. `align` compares the changed surface with the declared scope and key results. `round-end --mode final` runs the declared checks and blocks if a required criterion is still `unknown`; `--mode fast` preserves that uncertainty. For the next piece of work, open a successor with `oguard next-round ...`, which requires a clean tree.

## What the harness cannot see

Keep every limit below that applies, and add the ones specific to this harness.

- The gate only inspects structured tool payloads. TODO name the fields it reads here. A write performed inside a shell command — `sed -i`, `tee`, a redirection, `git apply`, a script that rewrites files — is neither gated nor classified.
- A repository with no `oguard.contract.json` is never blocked: `allow` with reason `no-contract`; a file outside the contract root returns `allow` with reason `file-outside-contract`. Absence of a denial is not evidence of governance.
- The `ready` authorization is cached, not continuous. It lives in `.oguard/state.json` against the contract hash and the versioned KPI policy hash, and expires one hour after it was granted. Editing either invalidates it immediately.
- The post-edit detector is advisory: it runs after the mutation and returns context, never a rejection. Its scope is four checks per file.
- Prompt injection is not enforcement. Only the pre-edit gate produces a denial.
- Telemetry proves usage, not benefit; `oguard inventory dashboard --json` reports `causal_effect: not-evaluable`.
- TODO anything this harness specifically hides: unsupported events, payloads without a file path, tool names the matcher misses.

## Troubleshooting

| Symptom | Likely cause | Command that shows the truth |
| --- | --- | --- |
| Every edit is denied | No current authorization, or the contract or KPI policy changed | `node src/cli.mjs task-flow --json` |
| Denial names an unexpected contract root | A parent directory holds `oguard.contract.json` | `printf '{"cwd":"%s","tool_input":{"file_path":"%s/file.mjs"}}' "$PWD" "$PWD" \| node src/pre-edit-gate.mjs` |
| `task-flow` returns `action-required` | Missing contract, baseline mismatch, governance finding, or blocking KPI violation — the `actions` array names which | `node src/cli.mjs task-flow --json` |
| Nothing is ever denied | No contract in that repository, or hooks not installed for this harness | `ls oguard.contract.json` and inspect TODO the harness configuration path |
| No findings after a bad edit | Hook skipped, or the change is outside the four detectors | TODO the debug switch for this harness, then `node src/cli.mjs check --file <path> --json` |
| Inventory stays empty or shows `tool: "unknown"` | `OGUARD_INVENTORY_DIR` points elsewhere, or `OGUARD_HARNESS` is missing from the command | `tail -3 ~/.oguard/inventory/events.jsonl` |
| `round-end` blocks on `unknown` criteria | The round declared no reproducible check for a required criterion | `node src/cli.mjs round-end --mode fast --json` |
