---
name: backend-architect-contract-spec
description: Contract-specification reference for the DevForgeAI per-invocation work-contract handoff between the primary Claude session and the 5 development subagents (backend-architect, frontend-developer, refactoring-specialist, test-automator, integration-tester). Covers schema fields, lifecycle (primary writes → subagent reads + appends completion → gate verifies), file-path conventions (tmp/${STORY_ID}/contracts/), per-subagent phase-specific extensions, and the canonical template at assets/templates/contract-template.yaml. Preloaded into each of the 5 subagents via the `skills:` frontmatter array so the contract schema is available at subagent startup without on-demand reads.
version: "1.0"
---

# Contract Specification — Work Contract for Development Subagents

**Status**: Preloaded skill (BA-018) | **Consumers**: 5 dev subagents | **Governance**: ADR-055

This skill documents the YAML work-contract format that the primary Claude session writes to `tmp/${STORY_ID}/contracts/phase-${PHASE}-${SUBAGENT}.yaml` before dispatching a development subagent via `Task()`. The subagent reads the contract, executes the work, and appends its `completion_record` to the same file. An `artifact-verification-gate.sh` hook then verifies the completion before phase-complete.

The per-invocation contract replaces the prose-flattening path where the primary session composed a ~60-line English prompt and the subagent re-Read() the story + re-Glob()ed tests. With the contract, primary passes structured state once; the subagent has no need to rebuild it.

---

## When this skill fires

This is a **preloaded skill**. It is injected into the subagent's startup context via the `skills:` YAML array in the subagent's frontmatter (`src/claude/agents/<subagent>.md`). Per Anthropic's subagent architecture (ADR-055, constraints A-D), preloaded skills load their full content at dispatch — no runtime lookup, no on-demand Read().

The skill is NOT triggered by description matching. It is preloaded unconditionally whenever any of the 5 dev subagents are dispatched.

---

## Schema reference

**Machine-readable source of truth:** `devforgeai/config/contract.schema.json`
**Template (start here to compose a new contract):** `assets/templates/contract-template.yaml`
**Proposal (full design rationale):** `docs/Optimization/agents/backend-architect/contract-specification-proposal.md`

### Top-level required fields (always)

| Field | Type | Purpose |
|---|---|---|
| `schema_version` | string enum ["1.0"] | Forward compatibility. Bumps via additive enum expansion. |
| `work_id` | string pattern | Unique per-invocation id: `phase-NN-<subagent>-<story-id>-<ISO8601-compact>`. |
| `story_id` | string pattern `^STORY-\d+$` | Aligns with all other DevForgeAI state. |
| `phase` | string pattern `^\d{2}$` | Two-digit zero-padded phase number. |
| `phase_mode` | enum | `test-first` / `implementation` / `refactor` / `integration`. Drives conditional-required fields. |
| `subagent` | enum | One of the 5 dev subagents. |
| `invoked_by` | string | Caller identity for audit trail. |
| `issued_at` | string ISO 8601 UTC | When the contract was written. |
| `primary_context_hash` | string `sha256:` | SHA-256 over {6 context files + story + phase-state.json} at issue time. Enables drift detection. |
| `tech_stack_snapshot` | object | From Phase 01 detected_tech_stack (BA-003 extension). |
| `overflow_budget` | object | max_turns (BA-014), soft_warn_at, on_overflow handler ref. |
| `completion_schema_ref` | string | Path to observation JSON schema subagent emits on Stop hook (BA-009 + BA-012). |
| `required_agent_steps` | array of strings | Names of agent-step records subagent must emit (BA-010). |
| `completion_record` | null or object | Null at issue; subagent appends populated object on Stop. |

### Conditional required fields (per `phase_mode`)

| `phase_mode` | Additionally required |
|---|---|
| `implementation` | `ac_list`, `files_to_modify`, `test_files` |
| `test-first` | `ac_list`, `test_files_to_create` |
| `refactor` | `refactor_targets`, `files_to_modify` |
| `integration` | `ac_list`, `test_files`, `service_boundaries` |

