diff --git a/.ciagent/ARCHITECTURE.md b/.ciagent/ARCHITECTURE.md index 0247b77..f36c271 100644 --- a/.ciagent/ARCHITECTURE.md +++ b/.ciagent/ARCHITECTURE.md @@ -1,323 +1,301 @@ -# ACDL — Architecture (initial) +# ACDL — Architecture (v1.1 target) -> Initial architecture for the ACDL demo. May be incomplete; refined at phase boundaries. +> Target architecture for the real Agentic Cloud Delivery Platform. +> Source of truth for **how**: `docs/architecture.md` (v0.2) is the upstream +> draft; this file is the ACDL-repo operating copy, refined at phase +> boundaries. Where this file and `docs/vision.md` conflict, the vision wins. + +## Status + +Architecture is at **v0.2** upstream (`docs/architecture.md`). Milestone v1.1 +**finalizes it to v1.0** in Phase 07 by resolving the 11 open decisions +(see `PROJECT.md` open-decision resolutions table). This file records the +locked commitments and the v1.1 spike scope. ## Overview -The demo is a three-repo, stub-driven system that simulates an autonomous cloud delivery platform. No real cloud or AI is used; every "infrastructure" action is a bash/Python stub that emits structured evidence. The platform is driven by either a developer-supplied `contract.yaml` (L3A) or a natural-language GitHub Issue parsed by a keyword script (L3B), then flows through an autonomous Dev stage, manual QA and Prod approval gates, and finally publishes a hash-chained audit trail to a Pages site. +The platform is **four layers + six cross-cutting concerns**. The sixth +concern — the substrate abstraction (§12) — is first-class, not an +implementation detail. The vision's "Two Consumer Surfaces, One Platform" +tenet binds everything: L3A and L3B converge on the same contract schema, +the same policy envelope, and the same evidence stream. ``` - ┌──────────────── acdl-contracts ─────────────────┐ - Developer ───▶ │ commit contract.yaml Issue (NL intent) │ - └────────────┬───────────────────┬────────────────┘ - │ (push) │ (issue opened) - ▼ ▼ - ┌─────────────────┐ ┌──────────────────────┐ - │ reusable │ │ issue workflow → │ - │ pipeline │ │ l3b_agent_stub.py → │ - │ (acdl repo) │ │ contract.yaml → push │ - └────────┬────────┘ └──────────────────────┘ - │ - ┌────────────────────┼────────────────────┐ - ▼ ▼ ▼ - Dev (autonomous) QA (approval) Prod (approval) - mock_executor.sh environment gate environment gate - policy_checker.py - confidence_signal.py + ┌──────────── acdl-contracts ────────────┐ + Developer ───▶ │ commit contract.yaml │ (L3A) + Citizen dev ──▶ │ Issue → agent → contract.yaml │ (L3B) + └────────────────┬───────────────────────┘ + │ (push) + ▼ + ┌──────────────────────┐ + │ central pipeline │ + │ (acdl repo, Gitea │ + │ Actions / act_runner) │ + └────────┬─────────────┘ + │ + ┌─────────────────────────┼─────────────────────────┐ + ▼ ▼ ▼ + contract→IR resolution policy (Checkov/Kyverno) confidence signal + │ │ │ + ▼ ▼ ▼ + Terraform adapter ──▶ terraform plan ──▶ PolicyCheckResult ──▶ {score,band} + │ │ + ▼ ▼ + dev (autonomous, ≥0.50) qa (HITL, ≥0.75) prod (HITL, ≥0.90) dr (HITL, ≥0.95) │ ▼ - evidence_writer.py ──▶ audit.json (hash-chained) ──▶ acdl-evidence - │ - ▼ - index.html (Pages) - timeline UI + DynamoDB outbox ──▶ S3 Object Lock (7-yr, source of truth) ──▶ GitHub audit repo (hot index) + │ + ▼ + acdl-evidence (timeline UI) ``` -## Components +## Layers -| Name | Description | Boundaries | Depends On | -|------|-------------|-----------|------------| -| `acdl` repo | Platform meta repo: reusable workflows, L1/L2 stub modules, core scripts | Owns workflows + stubs; does not hold contracts or evidence | — | -| L1 modules | Single-purpose infra primitives (EKS Fargate, IAM, Lambda, API Gateway, EventBridge, SQS, S3, CloudWatch) | One folder per L1; `manifest.yaml` + `mock_apply.sh`; do not compose with other L1s | `acdl` repo | -| L2 modules | Composed stacks (invoice, commodity-price-feed, energy-analytics-api, regulatory-reporting) | Reference L1s by name; max depth 5; expressed as a composition manifest | L1 modules | -| `mock_executor.sh` | Reads an L2 composition, invokes each L1 `mock_apply.sh`, writes `state.json` | Bash; reads L2 manifest + L1 manifests | L1/L2 modules | -| `policy_checker.py` | Reads `contract.yaml`; fails on forbidden keys (e.g. `public-ingress: true`) | Python; emits `POLICY_VIOLATION:` or pass | contract.yaml | -| `confidence_signal.py` | Base 0.90; on policy failure drops to 0.40 and echoes reason | Python; calls policy_checker | policy_checker.py | -| `evidence_writer.py` | Appends an event to `audit.json`, links to previous event via SHA-256 chain | Python; canonical-JSON hashing | audit.json | -| `l3b_agent_stub.py` | Parses Issue text by keywords, emits `contract.yaml` | Python keyword map; no external APIs | contract.yaml schema | -| `acdl-contracts` repo | Developer + agentic entry surface; holds contracts + issue workflow | Triggers main pipeline on push | `acdl` reusable workflow | -| `acdl-evidence` repo | Pages host for `audit.json` + `index.html` timeline | Read-only for the pipeline; written at finalize stage | evidence_writer.py output | -| Reusable pipeline workflow | Dev → QA → Prod → Finalize stages with environment gates | Gitea Actions; calls core scripts | All core scripts | -| `evidence-ui/index.html` | Vanilla-JS timeline UI (Phase 05); fetches `./audit.json` and renders events | Single HTML file with inline CSS+JS; no frameworks (REQ-14) | `audit.json` on `acdl-evidence` main | -| `scripts/run_demo.sh` | Phase 05 dry-run simulation of the 4 demo acts; calls core scripts + writes evidence + uploads `audit.json` + `index.html` to `acdl-evidence` | Bash; uses `evidence_writer.py` + `finalize_evidence.py` + the file-contents API | All Phase 03/04 artifacts | +### Layer 1 — Foundational Primitives +Single-purpose, **substrate-agnostic** primitive modules. L1 modules do +not compose with other L1s; L1 takes its environment as input. The L1 +interface is defined against the **Target Stack IR**, not against Terraform +directly (the IR is shaped to round-trip to Terraform in v1, per §12.1). -## Phase 04 pipeline topology (research) +- No inter-L1 references. L1 may call Terraform data sources. +- Semver: interface → MAJOR, behavior → MINOR, lifecycle → PATCH (W3.D). +- Immutability on publication. 12-month deprecation window. +- AI refinement is a flag; the trigger is the W1.A joint condition. -Gitea Actions limitations (confirmed via research, supersedes any -GitHub-Actions assumptions): +### Layer 2 — Composed Stacks +Combine L1 primitives into deployable shapes. Each codebase maps to one +canonical L2 stack (`multiStack: true` only per W1.B). Shape X +(parameterized module) or Shape Y (thin-composition layer). Hierarchical +composition, max depth 5, only registered L1s. The thin-composition tree's +`wires` field is defined against the IR's relationship type, not a Terraform +module block. -- `actions/upload-artifact@v3` / `download-artifact@v3` work; v4 is NOT supported by act_runner. -- Artifacts are scoped to a single workflow run; **re-dispatch starts a new run, so artifacts do NOT survive between dispatches**. -- `workflow_dispatch` API: `POST /api/v1/repos/{owner}/{repo}/actions/workflows/{filename}.yml/dispatches` with body `{ "ref": "", "inputs": {...} }`. -- `on: workflow_call` + `uses: //.gitea/workflows/@` works; pin to `@milestone/v1.0-initial`. -- `actions/checkout@v4` supports cross-repo (pass `repository:` + `ref:` + `token: ${{ secrets.GITEA_TOKEN }}` for private repos). -- File-contents API: POST to create (201), PUT to update (must include current `sha`, obtained via GET). -- `${{ secrets.GITEA_TOKEN }}` is a manually-created PAT secret on the `acdl` + `acdl-contracts` repos; the auto-injected token is current-repo only and cannot cross-repo. -- No native approval-gate UI; gates are `workflow_dispatch` inputs (`approve_qa`, `approve_prod`). +Pipeline quality checks: secrets-in-plaintext, public ingress, IAM +wildcard, KMS key reference, tag compliance, naming convention. Restricted +from thin-composition: IAM principal creation, network boundary creation, +key/secret creation, external data transfer. Auto-promote after 3 observed +usages. -### Approval-gate + state-persistence approach (D-027, D-028 refined) +### Layer 3A — Developer Consumer Surface +Tag-based reference to the central pipeline template. Developer-owned +workflow file, no platform auto-sync. L3A and L3B are parallel paths, not a +progression. **W2.A (Path B):** tag for dev/qa, SHA for prod; platform CLI +resolves tag→SHA for prod-bound workflows. -Because re-dispatch starts a new run and artifacts do not survive: +### Layer 3B — Agentic Consumer Surface +Hybrid runtime, skill as markdown, agent as executor. Trust model: trust +and always verify on the platform side. Skill envelope (4 dimensions). +Stateless agents, all state in the platform. `profile: agentic` marker +unlocks `naturalLanguageIntent`, `confidenceAtSubmission`, `agentTrace`. +Initial skill catalog (BA.A): web API, worker, scheduled job, static asset, +basic observability bootstrap. -1. The pipeline workflow has `workflow_dispatch` inputs: - - `contract-ref` (string; default `main`) — the ref on `acdl-contracts` carrying the contract. - - `approve_qa` (boolean; default `false`) — the human sets this to `true` to advance past QA. - - `approve_prod` (boolean; default `false`) — the human sets this to `true` to advance past Prod. +Environment progression: -2. Each stage job (`dev`, `qa-gate`, `prod-gate`, `finalize`) writes its evidence to `acdl-evidence` via the file-contents API (PUT `audit.json` with the new event appended). This is the persistent state across re-dispatches. +| Environment | Autonomy | Attester | Gate | +|---|---|---|---| +| dev | Full autonomy (no HITL) | — | Confidence ≥ 0.50, all six inputs present | +| qa | Held for attestation | QA | GitHub Deployment approval + full QA matrix (§10) | +| prod | Held for attestation | SRE | GitHub Deployment approval + full SRE matrix (§10) | +| dr | Held for attestation | SRE | GitHub Deployment approval + dr-drill evidence | -3. **Dev stage** (always runs on dispatch): check out `acdl` + `acdl-contracts@`, run `policy_checker.py` + `confidence_signal.py`; if `score < 0.50`, write a `dev_rejected` evidence event and exit 1 (Act 4). Otherwise run `mock_executor.sh`, write a `dev_applied` evidence event, and exit 0. The run ends here. +**Staging is removed.** Dev is the only autonomous environment. -4. **QA gate** (next dispatch with `approve_qa=true`): check out, run `evidence_writer.py --stage qa --event "qa approved"`, commit updated `audit.json` to `acdl-evidence`. Exit 0. The run ends. +## Cross-cutting concerns -5. **Prod gate** (next dispatch with `approve_prod=true`): same as QA but `--stage prod`. +### Central pipeline template (§6) +JSON Schema (draft 2020-12) with a thin domain wrapper. Central repo + +generated client libraries. Multi-stage validation: schema → policy → NFR → +confidence. Distributed enrichment. GitOps reconciler (K8s API; cdlc-gitops +state → CRDs) + Terraform execution layer (§12.5). The pipeline emits one +`PolicyCheckResult` per policy rule; the confidence signal consumes them as +one normalized input. -6. **Finalize** (same dispatch as Prod, chained via `needs: prod-gate`): write the `finalize` evidence event, commit final `audit.json` to `acdl-evidence`. The raw URL now serves the updated timeline. +### Contract schema (§7) +Central repo + generated client libraries. Strict fail-fast at schema +stage, multi-stage validation with reason codes from a published +vocabulary. **W3.E:** per-env mandatory inputs — +- dev: `stack`, `environment` +- qa adds: `validation.e2eSuite`, `validation.loadTest` +- prod adds: `runbook`, `dashboard`, `oncall` +- dr adds: `drDrillRef` +- `inputs` always optional; `profile: agentic` fields optional everywhere. -Because each stage is a separate dispatch, the workflow file uses `if:` conditions on each job: -- `dev` runs when `inputs.approve_qa != true && inputs.approve_prod != true` (the initial dispatch). -- `qa-gate` runs when `inputs.approve_qa == true && inputs.approve_prod != true`. -- `prod-gate` runs when `inputs.approve_prod == true`. -- `finalize` runs after `prod-gate` (`needs: prod-gate`). +### Confidence signal (§8) +Six canonical inputs, weighted sum with per-input breakdown. Per-env +thresholds: dev ≥ 0.50, qa ≥ 0.75, prod ≥ 0.90, dr ≥ 0.95. Structured output +`{ score, band, perInput, reasonCodes }`. 1-year storage, no retraining in +v1. Halt with explicit reason on missing input. -This means a full pipeline = 3 dispatches (initial, qa-approve, prod-approve). The human drives each via the Gitea UI or the dispatch API. +Policy input = list of `PolicyCheckResult` records (engine-agnostic). +Severity → penalty: critical → hard override to mandatory block; high → +-0.2; medium → -0.05; low → -0.01; info → 0.0. One critical finding +hard-overrides the score regardless of all other inputs. -## Phase 05 dry-run + UI (research) +**BA.B:** thresholds frozen for v1; tuning begins v1.2 (quarterly FP/FN +tracking; override = Infra & Ops + SRE joint sign-off, itself a +confidence-event). -Phase 05 has no act_runner available in this environment, so the "dry run" -is a local bash simulation (`scripts/run_demo.sh`) that produces the same -`audit.json` shape a real pipeline run would, then uploads it (plus the -UI) to `acdl-evidence` via the file-contents API. The simulation covers: +### Audit and evidence stream (§9) +Tiered ledger: **S3 with Object Lock in compliance mode** (cold, source of +truth, 7-year retention) + **GitHub audit repo** (`acdl-evidence`, hot +query index, not part of the chain). Daily checkpoints. Event schema: JWS +detached signature, `prev_event_hash` chain, controlled-vocabulary +`event_type`. Outbox pattern: local durable outbox + async worker. -- **Act 1 — Friction:** a single evidence event "manual 2-week deployment (legacy process)" at `stage: dev` with a red-colored timeline marker. -- **Act 2 — Developer Self-Service:** `l2-commodity-price-feed` contract, full pipeline (dev → qa → prod → finalize), 4 evidence events. -- **Act 3 — Citizen Developer:** Issue body fed to `l3b_agent_stub.py`, generates the same `l2-commodity-price-feed` contract, identical pipeline, 4 evidence events. -- **Act 4 — Safety Net:** `l2-regulatory-reporting` contract with `public-ingress: true`, dev rejects (confidence 0.40 < 0.50), 1 evidence event "dev rejected: POLICY_VIOLATION:PUBLIC_INGRESS". +Outbox database = **DynamoDB**. RPO = 0 (synchronous write to local outbox +before contract submission ack); RTO = async worker's dead-letter recovery. +Single-region in v1. The outbox also stores per-contract QA and prod +approver identities (the only durable record outside GitHub's audit log). -The `audit.json` after `run_demo.sh` contains the genesis + all act -events (typically ~14 events). The UI fetches `./audit.json` and renders -a vertical timeline with stage-colored markers and a per-event hash -preview. +### Human-in-the-Loop mechanics (§10) +Pre-execution gates. qa, prod, dr are PR-based attestation gates backed by +GitHub Environments with required reviewers. No partial deployment to roll +back on rejection (qa, prod); dr is a separate GitHub Deployment against a +separate cluster/region. -### UI rendering contract (D-032, D-033) +Reviewer routing: GitHub CODEOWNERS + Environment required reviewers +(qa → QA; prod → SRE; dr → SRE). CODEOWNERS routes, does not enforce +identity distinctness. -`evidence-ui/index.html`: -- Single file, inline CSS + JS, no external resources. -- Fetches `./audit.json` (relative URL; works against any raw-URL origin). -- Renders events as a vertical timeline; each event card shows `seq`, `ts`, `stage` (color-coded: `dev` blue, `qa` yellow, `prod` orange, `finalize` green, `genesis` gray, rejected events red), `event` text, and a 12-char hash preview (`hash.slice(0, 12)…`). -- Handles fetch failure with a "No audit data yet" message. -- Refresh button to re-fetch. +**Separation of duties** (platform-internal, not GitHub-native, not Kyverno +in v1): on dev→qa promotion the platform writes the QA approver's GitHub +identity to the DynamoDB outbox keyed by `contractId`; on qa→prod it reads +the stored QA approver and the new SRE approver; if equal, it blocks, emits +`SEPARATION_OF_DUTIES_VIOLATION`, and routes a halt artifact to SRE on-call. -## Data Flow +Full 8-concern attestation matrix (functional, performance, security +posture, contract NFRs, operational readiness, incident response, +capacity/cost, resilience) — see `docs/architecture.md` §10.4. -1. A `contract.yaml` arrives either by direct push (L3A) or by the issue workflow running `l3b_agent_stub.py` (L3B). -2. Push to `acdl-contracts` triggers the reusable pipeline in the `acdl` repo. -3. **Dev stage:** `policy_checker.py` validates the contract; `mock_executor.sh` applies the L2 composition's L1s; `confidence_signal.py` computes the score; `evidence_writer.py` records each step. If score < 0.50, the stage fails and evidence records the rejection. -4. **QA stage:** the workflow pauses on the `qa` environment; a human approves. -5. **Prod stage:** same gate on the `prod` environment. -6. **Finalize:** the workflow commits the updated `audit.json` to `acdl-evidence`; Pages republishes `index.html`, which fetches and renders the timeline. +Timeout: 1 business day = warn + escalate; 2 business days = auto-freeze + +re-submit (linked via `supersedes`). Rejection returns the contract to HELD; +the audit chain is extended, not torn up. -## Build Order +### Agentic stack (§11) +Hybrid runtime: platform-managed control plane + consumer-owned agent. +Versioned, signed skill catalog over MCP. Skill envelope enforced on +invocation and result submission. Consumer-owned skill execution; the +platform does not run the skill. Stateless agents, all state in the +platform. Skills are reviewed for sensitive data before release (Infra & +Ops owns the review; it is the mandatory release gate). -1. Repo scaffolding: create `acdl-contracts` and `acdl-evidence` in the org; seed `acdl` directory layout. -2. L1 modules (8 stubs). -3. L2 modules (4 compositions). -4. Core scripts (`mock_executor.sh`, `policy_checker.py`, `confidence_signal.py`, `evidence_writer.py`, `l3b_agent_stub.py`). -5. Reusable pipeline workflow (Dev → QA → Prod → Finalize) + environment gates. -6. Issue-triggered L3B workflow in `acdl-contracts`. -7. Evidence UI (`index.html` + Pages config). -8. Demo dry-run + the four scripted acts. +### Substrate execution (§12) — the binding constraint +**Target Stack IR** (locked): a substrate-neutral description of resources +(typed inputs/outputs/NFRs), relationships (single parent per child), +composition (tree, max depth 5), and policy hooks. The L1 registry, L2 +thin-composition tree, contract YML, and PolicyCheckResult schema are all +defined against the IR — none against any specific substrate. -## Gitea API Surface (Phase 01 research) +**Substrate adapters** are the only substrate-specific code. An adapter +compiles the IR into a substrate execution plan. **v1 ships exactly one +adapter: the Terraform adapter.** v2+ may add OpenTofu, Pulumi, K8s CRDs +without architectural change. -Authoritative findings from the Gitea docs (added in RESEARCH; supersedes any -GitHub-Pages / GitHub-Environments assumptions carried over from the spec): +v1 reality: the IR is shaped to round-trip cleanly to Terraform (nearly +isomorphic). As more adapters appear, the IR gets more expressive and the +adapters gain translation logic; the L1 content, the YML standard, and the +thin-composition tree do not change. -| Capability | Gitea support | ACDL approach | -|------------|---------------|---------------| -| Org-scoped repo create | `POST /api/v1/orgs/{org}/repos` (`CreateRepoOption`) | Used to create `acdl-contracts` + `acdl-evidence` | -| Native Pages | **None** (no `[pages]` config section) | Serve `acdl-evidence` via raw file URLs: `https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html`; `index.html` fetches `audit.json` from the same raw path. Requires `[cors] ENABLED=true` on the server if the UI is loaded cross-origin. | -| Environments API | **None**; `jobs..environment` is ignored by act_runner | Model QA/Prod gates as `workflow_dispatch` approval inputs (D-004 / D-013); optionally create `qa` and `prod` branches as a visible stand-in | -| `repository_dispatch` trigger | **Not supported** | Cross-repo trigger via `workflow_dispatch` API: `POST /api/v1/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches` called from a step using `$GITEA_TOKEN` | -| Reusable workflows (`workflow_call`) | Supported | `acdl/.gitea/workflows/pipeline.yml` called via `uses: continuous-intelligence/acdl/.gitea/workflows/pipeline.yml@milestone/v1.0-initial` | -| `workflow_dispatch` | Supported (trigger + API) | Used for the manual-approval fallback and the issue workflow's cross-repo trigger | -| `issues.opened` trigger | Supported | Drives the L3B issue-trigger workflow in `acdl-contracts` | -| `act_runner` labels | Single label only (`runs-on: ubuntu-latest`) | All workflows use `runs-on: ubuntu-latest` | -| Context | `${{ gitea.* }}` and `${{ github.* }}` both work | Workflows use `gitea.*` for clarity | +**Terraform adapter (v1):** translates IR-typed L1 interface → Terraform +`variable`/`output` blocks; IR-typed L2 thin-composition tree → Terraform +root module; IR-typed relationships → module references; emits a +`terraform plan` from the IR. The adapter is a thin layer; it does not own +L1/L2 content. -### Branch pinning rule +State storage: S3 (state) + DynamoDB (locking), cloud-managed, +single-region in v1. -The reusable workflow in the `acdl` repo lives on `milestone/v1.0-initial` -(that is the repo's default branch). `uses:` references from `acdl-contracts` -must pin to `@milestone/v1.0-initial`, not `@main` (the `acdl` repo has no -`main` branch). The new repos `acdl-contracts` and `acdl-evidence` use -`default_branch: "main"` (D-015) so their default branch exists immediately -for pushes. +Policy toolchain: **Checkov** for Terraform plan policy (the L2 checks + +tag/naming); **Kyverno** for K8s-native/platform-internal policy; **OPA** +reserved for cross-resource cases, explicitly last resort. -### Default verification toolchain - -There is no `package.json`; ACDL is bash + python stubs. The verification gate -substitutes `bash -n` and `python -m py_compile` for `npm run typecheck`, and -per-phase `scripts/verify_phaseNN.sh` for `npm test`. `npm run build` is a -no-op (no build step). See PERSONAS.md / VERIFICATION note. - -## L1 module schema (Phase 02 research) - -Each L1 module lives at `modules/l1//` with exactly two files: - -- `manifest.yaml` — declares the L1's identity + a flat `inputs:` map. - Schema (D-017): - ```yaml - name: l1-eks-fargate # matches the folder name - kind: l1 # literal "l1"; substrate-agnostic - description: - inputs: - : - description: - type: string # only "string" allowed (flat, max-depth-1) - ``` -- `mock_apply.sh` — uniform stub per D-007 + D-018: - ```bash - #!/usr/bin/env bash - set -euo pipefail - echo "[L1: ] applying..." - sleep 1 - echo "[L1: ] OK" - exit 0 - ``` - `mock_apply.sh` does NOT read input values; the manifest is for traceability - and for Phase 03's `mock_executor.sh` to enumerate the L1s in an L2. - -### L1 list (fixed per REQ-02 / D-019) - -| Folder | Description | -|--------|-------------| -| `l1-eks-fargate` | Serverless container compute substrate | -| `l1-iam-role` | Identity and access role primitive | -| `l1-lambda` | Event-driven function primitive | -| `l1-api-gateway` | HTTP routing primitive | -| `l1-eventbridge` | Event bus primitive | -| `l1-sqs` | Queue primitive | -| `l1-s3` | Object store primitive | -| `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. - -## 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: -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//`. - -### 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: +**Policy result normalization (§12.6):** the confidence signal consumes a +normalized `PolicyCheckResult` schema, not raw engine output. ```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 - } + "contractId": "uuid", + "evaluatedAt": "ISO-8601", + "engine": "checkov | kyverno | opa", + "ruleId": "CKV_AWS_24 | KYVERNO_NO_PRIVILEGED | ...", + "severity": "critical | high | medium | low | info", + "result": "pass | fail | skipped | error", + "message": "human-readable", + "evidence": { "...engine-specific, opaque to the signal..." }, + "resourceRef": "IR-typed resource identifier" } ``` -### audit.json event + hash chain (D-023) +Execution layer: GitHub/Gitea Actions in the central pipeline repo. State +locking via DynamoDB. **AWS credentials via OIDC federation — long-lived +credentials are forbidden** (§12.5). The platform does not run +`terraform apply` against a developer's workstation; all execution is in +the central pipeline. -`audit.json` is a JSON array of event objects. `evidence_writer.py` -appends one event per call. Hash chain: +Registry maintenance: L1 publication updates the L1 registry in the same +PR. The registry is the IR-typed contract, not a Terraform-specific +variable schema. -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`. +Contract→IR resolution: the contract declares intent in IR-typed terms; +the pipeline resolves it to a target stack (list of L1 instances + inputs + +relationships); the Terraform adapter compiles the target stack to a plan. -Genesis event (when `audit.json` is empty or missing): +## v1.1 spike scope -```json -{ - "seq": 0, - "ts": "2026-07-21T13:00:00Z", - "stage": "genesis", - "event": "audit log initialized", - "prev_hash": "GENESIS", - "hash": "" -} -``` +The spike (Phases 08–10) materializes the **minimum** that proves the IR +commitments hold (no polyglot mess): -Subsequent events: `seq = prev.seq + 1`, `prev_hash = prev.hash`. +- One L1: `l1-s3` (IR-typed interface; the only AWS resource in the spike). +- One L2 thin-composition: `l2-static-asset` (references `l1-s3` only). +- Terraform adapter: IR → `terraform plan` against AWS via OIDC. +- One contract submission → contract→IR → `terraform plan` → Checkov + `PolicyCheckResult` → confidence signal → evidence event to the DynamoDB + outbox. +- State: S3 + DynamoDB (real AWS, single-region). -### Core script I/O contracts +Out of spike scope: full HITL matrix wiring, Kyverno, OPA, MCP skill +catalog, GitOps reconciler, multi-region, prod/dr environments, the 5-skill +L3B catalog. Those are post-spike (v1.2+) platform build-out. -| Script | Input | Output | Exit | -|--------|-------|--------|------| -| `mock_executor.sh` | `` (argv[1]); reads L2 manifest from `modules/l2//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` | `` (argv[1]) | stdout: `POLICY_PASS` or `POLICY_VIOLATION:PUBLIC_INGRESS` | 0 on pass; 1 on violation | -| `confidence_signal.py` | `` (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 ` `--event ""` `--audit ` (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 ` (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 | \ No newline at end of file +## Gitea API surface (carried from v1.0, refined) + +| Capability | Gitea support | ACDL approach (v1.1) | +|------------|---------------|----------------------| +| Org-scoped repo create | `POST /api/v1/orgs/{org}/repos` | Used for any new repos | +| Native Pages | **None** | Serve `acdl-evidence` via raw file URLs (unchanged from v1.0) | +| Environments API | **None**; act_runner ignores `environment:` | Model HITL gates via `workflow_dispatch` approval inputs (v1.0 D-013 pattern) — **refined in Phase 07** for the real pre-execution gate model | +| `repository_dispatch` | Not supported | Cross-repo trigger via `workflow_dispatch` API (unchanged) | +| Reusable workflows | Supported | `acdl/.gitea/workflows/pipeline.yml` via `uses: ...@` | +| `id-token: write` / OIDC | **To be confirmed in RESEARCH** (highest-priority unknown) | If act_runner supports OIDC, configure AWS trust; if not, use a documented spike-only waiver and revisit in v1.2 | +| `actions/configure-aws-credentials` | Depends on OIDC support | If OIDC unavailable, fall back to short-lived `aws sts assume-role-with-web-identity` from a step | + +### Branch pinning rule (refined for W2.A) + +- Dev/qa contracts reference the reusable workflow by **tag** + (`@v1.1-spike`). +- Prod-bound workflows reference by **SHA**; the platform CLI + (`platform/cli/resolve-tag.ts`, Phase 07) resolves the current tag to its + SHA. (Spike scope: the CLI is a stub; the real CLI lands in v1.2.) + +### Verification toolchain + +ACDL has no `package.json`. The verification gate substitutes: +- **typecheck:** `terraform validate`, `python3 -m py_compile`, JSON Schema + validation (`ajv` or `python -m jsonschema`) against `schemas/`. +- **test:** per-phase `scripts/verify_phaseNN.sh` (Phase 06: archive integrity; + Phase 07: schema validation + decision-resolution completeness; Phase 08: + OIDC assume-role + state backend; Phase 09: IR + L1 + adapter `terraform + plan`; Phase 10: end-to-end contract submission). +- **build:** `terraform init` (real build for the spike). +- See `PERSONAS.md` verification_toolchain. + +## Build order (v1.1) + +1. Phase 06 — archive demo, reorient repo. +2. Phase 07 — finalize architecture v1.0; author schemas + designs. +3. Phase 08 — AWS OIDC bootstrap (use temp key once, rotate). +4. Phase 09 — IR + `l1-s3` + Terraform adapter → `terraform plan`. +5. Phase 10 — `l2-static-asset` + contract→IR → end-to-end spike. +6. COMPLETE gate — review → ship `v1.2.0` → audit. \ No newline at end of file diff --git a/.ciagent/PERSONAS.md b/.ciagent/PERSONAS.md index 7288b94..1b2887a 100644 --- a/.ciagent/PERSONAS.md +++ b/.ciagent/PERSONAS.md @@ -1,21 +1,22 @@ --- project: acdl -milestone: v1.0 +milestone: v1.1 generated_at: 2026-07-21 generator: lead-developer verification_toolchain: - typecheck: "bash -n scripts/**/*.sh modules/**/*.sh && python3 -m py_compile scripts/**/*.py" + typecheck: "terraform validate && python3 -m py_compile platform/**/*.py && python3 -m jsonschema schemas/*.schema.json" test: "scripts/verify_phaseNN.sh" - build: "no-op (no build step; bash + python stubs)" + build: "terraform init" note: | ACDL has no package.json. The execute/verify/ship workflows substitute - bash -n and python -m py_compile for npm run typecheck, a per-phase - verify script for npm test, and treat npm run build as a no-op. This - override is documented here as the single source of truth; the ci-* - agents read PERSONAS.md before running verification commands. + `terraform validate` + `python -m py_compile` + JSON Schema validation + (`python -m jsonschema` or `ajv`) for npm run typecheck, a per-phase + verify script for npm test, and `terraform init` for npm run build. + This override is documented here as the single source of truth; the + ci-* agents read PERSONAS.md before running verification commands. --- -# ACDL — Persona Roster (project-level) +# ACDL — Persona Roster (project-level, v1.1) ## Active personas @@ -24,68 +25,94 @@ verification_toolchain: - **Active:** true - **Phase-specific:** false - **Frameworks:** (none) -- **Constraints:** pragmatic, battle-tested defaults, no-cross-territory-edits -- **Territory:** `.ciagent/**`, `scripts/verify_phase*.sh`, `README.md`, `.gitignore` -- **Reason:** Owns CIAgent metadata and cross-phase verification scripts. +- **Constraints:** pragmatic, battle-tested defaults, no-cross-territory-edits, vision-is-source-of-truth-for-why +- **Territory:** `.ciagent/**`, `scripts/verify_phase*.sh`, `README.md`, `docs/**` (meta only — not architecture authoring), `.gitignore` +- **Reason:** Owns CIAgent metadata, cross-phase verification scripts, and the v1.1 phase orchestration. Resolves the 11 open decisions (D-038) and arbitrates persona conflicts. ### backend-engineer - **Domain:** backend - **Active:** true - **Phase-specific:** false -- **Frameworks:** gitea-actions, act_runner, bash, python, yaml -- **Constraints:** no-cloud, no-ai, stub-only, hash-chain-must-be-deterministic, max-depth-5 -- **Territory:** `.gitea/workflows/**`, `scripts/**` (except `scripts/verify_phase*.sh`), `modules/l2/**/manifest.yaml` -- **Reason:** Owns workflow YAML, core scripts (mock_executor, policy_checker, confidence_signal, evidence_writer, l3b_agent_stub), and L2 composition manifests. +- **Frameworks:** python, json-schema, gitea-actions, act_runner, bash, yaml +- **Constraints:** contract-schema-first, fail-fast-with-reason-codes, no-long-lived-credentials, severity-to-penalty-mapping-immutable +- **Territory:** `platform/confidence_signal.py`, `platform/contract_resolver.py`, `platform/outbox/**`, `schemas/**` (contract + IR + PolicyCheckResult), `contracts/**` (sample contracts), `.gitea/workflows/**` (pipeline) +- **Reason:** Owns the contract schema, contract→IR resolution, the confidence signal (6 inputs + severity mapping), the DynamoDB outbox writer, and the central pipeline workflow. -### infra-stub-engineer (custom) -- **Domain:** backend +### platform-engineer (custom) +- **Domain:** infra - **Active:** true - **Phase-specific:** false -- **Frameworks:** bash, yaml -- **Constraints:** mock-only, echo-contract-from-D-007, sleep-1s-exit-0, substrate-agnostic, single-purpose -- **Territory:** `modules/l1/**` -- **Reason:** Created to own L1 stub modules (Phase 02) and their uniform mock_apply.sh behavior per D-007. Domain is backend (bash stubs) but territory is strictly L1 modules to keep L1/L2 concerns separated from workflow YAML. +- **Frameworks:** terraform, aws-iam, aws-s3, aws-dynamodb, oidc, json-schema +- **Constraints:** ir-is-substrate-agnostic, adapter-is-only-substrate-specific-code, state-in-s3+dynamodb-single-region, oidc-only-no-long-lived-keys (waiver D-034 for bootstrap), terraform-plan-only-in-spike +- **Territory:** `adapters/terraform/**`, `modules-ir/**`, `terraform/**` (state backend, provider config), `platform/registry/**` +- **Reason:** Owns the Target Stack IR, the L1/L2 IR-typed modules, the Terraform adapter, the AWS OIDC bootstrap, and the state backend. The IR is substrate-agnostic; the adapter is the only substrate-specific code (the binding constraint per §12). + +### security-engineer (custom) +- **Domain:** security +- **Active:** true +- **Phase-specific:** false +- **Frameworks:** aws-iam, oidc, checkov, json-schema +- **Constraints:** least-privilege, separation-of-duties-identity-distinctness, no-secrets-in-skill-markdown, audit-chain-extends-not-tears-up, critical-finding-hard-overrides-confidence +- **Territory:** `platform/hitl_matrix_design.md`, `platform/audit_ledger_design.md`, `adapters/terraform/policy/**` (Checkov adapter → PolicyCheckResult), `platform/separation_of_duties.py` +- **Reason:** Owns the HITL matrix design, separation-of-duties (DynamoDB identity-distinctness), the audit ledger design (S3 Object Lock + JWS + chain), and the Checkov→PolicyCheckResult adapter. Enforces the "Safety is Computed, Not Assumed" + "Audit truth lives outside the repository" vision tenets. + +### frontend-engineer +- **Domain:** frontend +- **Active:** true +- **Phase-specific:** false +- **Frameworks:** vanilla-js, dom-api, fetch-api +- **Constraints:** no-frameworks, single-file, fetch-from-same-origin-raw-url, relative-url-for-audit-json +- **Territory:** `evidence-ui/**` (the timeline UI; pushed to `acdl-evidence`) +- **Reason:** Owns the evidence timeline UI (`index.html`). Carried over from v1.0; the UI continues to render the audit stream. The v1.1 spike writes events to the DynamoDB outbox; the UI continues to read `audit.json` published to `acdl-evidence`. ## Deactivated personas +### infra-stub-engineer (custom, v1.0 only) +- **Domain:** backend +- **Active:** false +- **Reason:** Owned L1 stub modules (`modules/l1/**`) in the v1.0 demo. The demo is archived to `demo/` in Phase 06; real L1 modules (`modules-ir/l1/**`) are owned by platform-engineer (substrate-agnostic IR + Terraform adapter). The stub engineer is no longer needed. +- **Phase-specific:** false (was v1.0) +- **Territory (would have been):** `demo/modules/l1/**` + ### data-engineer - **Domain:** data - **Active:** false -- **Reason:** No persistence layer. ACDL state is flat JSON files (`audit.json`, `state.json`) written by bash/python scripts; no ORM, no migrations, no DB. Schema contracts live in `manifest.yaml` (owned by backend-engineer / infra-stub-engineer). +- **Reason:** No ORM/persistence framework. The v1.1 outbox is DynamoDB but accessed via boto3 calls inside `platform/outbox/**` (owned by backend-engineer); the audit ledger is S3 Object Lock + JWS (owned by security-engineer). No schema-migration layer, no ORM, no data-engineer territory. - **Phase-specific:** false - **Frameworks:** (would have been: drizzle, prisma) - **Constraints:** (would have been: schema-first, type-safe-orm) - **Territory:** (would have been: `**/db/**`, `**/migrations/**`) -### frontend-engineer -- **Domain:** frontend -- **Active:** true # REACTIVATED for Phase 05 (evidence UI + dry run) -- **Reason:** Phase 05 builds the vanilla-JS `index.html` timeline UI (REQ-14) and runs the 4 demo acts end-to-end dry run (REQ-15). Inactive for Phases 01-04 (no UI). -- **Phase-specific:** true (this reactivation is for Phase 05 only; will be deactivated again after the milestone ships if the project continues) -- **Frameworks:** vanilla-js, dom-api, fetch-api -- **Constraints:** no-frameworks, single-file, fetch-from-same-origin-raw-url, relative-url-for-audit-json -- **Territory:** `evidence-ui/**` (the source-of-truth `index.html` in the `acdl` repo; pushed to `acdl-evidence` by `run_demo.sh`) - ## Phase-specific overrides -| Phase | Personas active | Reactivations / notes | -|-------|-----------------|----------------------| -| 01 repo-scaffolding | lead-developer, backend-engineer | infra-stub-engineer idle (no L1 work this phase) | -| 02 l1-modules | lead-developer, backend-engineer, infra-stub-engineer | infra-stub-engineer owns L1 stubs | -| 03 l2-modules-and-core-scripts | lead-developer, backend-engineer, infra-stub-engineer | backend-engineer owns core scripts + L2 manifests; infra-stub-engineer only updates L1 manifests if referenced | -| 04 pipeline-and-approval-gates | lead-developer, backend-engineer | infra-stub-engineer idle; frontend-engineer still off | -| 05 evidence-ui-and-demo-dry-run | lead-developer, backend-engineer, frontend-engineer | frontend-engineer REACTIVATED for `index.html` only; backend-engineer owns the dry-run script and audit.json wiring | +| Phase | Personas active | Notes | +|-------|------------------|-------| +| 06 archive-demo-and-reorient | lead-developer, frontend-engineer (demo UI move only) | backend/platform/security idle | +| 07 architecture-v1-finalization | lead-developer, backend-engineer (schemas), security-engineer (HITL/ledger/SoD), platform-engineer (IR) | frontend idle | +| 08 aws-oidc-bootstrap | platform-engineer (lead), security-engineer (trust policy review) | backend/frontend idle | +| 09 v1-spike-ir-and-l1-and-adapter | platform-engineer (lead), backend-engineer (IR schema co-author) | security/frontend idle | +| 10 v1-spike-l2-and-contract-e2e | platform-engineer (L2 + adapter), backend-engineer (contract→IR + confidence + outbox), security-engineer (Checkov→PolicyCheckResult), frontend-engineer (evidence event surfaces in timeline) | Full roster | ## Domain priority (used by TaskDecomposer) -`coordination -> backend -> infra-stub-engineer -> frontend-engineer (Phase 05 only)` +`coordination → security → platform → backend → frontend` + +Rationale: in v1.1, the security/architecture commitments (IR, confidence, +HITL, ledger, SoD) are the binding constraints; the platform layer +materializes them; backend wires the pipeline; frontend surfaces the +evidence. The spike's correctness depends on the security + platform layers +being right before backend wiring. ## Conflict resolutions (lead-developer arbitration) -- `backend-engineer` vs `infra-stub-engineer` over `modules/l2/**/manifest.yaml`: backend-engineer owns L2 manifests; infra-stub-engineer owns L1 manifests. No overlap. -- `backend-engineer` vs `frontend-engineer` over `acdl-evidence/index.html`: frontend-engineer owns the file in Phase 05; backend-engineer provides the `audit.json` schema contract (event shape) via `evidence_writer.py` and a `SCHEMA.md` note in ARCHITECTURE.md. -- `lead-developer` vs any: lead-developer owns `.ciagent/**` and verification scripts; persona engineers do not edit CIAgent metadata. +- `backend-engineer` vs `platform-engineer` over `schemas/ir.schema.json`: platform-engineer owns the IR (it is substrate-agnostic but infra-shaped); backend-engineer owns the contract schema and the contract→IR resolution (contract is the consumer surface). Co-authoring is expected; conflict goes to lead-developer. +- `backend-engineer` vs `security-engineer` over `platform/confidence_signal.py`: security-engineer owns the severity→penalty mapping + critical-override semantics; backend-engineer owns the 6-input weighted sum + per-env thresholds. The confidence signal is co-owned; conflicts go to lead-developer. +- `platform-engineer` vs `security-engineer` over `adapters/terraform/policy/**`: security-engineer owns the Checkov→PolicyCheckResult adapter (policy is a security concern); platform-engineer owns the Terraform adapter (substrate translation). No overlap. +- `lead-developer` vs any: lead-developer owns `.ciagent/**` + `docs/**` meta + verification scripts; persona engineers do not edit CIAgent metadata or the vision/architecture source docs. ## Territory enforcement mode -`warn` — config.json has no `personas.territory_enforcement` field, so the default per execute.md is `warn`. Cross-territory edits are logged in the commit message but do not fail the task. \ No newline at end of file +`warn` — config.json has no `personas.territory_enforcement` field, so the +default per execute.md is `warn`. Cross-territory edits are logged in the +commit message but do not fail the task. The spike's small scope means +co-authoring across territories is likely; `warn` keeps it frictionless. \ No newline at end of file diff --git a/.ciagent/PLAN.md b/.ciagent/PLAN.md index 4bb20fc..355d5ad 100644 --- a/.ciagent/PLAN.md +++ b/.ciagent/PLAN.md @@ -1,100 +1,63 @@ --- -phase: 05 -name: evidence-ui-and-demo-dry-run -milestone: v1.0 +phase: 0 +name: v1.1-specify +milestone: v1.1 milestone_type: feature -status: planned -requirements: [REQ-13, REQ-14, REQ-15] +status: specify +requirements: [REQ-16..REQ-28] must_haves: - - "evidence-ui/index.html exists: single HTML file with inline CSS + JS, no external resources, no frameworks (D-032, REQ-14)" - - "index.html fetches ./audit.json (relative URL) and renders events as a vertical timeline with stage color-coding (dev/qa/prod/finalize/genesis) + 12-char hash preview" - - "scripts/run_demo.sh exists: simulates all 4 acts (Friction, Dev Self-Service, Citizen Developer, Safety Net) by calling the Phase 03 core scripts + evidence_writer.py + finalize_evidence.py; writes a final audit.json; uploads audit.json + evidence-ui/index.html to acdl-evidence main via the Gitea file-contents API (D-031/D-033)" - - "scripts/run_demo.sh is idempotent: re-running overwrites both files on acdl-evidence and produces the same audit.json (deterministic hash chain)" - - "Act 4 produces a 'dev rejected: POLICY_VIOLATION:PUBLIC_INGRESS' evidence event with score 0.40 (the Safety Net)" - - "scripts/verify_phase05.sh passes: validates index.html structure (single file, inline, fetch call), runs run_demo.sh, fetches the raw audit.json + index.html URLs from acdl-evidence and confirms HTTP 200" + - "config.json project.milestone = v1.1, status = specify" + - "PROJECT.md reframed from stub demo to real platform (vision tenets + 4-layer/6-concern model + 11 open-decision resolutions + D-034..D-038)" + - "ARCHITECTURE.md rewritten to the target architecture (IR, confidence, ledger, HITL, SoD, substrate abstraction) with v1.1 spike scope" + - "REQUIREMENTS.md adds v1.1 section (REQ-16..REQ-28) + traceability" + - "ROADMAP.md adds v1.1 Phases 06–10" + - "PERSONAS.md adds platform-engineer + security-engineer, retires infra-stub-engineer, updates territories + verification toolchain" + - "docs/vision.md + docs/architecture.md (upstream) referenced as the why/how source of truth" verification: - typecheck: "bash -n scripts/*.sh && python3 -m py_compile scripts/*.py" - test: "scripts/verify_phase05.sh" + typecheck: "python3 -m jsonschema schemas/*.schema.json 2>/dev/null || true # schemas authored in Phase 07" + test: "scripts/verify_phase06.sh # authored in Phase 06" build: no-op --- -# Phase 05 — evidence-ui-and-demo-dry-run PLAN +# v1.1 — Specify PLAN ## Goal -Build the vanilla-JS timeline UI and run the 4 demo acts as a local dry -run that produces a real `audit.json` and publishes it (plus the UI) to -`acdl-evidence` main. This is the milestone's capstone phase. +Ingest `docs/vision.md` + `docs/architecture.md` and update all `.ciagent` +files to reframe the project from the v1.0 stub demo to the real Agentic +Cloud Delivery Platform, milestone v1.1 (architecture finalization + v1 +spike). -## Requirements covered +## Scope of this stage (SPECIFY only) -- REQ-13: `acdl-evidence` is Pages-enabled and serves `audit.json` plus `index.html` (substituted by D-012: raw-URL 200 on both files) -- REQ-14: `index.html` uses vanilla JS to fetch `audit.json` and render events as a timeline -- REQ-15: All four demo acts reproduce deterministically in a dry run +Rewrite the five `.ciagent/` files + `config.json`: +- `config.json` — milestone `v1.1`, status `specify`. +- `PROJECT.md` — reframe; carry the 6 vision tenets; record the 11 + open-decision resolutions (D-038) + the OIDC waiver (D-034) + spike picks + (D-036) + archive decision (D-037) + version (D-035). +- `ARCHITECTURE.md` — target architecture (4 layers + 6 cross-cutting + concerns incl. substrate abstraction); v1.1 spike scope. +- `REQUIREMENTS.md` — add REQ-16..REQ-28 + traceability. +- `ROADMAP.md` — add v1.1 Phases 06–10. +- `PERSONAS.md` — add platform-engineer + security-engineer; retire + infra-stub-engineer; update territories + verification toolchain. -## Waves (vertical slices, domain priority order) +## Waves -### Wave 1 — frontend-engineer (the UI) - -**Tasks:** - -- **T-5.1** Create `evidence-ui/index.html` — single HTML file with inline `