# Feature Spec: Evidence Integrity Chain + Doctor Diagnostics (AOP)

> **Split from**: `agentic_orchestrator_observability_integrity_diagnostics_spec.md` (v2.0)
> **Covers**: OID2 (Q4 Evidence Integrity) + OID3 (Q11 Doctor) + OID4 (CLI surface) + OID5 (Hardening)
> **Roadmap Mapping:** M33 / Q4 + Q11

**Version:** 1.2
**Date:** 2026-03-16
**Status:** Draft (Audited Against Current Repo State)

---

## 0. Standards and Dependencies

### 0.1 Prerequisite

**Prerequisite status (2026-03-15): satisfied.** `agentic_orchestrator_observability_replay_spec` OID0/OID1/OID4 has been implemented in the repository.

This spec was originally blocked on that merge because it depends on shared observability scaffolding from the replay spec.

Specifically, that spec's OID0 must be complete, which provides:

- Policy schema extensions for `innovation`, `observability`, and `diagnostics` sections
- Error codes: `evidence_chain_missing`, `evidence_chain_artifact_missing`, `evidence_chain_hash_mismatch`, `evidence_chain_discontinuity`, `evidence_integrity_write_failed`, `doctor_check_failed`, `doctor_report_write_failed`
- Tool catalog stubs for `evidence.verify_chain` and `doctor.run`
- Tool schema stub files for both tools
- TOOLS constants: `TOOLS.EVIDENCE_VERIFY_CHAIN`, `TOOLS.DOCTOR_RUN`

Verify this before planning:

```bash
grep -q "evidence_chain_missing" apps/control-plane/src/core/error-codes.ts
grep -q "evidence.verify_chain" agentic/orchestrator/tools/catalog.json
```

If either check fails, assume the local branch has drifted or regressed and block on restoring the prerequisite scaffolding before continuing.

### 0.2 Required Standards

All implementation MUST preserve:

- deterministic tool behavior and normalized error envelopes
- MCP/in-process transport parity for all new tools
- strict contract validation (`validate:mcp-contracts`) and architecture boundaries (`validate:architecture`)
- runtime artifact ownership under `.aop/**`
- existing idempotency semantics for mutating tools

### 0.3 Required Upstream Inputs

Implementing agents MUST read before writing any code:

- `apps/control-plane/src/application/services/gate-service.ts`
- `apps/control-plane/src/core/gates.ts`
- `apps/control-plane/src/core/path-layout.ts`
- `apps/control-plane/src/core/kernel.ts`
- `apps/control-plane/src/core/constants.ts`
- `apps/control-plane/src/core/error-codes.ts`
- `apps/control-plane/src/application/services/reporting-service.ts`
- `apps/control-plane/src/cli/types.ts`
- `apps/control-plane/src/cli/cli-argument-parser.ts`
- `apps/control-plane/src/cli/help-command-handler.ts`
- `apps/control-plane/src/interfaces/cli/bootstrap.ts`
- `apps/control-plane/src/application/tools/tool-metadata.ts`
- `agentic/orchestrator/defaults/policy.defaults.yaml`
- `agentic/orchestrator/schemas/policy.schema.json`
- `agentic/orchestrator/tools/catalog.json`

### 0.4 Feature Scope

This spec implements:

- **OID2**: Q4 Tamper-Evident Evidence Integrity Chain
- **OID3**: Q11 `aop doctor` Readiness + Drift Diagnostics
- **OID4** (evidence + doctor portion): `aop evidence verify` and `aop doctor` CLI commands
- **OID5**: Hardening, performance, and retention rules

Out of scope:

- Policy schema extensions (already done by prerequisite spec)
- Error code additions (already done by prerequisite spec)
- Replay timeline (covered by prerequisite spec)
- `aop replay` CLI command (covered by prerequisite spec)
- Autonomous RCA narrative generation
- External KMS/HSM signing
- Remote telemetry backends

### 0.5 Current Project State

This spec was audited against the live repository on 2026-03-16.