The schema enforces these via `allOf` + `if`/`then` branches. A contract that violates its `phase_mode` shape is rejected by `contract-schema-validator.sh` at write time (exit code 2, stderr enumerates every missing field).

### Optional fields (any `phase_mode`)

- `mode` — enum `normal | remediation`. Phase-02 variant flag. In `remediation` mode the contract generates tests for specific REC entries only and does NOT claim full-AC coverage.
- `context_ai_rules` — string (.ai.md YAML block from Phase 01 Step 2.5).
- `detected_components[]` — Treelint-extracted component map from Phase 3.5.
- `file_overlap_warnings[]` — from Phase 0.2.6 file-overlap-detector.
- `friction_catalog_excerpt` — string.
- `subagent_extensions` — object; open schema for subagent-specific fields not generalized to all 5 (per proposal §5.1).

### Per-subagent extensions (proposal §5.1)

| Subagent | Phase | Extensions block (optional) |
|---|---|---|
| `backend-architect` | 03 | `files_to_modify[].layer` uses `domain / application / infrastructure`. |
| `frontend-developer` | 03 | `files_to_modify[].layer` uses `component / container / page / hook / store`. `ui_source_of_truth_ref` pointer to design.md if extracted. |
| `refactoring-specialist` | 04 | `test_green_invariant: true`. `before_complexity` / `after_complexity_target` numeric. |
| `test-automator` | 02 | `red_phase_snapshot_ref` (STORY-502). `test_framework_config`. |
| `integration-tester` | 05 | `service_boundaries[]` with upstream/downstream direction flags. |

### `inputs.*` field group

The `contract.inputs.*` sub-object carries the work-state the subagent needs to execute. It is populated by `devforgeai-validate build-test-contract` (deterministic, never LLM-assembled). The 5 dev subagents read these fields and MUST NOT re-fetch the underlying sources.

| Field | Type | Purpose | Source |
|---|---|---|---|
| `story_summary` | object | Story title, type, AC count, DoD count | Story file (parsed at build) |
| `ac_list` | array | Pre-parsed Given/When/Then per AC | Story file |
| `detected_tech_stack` | object | Framework, test_command, coverage_command | `phase-state.json` (Phase 01) |
| `test_plan_subset` | object | Subset of test-plan content (naming, mocking, fixtures, coverage thresholds) | `devforgeai/specs/context/test-plan.ai.yaml` |
| `coverage_plan` | object | Per-file layer + required error-branch test counts | `tmp/${STORY_ID}/coverage-plan.json` |
| `rec_entries` | array | REC entries to address (Phase 02 remediation only) | `devforgeai/qa/recommendations/${STORY_ID}-qa-recommendations.md` |
| `failing_tests` | array | Failing test entries (Phase 04 coverage-gap only) | `tmp/${STORY_ID}/failing-tests.json` |
| `previous_observations` | array | Prior observation JSONs (optional learning context) | `tmp/${STORY_ID}/observations/*.json` |

**`test_plan_subset` specifics**:

- **Emitter**: `src/claude/scripts/devforgeai_cli/commands/build_test_contract.py` — function `_extract_test_plan_subset` at lines 208-222; the `_build_source_artifacts` block at lines 251-253 additionally records `source_artifacts.test_plan_file` as the realpath to `devforgeai/specs/context/test-plan.ai.yaml`.
- **Consumer**: `test-automator` agent — the field is documented at `.claude/agents/test-automator.md` line 68 (verified); additional references inside the agent body are reachable via `grep -n "test_plan_subset" .claude/agents/test-automator.md`.
- **Subset extraction rule**: `_extract_test_plan_subset` accepts both a top-level `test_plan_subset` key (canonical) and a flat document shape (callers may write either); when the explicit sub-object is present it is preferred.
- **Authoritative source**: the full artifact at `devforgeai/specs/context/test-plan.ai.yaml` (constitutional, immutable per ADR-054). The subset is a per-invocation view; do NOT treat the subset as authoritative for cross-story decisions.

