Files
clean-architecture-backend-…/docs/superpowers/specs/2026-07-20-harness-policy-engine-design.md
T

192 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> **SUPERSEDED — HISTORICAL PROVENANCE ONLY (2026-07-25):** The user-approved harness-free
> Mode B amendment supersedes this design. Retain the body as historical provenance; it is not
> executable instruction.
# Harness Policy Engine Refactoring Design
- **Date:** 2026-07-20
- **Status:** Approved by user request
- **Scope:** repository-local development harness (`.harness`, `.agents`, `.claude`, `.codex`, root/module guidance, Gradle module registry integration)
- **Source:** user-provided “개발 하네스 분석·리뷰” plus repository evidence gathered on 2026-07-20
## 1. Problem Statement
The repository now has 19 nested Gradle leaf modules, but the write-time import gate,
agent prompts, runner allowlist, and root guidance still contain parts of the previous flat
module topology. Platform variants are copied manually, so commit policy and orchestration
already differ between Claude, Codex, and Antigravity. Verdict validation checks a text
summary but does not consistently require enum fields, non-negative counts, or arithmetic
balance.
The harness must move from duplicated platform prompts to a small policy engine with one
project manifest, deterministic renderers, strict validators, and platform adapters.
## 2. Goals
1. Make the actual nested Gradle topology a single machine-readable source of truth.
2. Resolve a touched file to its nearest owning leaf module without assuming `src/<module>`.
3. Generate write-time import policy and focused Gradle task validation from that registry.
4. Validate machine verdicts with required fields, non-negative integers, arithmetic rules,
upstream evidence, revision identity, and TDD red evidence for behavior changes.
5. Materialize validated evidence as JSON artifacts that platform hooks can share.
6. Render Claude, Codex, and Antigravity agent variants from one canonical source and fail
parity checks when generated files drift.
7. Use one human-only commit policy on every platform.
8. Replace file-count and exhaustive-report rules with risk and review profiles.
9. Add mutation and cross-platform static parity tests.
## 3. Non-Goals
- This change does not run authenticated end-to-end golden tasks inside all three external
products. It supplies the deterministic fixtures and validators those runs will consume.
- It does not add application features or alter production Java behavior.
- It does not require PyYAML, jsonschema, Pydantic, or another runtime dependency. Harness
data files use JSON syntax, which is valid YAML, and validators use Python stdlib only.
- It does not make natural-language agent self-reports authoritative. Hooks convert accepted
reports into evidence artifacts; validators remain authoritative.
## 4. Architecture
```text
.harness/project/modules.yaml ──┬── Gradle settings/includes
├── Gradle dependency verification
├── owning-module resolver
├── import gate
└── Gradle command validator
.harness/agents/*.md + platforms.yaml
└── render_agents.py
├── .claude/agents/*.md
├── .codex/agents/*.toml
└── .agents/agents/*/agent.json
Claude hook ───────────────┐
Antigravity hook adapter ──┼── verdict validator ── evidence JSON
Codex validation command ──┘
```
### 4.1 Project registry
`modules.yaml` contains, per leaf module:
- stable module id
- repository-relative source path
- Gradle path
- role
- Java package roots (informational and import-policy lookup only)
- allowed project dependencies
- focused test command
- profiles/capabilities
- owning `CLAUDE.md` when present
- an intentional mutation import used by gate tests
`src/settings.gradle` reads the registry to declare projects. The
`verifyCleanArchitectureDependencies` task reads the same registry instead of maintaining a
second dependency map.
### 4.2 Owning-module resolution
Owner selection uses the longest filesystem-boundary match among registered leaf source
paths. Package prefixes never decide ownership because `support` owns a broad
`dev.caskeleton.adapter.outbound` package and sample code mirrors production packages.
Instruction discovery walks upward from the touched file and returns the nearest
`CLAUDE.md`; if a leaf has none, root `CLAUDE.md` and `AGENTS.md` are the explicit fallback.
### 4.3 Import gate
The import gate first resolves the registered leaf module, then applies:
- dependency-derived sibling module isolation
- role-specific framework rules for domain, application, inbound, outbound, persistence,
identifier, shared-contract, bootstrap, and sample roles
- global unsafe-pattern checks
All registered production modules receive a mutation test using their real nested source
path. Sample-only exemptions are explicit registry data, not accidental regex misses.
### 4.4 Verdict and evidence
The canonical verdict schema requires `agent`, `verdict`, `task_id`, `revision`, and agent
specific evidence. Non-blocked verdicts require every declared field. Counts are non-negative.
Required equations include:
- spec totals balance
- Gradle `run = passed + failed + skipped`
- ready Gradle results include at least one command and no failed command
- behavior-changing implementation requires at least one observed red test
- quality-ready references validated architecture and spec artifacts
Claude's fenced `ca-verdict` remains a compatibility input, but its accepted form is converted
to the same JSON evidence model. Missing or malformed payloads for detected CA agents fail
closed. Evidence records include a source-message hash and current revision/diff identity.
### 4.5 Platform rendering and hook adapters
Canonical agent Markdown lives under `.harness/agents/`; platform metadata lives in
`.harness/project/platforms.yaml`. Generated files carry `generated_from`, `source_hash`,
`generator_version`, and `do_not_edit` metadata.
Antigravity gains a plugin `hooks.json` and a platform adapter using the documented camelCase
stdin/stdout contract. Claude keeps its native hook entry points but calls the common library.
Codex variants instruct the runner/reviewer to invoke the common validation command because
the repository has no equivalent local lifecycle-hook registration surface.
### 4.6 Risk and review profiles
Risk is determined by change surface, not file count:
- high: security, migration/schema, public contract, module dependency, architecture rule,
transaction/concurrency, CI/deployment
- medium: behavior, multiple modules, external integration
- low: docs/comments, test fixture, local refactor protected by characterization tests
Review profiles:
- `review-lite`: direct diff references; no saved report by default
- `review-standard`: verify blocking citations; one report only when risk or findings justify it
- `audit-deep`: verify all quotes and persist detailed findings
- `regulated`: immutable evidence and full traceability
Option analysis uses a dependency DAG and at most 35 materially distinct alternatives.
Counterarguments are required for judgment-dependent findings, not deterministic failures.
## 5. Commit Policy
All platforms use `human-only`. Implementers never stage or commit. Reviewers may inspect a
working-tree diff before commit or an explicit immutable range after the human commits.
## 6. Verification Strategy
1. Stdlib unit tests for registry loading and owner resolution.
2. Mutation tests for every registered production module path.
3. Strict verdict negative tests: missing fields, negatives, arithmetic imbalance, missing
upstream evidence, revision mismatch, and behavior change without red evidence.
4. Golden renderer tests and `--check` parity validation.
5. JSON validation of generated Antigravity hook and agent files.
6. Gradle `projects`, architecture dependency verification, focused ArchUnit test, and full
`check` after harness tests pass.
## 7. Migration and Compatibility
- Existing fenced verdicts remain parseable only when they satisfy the new required fields.
- Generated platform files are overwritten only by the renderer and documented as generated.
- Root and module guidance is updated to the registered nested topology.
- Actual external cross-platform golden executions remain a follow-up; static parity and seeded
mutation coverage become mandatory in this change.
## 8. Acceptance Criteria
- A seeded forbidden import under every nested production module is rejected.
- No legacy flat adapter path remains in gate tests or agent task allowlists.
- `settings.gradle`, dependency verification, import gate, and Gradle runner resolve the same
19 leaf modules from `modules.yaml`.
- Missing/negative/inconsistent ready verdicts fail validation.
- Claude and Antigravity adapters invoke the shared validator; accepted verdicts produce JSON
evidence.
- Rendering followed by `--check` reports no platform drift.
- Agent variants uniformly state human-only commit policy and risk-based orchestration.
- `N!` enumeration, all-quote routine grep, file-count report splitting, and unconditional
counterargument requirements are absent from active rules.
- Harness tests and Gradle checks pass, or every unrun/failing command is reported with risk.