Current status:

1. **Replay scaffolding is complete; evidence/doctor implementation is not.**
   - `replay.timeline_get` and `aop replay` are implemented.
   - `evidence.verify_chain` and `doctor.run` exist only as catalog entries plus stub schemas.

2. **There is currently no kernel or runtime handler wiring for evidence/doctor.**
   - `apps/control-plane/src/application/kernel-tool-wiring.ts` and `apps/control-plane/src/core/kernel.ts` do not expose `evidence.verify_chain` or `doctor.run`.
   - `agentic/orchestrator/policy.yaml` and `agentic/orchestrator/defaults/policy.defaults.yaml` do not currently grant RBAC access to either tool.

3. **There is currently no CLI surface for either feature.**
   - `CliCommand`, `CliArgumentParser`, `COMMAND_CATALOG`, and CLI bootstrap do not include `doctor` or `evidence verify`.
   - the spec must therefore describe the full command lifecycle against the current command-catalog architecture, not the older help-only command wiring model.

4. **`GateService.evidenceLatest()` still has the exact broad-scan behavior this spec warned about.**
   - it still scans all `.json` files in the evidence directory when no mode is specified.
   - this pre-work remains mandatory before chain metadata is introduced into that directory.

5. **The current stub schemas do not match the desired final contracts.**
   - `evidence.verify_chain` output schema is still a loose placeholder.
   - `doctor.run` input/output schemas are still placeholders and do not yet encode the report contract defined here.
   - implementation must replace those stubs, not build around them.

---

## 1. Architectural Context

### 1.1 Critical Integration Corrections

Before implementing OID2, apply this fix to `GateService.evidenceLatest()`:

**Current behavior**: scans all `*.json` files in the evidence directory by mtime.
**Problem**: adding `chain.jsonl` and `manifest.integrity.json` to the evidence directory will cause `evidence.latest` to return chain metadata instead of the actual latest gate evidence.
**Fix**: restrict `evidenceLatest()` to files matching `gate-*.json` and `latest-*.json` patterns only.

This fix must land before any chain files are written to the evidence directory.

### 1.2 Existing Runtime Touchpoints

- **Evidence write path**: `GateService.gatesRun()` + `core/gates.ts` is the authoritative source for gate evidence artifacts. `EvidenceIntegrityService` hooks into the GateService write path.
- **Read/report path**: `ReportingService` is the read aggregation surface. Integrity checks must not bypass service boundaries.
- **Config validation**: `SchemaRegistry` + `loadComposedPolicy` used by doctor for DRIFT_001/DRIFT_002 checks.
- **Current tool wiring seam**: kernel dispatch now flows through `apps/control-plane/src/application/kernel-tool-wiring.ts`; this spec must add evidence/doctor handlers there instead of assuming a monolithic switch-only kernel path.
- **Current CLI help/completion seam**: command usage/help metadata is centralized in `apps/control-plane/src/cli/command-catalog.ts`.

### 1.3 Boundary Rules (Normative)

- `core/*` remains pure infrastructure/domain helpers.
- Evidence chain append/verify belongs in `application/services/` and is invoked from `GateService` write path.
- Doctor scans are deterministic local checks only (file/config/runtime state). No network dependency.
- Chain verification is read-only — it never mutates evidence artifacts.

---

## 2. Contracts

### 2.1 Evidence Integrity Chain Contracts

Paths:

```text
.aop/features/<feature_id>/evidence/chain.jsonl
.aop/features/<feature_id>/evidence/manifest.integrity.json
```

Chain entry contract (one JSON line per tracked artifact):

```json
{
  "algorithm_version": 1,
  "sequence": 7,
  "feature_id": "feature_x",
  "artifact_rel_path": "evidence/gate-full-1741050000.json",
  "artifact_hash": "sha256:...",
  "prev_chain_hash": "sha256:...",
  "chain_hash": "sha256:...",
  "created_at": "2026-03-04T10:15:01.000Z"
}
```