**Future consumer expansion**: `backend-architect`, `frontend-developer`, `refactoring-specialist`, and `integration-tester` are candidates for receiving `test_plan_subset` via this same channel (see `docs/context/test-plan-generation.md` Gaps 9–11, deferred). The decision (direct-artifact vs work-contract-mediated) is out of scope for this PR.

---

## Lifecycle

### Write-side (primary Claude session)

Executed at the start of Phase 02 / 03 / 04 / 05 Step 2, BEFORE the `Task()` call that dispatches the subagent.

1. Gather primary-session state:
   - `STORY_FILE`, parsed `ac_list[]` (from Phase 01 requirements-analyst)
   - `DETECTED_TECH_STACK` from `phase-state.json` (BA-003, already propagated)
   - `CONTEXT_AI_RULES` from `phase-state.json` (Phase 01 Step 2.5)
   - `FRICTION_CATALOG_CONTENT` (Phase 01 friction-catalog lookup)
   - File-overlap warnings (Phase 0.2.6)
   - Static constants: `overflow_budget`, `completion_schema_ref`, `required_agent_steps`
2. Compose YAML contract per the schema at `devforgeai/config/contract.schema.json`. Use the template at `assets/templates/contract-template.yaml` as a skeleton.
3. Compute `primary_context_hash = sha256(concat(6 context files + STORY_FILE + phase-state.json))`.
4. Write contract to `tmp/${STORY_ID}/contracts/phase-${PHASE}-${SUBAGENT}.yaml` (path constraint per `.claude/rules/workflow/operational-safety.md` Rule 2 — project-scoped tmp).
5. `PreToolUse` hook `contract-schema-validator.sh` fires on the Write:
   - Loads `devforgeai/config/contract.schema.json`
   - Validates via `python3` + `jsonschema` Draft-2020-12
   - Exit 0 → allow; Exit 2 → block + stderr enumerates violations
6. Primary retries on rejection (fix missing/invalid fields, re-write).

### Invocation

The `Task()` prompt is the lean-pointer form:

```
Task(
  subagent_type="<subagent>",
  description="<phase-role> for ${STORY_ID}",
  prompt="Read your work contract at tmp/${STORY_ID}/contracts/phase-${PHASE}-<subagent>.yaml and execute it end-to-end. Schema reference is preloaded as skill 'backend-architect-contract-spec'. All 6 context files in devforgeai/specs/context/ MUST still be read (Signal 1 INTENTIONAL). Append your completion_record to the contract file when done."
)
```

### Read-side (subagent)

When the subagent starts:

