From e00393adfde70b991ada37c79b51f0e83570ee18 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Tue, 21 Jul 2026 13:19:43 +0000 Subject: [PATCH] =?UTF-8?q?decision(P03):=20clarification=20=E2=80=94=20L2?= =?UTF-8?q?/contract/evidence/hash-chain=20schemas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- phase: 3 milestone: v1.0 status: clarify decisions: - id: D-020 decision: L2 manifest.yaml schema with l1s: list of {name, inputs: map} rationale: REQ-04 says L2 composes L1s; REQ-05 caps depth at 5 (L2->L1 is depth 1) confidence: 0.90 alternatives: [graph-of-L1s with edges, single flat list of L1 names with no inputs] - id: D-021 decision: contract.yaml schema with stack, inputs, optional public-ingress: bool rationale: REQ-07 cites public-ingress:true as the forbidden key; REQ-08 keys off policy pass/fail confidence: 0.90 alternatives: [separate policy file, contract-free intent] - id: D-022 decision: mock_executor.sh writes state.json with l2, l1s array (name+applied+exit_code), contract rationale: REQ-06 says writes state.json but does not specify shape confidence: 0.85 alternatives: [per-L1 state files, no state file] - id: D-023 decision: evidence_writer.py appends to audit.json (JSON array); each event has seq, ts, stage, event, prev_hash, hash (SHA-256 of canonical JSON); genesis has prev_hash=GENESIS, seq=0 rationale: D-005 mandates hash-chained ledger; canonical JSON for deterministic hashing confidence: 0.90 alternatives: [signed commits only, append-only log file] - id: D-024 decision: confidence_signal.py prints {score, reason} JSON to stdout; exit 0 always rationale: REQ-08 literal: base 0.90, drops to 0.40, gate >= 0.50 confidence: 0.95 alternatives: [exit non-zero on fail, separate side-channel file] - id: D-025 decision: policy_checker.py exits 1 with stdout POLICY_VIOLATION:PUBLIC_INGRESS on public-ingress:true; else exit 0 with stdout POLICY_PASS rationale: REQ-07 literal confidence: 0.99 alternatives: [] - id: D-026 decision: l3b_agent_stub.py reads issue body from argv[1] or stdin, applies D-008 keyword map, writes contract.yaml to stdout (or -o ) rationale: D-008 + Act 3 example; L3B must produce same contract format as L3A confidence: 0.90 alternatives: [fixed-output contract per stack, no -o flag] ---/ci--- Phase 03 has real ambiguities (no schema was specified for L2 manifests, contract.yaml, audit.json events, or the L3B output format). Seven decisions logged: D-020 L2 schema, D-021 contract.yaml schema, D-022 state.json shape, D-023 audit.json event + hash chain, D-024 confidence_signal output, D-025 policy_checker output, D-026 l3b_agent I/O contract. --- .ciagent/PROJECT.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index 17057a4..693f59a 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -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 (`ACDL Evidence` + "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 | \ No newline at end of file +| 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": "", "l1s": [{"name":"...","applied":true,"exit_code":0}], "contract": }` 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": , "stage": "dev|qa|prod|finalize", "event": "", "prev_hash": "", "hash": ""}`. 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": ""}` 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 `). 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 | \ No newline at end of file