Hash payload (canonical JSON with stable key order, used to compute `chain_hash`):

```json
{
  "algorithm_version": 1,
  "sequence": 7,
  "feature_id": "feature_x",
  "artifact_rel_path": "evidence/gate-full-1741050000.json",
  "artifact_hash": "sha256:...",
  "prev_chain_hash": "sha256:..."
}
```

Manifest contract (`.manifest.integrity.json`):

```json
{
  "entry_count": 7,
  "head_hash": "sha256:...",
  "last_verified_at": "2026-03-04T10:30:00.000Z",
  "last_verified_result": "ok"
}
```

Rules:

- `chain_hash = sha256(canonical_json(hash_payload))`.
- `prev_chain_hash` for the first entry is `"sha256:genesis"` (fixed sentinel).
- Key order for canonical JSON: `algorithm_version`, `sequence`, `feature_id`, `artifact_rel_path`, `artifact_hash`, `prev_chain_hash`.
- `artifact_hash = sha256(file_contents)` in hex format, prefixed `sha256:`.
- Chain append is per-feature file-locked on `chain.jsonl`.
- Tracked artifacts in v1 scope: files matching `gate-*.json` and `latest-*.json` only.
- Verification fails closed: missing artifact, hash mismatch, or chain discontinuity all return failure with first failing sequence and reason.

### 2.2 Doctor Report Contract

Paths:

```text
.aop/runtime/doctor/last_report.json
.aop/runtime/doctor/history/<timestamp>.json
```

Report contract:

```json
{
  "ok": true,
  "generated_at": "2026-03-04T10:30:00.000Z",
  "summary": {
    "critical": 0,
    "warning": 1,
    "info": 3
  },
  "findings": [
    {
      "id": "DRIFT_004_STALE_RUN_LEASE",
      "severity": "warning",
      "message": "Run lease appears stale and still populated",
      "remediation": "Run `aop run --takeover-stale-run` or clear stale lease after verification",
      "refs": [".aop/runtime/default/run-lease.json"]
    }
  ]
}
```

Rules:

- Findings sorted lexically by `id`.
- `summary` counts derived strictly from the `findings` array — never set independently.
- `ok = (summary.critical === 0)` in normal mode.
- `ok = (summary.critical === 0 && summary.warning === 0)` in strict mode (affects CLI exit code only, not stored `ok`).

### 2.3 `evidence.verify_chain` Tool (Replaces Stub from Prerequisite Spec)

Read-only tool. Verifies the integrity chain for a feature.

Input schema:

```json
{
  "type": "object",
  "required": ["feature_id"],
  "properties": {
    "feature_id": { "type": "string", "minLength": 1 }
  }
}
```

Output schema:

```json
{
  "type": "object",
  "required": ["feature_id", "valid", "entry_count"],
  "properties": {
    "feature_id": { "type": "string" },
    "valid": { "type": "boolean" },
    "entry_count": { "type": "integer" },
    "first_failure_sequence": { "type": "integer" },
    "failure_reason": { "type": "string" }
  }
}
```

Returns `evidence_chain_missing` error if `chain.jsonl` does not exist.

### 2.4 `doctor.run` Tool (Replaces Stub from Prerequisite Spec)

Mutating tool (persists report artifacts). Requires `operation_id`.

Input schema:

```json
{
  "type": "object",
  "properties": {
    "strict": { "type": "boolean" }
  }
}
```

Output schema: the full doctor report object (§2.2 contract).

---

## 3. Detailed Implementation Plan

### OID2: Q4 Evidence Integrity Chain

#### 3.1 Pre-work: Fix `GateService.evidenceLatest()`

**Immediate fix before any chain files exist:**

In `apps/control-plane/src/application/services/gate-service.ts`, update `evidenceLatest()` to filter the evidence directory contents to only files matching `gate-*.json` or `latest-*.json`. Reject `chain.jsonl`, `manifest.integrity.json`, and any other file.