1. This skill is already in the subagent's context (startup injection via `skills:` frontmatter).
2. Read the contract file from the Task() prompt's `tmp/...` path.
3. Validate locally (optional — the PreToolUse hook already validated on primary's write).
4. Execute work per contract:
   - Read 6 context files at `devforgeai/specs/context/` (Signal 1 INTENTIONAL; unchanged)
   - Do NOT re-Read the story file — use `contract.ac_list`
   - Do NOT re-Glob tests — use `contract.test_files` (or `contract.test_files_to_create` for phase-02)
   - Apply `contract.ac_list[].implementation_hints` if present
   - Write to files per `contract.files_to_modify[]`
   - Record each step in `contract.required_agent_steps[]` via `devforgeai-validate phase-record --agent-step <step-name>` (BA-010)
   - Run tests per existing Phase 5 pattern
5. Append `completion_record` to the contract file **in place** (YAML merge, NOT overwrite — preserves the original work spec for audit).
6. Emit the existing observation JSON per BA-009 schema (no change from today's behavior).

### Post-invocation

After `Task()` returns:

1. Existing `artifact-verification-gate.sh` runs (BA-010 baseline).
2. BA-018 extension (commit BA-018.5): hook additionally reads the contract's `completion_record` and checks:
   - `agent_steps_recorded ⊇ required_agent_steps` (set inclusion)
   - `tests_passing == true`
   - `observation_json_ref` points to an existing file
3. If any check fails: block `phase-complete --phase=<NN>`.
4. If all pass: advance to next phase.

---

## Completion record schema

When the subagent appends `completion_record` at the end of execution, the object must satisfy:

| Field | Required | Type | Purpose |
|---|:-:|---|---|
| `completed_at` | YES | ISO 8601 UTC | When execution finished. |
| `files_written[]` | YES | array | Per-file: `path`, `lines_added`, `lines_removed`. |
| `tests_passing` | YES | boolean | From Phase 5 run-tests result. |
| `test_run_output_ref` | NO | string | Path to test run log for audit. |
| `agent_steps_recorded[]` | YES | array of strings | Actual agent-step names emitted (verified against `required_agent_steps`). |
| `self_attestation` | YES | object (BA-008) | 6 booleans: `coding_standards_followed`, `architecture_constraints_respected`, `dependency_injection_used`, `error_handling_implemented`, `input_validation_present`, `code_readable`. |
| `self_attestation_notes` | Conditional | object | Required per BA-008 if any `self_attestation.*` is `false`. |
| `observation_json_ref` | YES | string | Path to observation JSON written per BA-009. |
| `turns_used` | NO | integer | Actual turn count for overflow-budget telemetry. |

---

## File ownership and cleanup

- Contract files live at `tmp/${STORY_ID}/contracts/` per `.claude/rules/workflow/operational-safety.md` Rule 2.
- They are **NOT committed to git** (tmp is gitignored).
- They survive the workflow for audit purposes within a session.
- They are cleaned up when `tmp/${STORY_ID}/` is cleaned at story completion (existing framework behavior).

---

## Template usage

To compose a new contract, copy the template from `assets/templates/contract-template.yaml` and fill in the fields for your phase:

```
cp src/claude/skills/backend-architect-contract-spec/assets/templates/contract-template.yaml \
   tmp/${STORY_ID}/contracts/phase-${PHASE}-${SUBAGENT}.yaml
# Then edit the file to substitute story-specific values.
```

The template is annotated with every field's purpose and cites the schema sections. Use it as a starting point; the validator hook will reject malformed contracts before they reach the subagent.

---

## Governance and related artifacts

- **ADR-055** — `devforgeai/specs/adrs/ADR-055-subagent-skill-preload-isolation.md` — formalizes the decision to keep the 3 `backend-architect-*` skills separate from `spec-driven-dev`. Cites 4 verbatim Anthropic quotes.
- **Design proposal** — `docs/Optimization/agents/backend-architect/contract-specification-proposal.md` (807 lines). §3 schema, §4 lifecycle, §5 applicability, §6 consolidation decision, §7 validation strategy, §8 scriptable opportunities, §9 open questions.
- **Backlog entry** — `docs/Optimization/agents/backend-architect/optimization-recommendations.md` §A.6bis lines 1754-1811.
- **Validator** — `src/claude/hooks/contract-schema-validator.sh` + `contract_validator.py`.
- **Schema** — `devforgeai/config/contract.schema.json`.
- **Gate extension (to be added)** — `src/claude/hooks/artifact-verification-gate.sh` will be extended at BA-018.5 commit.

---

## What this skill is NOT

- NOT a replacement for the 6 constitutional context files. Subagents still Read() all 6 (Signal 1 INTENTIONAL).
- NOT a replacement for the observation JSON (BA-009). The contract references the observation schema via `completion_schema_ref`; it does not supersede it.
- NOT a replacement for the `skills:` preload mechanism. The schema itself is preloaded as this skill; the per-invocation contract is a tmp file.
- NOT a single-file monolith. The contract is per-phase-per-subagent; different phases of the same story produce different contracts.
- NOT an orchestration playbook. `spec-driven-dev` remains the orchestration skill for primary Claude; this skill is subagent-scoped only (per ADR-055).
