Squash merge of phase/03-l2-modules-and-core-scripts; 4 L2s + 5 core scripts; verify_phase03.sh green.
7.1 KiB
phase, name, milestone, milestone_type, status, requirements, must_haves, verification
| phase | name | milestone | milestone_type | status | requirements | must_haves | verification | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03 | l2-modules-and-core-scripts | v1.0 | feature | planned |
|
|
|
Phase 03 — l2-modules-and-core-scripts PLAN
Goal
Create the 4 L2 composition modules and the 5 core scripts. After this phase, the demo has every primitive needed for Phase 04 to wire the pipeline and Phase 05 to render the evidence UI.
Requirements covered
- REQ-04: 4 L2 modules under modules/l2/ composing L1s
- REQ-05: L2s compose L1s, max depth 5
- REQ-06: mock_executor.sh reads L2 + invokes L1s + writes state.json
- REQ-07: policy_checker.py fails on public-ingress:true
- REQ-08: confidence_signal.py 0.90/0.40 + gate ≥ 0.50
- REQ-11: evidence_writer.py SHA-256 hash chain
Waves (vertical slices, domain priority order)
Wave 1 — infra-stub-engineer (4 L2 manifests)
Tasks:
- T-3.1 Create
modules/l2/l2-invoice-service/manifest.yaml(L1s: l1-eks-fargate, l1-iam-role, l1-lambda, l1-sqs, l1-s3) - T-3.2 Create
modules/l2/l2-commodity-price-feed/manifest.yaml(L1s: l1-eks-fargate, l1-lambda, l1-api-gateway, l1-eventbridge, l1-s3) - T-3.3 Create
modules/l2/l2-energy-analytics-api/manifest.yaml(L1s: l1-eks-fargate, l1-api-gateway, l1-lambda, l1-s3, l1-cloudwatch) - T-3.4 Create
modules/l2/l2-regulatory-reporting/manifest.yaml(L1s: l1-eks-fargate, l1-iam-role, l1-lambda, l1-sqs, l1-s3)
Each manifest declares plausible inputs per L1 (string map per D-017).
Remove modules/l2/.gitkeep in T-3.1.
Files owned: modules/l2/**
Commits: one per task, phase: 3, status: plan-as-execute, persona: infra-stub-engineer, task: T-3.x, requirements.covered: [REQ-04, REQ-05].
Wave 2 — backend-engineer (5 core scripts)
Tasks:
- T-3.5 Create
scripts/policy_checker.py— reads contract.yaml (argv[1]); ifpublic-ingress: true, printPOLICY_VIOLATION:PUBLIC_INGRESSand exit 1; else printPOLICY_PASSand exit 0. Use only stdlib (yaml is available). Idempotent, no side effects. - T-3.6 Create
scripts/confidence_signal.py— reads contract.yaml (argv[1]); calls policy_checker as a subprocess; if pass →{"score": 0.90, "reason": "POLICY_PASS"}, if fail →{"score": 0.40, "reason": "POLICY_VIOLATION:PUBLIC_INGRESS"}. Print JSON to stdout. Exit 0 always. - T-3.7 Create
scripts/evidence_writer.py— argv flags--stage,--event,--audit <path>(default./audit.json). Loads audit.json (or empty list), computes the new event with canonical-JSON SHA-256 hash chain per D-023, appends, writes back atomically (write tmp + rename). Prints{"seq": N, "hash": "..."}to stdout. Genesis event automatically inserted if the file is empty/missing. - T-3.8 Create
scripts/mock_executor.sh— argv[1] = contract.yaml path. Reads contract.stack, resolvesmodules/l2/<stack>/manifest.yaml, iteratesl1s, invokesmodules/l1/<name>/mock_apply.shfor each, captures exit code, writesstate.jsonper D-022. Exit 0 if all L1s exit 0; non-zero otherwise. - T-3.9 Create
scripts/l3b_agent_stub.py— argv[1] = issue body (or read stdin if absent); optional-o <path>(default stdout). Applies the D-008 keyword map; writes a contract.yaml (D-021 schema) withstackset to the mapped L2 name and a fixedinputs:map per stack. Exit 0 on success, 1 on empty input.
Files owned: scripts/policy_checker.py, scripts/confidence_signal.py, scripts/evidence_writer.py, scripts/mock_executor.sh, scripts/l3b_agent_stub.py
Commits: one per task, phase: 3, status: plan-as-execute, persona: backend-engineer, task: T-3.x, requirements.covered: [REQ-06/07/08/11/12].
Wave 3 — lead-developer (verify script + traceability)
Tasks:
- T-3.10 Create
scripts/verify_phase03.sh. Checks:- Exactly 4 L2 folders with the expected names.
- Each L2 manifest.yaml parses, name matches folder, kind=l2, l1s is a list of 5 entries, all referenced L1 names exist in modules/l1/.
- policy_checker.py on a passing contract → exit 0 +
POLICY_PASS; onpublic-ingress: truecontract → exit 1 +POLICY_VIOLATION:PUBLIC_INGRESS. - confidence_signal.py on passing contract →
{"score": 0.90, ...}; on failing contract →{"score": 0.40, ...}. Both exit 0. - mock_executor.sh on a sample contract → writes state.json with l2 + l1s (all applied=true, exit_code=0) + contract fields.
- evidence_writer.py: append 3 events to a temp audit.json; verify seq increments 0/1/2, prev_hash chain links, each hash matches a recompute.
- l3b_agent_stub.py on the Act 3 example issue text ("We need to ingest natural gas prices from Platts...") → emits a contract.yaml with
stack: l2-commodity-price-feed.
- T-3.11 Update
.ciagent/REQUIREMENTS.md(REQ-04/05/06/07/08/11 → covered pending VERIFY) and.ciagent/ROADMAP.md(Phase 03 → executing).
Files owned: scripts/verify_phase03.sh, .ciagent/REQUIREMENTS.md, .ciagent/ROADMAP.md
Commits: one per task, phase: 3, status: plan-as-execute, persona: lead-developer, task: T-3.10/3.11.
Wave ordering
- Wave 1 (infra-stub-engineer) creates the 4 L2 manifests first so mock_executor.sh has something to resolve.
- Wave 2 (backend-engineer) builds the 5 core scripts. policy_checker + confidence_signal have no L2 dependency; mock_executor depends on Wave 1; l3b_agent_stub is independent.
- Wave 3 (lead-developer) wires the verify script after both Waves 1 and 2 are complete.
data-engineer and frontend-engineer have 0 tasks this phase.
Dependencies
- Depends on Phase 02 (L1 modules exist so mock_executor can invoke them and verify_phase03 can confirm L2 references resolve).
- Phase 04 depends on this phase for the pipeline to call policy_checker, mock_executor, confidence_signal, evidence_writer, and for the issue workflow to call l3b_agent_stub.