Add a regression test in `apps/control-plane/test/gates.spec.ts`:

- `evidenceLatest` ignores `chain.jsonl` when present alongside gate files.
- `evidenceLatest` ignores `manifest.integrity.json` when present.

#### 3.2 Path-layout Helpers

Add to `AopPathLayout` in `apps/control-plane/src/core/path-layout.ts`:

```
evidenceChainPath(featureId): string       // .aop/features/<id>/evidence/chain.jsonl
evidenceManifestPath(featureId): string    // .aop/features/<id>/evidence/manifest.integrity.json
evidenceChainLockPath(featureId): string   // .aop/features/<id>/evidence/chain.lock
doctorReportPath(): string                 // .aop/runtime/doctor/last_report.json
doctorHistoryDir(): string                 // .aop/runtime/doctor/history/
doctorHistoryPath(ts: string): string      // .aop/runtime/doctor/history/<ts>.json
```

#### 3.3 EvidenceIntegrityService

**Write path algorithm** (`append(featureId, artifactRelPath)`):

1. Check policy: `innovation.tamper_evident_evidence && observability.evidence_integrity.enabled`. If false, return early (no-op).
2. Acquire per-feature chain lock.
3. Compute `artifact_hash = sha256(file_contents)` of the artifact.
4. Read current chain tail: last line of `chain.jsonl` to get `prev_chain_hash` and `sequence`. If file is empty or missing, use `prev_chain_hash = "sha256:genesis"` and `sequence = 0`.
5. Compute `chain_hash` from canonical hash payload.
6. Append new entry to `chain.jsonl`.
7. Update `manifest.integrity.json` with new `entry_count` and `head_hash`.
8. Release lock.
9. On error: if enabled via policy, propagate as `evidence_integrity_write_failed`. Otherwise log and continue.

**Verify algorithm** (`verify(featureId)`):

1. Check `chain.jsonl` exists; return `evidence_chain_missing` error if not.
2. Read all entries in order.
3. For each entry:
   a. Check artifact file exists; fail with `evidence_chain_artifact_missing` if not.
   b. Recompute `artifact_hash`; fail with `evidence_chain_hash_mismatch` if mismatch.
   c. Recompute `chain_hash` from canonical payload; fail with `evidence_chain_hash_mismatch` if mismatch.
   d. Check `prev_chain_hash` matches previous entry's `chain_hash` (or genesis for sequence 0); fail with `evidence_chain_discontinuity` if not.
4. Return `{ valid: true, entry_count }` on full pass.
5. Return `{ valid: false, entry_count, first_failure_sequence, failure_reason }` on first failure.

**GateService integration** — after `gatesRun()` successfully writes gate evidence files, call `EvidenceIntegrityService.append()` for each tracked artifact (`gate-*.json`, `latest-*.json`). This is a best-effort call by default.

**Implementation targets**:

- `apps/control-plane/src/application/services/evidence-integrity-service.ts` (new)
- `apps/control-plane/src/application/services/gate-service.ts` — fix `evidenceLatest`, add `EvidenceIntegrityService` integration
- `apps/control-plane/src/core/path-layout.ts` — evidence chain + doctor path helpers
- `apps/control-plane/src/core/constants.ts`
- `apps/control-plane/src/application/tools/tool-metadata.ts`
- `apps/control-plane/src/core/kernel.ts`
- `apps/control-plane/src/application/kernel-tool-wiring.ts`
- `agentic/orchestrator/policy.yaml`
- `agentic/orchestrator/defaults/policy.defaults.yaml`
- `agentic/orchestrator/tools/catalog.json`
- `agentic/orchestrator/tools/schemas/input/evidence.verify_chain.input.schema.json` — replace stub
- `agentic/orchestrator/tools/schemas/output/evidence.verify_chain.output.schema.json` — replace stub
- `agentic/orchestrator/tools.md` — regenerate after replacing the stub contract

**Test plan**:

- `apps/control-plane/test/evidence-integrity-service.spec.ts` (new):
  - genesis entry written correctly (prev_chain_hash sentinel)
  - chain append: sequence increments, chain_hash computed correctly
  - verify: untampered chain returns `valid: true`
  - verify: tampered artifact content → `evidence_chain_hash_mismatch`
  - verify: tampered chain_hash in entry → `evidence_chain_hash_mismatch`
  - verify: deleted artifact → `evidence_chain_artifact_missing`
  - verify: discontinuous `prev_chain_hash` → `evidence_chain_discontinuity`
  - append when policy disabled: no-op, no files created
- Extend `apps/control-plane/test/gates.spec.ts`:
  - `evidenceLatest` ignores `chain.jsonl` and `manifest.integrity.json`
- Extend `apps/control-plane/test/kernel.spec.ts`:
  - `evidence.latest` still returns gate evidence artifact, not chain metadata
- Extend `apps/control-plane/test/mcp.spec.ts`:
  - `evidence.verify_chain` parity (in-process vs MCP)

**Exit criteria**:

- Tampered artifact triggers deterministic failure with reason and first failing sequence
- Untampered chain verifies successfully end-to-end
- `evidenceLatest` unaffected by chain files

---

### OID3: Q11 Doctor Diagnostics

#### 3.4 DoctorService

Implement deterministic scanner with fixed check IDs, strict severity, and stable output ordering.

**Required checks (v1)** — executed in lexical order by check ID:

| ID                                    | Severity | Description                                                                                         |
| ------------------------------------- | -------- | --------------------------------------------------------------------------------------------------- |
| `DRIFT_001_POLICY_SCHEMA_INVALID`     | critical | Policy file fails `loadComposedPolicy` validation                                                   |
| `DRIFT_002_GATES_SCHEMA_INVALID`      | critical | Gates file fails schema validation                                                                  |
| `DRIFT_003_TOOL_CONTRACT_DRIFT`       | warning  | Any tool schema in catalog fails `validate:mcp-contracts` logic                                     |
| `DRIFT_004_STALE_RUN_LEASE`           | warning  | Run lease exists and `lease_expires_at` is in the past                                              |
| `DRIFT_005_RUNTIME_SESSION_ORPHANS`   | warning  | Feature session IDs in run lease reference feature IDs not in `index.active`                        |
| `DRIFT_006_TIMELINE_CORRUPTION`       | warning  | Any timeline file contains unparseable lines (only checked if replay enabled)                       |
| `DRIFT_007_EVIDENCE_CHAIN_INVALID`    | warning  | Any feature's integrity chain fails verification (only checked if evidence integrity enabled)       |
| `DRIFT_008_INDEX_STATE_INCONSISTENCY` | critical | Feature IDs appear in multiple index lists simultaneously (active + blocked, active + merged, etc.) |

**Deterministic output rules**:

- Check execution order: fixed lexically by check ID (DRIFT_001 → DRIFT_008).
- Findings sorted by check ID in output.
- Same repo state yields identical findings array except `generated_at` and `last_verified_at` fields.
- Each check is fully independent — one check failing must not prevent subsequent checks from running.

**Doctor report persistence**:

1. Write report to `doctorHistoryPath(generatedAt)`.
2. Write (overwrite) `last_report.json` with same content.
3. Prune history directory to keep newest 20 reports.

**Implementation targets**:

- `apps/control-plane/src/application/services/doctor-service.ts` (new)
- `agentic/orchestrator/schemas/doctor_report.schema.json` (new — validates report output)
- `apps/control-plane/src/core/path-layout.ts` — doctor path helpers (if not already added in OID2)
- `apps/control-plane/src/core/constants.ts`
- `apps/control-plane/src/application/tools/tool-metadata.ts`
- `apps/control-plane/src/core/kernel.ts`
- `apps/control-plane/src/application/kernel-tool-wiring.ts`
- `agentic/orchestrator/policy.yaml`
- `agentic/orchestrator/defaults/policy.defaults.yaml`
- `agentic/orchestrator/tools/catalog.json`
- `agentic/orchestrator/tools/schemas/input/doctor.run.input.schema.json` — replace stub
- `agentic/orchestrator/tools/schemas/output/doctor.run.output.schema.json` — replace stub
- `agentic/orchestrator/tools.md` — regenerate after replacing the stub contract

