188 lines
9.1 KiB
Markdown
188 lines
9.1 KiB
Markdown
# 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 3–5 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.
|