ship: phase-03 l2-modules-and-core-scripts (v1.0.3)
Squash merge of phase/03-l2-modules-and-core-scripts; 4 L2s + 5 core scripts; verify_phase03.sh green.
This commit was merged in pull request #3.
This commit is contained in:
+109
-1
@@ -143,4 +143,112 @@ Each L1 module lives at `modules/l1/<name>/` with exactly two files:
|
||||
| `l1-cloudwatch` | Observability primitive |
|
||||
|
||||
L1 modules are single-purpose, substrate-agnostic, max-depth-1 (per
|
||||
PROJECT.md Constraints). They do not compose with other L1s.
|
||||
PROJECT.md Constraints). They do not compose with other L1s.
|
||||
|
||||
## L2 module schema + core scripts (Phase 03 research)
|
||||
|
||||
### L2 manifest.yaml schema (D-020)
|
||||
|
||||
```yaml
|
||||
name: l2-commodity-price-feed # matches the folder name
|
||||
kind: l2 # literal "l2"
|
||||
description: <one-line>
|
||||
l1s: # ordered list of L1 references
|
||||
- name: l1-eks-fargate # MUST match an existing L1 folder name
|
||||
inputs:
|
||||
cluster_name: price-feed-cluster
|
||||
region: us-east-1
|
||||
cpu_arch: arm64
|
||||
- name: l1-lambda
|
||||
inputs:
|
||||
function_name: price-ingest
|
||||
runtime: python3.11
|
||||
handler: index.handler
|
||||
# ... up to 5 L1 references per L2 (max-depth-5 per REQ-05; L2->L1 is depth 1)
|
||||
```
|
||||
|
||||
L2s reference L1s **by name only** (no path); `mock_executor.sh` resolves
|
||||
the name to `modules/l1/<name>/`.
|
||||
|
||||
### L2 list (fixed per REQ-04)
|
||||
|
||||
| Folder | Description | L1s (per S&P Global Energy / Platts use cases) |
|
||||
|--------|-------------|------------------------------------------------|
|
||||
| `l2-invoice-service` | Billing + invoicing microservice | `l1-eks-fargate`, `l1-iam-role`, `l1-lambda`, `l1-sqs`, `l1-s3` |
|
||||
| `l2-commodity-price-feed` | Real-time price ingestion | `l1-eks-fargate`, `l1-lambda`, `l1-api-gateway`, `l1-eventbridge`, `l1-s3` |
|
||||
| `l2-energy-analytics-api` | Historical query API | `l1-eks-fargate`, `l1-api-gateway`, `l1-lambda`, `l1-s3`, `l1-cloudwatch` |
|
||||
| `l2-regulatory-reporting` | Compliance + reporting | `l1-eks-fargate`, `l1-iam-role`, `l1-lambda`, `l1-sqs`, `l1-s3` |
|
||||
|
||||
Each L2 references exactly 5 L1s (within the max-depth-5 constraint; L2→L1
|
||||
is depth 1, so depth-5 is generous but the spec caps composition depth at
|
||||
5 — the count is 5 to demonstrate a realistic composed stack).
|
||||
|
||||
### contract.yaml schema (D-021)
|
||||
|
||||
```yaml
|
||||
stack: l2-commodity-price-feed # MUST match an existing L2 folder name
|
||||
inputs: # top-level params for the L2 (optional)
|
||||
environment: dev
|
||||
owner: platform-team
|
||||
public-ingress: false # bool; true triggers POLICY_VIOLATION:PUBLIC_INGRESS
|
||||
```
|
||||
|
||||
The `public-ingress` key is the only policy-enforced field in Phase 03.
|
||||
Phase 04's pipeline reads `contract.yaml`, runs `policy_checker.py`, then
|
||||
`mock_executor.sh` to apply the L2.
|
||||
|
||||
### state.json shape (D-022)
|
||||
|
||||
`mock_executor.sh` writes `state.json` to its working directory:
|
||||
|
||||
```json
|
||||
{
|
||||
"l2": "l2-commodity-price-feed",
|
||||
"l1s": [
|
||||
{"name": "l1-eks-fargate", "applied": true, "exit_code": 0},
|
||||
{"name": "l1-lambda", "applied": true, "exit_code": 0},
|
||||
...
|
||||
],
|
||||
"contract": {
|
||||
"stack": "l2-commodity-price-feed",
|
||||
"inputs": {...},
|
||||
"public-ingress": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### audit.json event + hash chain (D-023)
|
||||
|
||||
`audit.json` is a JSON array of event objects. `evidence_writer.py`
|
||||
appends one event per call. Hash chain:
|
||||
|
||||
1. Construct the event dict with `hash` set to empty string.
|
||||
2. Serialize via `json.dumps(event, sort_keys=True, separators=(",", ":"))` — canonical JSON (deterministic key order, no whitespace).
|
||||
3. Compute `hash = sha256(canonical_json.encode("utf-8")).hexdigest()`.
|
||||
4. Set `event["hash"] = hash`.
|
||||
5. Append to `audit.json`.
|
||||
|
||||
Genesis event (when `audit.json` is empty or missing):
|
||||
|
||||
```json
|
||||
{
|
||||
"seq": 0,
|
||||
"ts": "2026-07-21T13:00:00Z",
|
||||
"stage": "genesis",
|
||||
"event": "audit log initialized",
|
||||
"prev_hash": "GENESIS",
|
||||
"hash": "<sha256 of the canonical json of this event with hash empty>"
|
||||
}
|
||||
```
|
||||
|
||||
Subsequent events: `seq = prev.seq + 1`, `prev_hash = prev.hash`.
|
||||
|
||||
### Core script I/O contracts
|
||||
|
||||
| Script | Input | Output | Exit |
|
||||
|--------|-------|--------|------|
|
||||
| `mock_executor.sh` | `<contract.yaml path>` (argv[1]); reads L2 manifest from `modules/l2/<contract.stack>/manifest.yaml` | writes `state.json` to cwd; prints per-L1 progress | 0 on all-L1s-pass; non-zero on any L1 failure |
|
||||
| `policy_checker.py` | `<contract.yaml path>` (argv[1]) | stdout: `POLICY_PASS` or `POLICY_VIOLATION:PUBLIC_INGRESS` | 0 on pass; 1 on violation |
|
||||
| `confidence_signal.py` | `<contract.yaml path>` (argv[1]); calls policy_checker | stdout: `{"score": 0.90|0.40, "reason": "..."}` | 0 always (per D-024; pipeline decides gate) |
|
||||
| `evidence_writer.py` | argv: `--stage <dev|qa|prod|finalize|genesis>` `--event "<text>"` `--audit <path to audit.json>` (default `./audit.json`) | appends event to audit.json; prints the new event's hash + seq | 0 on success; 1 on I/O error |
|
||||
| `l3b_agent_stub.py` | argv[1] = issue body text (or stdin if no argv); optional `-o <path>` (default stdout) | writes a `contract.yaml` (D-021 schema) with `stack` set by the D-008 keyword map | 0 on success; 1 on empty input |
|
||||
+66
-49
@@ -1,85 +1,102 @@
|
||||
---
|
||||
phase: 02
|
||||
name: l1-modules
|
||||
phase: 03
|
||||
name: l2-modules-and-core-scripts
|
||||
milestone: v1.0
|
||||
milestone_type: feature
|
||||
status: planned
|
||||
requirements: [REQ-02, REQ-03]
|
||||
requirements: [REQ-04, REQ-05, REQ-06, REQ-07, REQ-08, REQ-11]
|
||||
must_haves:
|
||||
- "All 8 L1 module folders exist under modules/l1/ with the exact names from REQ-02"
|
||||
- "Each L1 has a manifest.yaml matching the schema in ARCHITECTURE.md (name, kind: l1, description, inputs: map of string keys)"
|
||||
- "Each L1 has a mock_apply.sh that echoes '[L1: <name>] applying...', sleeps 1s, echoes '[L1: <name>] OK', exits 0 (D-007)"
|
||||
- "All mock_apply.sh are executable (chmod +x) and bash -n clean"
|
||||
- "All manifest.yaml files parse as valid YAML"
|
||||
- "scripts/verify_phase02.sh passes: enumerates 8 L1s, validates each manifest, runs each mock_apply.sh, confirms exit 0 + expected output"
|
||||
- "4 L2 module folders exist under modules/l2/ with exact names: l2-invoice-service, l2-commodity-price-feed, l2-energy-analytics-api, l2-regulatory-reporting"
|
||||
- "Each L2 has a manifest.yaml matching the D-020 schema (name, kind: l2, description, l1s: list of {name, inputs: map})"
|
||||
- "Each L2 references 5 L1s by name; all referenced L1 names exist in modules/l1/"
|
||||
- "mock_executor.sh reads a contract.yaml, resolves the L2, invokes each L1 mock_apply.sh, writes state.json per D-022"
|
||||
- "policy_checker.py exits 1 with 'POLICY_VIOLATION:PUBLIC_INGRESS' on public-ingress:true; exits 0 with 'POLICY_PASS' otherwise (D-025)"
|
||||
- "confidence_signal.py prints {score, reason} JSON; score 0.90 on pass, 0.40 on policy fail (D-024)"
|
||||
- "evidence_writer.py appends an event to audit.json with a valid canonical-JSON SHA-256 hash chain (D-023)"
|
||||
- "l3b_agent_stub.py maps the Act 3 example issue text to l2-commodity-price-feed and emits a valid contract.yaml (D-026/D-008)"
|
||||
- "scripts/verify_phase03.sh passes: validates all 4 L2s, runs each core script with a sample contract, confirms hash chain integrity"
|
||||
verification:
|
||||
typecheck: "bash -n modules/l1/*/mock_apply.sh scripts/*.sh && python3 -c 'import yaml; [yaml.safe_load(open(f)) for f in glob.glob(\"modules/l1/*/manifest.yaml\")]'"
|
||||
test: "scripts/verify_phase02.sh"
|
||||
typecheck: "bash -n scripts/*.sh && python3 -m py_compile scripts/*.py && python3 -c 'import yaml, glob; [yaml.safe_load(open(f)) for f in glob.glob(\"modules/l2/*/manifest.yaml\")]'"
|
||||
test: "scripts/verify_phase03.sh"
|
||||
build: no-op
|
||||
---
|
||||
|
||||
# Phase 02 — l1-modules PLAN
|
||||
# Phase 03 — l2-modules-and-core-scripts PLAN
|
||||
|
||||
## Goal
|
||||
|
||||
Create the 8 L1 stub modules under `modules/l1/`. Each module has a
|
||||
`manifest.yaml` (declared inputs, flat string map per D-017) and a uniform
|
||||
`mock_apply.sh` (echo + 1s sleep + exit 0 per D-007/D-018). After this phase,
|
||||
Phase 03 can compose L1s into L2 modules and `mock_executor.sh` can iterate
|
||||
over an L2's L1 references.
|
||||
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-02: 8 L1 module folders exist (exact names)
|
||||
- REQ-03: each L1 has manifest.yaml + mock_apply.sh with the uniform behavior
|
||||
- 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)
|
||||
## Waves (vertical slices, domain priority order)
|
||||
|
||||
### Wave 1 — infra-stub-engineer (creates the 8 L1s)
|
||||
### Wave 1 — infra-stub-engineer (4 L2 manifests)
|
||||
|
||||
**Tasks:**
|
||||
|
||||
- **T-2.1** Create `modules/l1/l1-eks-fargate/{manifest.yaml, mock_apply.sh}`
|
||||
- **T-2.2** Create `modules/l1/l1-iam-role/{manifest.yaml, mock_apply.sh}`
|
||||
- **T-2.3** Create `modules/l1/l1-lambda/{manifest.yaml, mock_apply.sh}`
|
||||
- **T-2.4** Create `modules/l1/l1-api-gateway/{manifest.yaml, mock_apply.sh}`
|
||||
- **T-2.5** Create `modules/l1/l1-eventbridge/{manifest.yaml, mock_apply.sh}`
|
||||
- **T-2.6** Create `modules/l1/l1-sqs/{manifest.yaml, mock_apply.sh}`
|
||||
- **T-2.7** Create `modules/l1/l1-s3/{manifest.yaml, mock_apply.sh}`
|
||||
- **T-2.8** Create `modules/l1/l1-cloudwatch/{manifest.yaml, mock_apply.sh}`
|
||||
- **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 L1's `manifest.yaml` declares 1-3 plausible inputs for that primitive
|
||||
(e.g., `l1-s3` declares `bucket_name`, `region`, `retention_days`; `l1-iam-role`
|
||||
declares `role_name`, `trust_policy`). Each `mock_apply.sh` follows the exact
|
||||
uniform template from ARCHITECTURE.md.
|
||||
Each manifest declares plausible `inputs` per L1 (string map per D-017).
|
||||
Remove `modules/l2/.gitkeep` in T-3.1.
|
||||
|
||||
**Files owned (territory):** `modules/l1/**`
|
||||
**Files owned:** `modules/l2/**`
|
||||
|
||||
**Commits:** one per task, `---ci---` block has `phase: 2, status: plan-as-execute, persona: infra-stub-engineer, task: T-2.x, requirements.covered: [REQ-02, REQ-03]`.
|
||||
**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 — lead-developer (verification script + traceability)
|
||||
### Wave 2 — backend-engineer (5 core scripts)
|
||||
|
||||
**Tasks:**
|
||||
|
||||
- **T-2.9** Create `scripts/verify_phase02.sh`. It:
|
||||
1. Enumerates `modules/l1/*/` and confirms exactly 8 folders with the 8 expected names.
|
||||
2. For each L1: confirms `manifest.yaml` exists and parses as YAML with `name` matching the folder, `kind: l1`, and an `inputs:` map.
|
||||
3. For each L1: confirms `mock_apply.sh` is executable, `bash -n` clean, runs in <2s, exits 0, and its stdout contains the `[L1: <name>] applying...` and `[L1: <name>] OK` markers.
|
||||
4. Prints a PASS/FAIL summary; exits 0 on full success.
|
||||
- **T-2.10** Update `.ciagent/REQUIREMENTS.md` (REQ-02/03 → covered pending VERIFY) and `.ciagent/ROADMAP.md` (Phase 02 → executing). No README change.
|
||||
- **T-3.5** Create `scripts/policy_checker.py` — reads contract.yaml (argv[1]); if `public-ingress: true`, print `POLICY_VIOLATION:PUBLIC_INGRESS` and exit 1; else print `POLICY_PASS` and 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, resolves `modules/l2/<stack>/manifest.yaml`, iterates `l1s`, invokes `modules/l1/<name>/mock_apply.sh` for each, captures exit code, writes `state.json` per 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) with `stack` set to the mapped L2 name and a fixed `inputs:` map per stack. Exit 0 on success, 1 on empty input.
|
||||
|
||||
**Files owned (territory):** `scripts/verify_phase02.sh`, `.ciagent/REQUIREMENTS.md`, `.ciagent/ROADMAP.md`
|
||||
**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, `---ci---` block has `phase: 2, status: plan-as-execute, persona: lead-developer, task: T-2.9/2.10`.
|
||||
**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:
|
||||
1. Exactly 4 L2 folders with the expected names.
|
||||
2. 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/.
|
||||
3. policy_checker.py on a passing contract → exit 0 + `POLICY_PASS`; on `public-ingress: true` contract → exit 1 + `POLICY_VIOLATION:PUBLIC_INGRESS`.
|
||||
4. confidence_signal.py on passing contract → `{"score": 0.90, ...}`; on failing contract → `{"score": 0.40, ...}`. Both exit 0.
|
||||
5. mock_executor.sh on a sample contract → writes state.json with l2 + l1s (all applied=true, exit_code=0) + contract fields.
|
||||
6. 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.
|
||||
7. 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 all 8 L1s. A single subagent gets all 8 tasks; it commits per task.
|
||||
- Wave 2 (lead-developer) adds the verify script and traceability after the L1s exist.
|
||||
- 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.
|
||||
|
||||
`backend-engineer`, `data-engineer`, `frontend-engineer` have 0 tasks this phase.
|
||||
`data-engineer` and `frontend-engineer` have 0 tasks this phase.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Depends on Phase 01 (the `modules/l1/.gitkeep` from T-1.1 is replaced by real folders).
|
||||
- Phase 03 depends on this phase for L1 references in L2 compositions.
|
||||
- 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.
|
||||
+8
-1
@@ -78,4 +78,11 @@ Build a runnable demo (Linux + GitHub/Gitea Actions) that walks executives throu
|
||||
| D-016 | Pages placeholder for Phase 01 is a minimal HTML stub (`<title>ACDL Evidence</title>` + "evidence stream coming soon"); full UI deferred to Phase 05 | Phase 01 success criterion is "Pages returns 200 with placeholder index.html" but Gitea has no Pages | Raw-URL HTTP 200 against `index.html` substitutes for the Pages check; full timeline UI built in Phase 05 |
|
||||
| D-017 | Each L1 `manifest.yaml` declares a single `inputs:` map of named string keys with descriptions; no nested types (substrate-agnostic, max-depth-1) | REQ-02/03 say "declared inputs"; spec forbids composition and cloud-specific types | Uniform, parseable schema that Phase 03's `mock_executor.sh` can read with python+yaml |
|
||||
| D-018 | L1 `mock_apply.sh` reads its own `manifest.yaml` for self-identification but ignores the input values (uniform stub per D-007) | D-007 mandates a literal echo + 1s sleep + exit 0; inputs are declared for traceability, not consumed | Predictable evidence events + clean separation from Phase 03 where L2s pass inputs to L1s |
|
||||
| D-019 | The 8 L1 names are fixed per REQ-02: `l1-eks-fargate`, `l1-iam-role`, `l1-lambda`, `l1-api-gateway`, `l1-eventbridge`, `l1-sqs`, `l1-s3`, `l1-cloudwatch` | REQ-02 literal | Phase 02 enumerates them exactly; no naming freedom |
|
||||
| D-019 | The 8 L1 names are fixed per REQ-02: `l1-eks-fargate`, `l1-iam-role`, `l1-lambda`, `l1-api-gateway`, `l1-eventbridge`, `l1-sqs`, `l1-s3`, `l1-cloudwatch` | REQ-02 literal | Phase 02 enumerates them exactly; no naming freedom |
|
||||
| D-020 | L2 `manifest.yaml` schema: `name`, `kind: l2`, `description`, `l1s:` (list of `{name, inputs: map}` entries). L2 references L1s by name (no path); inputs are string maps per L1 manifest declarations | REQ-04 says L2 "composes L1s"; REQ-05 caps depth at 5 (L2→L1 is depth 1) | mock_executor.sh reads `l1s:` and invokes each L1's `mock_apply.sh` |
|
||||
| D-021 | `contract.yaml` schema: `stack` (L2 name), `inputs` (string map for the L2's top-level params), optional `public-ingress: bool` (the policy violation key per REQ-07) | REQ-07 cites `public-ingress: true` as the forbidden key; REQ-08's confidence signal keys off policy pass/fail | Single flat schema drives both policy_checker and the mock_executor |
|
||||
| D-022 | `mock_executor.sh` writes `state.json` with shape `{"l2": "<name>", "l1s": [{"name":"...","applied":true,"exit_code":0}], "contract": <contract.yaml parsed>}` to the cwd; idempotent (overwrites) | REQ-06 says "writes state.json" but does not specify shape | Deterministic, parseable; Phase 05's evidence UI can include it in the audit trail |
|
||||
| D-023 | `evidence_writer.py` appends events to `audit.json` (a JSON array of event objects). Each event: `{"seq": N, "ts": <iso8601>, "stage": "dev|qa|prod|finalize", "event": "<string>", "prev_hash": "<sha256>", "hash": "<sha256 of canonical json of this event with hash field empty>"}`. The genesis event has `prev_hash: "GENESIS"` and `seq: 0` | D-005 mandates hash-chained ledger; canonical JSON for deterministic hashing | Visible tamper-evidence without overengineering; Phase 05 UI reads the array |
|
||||
| D-024 | `confidence_signal.py` reads `contract.yaml`, calls `policy_checker.py` (as a subprocess or import), returns base 0.90 on pass and 0.40 with reason code on policy failure; prints `{"score": 0.90|0.40, "reason": "<POLICY_VIOLATION:...|>"}` to stdout; exit 0 always | REQ-08 literal: base 0.90, drops to 0.40, gate ≥ 0.50 | Deterministic JSON output for the pipeline to consume |
|
||||
| D-025 | `policy_checker.py` reads `contract.yaml`, fails with exit code 1 and stdout `POLICY_VIOLATION:PUBLIC_INGRESS` if `public-ingress: true`; otherwise exits 0 with stdout `POLICY_PASS` | REQ-07 literal | Single source of policy truth; called by confidence_signal and the pipeline directly |
|
||||
| D-026 | `l3b_agent_stub.py` reads Issue body text from argv[1] (or stdin if no argv), applies the D-008 keyword map, writes a `contract.yaml` to stdout (or to `-o <path>`). Output contract uses the D-021 schema with `stack:` set to the mapped L2 name and a fixed `inputs:` map per L2 | D-008 + Act 3 example; L3B must produce the same contract format as L3A | Deterministic keyword parser; no external APIs |
|
||||
@@ -60,15 +60,15 @@
|
||||
| REQ-01 | 1 | complete (v1.0.1) |
|
||||
| REQ-02 | 2 | complete (v1.0.2) |
|
||||
| REQ-03 | 2 | complete (v1.0.2) |
|
||||
| REQ-04 | 3 | pending |
|
||||
| REQ-05 | 3 | pending |
|
||||
| REQ-06 | 3 | pending |
|
||||
| REQ-07 | 3 | pending |
|
||||
| REQ-08 | 3 | pending |
|
||||
| REQ-04 | 3 | covered (pending VERIFY) |
|
||||
| REQ-05 | 3 | covered (pending VERIFY) |
|
||||
| REQ-06 | 3 | covered (pending VERIFY) |
|
||||
| REQ-07 | 3 | covered (pending VERIFY) |
|
||||
| REQ-08 | 3 | covered (pending VERIFY) |
|
||||
| REQ-09 | 1 | complete (v1.0.1) |
|
||||
| REQ-10 | 4 | partial (skeleton in Phase 01 v1.0.1; full impl in Phase 04) |
|
||||
| REQ-11 | 3 | pending |
|
||||
| REQ-12 | 4 | partial (skeleton in Phase 01 v1.0.1; full impl in Phase 04) |
|
||||
| REQ-11 | 3 | covered (pending VERIFY) |
|
||||
| REQ-12 | 4 | partial (skeleton in Phase 01 v1.0.1; l3b_agent_stub in Phase 03; full trigger wiring in Phase 04) |
|
||||
| REQ-13 | 5 | pending |
|
||||
| REQ-14 | 5 | pending |
|
||||
| REQ-15 | 5 | pending |
|
||||
+1
-1
@@ -27,7 +27,7 @@ Five-phase breakdown to take ACDL from empty repo to a reproducible 4-act execut
|
||||
|
||||
### Phase 03 — l2-modules-and-core-scripts
|
||||
- **Description:** Create the 4 L2 compositions under `acdl/modules/l2/` referencing L1s, plus the 5 core scripts in `acdl/scripts/` (`mock_executor.sh`, `policy_checker.py`, `confidence_signal.py`, `evidence_writer.py`, `l3b_agent_stub.py`).
|
||||
- **Status:** not_started
|
||||
- **Status:** executing
|
||||
- **Depends on:** [2]
|
||||
- **Requirements:** REQ-04, REQ-05, REQ-06, REQ-07
|
||||
- **Success Criteria:**
|
||||
|
||||
Reference in New Issue
Block a user