**Test plan**:

- `apps/control-plane/test/doctor-service.spec.ts` (new):
  - all 8 check IDs present in output when all failures triggered
  - findings sorted lexically by ID
  - `ok=false` when any critical finding present
  - `ok=true` when no critical findings (warnings allowed)
  - DRIFT_006 skipped (no finding emitted) when replay disabled via policy
  - DRIFT_007 skipped when evidence integrity disabled via policy
  - DRIFT_008 detects feature ID in both `active` and `blocked` simultaneously
  - report artifact is schema-valid
  - history is pruned to 20 entries
- Extend `apps/control-plane/test/cli.unit.spec.ts`:
  - `doctor` command parser coverage
  - `--strict` flag parsed correctly
  - `--json` flag parsed correctly
- Extend `apps/control-plane/test/mcp.spec.ts`:
  - `doctor.run` parity (in-process vs MCP)

**Exit criteria**:

- Report artifact passes `doctor_report.schema.json` validation
- Strict-mode exit behavior deterministic and tested
- All 8 checks execute independently

---

### OID4 (Evidence + Doctor Portion): CLI Surface

Add `aop evidence verify` and `aop doctor` commands.

**CLI specifications**:

```
aop evidence verify --feature-id <id> [--json]
aop doctor [--strict] [--json]
```

- `aop evidence verify`: calls `evidence.verify_chain` and displays result.
- `aop doctor`: calls `doctor.run`, displays findings, exits non-zero on critical (or warnings in `--strict`).
- Both support `--json` for raw tool response output.

**Required file changes** (per CLAUDE.md — all in the same change):

1. `apps/control-plane/src/cli/types.ts` — add `CliCommand.Evidence`, `CliCommand.Doctor`; add `strict` option field
2. `apps/control-plane/src/cli/cli-argument-parser.ts` — parse `evidence verify` subcommand and `doctor`
3. `apps/control-plane/src/interfaces/cli/bootstrap.ts` — dispatch both commands to handlers
4. `apps/control-plane/src/cli/command-catalog.ts` — add `evidence` and `doctor` command definitions so help/completion stay aligned
5. `apps/control-plane/src/cli/evidence-command-handler.ts` (new)
6. `apps/control-plane/src/cli/doctor-command-handler.ts` (new)

If `help-command-handler.ts` requires explicit updates beyond `COMMAND_CATALOG`, those updates must be made in the same change, but `command-catalog.ts` is now the primary help surface to keep aligned.

**Doctor CLI semantics**:

- Normal mode: exits non-zero if any critical finding present.
- `--strict` mode: exits non-zero if any critical **or** warning finding present.
- Both modes: exits 0 if only info findings.
- `--json`: emit full report JSON regardless of findings.

**Test additions**:

- Extend `apps/control-plane/test/cli.unit.spec.ts`: parser coverage for `evidence verify` and `doctor` + flags
- `apps/control-plane/test/evidence-command-handler.spec.ts` (new): dispatch, JSON mode, error passthrough
- `apps/control-plane/test/doctor-command-handler.spec.ts` (new): strict vs normal exit codes, JSON mode

---

### OID5: Hardening and Retention

#### Replay Retention (Companion to Prerequisite Spec)

The prerequisite spec's `ReplayTimelineService` implements retention. This spec adds a doctor check (DRIFT_006) that detects timeline corruption. No additional replay retention work is needed here.

#### Evidence Integrity vs Retention Rule

If any evidence pruning occurs (manual or policy-driven), chain integrity may fail because chain entries reference deleted artifacts. The following invariant must be documented and enforced:

- `DRIFT_007_EVIDENCE_CHAIN_INVALID` in doctor will fire if chain references a missing file.
- Documentation must explicitly state: integrity verification requires preserving all tracked artifacts.
- Doctor finding for DRIFT_007 must include remediation text: `"Do not prune evidence artifacts when evidence_integrity is enabled. Disable integrity before pruning."`.

**Implementation targets**:

- `apps/control-plane/src/application/services/doctor-service.ts` — DRIFT_007 remediation text
- `README.md` — operational caveat section on integrity and retention

**Test plan**:

- `apps/control-plane/test/evidence-integrity-service.spec.ts`: verify correctly returns `evidence_chain_artifact_missing` when artifact deleted after chain written
- `apps/control-plane/test/doctor-service.spec.ts`: DRIFT_007 fires with correct remediation when chain references missing artifact

**Exit criteria**:

- Doctor correctly identifies integrity failures after evidence file deletion
- Remediation text is actionable and present in finding

---

## 4. Test Strategy Summary

### 4.1 Unit Tests

- Chain hash recomputation and discontinuity detection
- Doctor check ID ordering and severity aggregation
- Evidence integrity write path under per-feature lock
- DRIFT_006/007 conditional execution based on policy toggles

### 4.2 Integration Tests

- Evidence tamper triggers `evidence.verify_chain` failure with correct sequence and reason
- Doctor identifies intentionally broken policy/schema/runtime artifacts
- `evidenceLatest` unaffected by chain metadata files in evidence directory

### 4.3 Transport Parity

- `evidence.verify_chain` parity: in-process vs MCP
- `doctor.run` parity: in-process vs MCP

### 4.4 CLI Tests

- Parser/help/bootstrap coverage for `evidence verify` and `doctor`
- `--strict` exit code behavior
- `--json` output correctness

### 4.5 Regression Tests

- `evidence.latest` unaffected by integrity metadata files (must be verified independently of prerequisite spec)
- Existing gate behavior preserved when integrity is disabled

---

## 5. Acceptance Criteria

1. Evidence integrity chain detects tampering and discontinuities deterministically, returning first failing sequence and reason.
2. `evidence.latest` returns gate evidence, not chain metadata, even when chain files are present.
3. `aop doctor` produces deterministic, schema-valid findings with actionable remediations, sorted by check ID.
4. Doctor strict mode exits non-zero on warnings; normal mode exits non-zero only on criticals.
5. `evidence.verify_chain` and `doctor.run` tools are fully wired: constants / kernel / tool-metadata / catalog / schemas / RBAC / tools.md.
6. `aop evidence verify` and `aop doctor` commands are fully wired: types / parser / command-catalog / bootstrap / handlers.
7. DRIFT_007 correctly fires when an integrity-tracked artifact is missing.
8. Quality gates pass: `lint`, `typecheck`, `test`, `validate:mcp-contracts`, `validate:architecture`.

---

## 6. Risks and Mitigations

- **Risk**: Chain file corruption under concurrent gate runs.
  - **Mitigation**: Per-feature file lock around all chain append operations.

- **Risk**: False confidence from disabled checks in doctor.
  - **Mitigation**: DRIFT_006/007 explicitly skip with an info finding when the relevant feature is disabled (no silent suppression).

- **Risk**: Schema drift between `doctor_report.schema.json` and actual service output.
  - **Mitigation**: Doctor output validated against schema in service tests.

- **Risk**: `evidenceLatest` regression introduced by fix.
  - **Mitigation**: Explicit regression tests for `evidenceLatest` with chain files present.

---

## 7. Definition of Done

A completed implementation session MUST provide:

- Changed files and rationale by phase (OID2 → OID3 → OID4 → OID5)
- Schema/catalog/RBAC deltas (tool stub schemas replaced with real schemas)
- Regenerated `tools.md`
- Test additions and executed command results (`npm test`, `npm run lint`, `npm run validate:mcp-contracts`)
- `spec-files/progress.md` update entry covering OID2, OID3, OID4, and OID5 milestones
