Commit Graph

58 Commits

Author SHA1 Message Date
Jon Chery f83b974c0e Merge milestone/v1.16-nova-simplification — v1.16 complete (Nova Simplification: 20-phase NFR sweep + final; tag v1.15.26)
acdl-ci / Lint (push) Successful in 11s
acdl-ci / Platform check-only (offline) (push) Successful in 29s
acdl-ci / Test (push) Failing after 7m25s
2026-08-01 13:37:18 +00:00
Jon Chery e15eea067b docs(milestone): complete v1.15 — Nova Rebrand (tag v1.15.4)
P5 final-review-ship complete: dual-read fallback removed (REQ-164) —
core/env.py NOVA-only, .env.secrets load paths NOVA-only (G-106 retired),
nova_tagging.py hard-fails any acdl:* tag, legacy ACDL_* Gitea secrets
deleted, ACDL_LIFECYCLE_MODE/ACDL_LOCAL_TIER/ACDL_HITL_* exports removed
from scripts, SNS subject → Nova SoD halt (P1-2), bootstrap scripts
NOVA-only. Review: 2 P0 auto-fixed (duplicate delenv), P1-1/P1-2 resolved,
doc-drift fixed. Audit: tags v1.15.0-4 exist; traceability REQ-155..164
all complete; ARCHITECTURE naming table matches codebase. 615 pytest PASS;
run_ci.sh 3-stage PASS. NOVA_MIGRATION.md marked COMPLETE.

---ci---
project: acdl
phase: 5
milestone: v1.15
status: complete
phase_role: final
requirements:
  covered: [REQ-155, REQ-156, REQ-157, REQ-158, REQ-159, REQ-160, REQ-161, REQ-162, REQ-163, REQ-164]
  partial: []
---/ci---
2026-07-30 02:23:55 +00:00
Jon Chery 0e6ecae26d feat(P4): Nova rebrand — AWS resource migration (REQ-163)
Rename all acdl-* AWS resources → nova-* across terraform (DynamoDB,
Secrets Manager, Lambda, SNS, SG, KMS alias, ECS, ECR, IAM user/policy,
state bucket, ALB, VPC/subnet names). Lambda default table names → nova-*
(D-111). State bucket backend → nova-tfstate (-migrate-state documented).
New docs/NOVA_AWS_MIGRATION.md runbook (staged migration + rollback).
New scripts/migrate_dynamodb_data.py (scan+copy, dry-run default).
acdl-deploy- → nova-deploy- role ARN in deploy workflows. Test fixtures
updated; terraform validate + pytest + run_ci.sh PASS.

---ci---
project: acdl
phase: 4
milestone: v1.15
status: execute
---/ci---
2026-07-30 01:54:26 +00:00
Jon Chery 51c3edf458 feat(P3): Nova rebrand — SSM path + tag keys (REQ-161/162)
SSM path /acdl/{env}/{contractId}/{output} → /nova/... across
core/output_publisher + contract resolver + consumer docs. New
scripts/migrate_ssm_paths.py (copy/verify/delete, dry-run default).
AWS tag keys acdl:owner|environment|contract|cost-center|ref → nova:*
across terraform tagging + ABAC session policies (iam:ResourceTag/acdl:*
→ iam:ResourceTag/nova:*). nova_tagging.py hard mode (D-109 warn→hard).
tagging-standard.json tag-key values → nova:*. New
scripts/untag_acdl_keys.py (remove old acdl:* tags, dry-run default).
Test fixtures updated; pytest + run_ci.sh PASS.

---ci---
project: acdl
phase: 3
milestone: v1.15
status: execute
---/ci---
2026-07-30 01:38:30 +00:00
Jon Chery d5bae868a4 feat(P2): Nova rebrand — code/env-vars/consumer-path (REQ-158/159/160)
core/env.py dual-read helper (D-108); 21 ACDL_*→NOVA_* env vars migrated
across core/scripts/adapters/tests/workflows + .env/.env.secrets (key
rename, values stay). G-106 binding: run_platform.sh:288-289 +
regression_verify.py:309-312 dual-read (NOVA first, ACDL fallback).
G-108 binding: Gitea NOVA_* secrets created via API + workflow secrets:
refs updated (deploy.yml + modules-lifecycle.yml, .gitea + .github).
acdl_tagging.py→nova_tagging.py (D-109 warn mode, nova:* enforced).
.acdl/→.nova/ consumer path (resolver + deploy workflow + schema +
tests + docs). Test fixtures updated; pytest + run_ci.sh PASS.

---ci---
project: acdl
phase: 2
milestone: v1.15
status: execute
---/ci---
2026-07-30 01:25:24 +00:00
Jon Chery 3b1181f39b Merge milestone/v1.14-refinement — v1.14 complete (NFR Refinement: bug fixes, security, stubs, tests, docs; 20 phases + final; tag v1.13.24)
acdl-ci / Lint (push) Successful in 10s
acdl-ci / Platform check-only (offline) (push) Successful in 25s
acdl-ci / Test (push) Successful in 6m34s
v1.14 NFR Refinement milestone complete. 20 execution phases (P1-P20) +
1 final (P21). All P1/P2 backlog from v1.11 review resolved. Security
posture hardened (swallowed errors, account ID externalized, IAM scoped,
schema validation, credential hygiene). Stubs resolved (kyverno --kube-
version removed). 7 untested scripts gained coverage. Documentation
synced (ARCHITECTURE v1.11-v1.14 addenda, stale @v1.6-1.9 -> @v1.13,
GRILL G-005/G-008 resolved, COST.md window extended, D-083 deferral
recorded). Platform VPC parameterized.

561 tests pass (was 528 at v1.13.2; +33). 22/22 capabilities Verified.
6 grill binding decisions (G-101..G-106) applied. 1 escalation (E-001)
auto-resolved at full autonomy (D-101).

---ci---
project: acdl
phase: 21
milestone: v1.14
status: complete
---/ci---
2026-07-29 21:36:37 +00:00
Jon Chery 41c3377b96 feat(P67b): lifecycle tests default to plan-only; ACDL_LIFECYCLE_MODE flag overrides to full (REQ-134)
---
ci---
project: acdl
phase: 67b
milestone: v1.12
status: execute
---
/ci---

The modules-lifecycle pipeline now defaults to plan-only (fast, no AWS
mutation, no credentials, no cost) so it runs on every PR. A CI variable
ACDL_LIFECYCLE_MODE (workflow_dispatch input 'lifecycle_mode', default
'plan') overrides to 'full' for the real apply->modify->destroy against
live AWS.

Scripts: run_lifecycle_test.sh / run_lifecycle_destroy.sh /
run_l2_lifecycle_test.sh / run_l2_lifecycle_destroy.sh read the flag and
dispatch to --plan-only (plan mode) or --apply/--destroy (full mode).
Destroy is a no-op exit 0 in plan mode (nothing was applied). VPC-output
injection is gated on full mode.

Workflows: both .github + .gitea (byte-identical) expose lifecycle_mode
as a workflow_dispatch input (choice: plan/full), pass it via env:
ACDL_LIFECYCLE_MODE to every lifecycle step, skip ci-vpc-apply +
ci-vpc-destroy + Read-CI-VPC-outputs in plan mode, and run the lifecycle
+ l2-lifecycle jobs with if: always() so they execute (plan-only) even
when ci-vpc-apply is skipped.

Contract + schema: pipelines/modules-lifecycle.yml gains default_mode:
plan; the schema accepts default_mode (enum plan|full) and a richer
workflow_dispatch inputs shape.

Tests: 14 new tests in test_lifecycle_mode_flag.py (script dispatch) +
10 new tests in TestModulesLifecyclePipeline (workflow flag wiring,
byte-identity, plan-mode skips). Updated test_platform_vpc_destroy to
reflect the plan-mode skip. 516 tests pass; smoke-tested plan mode on
the s3 module (--plan-only green, no AWS apply).
2026-07-29 13:16:03 +00:00
Jon Chery 361fe600a9 feat(P61): L2 lifecycle pipeline — extend matrix + workflows + tests
Extend the modules-lifecycle pipeline with L2 composition modules
(static-assets, microservice) per REQ-128:

- pipelines/modules-lifecycle.yml: added l2-lifecycle-apply/modify/destroy
  stages + l2_modules matrix entry
- .gitea/workflows/modules-lifecycle.yml + .github/workflows/modules-lifecycle.yml:
  added l2-lifecycle job (byte-identical), matrix over [static-assets,
  microservice], needs ci-vpc-apply, has apply/modify/destroy steps.
  ci-vpc-destroy now needs both [lifecycle, l2-lifecycle].
- schemas/modules-lifecycle-pipeline.schema.json: added l2_modules to matrix
- scripts/run_l2_lifecycle_test.sh + run_l2_lifecycle_destroy.sh: L2 wrappers
  that set ACDL_REMOTE_STATE_KEY=spike/ci-vpc/terraform.tfstate so the
  microservice composition's terraform_remote_state reads from the CI VPC
- adapters/terraform/adapter.py: parameterized remote_state key via
  ACDL_REMOTE_STATE_KEY env var (default: platform/terraform.tfstate)
- modules/l2/static-assets/examples/complex.yml: fixed bucket_name to match
  simple (my-static-site) so terraform modifies in-place (adds CDN + WAF)
- modules/l2/microservice/examples/complex.yml: fixed bucket_name to match
  simple (my-microservice-demo), added desired_count:2 (modify variant)
- tests/test_pipeline_contract.py: 7 new L2 tests (l2 job exists, matrix
  lists both modules, apply/modify/destroy steps, needs ci-vpc-apply,
  ci-vpc-destroy needs both, contract matrix lists l2_modules)
- pipelines/README.md: updated stages for L2

Regression: 485 passed, 5 deselected. Gitea + GitHub workflows byte-identical.

---ci---
project: acdl
phase: P61
milestone: v1.11
status: execute
---/ci---
2026-07-28 20:17:27 +00:00
Jon Chery ad3cc5f129 fix(ci): separate short-lived CI VPC + fix 8 module lifecycle failures
acdl-ci / Lint (pull_request) Successful in 7s
acdl-ci / Test (pull_request) Successful in 4m3s
acdl-ci / Platform check-only (offline) (pull_request) Successful in 21s
acdl-modules-lifecycle / CI VPC apply (pull_request) Failing after 1m25s
acdl-modules-lifecycle / L1 lifecycle (alb) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (cloudfront) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecr) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecs-cluster) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecs-service) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (iam-role) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (kms-key) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (rds) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (s3) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (uptime) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (vpc) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (waf) (pull_request) Has been skipped
acdl-modules-lifecycle / CI VPC destroy (pull_request) Successful in 44s
Two architectural changes:
1. Created terraform/ci-vpc/ — a short-lived VPC for L1 module lifecycle
   testing, separate from the long-lived platform VPC. Created before
   VPC-dependent modules (alb, ecs-service, rds, uptime) are tested,
   destroyed after. Outputs (vpc_id, subnet_ids, sg_id, cluster_arn) are
   passed to those modules via scripts/run_lifecycle_test.sh +
   run_lifecycle_destroy.sh wrappers that inject the CI VPC outputs into
   the example contracts.
2. Updated the workflow to use ci-vpc-apply → lifecycle (with artifact
   passing) → ci-vpc-destroy (always runs).

8 module-specific fixes:
- s3: unique bucket names (acdl-ci-s3a-simple/complex) instead of
  globally-taken 'my-simple-bucket'
- kms-key: alias name with no spaces (locals.tf → alias/acdl-ci-kms)
- iam-role: example contract uses role_name (not name, which the interface
  doesn't declare)
- ecs-service: example contract uses family (not name); VPC inputs
  (cluster_arn, subnets, security_group) injected by CI VPC wrapper
- uptime: added subnets, security_group, cluster_arn to interface + module;
  network_configuration is dynamic (only when subnets provided)
- rds: added subnet_ids input + db_subnet_group resource (conditional
  on subnet_ids being non-empty)
- alb: removed hardcoded placeholder sg/subnet values from examples;
  vpc_id + subnets + security_group injected by CI VPC wrapper
- cloudfront: removed invalid placeholder WAF ARN from complex example

Regression: 479 passed, 0 skipped, 5 deselected. All 24 example contracts
pass --check-only.

---ci---
project: acdl
phase: P59
milestone: v1.11
status: execute
---/ci---
2026-07-28 17:52:58 +00:00
Jon Chery 60f767d125 fix(P59): 3 pipeline-readiness fixes — resolver id, schema inputs, CI creds
acdl-ci / Lint (pull_request) Successful in 8s
acdl-ci / Test (pull_request) Failing after 1m59s
acdl-ci / Platform check-only (offline) (pull_request) Successful in 10s
acdl-modules-lifecycle / Platform VPC apply (pull_request) Failing after 23s
acdl-modules-lifecycle / L1 lifecycle (alb) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (cloudfront) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecr) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecs-cluster) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecs-service) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (iam-role) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (kms-key) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (rds) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (s3) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (uptime) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (vpc) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (waf) (pull_request) Has been skipped
acdl-modules-lifecycle / Platform VPC destroy (pull_request) Failing after 22s
3 fixes found during the pipeline-readiness audit (all 24 example contracts
now resolve + adapt + pass --check-only):

1. core/contract_resolver.py: L1 resolver resource id now replaces underscores
   with hyphens (task_definition → task-definition), matching the L2 resolver
   pattern. The stack schema requires ^[a-z][a-z0-9-]*$ (no underscores).

2. schemas/stack.schema.json: relaxed input type constraint to allow array +
   object (was string/number/boolean only). Real-world inputs include lists
   (monitored_endpoints, static_checks, rules) and dicts (alert_channels).

3. scripts/run_platform.sh: AWS creds loading is now conditional — if
   AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY are already set (by the CI
   configure-aws-credentials action), skip loading .env.secrets. This makes
   the --apply/--destroy modes work in CI without the gitignored secrets file.

Regression: 479 passed, 0 skipped, 5 deselected.

---ci---
project: acdl
phase: P59
milestone: v1.11
status: execute
---/ci---
2026-07-28 16:07:57 +00:00
Jon Chery 4491d0fa72 feat(P57): shell orchestrator lifecycle modes --apply/--destroy
EXECUTE stage. Adds --apply and --destroy modes to run_platform.sh.
The shell owns all terraform lifecycle; Python never runs terraform.

Changes to scripts/run_platform.sh:
- Added APPLY_ONLY and DESTROY_ONLY flags to arg parsing.
- --apply <contract>: resolve -> adapter -> terraform init/validate/plan/
  apply -auto-approve. HITL attestation gate runs before apply for
  qa/prod/dr (REQ-108). Prints terraform outputs after apply. Exits
  with PLATFORM APPLY OK.
- --destroy <contract>: resolve -> adapter -> terraform init/validate/
  destroy -auto-approve. Use --decommission <CR> for gated production
  teardown (D-070 two-step CR validation). Exits with PLATFORM DESTROY OK.
- Updated usage header to document all 5 modes (check-only, plan-only,
  apply, destroy, default full e2e).
- Existing --check-only and --plan-only modes preserved unchanged.

Tests (tests/test_pipeline.py):
- test_run_platform_apply_mode_parses: --apply parses without unknown flag.
- test_run_platform_destroy_mode_parses: --destroy parses without unknown flag.
- test_no_python_runs_terraform_apply_or_destroy: D-101 grep assertion —
  no .py file in scripts/ contains 'terraform apply' or 'terraform destroy'.

Regression: 464 passed, 0 skipped, 5 deselected (slow). --check-only
still works (no regression in existing modes).

---ci---
project: acdl
phase: P57
milestone: v1.11
status: execute
---/ci---
2026-07-28 16:07:57 +00:00
Jon Chery 2397336cbb verify(P57): code review — 3 P0 auto-fixed, 2 P1+ flagged
acdl-ci / Lint (push) Successful in 9s
acdl-ci / Test (push) Successful in 2m9s
acdl-ci / Platform check-only (offline) (push) Successful in 10s
Multi-persona review of the contract surface redesign (031887e + 10b87a6).

P0-1 (auto-fixed): scripts/run_platform.sh:437 read the uptime_enabled
feature flag from the OLD top-level contract.inputs.uptime_enabled path,
which P57 removed. With the new contract shape c.get('inputs',{}) returns
{} so the flag silently always defaulted to True — a consumer setting
uptime_enabled:false under infrastructure.<module>.inputs could NOT
disable uptime monitoring. Fixed to scan
infrastructure.<module>.inputs.uptime_enabled (any module false wins).

P0-2 (auto-fixed): docs/consumer-guide.md:417,472 documented the
${contract.module} interpolation token, but P57 dropped the `module`
field. _expand_vars fails loud (D-081) on unknown tokens, so a consumer
following the documented bucket_name example
(acdl-${env.environment}-${contract.module}-...) hit a hard ValueError
at resolve time. Replaced with ${contract.id} (the surviving short
acronym field) in both the example and the interpolation reference table.

P0-3 (auto-fixed): core/regression_verify.py CAP-006 and
tests/test_consumer_guide_per_env_section.py both asserted the dropped
${contract.module} token. Updated CAP-006 to use ${contract.id} and the
doc test to assert ${contract.id} present / ${contract.module} absent.

P1+ flags (post-hoc):
- P1: _namespace_resources does not rewrite ref: targets in
  stack.outputs[].from for cross-module refs (within-module is handled;
  multi-module refs across fragments are not wired today, but no
  contract uses them yet).
- P1: _latest_version raises ValueError (not a clear message) on a
  malformed semver string in the registry; the schema pins version to
  ^\d+\.\d+\.\d+$ so this is unreachable from a contract, but registry
  authors have no guardrail.
- P2: docs/consumer-guide.md:407 example path uses .yaml extension while
  the repo-wide rename standardized on .yml (consumer-repo paths, not
  platform, so non-blocking).

---ci---
project: acdl
phase: 57
milestone: v1.10.2
status: verify
lessons:
  - P0 fix applied: uptime_enabled read path migrated to infrastructure.<module>.inputs (was stale top-level contract.inputs)
  - P0 fix applied: docs + tests migrated off dropped ${contract.module} interpolation token to ${contract.id}
---/ci---
2026-07-28 12:04:34 +00:00
Jon Chery 031887ec56 refactor(P57): contract surface redesign + rename + .yml repo-wide
Contract surface redesign:
- New top-level fields: id (3-6 char acronym → stack.name), name (full → stack.title),
  infrastructure (map keyed by module name, replaces module:)
- Drop uses: field (dead reference; version pin lives in CI workflow uses: line)
- Drop top-level module/inputs (now nested under infrastructure map)
- Per-module optional version (defaults to latest published from registry)
- Multi-module contracts: one file deploys N modules in one pipeline run,
  resource IDs namespaced with module name to avoid collisions
- stack.schema.json: add optional title field for display name

Rename:
- pipelines/deploy.yaml → pipelines/contract.yml (declarative spec, not a pipeline)
- pipelines/ci.yaml → pipelines/ci.yml
- All 44 .yaml files → .yml repo-wide (contracts, module examples, kyverno policies)
- .acdl/contract.yaml → .acdl/contract.yml

Resolver (core/contract_resolver.py):
- Rewrite resolve() to loop infrastructure map, default version to latest,
  merge module fragments into one stack with namespaced resource IDs
- _latest_version() picks highest non-deprecated from registry
- _namespace_resources() prefixes IDs + rewrites ref: expressions for multi-module
- Single-module path: unprefixed IDs (backward compatible)

Verification:
- 494 tests pass (0 contract-shape failures)
- Local E2E passes (contract → resolver → adapter → local ECS HTTP 200 → outbox)

---ci---
project: acdl
phase: 57
milestone: v1.10.2
status: execute
---/ci---
2026-07-27 21:37:40 +00:00
Jon Chery 217653d6f4 feat(P53): local emulating adapters (D-092) — full local E2E, no AWS
The platform is now fully locally testable without cloud credentials.
The headline E2E (contract -> resolver -> adapter -> S3 state -> ECS
service -> DynamoDB outbox -> contract-ingestor Lambda) runs end-to-end
against the local emulating tier (D-092, REQ-113).

Four local emulating adapters in core/local_emulators.py:
- FlatFileOutbox: flat-file DynamoDB outbox emulator (hash-chained JSONL;
  resumable across instances; chain verification).
- LocalEcsEmulator: local ECS Fargate HTTP 200 emulator (free-port
  binding on 127.0.0.1; health check; clean destroy).
- LocalS3StateBackend: rewrites the terraform S3 backend to a local
  backend (per-stack tfstate in a temp folder).
- LocalLambdaStub: invokes the contract_ingestor handler in-process
  (patches _get_dynamodb / _get_secrets_client / urllib.urlopen;
  DynamoDB writes redirected to the FlatFileOutbox).

run_platform.sh gains a --local flag that short-circuits to the local
emulating tier (no AWS, no Checkov, no DynamoDB).

Regression gate (D-091) now covers 12 capabilities (was 10): +CAP-011
(local E2E microservice) + CAP-012 (local E2E static-assets).

Verified: 513 fast tests pass (was 502; +11 new). 2 slow local E2E
tests pass. run_regression.sh reports 12/12 Verified. run_platform.sh
--local exits 0 with LOCAL E2E OK. No AWS credentials required.

---ci---
project: acdl
phase: 53
milestone: v1.10
status: verify
requirements:
  covered: [REQ-113]
  partial: []
decisions: [D-092]
regression:
  - { capability: CAP-011, status: Verified }
  - { capability: CAP-012, status: Verified }
---/ci---
2026-07-27 17:39:33 +00:00
Jon Chery 9897df04b2 fix(P52): add regression-class VERIFY (D-091) — catches capability decay
The prior VERIFY stage was diff-scoped: it checked the phase diff only
and never re-ran underlying platform capability. This structural defect
(D-091) let 8 NFR-patch phases (v1.9.1-v1.9.8, deck rework) pass VERIFY
while the platform they described decayed underneath.

Phase 52 remediation:
- core/regression_verify.py: regression-class VERIFY with 10 seeded
  local-tier capability checks (CAP-001..CAP-010). Tags each
  Verified/Decayed/Broken; fails closed on any non-Verified.
- scripts/run_regression.sh: shell wrapper; writes
  .ciagent/REGRESSION_REPORT.{md,json}; exits non-zero on decay.
- tests/test_verify_regression_mode.py: 11 tests (8 fast + 3 slow).
  Confirms the gate catches decay (fails closed) and that regression
  mode is additive (diff-scoped VERIFY behavior preserved).
- pyproject.toml: slow marker registered; run_ci.sh excludes slow
  tests to avoid recursion.

Verified: 502 fast tests pass (was 493 at v1.9; +9 new). 3 slow
integration tests pass. run_regression.sh reports all 10 seeded
local-tier capabilities Verified against current code. The
decay-surfacing test injects a broken cloud-backed check and confirms
the run tags it Broken and fails closed.

Cloud-backed capability re-verification (live ECS, DynamoDB writes,
Lambda invocation) lands in Phase 54 (D-093).

---ci---
project: acdl
phase: 52
milestone: v1.10
status: verify
requirements:
  covered: [REQ-112]
  partial: []
decisions: [D-091]
regression:
  - { capability: CAP-001, status: Verified }
  - { capability: CAP-002, status: Verified }
  - { capability: CAP-003, status: Verified }
  - { capability: CAP-004, status: Verified }
  - { capability: CAP-005, status: Verified }
  - { capability: CAP-006, status: Verified }
  - { capability: CAP-007, status: Verified }
  - { capability: CAP-008, status: Verified }
  - { capability: CAP-009, status: Verified }
  - { capability: CAP-010, status: Verified }
---/ci---
2026-07-27 17:29:52 +00:00
Jon Chery a4481e20de docs(P51): full presentation rework — scope, story arc, visuals, appendix
acdl-ci / Lint (push) Successful in 9s
acdl-ci / Test (push) Successful in 29s
acdl-ci / Platform check-only (offline) (push) Successful in 10s
Major rework of both presentation decks based on leadership feedback.
Addresses: story arc, concept clarity, scope clarification, more visuals,
appendix for detail-heavy slides, and a complete Road to the North Star.

6 new mermaid diagrams:
- platform-works-03-scope-boundary (Upstream → Contract → ACDL → AWS)
- developer-experience-01b-scope-boundary (both consumer paths + scope)
- platform-works-04-confidence-signal (6 inputs → score → gate → decision)
- platform-works-05-attestation-flow (deploy → gate → approver → evidence)
- developer-experience-04-promotion-journey (dev → qa → prod → dr)
- road-to-north-star (v1.0 demo → v1.9 → v1.10 → v2.0 → North Star)

Both Marp decks restructured to 10 main + 6 appendix slides:

PW deck (17 slides):
1. Title
2. The Problem & The North Star (anti-goals moved to slide 3)
3. Where ACDL Sits in Your World (NEW — scope boundary, infra only)
4. The Contract-Driven Model (image: removed, infra inputs instead)
5. The End-to-End Flow
6. Zero-Trust by Default
7. Safety is Computed (NEW confidence signal diagram)
8. Security by Construction
9. Accountability & Audit (NEW attestation flow diagram, QA clarification,
   badge reclassification: dev=Testing, qa/prod/dr=Planned)
10. Testing vs. Planned (summary, full inventory in appendix)
11. The Vision Realized
+ Appendix: TOC, Platform-Managed Environments, Observability, Road to
  North Star, Full Inventory, Glossary

DX deck (16 slides):
1. Title
2. Where ACDL Sits in Your World (REPLACES Two Consumer Surfaces — scope
   boundary with both consumer paths)
3. The Contract — The Entire Consumer Surface (image: removed)
4. The Developer Feedback Loop
5. Versioned, Predictable Releases
6. Friendly Onboarding
7. Safe Promotion Path (NEW promotion journey diagram, rising bar
   annotated: dev=Testing, qa/prod/dr=Planned)
8. Safe Decommission
9. Self-Service Module Catalog
10. The Desired Outcomes
+ Appendix: TOC, Citizen Developer Experience, No Platform Code, Local
  Reproducibility, Road to North Star, Glossary

Story arc: every slide has an italic 'Story beat' line connecting it to
the narrative progression.

Scope clarification: ACDL is infrastructure only. Upstream is anything
(IDE, agentic SDLC, citizen dev vibe coding). ACDL provisions and governs
AWS resources; application deployment is upstream. Contract examples now
show infrastructure inputs (cpu, memory, desired_count, port) not image:.

QA attestation reclassification: 'Design tested' → 'Planned'. QA attests
to infrastructure readiness (contract + Terraform plan + evidence), not
application code. Dev is autonomous (Testing); qa/prod/dr are Planned.

Road to the North Star: phased timeline (v1.0 → v1.9 → v1.10 → v2.0 →
North Star), annotated 'proposed phasing, not formally planned.'

Also: scripts/sync_to_gl.sh added (GitLab mirror sync utility).

---ci---
phase: 51
milestone: v1.9
status: complete
requirements:
  covered: []
  partial: []
---/ci---
2026-07-27 14:46:05 +00:00
Jon Chery 6e41f09c6e verify(P43): code review — 1 P0 auto-fixed, 1 P1 auto-fixed, 3 P1 flagged
acdl-ci / Lint (push) Successful in 6s
acdl-ci / Test (push) Successful in 26s
acdl-ci / Platform check-only (offline) (push) Successful in 9s
---ci---
phase: 43
milestone: v1.9
status: verify
lessons:
  - P0 fix: run_platform.sh HITL gate passed approver via string interpolation into Python (GITHUB_ACTOR injection vector) — fixed by passing env vars (ACDL_HITL_*) read via os.environ
  - P1 fix: attestation_matrix._is_fresh accepted future-dated artifacts (negative age bypassed freshness) — fixed with negative-age guard + test
  - P1 flagged: WizClient._post does not check GraphQL errors (silent empty-list mask)
  - P1 flagged: WizClient._post no SSRF validation on WIZ_API_URL
  - P1 flagged: contract_resolver._load_env duplicates environment_check.load (can drift)
---/ci---

Multi-persona review of the v1.9 diff (v1.8.0..HEAD). Review pass 2
(post-complete) caught issues the initial self-review missed:

P0-INJECT (auto-fixed): scripts/run_platform.sh Step 7b interpolated
$APPROVER (GITHUB_ACTOR/GITEA_ACTOR) directly into a Python string
literal — an attacker-controllable username containing shell/python
metacharacters would execute arbitrary Python. Fixed: approver, contract
id, and env are now passed as environment variables to the subprocess
and read via os.environ[...] (no string interpolation).

P1-FRESHNESS (auto-fixed): core/attestation_matrix.py _is_fresh
accepted future-dated artifacts (negative age.days <= window_days).
Fixed: added age.total_seconds() < 0 guard rejecting future timestamps.
Test added: test_freshness_rejects_future_dated_artifact.

3 P1 flagged for post-hoc:
- WizClient._post does not surface GraphQL errors (silent empty mask)
- WizClient._post no SSRF validation on WIZ_API_URL (operator-supplied, low risk)
- contract_resolver._load_env duplicates environment_check.load (drift risk)

REVIEW.md updated with the findings. 494 tests pass; run_ci.sh + run_platform.sh --check-only green.
2026-07-23 11:54:58 +00:00
Jon Chery e74a8c2f5d feat(P42): stub implementation — SoD, HITL gates, attestation matrix, Wiz, Kyverno
---ci---
project: acdl
phase: 42
milestone: v1.9
status: execute
---/ci---

Phase 42 — stub-implementation (REQ-107..111, D-084):

route_halt_artifact (REQ-107):
- core/separation_of_duties.py: real SNS publish (ACDL_SOD_HALT_TOPIC_ARN)
  + outbox fallback (SEPARATION_OF_DUTIES_VIOLATION event via
  outbox_writer) + stderr emission. No silent print-only stub.
- terraform/platform/main.tf: aws_sns_topic.acdl-sod-halt + output.

HITL attestation gates (REQ-108):
- core/hitl_gates.py: attest(contract_id, env, approver, evidence,
  outbox_client) records approver_qa/approver_prod/approver_dr to
  outbox, runs SoD check on prod, invokes attestation matrix, returns
  (ok, reason). Dev skips (autonomous). approver_from_env() reads
  GITHUB_ACTOR/GITEA_ACTOR.
- scripts/run_platform.sh: Step 7b HITL gate before apply for qa/prod/dr.

8-concern attestation matrix (REQ-109, D-084):
- core/attestation_matrix.py: check(env, evidence) runs the 8 concerns
  from hitl_matrix_design.md §10.4. Offline-testable (contract_nfrs,
  schema_validity, policy_pass) run for real. Operator-supplied accept
  signed artifacts validated for freshness (FRESHNESS_DAYS table) +
  schema. Signature skip when ACDL_ATTESTATION_SIGNING_KEY_ID unset
  (D-089). Fail loud if missing/expired for prod/dr.

Wiz real client (REQ-110):
- adapters/wiz/wiz_adapter.py: WizClient (GraphQL API, Bearer auth,
  pagination via pageInfo.hasNextPage + endCursor). fetch_and_adapt
  translates issues → PolicyCheckResult; graceful degrade when
  WIZ_API_TOKEN/WIZ_API_URL unset.

Kyverno fleshed out (REQ-111):
- adapters/kyverno/kyverno_adapter.py: full PolicyReport →
  PolicyCheckResult mapping (pass/fail/skip/warn + severity + skip-with-
  reason + resource ref construction from kind/name/namespace).
  adapt_inactive() emits KYVERNO_INACTIVE_TF_STACK guard. --kube-version
  stub parsed for future GitOps.

Tests: +47 (test_route_halt_artifact.py, test_hitl_gates.py,
test_attestation_matrix.py, test_wiz_adapter_real_client.py, expanded
test_kyverno_adapter.py). Existing wiz_adapter tests updated for the
real client's control.name ruleId. 493 passed; run_ci.sh green;
run_platform.sh --check-only green.
2026-07-23 04:40:44 +00:00
Jon Chery cd637808f5 feat(P41): per-environment CI jobs + environment workflow input
---ci---
project: acdl
phase: 41
milestone: v1.9
status: execute
---/ci---

Phase 41 — per-environment-ci-jobs (REQ-105, REQ-106, D-082):

Per-env contracts (REQ-105):
- contracts/static-assets.{dev,qa,prod,dr}.yaml + microservice.{dev,qa,prod,dr}.yaml
  (8 files, each sets environment: to its own name, uses interpolation).
- Default contracts/static-assets.yaml + microservice.yaml preserved (backwards compat).

Deploy workflow environment input (REQ-106):
- .github/workflows/deploy.yml + .gitea/workflows/deploy.yml (byte-identical):
  new 'environment' workflow_call input (default empty, override).
- scripts/run_platform.sh: --environment <name> flag; exports
  ACDL_ENVIRONMENT_OVERRIDE; re-runs env check against the override.
- core/contract_resolver.py: resolve(environment_override=...) (D-088);
  CLI honors --environment flag + ACDL_ENVIRONMENT_OVERRIDE env var.

Consumer guide (REQ-106):
- docs/consumer-guide.md: 'Per-environment deployment' section with 4
  caller-workflow examples (dev/qa/prod/dr), HITL gate structure
  (approve_qa/approve_prod/approve_dr, D-042), interpolation reference table.
- Documents promotion-without-editing + hybrid model (per-env contracts
  OR single contract + env input).

Tests: +40 (test_per_env_contracts.py, test_deploy_workflow_env_input.py,
test_consumer_guide_per_env_section.py). 446 passed; run_ci.sh green;
deploy workflows byte-identical.
2026-07-23 04:34:10 +00:00
Jon Chery ca99241843 verify(P28-38): code review — 1 P0 auto-fixed, 3 P1 fixes, 2 P1 flagged
acdl-ci / Lint (push) Successful in 7s
acdl-ci / Test (push) Successful in 27s
acdl-ci / Platform check-only (offline) (push) Successful in 9s
---ci---
project: acdl
phase: 28-38
milestone: v1.8
status: verify
lessons:
  - P0 fix: pipelines/deploy.yaml stale terraform/spike paths updated to run_platform.sh
  - P1 fix: removed import sys from inside _emit_resource function body
  - P1 fix: removed unused cpu/memory vars in uptime emission
  - P1 fix: decommission consumerRepo now uses GITHUB_REPOSITORY env
---/ci---

P0: deploy.yaml 3 stage commands referenced removed terraform/spike dir.
P1 fixes: import sys, unused vars, consumerRepo env.
P1 flagged: uptime hardcoded subnet/sg, uses ref not bumped to v1.8.
P2 flagged: deploy-uptime flag standalone, pre-v1.8 READMEs missing NFRs.

Tests: 350 passed.
2026-07-22 22:30:49 +00:00
Jon Chery 134f85d2df feat(P34): decommission alias + CMDB validation (REQ-92, REQ-93, REQ-94)
---ci---
project: acdl
phase: 34
milestone: v1.8
status: execute
---/ci---

- DynamoDB acdl-change-requests table added to terraform/platform/main.tf
  (PK changeRequestId, SK submittedAt, SSE via CMK, PITR).
- validate_change_request Lambda action added to contract_ingestor.py:
  queries CMDB, asserts status=approved + consumerRepo match.
- decommission_transform() added to contract_resolver.py: zeroes all
  counts (desired_count, min/max_capacity) + sets deletion_protection=false.
- Decommission mode added to deploy pipeline + both deploy workflows
  (mode: decommission + changeRequestId input). Byte-identical.
- run_platform.sh --decommission flag: validates CR, resolves with
  deletion_protection=false (step 1), then decommission_transform
  (step 2). HITL SRE gates documented.
- docs/consumer-guide.md: new "Decommissioning a stack" section with
  CR request, trigger, 2-step HITL SRE gates, CMK deletion window, uptime.

Tests: +14 (318 -> 332). All pass.
2026-07-22 22:18:28 +00:00
Jon Chery 491ba78768 feat(P33): uptime-kuma primitive + deploy-uptime pipeline stage (REQ-88..91)
---ci---
project: acdl
phase: 33
milestone: v1.8
status: execute
---/ci---

- New uptime L1 primitive (aws:ecs:uptime-service) deploying uptime-kuma
  on ECS Fargate with feature_flag_enabled, monitored_endpoints,
  static_checks, alert_channels (Teams/email/SMS/GitHub issues).
- Adapter emits ECS Fargate task + service when feature_flag_enabled=true;
  emits nothing when false. Container image louislam/uptime-kuma:1.
- New deploy-uptime pipeline stage in pipelines/deploy.yaml (after
  publish-outputs, before comment-outputs). Now 9 stages.
- run_platform.sh --deploy-uptime flag + automatic uptime deployment
  after L2 module (separate state $WORK/uptime-tf). Endpoints from L2
  outputs passed as monitored_endpoints. Feature flag from
  inputs.uptime_enabled (default true).
- scripts/seed_uptime_monitors.py for post-deploy monitor seeding via
  uptime-kuma API.
- Registered in registry.json (14 modules total).

Tests: +6 (312 -> 318). All pass.
2026-07-22 22:15:35 +00:00
Jon Chery 1e4133e11a fix(P30): temp dir isolation + forge-agnostic APIs + static-key override (P1-8, P1-9, S1)
---ci---
project: acdl
phase: 30
milestone: v1.8
status: execute
---/ci---

P1-8: run_platform.sh now emits adapter output to $WORK/tf (per-run temp
dir), not the committed terraform/spike/ directory. The committed
terraform/spike/*.tf files are removed — they were scratch artifacts.
Deploy workflow artifact upload path updated to /tmp/acdl_platform_run_v18/tf/.
P1-9: contract_ingestor.py now reads GITHUB_API_BASE env for forge-agnostic
API URLs. _forge_type() detects GitHub vs Gitea. Search URL is branched
(GitHub uses /search/issues, Gitea uses /repos/{owner}/{repo}/issues).
S1: Deploy workflow configure-aws-credentials step restructured as a single
conditional step. OIDC when no static key (role-to-assume), static-key
when ACDL_AWS_ACCESS_KEY_ID present (access-key-id/secret-access-key inputs).
Both deploy workflows remain byte-identical.

Tests: +8 (292 -> 300). All pass. run_platform.sh --check-only green.
2026-07-22 22:08:23 +00:00
Jon Chery e597c0b089 audit(v1.7): PASS — reconstruction + hygiene + discipline; temp dir name fixed
acdl-ci / Lint (push) Successful in 8s
acdl-ci / Test (push) Successful in 24s
acdl-ci / Platform check-only (offline) (push) Successful in 9s
---ci---
project: acdl
phase: 0
milestone: v1.7
status: audit
---/ci---

v1.7 audit: all checks pass.

Reconstruction: PASS — 122 ---ci--- blocks parsed; v1.7 state
(specify → clarify D-048..D-059 → research → execute P22-27 → complete
REQ-62..75 → verify) matches .ciagent/ files exactly.

.ciagent/ File Discipline: PASS — config.json valid, PROJECT.md has
all required sections + D-048..D-060, ROADMAP.md has 6 phases marked
complete, REQUIREMENTS.md traceability complete (14/14 v1.7 reqs),
ARCHITECTURE.md components match code, PERSONAS.md has lambda-engineer.

Branch Hygiene: 2 stale branches (phase/21-docs-restructure from v1.6,
milestone/v1.0-initial from v1.0) — non-blocking prior-milestone
artifacts. All v1.7 work committed directly to main (v1.1-v1.6 precedent).

Commit Discipline: PASS — 18/18 v1.7 commits have ---ci--- blocks.
0 unresolved escalations (2 prior audit commits have 'escalation' in
subject but are resolved audit actions).

Stale References: 0 stale references outside .ciagent/ (historical
narrative in .ciagent/ records pre-v1.6 dir structure acdl_platform/
modules-ir/ — these are verbatim historical records, not stale in v1.7
scope). Fixed 1 cosmetic temp dir name (acdl_platform_run →
acdl_platform_run_v17 in run_platform.sh).

Tests: 275 passed. CI pipeline green.
2026-07-22 21:26:40 +00:00
Jon Chery f2230edae0 fix(P26): generalize run_platform.sh check-only assertions for all contracts
The --check-only mode hardcoded static-assets-specific assertions
(stack name == 'static-assets', 'aws_s3_bucket' in main.tf, 'acdl-spike-bucket'
in main.tf). The platform-test.yml integration-test stage runs check-only for
every contracts/*.yaml, so contracts/microservice.yaml would fail the
AssertionError. Replace with generic structural checks valid for any contract.

verify(P0): code review — correctness

---ci---
phase: 26
milestone: v1.7
status: verify
lessons:
  - P0 fix applied: run_platform.sh check-only hardcoded static-assets assertions broke for non-static-assets contracts (microservice); generalized to structural checks
---/ci---
2026-07-22 21:05:12 +00:00
Jon Chery 90be5839ab feat(P26): 3 platform pipelines + release job with semver/tag updates
Phase 26 — platform-pipelines-and-release-automation:

- platform-test.yml: PR pipeline (lint + unit-test + integration-test +
  schema-validation) replacing ci.yml for PRs; integration-test runs
  run_platform.sh --check-only for every contracts/*.yaml
- primitives-plan.yml: PR pipeline with matrix over all 9 L1 primitives
  (s3, vpc, ecs-cluster, ecs-service, iam-role, alb, ecr, cloudfront, waf)
- patterns-plan.yml: PR pipeline with matrix over all 2 L2 modules
  (static-assets, microservice)
- release.yml: push-to-main pipeline computing next semver tag (PATCH for
  regular phases, MINOR for milestone completions), updating floating
  MAJOR.MINOR + MAJOR tags, and creating GitHub releases
- run_primitive_plan.sh: plan-only/check-only runner for a single L1
  primitive (adapter compile + structure validation offline)
- run_pattern_plan.sh: plan-only/check-only runner for a single L2 pattern
  (environment check + contract validate + resolve + adapter + structure
  validation offline)
- contracts/microservice.yaml: sample consumer contract for the
  microservice L2 module (schema-compliant scalar inputs)
- instance.json for 8 L1 primitives (vpc, ecs-cluster, ecs-service,
  iam-role, alb, ecr, cloudfront, waf) so the primitives-plan matrix can
  run the adapter offline; s3 already had one
- tests/test_release_logic.py: unit test for semver computation
  (PATCH bump, MINOR bump on milestone, floating tag format)
- tests/test_pipeline_contract.py: 19 new tests validating the 4 platform
  workflows exist and conform (stages, matrices, triggers, permissions)

DEVIATION: The microservice pattern (run_pattern_plan.sh --check-only
microservice + run_platform.sh --check-only contracts/microservice.yaml)
fails at the adapter stage due to a pre-existing resolver ref-id mismatch
for multi-resource L1s (resolver emits ref:vpc.subnet_ids but the expanded
resource id is vpc-subnet). This predates Phase 26 and is out of scope for
pipeline automation; the static-assets pattern passes end-to-end. The
microservice contract is schema-valid and resolves correctly (11
resources); only the adapter compilation of multi-resource L1 refs fails.

VERIFICATION:
- bash scripts/run_ci.sh: PASS (lint + test + check-only)
- python3 -m pytest tests/ -v: 266 passed
- bash scripts/run_primitive_plan.sh --check-only s3: PASS
- bash scripts/run_pattern_plan.sh --check-only static-assets: PASS
- All 9 primitives pass run_primitive_plan.sh --check-only
- All instance.json validate against stack.schema.json

---ci---
project: acdl
phase: 26
milestone: v1.7
status: execute
---/ci---
2026-07-22 20:13:36 +00:00
Jon Chery 4fe794c7a4 feat(P25): deploy outputs (SSM + PR comment) + error reporting via Lambda + stage comments
---ci---
project: acdl
phase: 25
milestone: v1.7
status: execute
---/ci---
2026-07-22 20:08:30 +00:00
Jon Chery 07c0349131 feat(P24): platform Lambda + DynamoDB contract ingestion + cross-account IAM
Phase 24 — platform-lambda-and-contract-ingestion.

- core/lambda/contract_ingestor.py: AWS Lambda handler invoked via Function
  URL (IAM auth). Parses JSON body, validates required fields, writes the
  contract to DynamoDB table acdl-contracts (PK consumerRepo, SK
  contractId#submittedAt, status submitted, ISO-8601 submittedAt). report_error
  action is a stub returning "error_report_prepared"; GitHub issue creation is
  wired in Phase 25. Returns 400 on missing fields / unknown action, 500 on
  error. Table name + GitHub-token secret ID come from env (set by Terraform).
- core/lambda/__init__.py: empty package marker.
- terraform/platform/main.tf: DynamoDB acdl-contracts (PITR, SSE via CMK),
  KMS customer-managed key with alias/acdl-platform, Secrets Manager secret
  acdl/github-token, IAM execution role (DynamoDB write + Secrets Manager read +
  KMS decrypt + CloudWatch logs), Lambda acdl-contract-ingestor (Python 3.12,
  handler contract_ingestor.lambda_handler), Function URL with AWS_IAM auth.
  State key platform/terraform.tfstate (distinct from spike/microservice).
- terraform/platform/README.md: documents what it deploys, the state key, how
  to apply, and the cross-account invocation model.
- terraform/platform/consumer_invoke_policy.json: ABAC-scoped policy template
  applied to consumer deploy roles during onboarding; grants
  lambda:InvokeFunctionUrl conditioned on aws:PrincipalTag/acdl:owner ==
  consumerRepo.
- tests/test_contract_ingestor.py: 11 tests (moto-backed DynamoDB mock) covering
  submit_contract put_item shape, report_error stub, missing-field 400, unknown
  action 400, the lambda_handler wrapper with a Function-URL-style event, dict
  body, default action, and internal-error 500.
- docs/environments/index.md: new section documenting the cross-account
  contract-ingestion grant (one-way consumer→platform, D-051) and that
  onboarding now also grants the consumer deploy role InvokeFunctionUrl.
- scripts/run_ci.sh, pipelines/ci.yaml, .gitea/workflows/ci.yml,
  .github/workflows/ci.yml: add core/lambda/contract_ingestor.py to the lint
  py_compile list. The two workflow YAMLs remain byte-identical.

Verification: scripts/run_ci.sh passes all 3 stages (lint/test/check-only);
python3 -m pytest tests/ -v passes all 213 tests (11 new + 202 existing).

---ci---
project: acdl
phase: 24
milestone: v1.7
status: execute
---/ci---
2026-07-22 20:04:10 +00:00
Jon Chery 1fd37a2843 feat(P23): tagging standard + Wiz adapter + Kyverno adapter
Phase 23 (v1.7) — tagging standards and security adapters.

* schemas/tagging-standard.json (D-054): canonical required-tags schema
  (acdl:owner, acdl:contract, acdl:environment, acdl:cost-center).
* adapters/terraform/policy/custom_rules/acdl_tagging.py: Checkov custom
  rule (ACDL_TAG_NAMING) loaded via --external-checks-dir; closes D-043
  (synthetic SKIPPED record replaced by real PASS/FAIL records).
* checkov_adapter.py: removed _emit_tag_naming_skipped(), added
  ACDL_TAG_NAMING to RULE_MAP, updated docstring.
* scripts/run_platform.sh: both Checkov invocations pass
  --external-checks-dir adapters/terraform/policy/custom_rules/.
* adapters/wiz/ (D-052): Wiz adapter translating issue records to
  PolicyCheckResult (engine: "wiz"); graceful degradation emits
  WIZ_NOT_CONFIGURED SKIPPED when unconfigured; is_configured() gate.
* adapters/kyverno/ (D-053): Kyverno adapter translating PolicyReport
  results to PolicyCheckResult (engine: "kyverno"); ready but inactive
  for Terraform-only stacks; 3 sample ClusterPolicies in policies/.
* schemas/policy_check_result.schema.json: engine enum += "wiz".
* tests: fixtures + test_wiz_adapter.py (8 tests) + test_kyverno_adapter.py
  (13 tests); updated test_checkov_adapter.py to not expect the removed
  synthetic ACDL_TAG_NAMING SKIPPED record.
* scripts/run_ci.sh: lint stage compiles the new adapter modules.

202 tests pass; CI pipeline OK (lint + test + check-only).

Deviations:
- Wiz adapt() had an AttributeError on bare-list top-level input
  (data.get() on a list); fixed to dispatch on isinstance(data, list)
  before calling .get(). No spec change — bare-list handling is implied
  by the original docstring's "data if isinstance(data, list)" branch.
- Kyverno _to_pcr({}) defaults result to "skipped" (entry.get("result",
  "skip") -> "skip"), not "error"; test expectation corrected. Added an
  explicit unknown-result-string test to cover the "error" fallback.

---ci---
project: acdl
phase: 23
milestone: v1.7
status: execute
---/ci---
2026-07-22 20:00:46 +00:00
Jon Chery dca35c78ec feat(P22): rename static-asset→static-assets + cloudfront/waf primitives + production stack + @v1.6 bump
---ci---
phase: 22
title: rename-and-production-static-assets-stack
status: complete
verification:
  - scripts/run_ci.sh: PASS (CI PIPELINE OK)
  - python3 -m pytest tests/ -v: 175 passed
  - scripts/run_platform.sh --check-only: PASS (PLATFORM CHECK OK)
  - grep -R "static-asset[^s]" . (excl .git/): 0 hits
  - grep -R "static-asset$" . (excl .git/): 0 hits
  - floating git tags v1.6 + v1 point at v1.6.0 (a90a756)
changed_files:
  - Task 1 (rename): contracts/static-asset.yaml→static-assets.yaml (git mv); modules/l2/static-asset→static-assets (git mv); sed replaceAll static-asset→static-assets in 22 files (README, docs, scripts/run_platform.sh, pipelines/deploy.yaml, modules/registry.json, tests/*, .ciagent/* historical narrative)
  - Task 2 (cloudfront primitive): modules/l1/cloudfront/interface.json + README.md
  - Task 3 (waf primitive): modules/l1/waf/interface.json + README.md
  - Task 4 (registry): modules/registry.json (+cloudfront, +waf, static-assets renamed)
  - Task 5 (augment static-assets): modules/l2/static-assets/composition.json (s3+cloudfront+waf, depth 1); modules/l1/s3/interface.json +instance.json (+bucket_regional_domain_name output); modules/l2/static-assets/README.md (production stack docs)
  - Task 6 (adapter): adapters/terraform/adapter.py (+TYPE_MAP/INPUT_MAP/OUTPUT_MAP for cloudfront distribution+OAC+wafv2 webacl; special handling in _emit_resource for OAC defaults, distribution origin/cache_behavior/restrictions/viewer_certificate/web_acl_id, waf scope/default_action/visibility_config/managed rules)
  - Task 7 (contract schema): no change needed (generic inputs object; new module names match ^[a-z][a-z0-9-]*$)
  - Task 8 (@v1.6 bump): contracts/static-assets.yaml, .gitea/.github/workflows/deploy.yml (ref: v1.6 + header comments), docs/consumer-guide.md, docs/contracts/index.md, docs/pipeline/versioning.md, docs/pipeline/index.md, docs/architecture.md, README.md, modules/l2/microservice/README.md, tests/test_environment_check.py, tests/test_pipeline_contract.py
  - Task 9 (floating tags): git tag -f v1.6 v1.6.0; git tag -f v1 v1.6.0
  - Task 10 (tests): tests/test_adapter.py (registry 11 entries/9 L1/2 L2; cloudfront+waf type map tests; TestS3Output bucket_regional_domain_name; TestStaticAssetsStack 4 tests); tests/test_contract_resolver.py (+s3/cloudfront/waf resource assertions)
generated:
  - terraform/spike/main.tf + terraform.tf (regenerated by run_platform.sh --check-only; reflect static-assets production stack + backend key spike/static-assets/)
notes:
  - D-048 full rewrite of .ciagent/ historical narrative (verbatim phase descriptions, REQ-25/27/50, D-036) — produces intentional tautologies (e.g. "Rename static-assets → static-assets") per the decision to override the v1.6 preservation precedent.
  - cloudfront interface.json resources array ordered distribution-first so the resolver (first-match wire resolution) routes bucket_regional_domain_name/waf_web_acl_arn/region to the distribution; the OAC gets adapter-provided defaults (name=acdl-oac, origin_type=s3, signing_behavior=always).
  - .ciagent/ @v1.4 references left as historical record (D-048 scope was static-asset rename only; @v1.4 is historical narrative of Phase 20).
  - s3 OUTPUT_MAP bucket_regional_domain_name not added (identity fallback in adapt() already handles it; OUTPUT_MAP documents non-identity mappings only).
---ci---
2026-07-22 19:56:52 +00:00
Jon Chery 4e495e5648 feat(P21): environments concept + onboarding scaffold (REQ-61)
---ci---
project: acdl
phase: 21
milestone: v1.6
status: execute
---/ci---

Introduce platform-managed environments: a consumer does not provide an
AWS account, VPC, subnet, S3 state bucket, or runner key. A named
environment is a platform-owned bundle of account + network + state
backend + IAM role (surfaced via ABAC), selected by name in the contract.

Scaffold:
- core/environments/dev.json (sample dev env definition)
- core/environments/README.md (how envs are used + how to add one)
- core/environment_check.py (reads a contract's environment field,
  looks up core/environments/<name>.json, prints a friendly onboarding
  prompt when none exists, exits non-zero)
- scripts/run_platform.sh: Step 0 calls environment_check.py before
  contract validation; a missing env halts the pipeline with the
  onboarding prompt
- tests/test_environment_check.py: 12 tests (dev bound, missing env ->
  onboarding prompt, onboarding message lists provisions, contract
  paths, wire-in, check-only still passes)

Tests: 166 pass (154 + 12 new).
2026-07-22 18:24:02 +00:00
Jon Chery b758a7c242 refactor(P21): rename acdl_platform/ -> core/ (REQ-53)
---ci---
project: acdl
phase: 21
milestone: v1.6
status: execute
---/ci---

Rename the acdl_platform/ package to core/ across the directory, all
imports in tests/scripts/pipelines/workflows, and doc references. The
package is imported as core.confidence_signal / core.contract_resolver /
core.outbox_writer. The deploy workflow's platform-repo checkout dir is
renamed acdl-platform/ -> platform/ (workspace path, not the python
package). Both .gitea + .github workflows stay byte-identical.

Note: the original target name 'platform/' shadows Python's stdlib
platform module (pytest's import uuid -> platform.system() fails when
the repo root is on sys.path, which every test does). 'core/' avoids
the clash while honoring the intent (drop the verbose acdl_platform).

Tests: 154 pass. run_ci.sh green.
2026-07-22 18:21:12 +00:00
Jon Chery f68f85c9fd review(v1.5): READY TO SHIP — multi-persona code review
acdl-ci / Lint (push) Successful in 7s
acdl-ci / Test (push) Successful in 15s
acdl-ci / Platform check-only (offline) (push) Successful in 9s
---ci---
project: acdl
phase: 20
milestone: v1.5
status: review
verdict: READY TO SHIP
p0: 1 (fixed — contract path resolution in deploy workflow)
p1: 6 (flagged post-hoc)
---/ci---

Multi-persona review of v1.5 phase 20 (docs + reusable deploy workflow).

P0 (blocking) — AUTO-FIXED:
- C1: scripts/run_platform.sh contract path resolution broken in deploy
  workflow. The reusable workflow invokes run_platform.sh from the consumer
  workspace root with a relative contract path (.acdl/contract.yaml), but
  run_platform.sh does `cd "$ROOT"` (platform repo) early, so the relative
  path resolved against the platform repo and the pipeline could never run.
  Fix (commit 75c2274): capture CALLER_CWD before cd "$ROOT"; resolve
  caller-supplied relative paths against CALLER_CWD; default no-arg contract
  stays relative to ROOT (preserves platform-local CI). Reproduced pre-fix;
  verified post-fix.

P1 (important) — FLAGGED FOR POST-HOC REVIEW (do not block ship):
- C2: ref: v1.4 in the deploy workflow platform checkout — no v1.4 tag exists
  (only v1.4.0 / v1.4.1). Operator must create a floating v1.4 tag or change
  the ref to v1.4.1.
- C3: modules/l2/{static-asset,microservice}/README.md still use @v1 in their
  Usage examples; missed by the v1.4 bump.
- S1: static-key override is not wired. ACDL_AWS_* env vars on the OIDC step
  are not read by aws-actions/configure-aws-credentials@v4 (it reads AWS_*
  or its own access-key/secret-key inputs). The README/CONSUMER_GUIDE claim
  a working override that doesn't function as written. Needs a conditional
  step or renamed env vars + input wiring.
- S2: README overstates ABAC repo:org/repo:ref:... scoping. The workflow
  constructs a numeric role name (github.repository_id); the actual claim
  enforcement lives in the IAM trust policy, not in this workflow.
- T1: no deploy-workflow triggers conformance test (CI workflow has one;
  deploy doesn't). Minor — reusable workflows use workflow_call, not push
  triggers, but the contract's triggers field is then unenforced.
- A1: terraform/spike/terraform.tf uploaded as artifact leaks the AWS account
  ID via the state-backend bucket name. Recommend excluding terraform.tf or
  gating artifact upload to non-public repos.

P2 (nits) — listed for awareness: floating-tag terminology imprecision (M1),
  header comment "Gitea Actions" in the GitHub copy (M2, intentional byte-
  identical), pip install split (P1-perf), comment drift in pipelines/deploy.yaml
  header (C4), module README internal inconsistency (C5).

Verdict: READY TO SHIP. The one P0 is fixed. The 6 P1s are post-hoc items —
the deploy workflow is a scaffold whose first real consumer run requires
operator setup (tag, IAM role, secrets) that gates go-live. The P1s should
be addressed before any consumer invokes uses: acdl/.gitea/workflows/
deploy.yml@v1.4 in earnest.

Tests: 154 pass (19 new). run_ci.sh green.
2026-07-22 17:24:28 +00:00
Jon Chery 75c227429a fix(P20): resolve consumer contract path against caller CWD (P0 review fix)
The reusable deploy workflow invokes run_platform.sh from the CONSUMER
repo's workspace root with a relative contract path (e.g.
.acdl/contract.yaml). run_platform.sh does `cd "$ROOT"` (the platform
repo) early in its lifecycle, which caused the relative contract path to
resolve against the platform repo (acdl-platform/) instead of the
consumer repo — the `[ -f "$CONTRACT" ]` check then failed with
"contract file missing" and the pipeline could never run.

Fix: capture CALLER_CWD before `cd "$ROOT"` and resolve a caller-supplied
relative contract path against CALLER_CWD. The default contract
(contracts/static-asset.yaml, used only when no contract is supplied)
remains relative to ROOT, preserving platform-local CI behavior.

Reproduced pre-fix: bash acdl-platform/scripts/run_platform.sh --check-only
.acdl/contract.yaml (from a consumer workspace) -> "contract file missing".
Verified post-fix: same invocation reads the consumer contract correctly.

verify(P0): code review — correctness

---ci---
phase: 20
milestone: v1.5
status: verify
lessons:
  - P0 fix applied: run_platform.sh now resolves relative contract path
    against caller CWD (deploy workflow contract path was broken)
---/ci---
2026-07-22 17:23:00 +00:00
Jon Chery 895a2f3806 docs(P20): specify phase 20 — consumer happy path + reusable deploy workflow (v1.5)
---ci---
project: acdl
phase: 20
milestone: v1.5
status: specify
---/ci---

Add v1.5 milestone to ROADMAP.md + REQUIREMENTS.md. Phase 20 covers
REQ-46 (README consumer model + mermaid + L3B/spike scrub), REQ-47
(generic CONSUMER_GUIDE.md + versioned uses: + consumer-scoped prereqs
+ run-time platform fetch), REQ-48 (zero-trust OIDC/ABAC credentials +
static-key override + daily rotation), REQ-49 (reusable byte-identical
deploy.yml Gitea+GitHub implementing pipelines/deploy.yaml), REQ-50
(contracts/static-asset.yaml @v1.4), REQ-51 (deploy-workflow conformance
tests). Update config.json milestone to v1.5.
2026-07-22 17:09:23 +00:00
Jon Chery e050e65158 feat(P19): central pipeline contract + shell reproducibility + output streaming (v1.4.1)
acdl-ci / Lint (push) Successful in 8s
acdl-ci / Test (push) Successful in 14s
acdl-ci / Platform check-only (offline) (push) Successful in 9s
---ci---
project: acdl
phase: 19
milestone: v1.4
status: execute
---

Add declarative pipeline contract (schemas/pipeline.schema.json +
pipelines/ci.yaml) as single source of truth for both Gitea Actions (dev)
and GitHub Actions (production) workflows. Both workflow files are
byte-identical and validated against the contract by 32 new tests.

Add scripts/run_ci.sh for shell reproducibility — mirrors the CI pipeline
locally (lint → test → check-only), exits 0 with 'CI PIPELINE OK'.

Update scripts/run_platform.sh to stream output by default: terraform
init/validate/plan via tee, Checkov compliance results with per-record
severity/rule/pass-fail, and emitted Terraform in --check-only. New
--quiet flag for log-only mode.

Requirements: REQ-43 (central pipeline contract), REQ-44 (shell
reproducibility), REQ-45 (output streaming). 122 tests pass (90 + 32).
2026-07-22 15:10:54 +00:00
Jon Chery 1598c54a8b feat(P18): testing + CI/CD pipelines - pytest suite, check-only mode, Gitea + GitHub workflows (v1.3.2)
90 offline tests covering adapter, confidence_signal, checkov_adapter,
outbox_writer, and pipeline integration. Identical CI/CD workflows for
Gitea Actions (dev) and GitHub Actions (production). New --check-only
mode for run_platform.sh (offline, no AWS).

---ci---
project: acdl
phase: 18
milestone: v1.3
status: verify
---/ci---
2026-07-22 14:26:11 +00:00
Jon Chery 3508671377 refactor(modules): remove thin-composition layer; rewrite all module READMEs
The L2 thin-composition layer (composition.json + contract_resolver.py +
contract schema + sample contracts) has been removed completely. The
implementation was unsatisfactory and is deferred for a later redesign.

- Delete: composition.json x2, contract_resolver.py, contracts/ x2,
  contract.schema.json
- Patch: run_platform.sh now loads a pre-existing IR instance instead of
  resolving a contract (the downstream adapter/checkov/confidence/outbox
  pipeline is unchanged)
- Prune: L2 entries removed from registry.json (L1 entries unchanged)
- Rewrite: all 7 L1 module READMEs in plain language (no jargon), each
  with Resources/Inputs/Outputs/Usage/Compliance-extension-points/Versioning
  sections derived from interface.json
- Add: 2 L2 placeholder READMEs noting the composition is under redesign
- Add: modules-ir/README.md catalog index + README-TEMPLATE.md

---ci---
project: acdl
phase: 17
milestone: v1.3
status: execute
---/ci---
2026-07-22 13:54:40 +00:00
Jon Chery 64d35c78e6 docs(P16): plan-as-execute + verify (v1.2.6, capstone)
---ci---
project: acdl
phase: 16
milestone: v1.2
status: verify
verdict: VERIFIED
requirements:
  covered: [REQ-35]
  partial: []
blocker:
  - P0-IAM: terraform apply blocked; operator must push spike_runner_policy.json (carried from Phase 15)
---/ci---

Phase 16 plan-as-execute + verify. scripts/verify_phase16.sh green (11
assertions). Capstone: full v1.2 platform verified end-to-end up to the
IAM-blocked terraform apply. MILESTONE_CAPSTONE_VERIFIED evidence event
written to outbox. v1.1 S3 regression passes. Ready to ship v1.2.6 +
enter the COMPLETE gate.
2026-07-21 22:24:20 +00:00
Jon Chery 699aa542df docs(P15): plan-as-execute + verify (v1.2.5, PARTIAL — terraform apply blocked by IAM)
---ci---
project: acdl
phase: 15
milestone: v1.2
status: verify
verdict: PARTIAL
requirements:
  covered: [REQ-34]
  partial: [REQ-33]
blocker:
  - id: P0-IAM
    description: terraform apply fails with AccessDenied on ECS/ECR/IAM/EC2 — live spike_runner_policy.json not pushed (root key deactivated per D-034)
    unblock: operator runs create_iam_user.py with root/admin creds to push the expanded policy, then terraform apply succeeds (plan valid, 13 to add)
---/ci---

Phase 15 plan-as-execute + verify. PARTIAL: terraform apply blocked by IAM.
- Consumer microservice content authored (app.py + Dockerfile + README.md).
- Docker image acdl-microservice:latest built.
- Adapter fixed: ref emission (bare), JSON-string jsonencode, ECS service
  network_configuration/load_balancer/desired_count/launch_type/task_definition,
  listener default_action/load_balancer_arn, target group target_type/vpc_id/protocol,
  VPC tags (not name), IGW + route table association, managed_policy_arns list.
- L1 fixes: l1-ecs-service (removed port from service sub-resource),
  l1-vpc (added intra_refs, removed igw_id output).
- Resolver: intra_refs resolution (refs between sub-resources of same L1).
- terraform validate + plan succeed (13 to add).
- terraform apply BLOCKED (AccessDenied — live IAM policy not updated).
- Evidence event TERRAFORM_APPLY_BLOCKED written to DynamoDB outbox.
- v1.1 S3 regression: byte-identical.
Ready to ship v1.2.5 (partial).
2026-07-21 22:21:36 +00:00
Jon Chery d103a37419 docs(P14): plan-as-execute + verify (v1.2.4)
---ci---
project: acdl
phase: 14
milestone: v1.2
status: verify
verdict: VERIFIED
requirements:
  covered: [REQ-32]
---/ci---

Phase 14 plan-as-execute + verify. scripts/verify_phase14.sh green.
l2-microservice composition (6 L1s, 2 wire kinds); contract schema
extended (inputs allow objects + healthcheck); resolver extended
(array-form wires, child->child refs, multi-resource L1 expansion);
adapter extended (ref: interpolation translation). v1.2 IR: 11 resources.
v1.1 S3 regression byte-identical. Ready to ship v1.2.4.
2026-07-21 21:12:17 +00:00
Jon Chery 4ed2542ecf docs(P13): plan-as-execute + verify (v1.2.3)
---ci---
project: acdl
phase: 13
milestone: v1.2
status: verify
verdict: VERIFIED
requirements:
  covered: [REQ-31]
---/ci---

Phase 13 plan-as-execute + verify. scripts/verify_phase13.sh green.
6 ECS L1s authored + registered (l1-vpc, l1-ecs-cluster, l1-ecs-service,
l1-iam-role, l1-alb, l1-ecr). Adapter generalized to table-driven
TYPE_MAP (12 IR types) + INPUT_MAP + OUTPUT_MAP. S3 regression: the v1.1
spike l1-s3 produces byte-identical main.tf. Ready to ship v1.2.3.
2026-07-21 21:05:48 +00:00
Jon Chery 0fea29cdbb docs(P12): plan-as-execute + verify (v1.2.2)
---ci---
project: acdl
phase: 12
milestone: v1.2
status: verify
verdict: VERIFIED
requirements:
  covered: [REQ-30]
---/ci---

Phase 12 plan-as-execute + verify. scripts/verify_phase12.sh green (22
assertions). All Wave 1 + Wave 2 tasks complete:
- T-12.1: run_spike_*.sh -> run_platform.sh (D-048, --plan-only flag)
- T-12.2: spike_runner_policy.json expanded (ECS + ECR + ELB + IAM + EC2)
- T-12.3: idempotency documented in bootstrap scripts
- T-12.4: P1-1 redacted (no live AWS key IDs in .ciagent/)
- T-12.5: P1-B fixed (PERSONAS.md platform/registry -> modules-ir/registry.json)
Subagent confirmed run_platform.sh --plan-only runs against real AWS, exit 0.
Ready to ship v1.2.2.
2026-07-21 21:01:51 +00:00
Jon Chery 81c6e3995e docs(P11): plan + verify + verify_phase11.sh (v1.2.1)
---ci---
project: acdl
phase: 11
milestone: v1.2
status: verify
verdict: VERIFIED
requirements:
  covered: [REQ-29]
---/ci---

Phase 11 plan-as-execute + verify. scripts/verify_phase11.sh green (24
assertions). Plan + VERIFY committed. Ready to ship v1.2.1.
2026-07-21 20:57:45 +00:00
Jon Chery e29319a720 phase: 10, status: plan-as-execute, persona: lead-developer, task: T-10.9
---ci---
project: acdl
phase: 10
milestone: v1.1
status: plan-as-execute
persona: lead-developer
task: T-10.9
requirements.covered: [REQ-28]
---/ci---

Wave 4: scripts/verify_phase10.sh - the capstone gate (8 checks).

(a) composition.json shape (l2 depth=1 one child l1-s3@1.0.0)
(b) spike.yaml validates against contract schema
(c) resolver py_compiles + emits IR validating against ir.schema.json
(d) adapter py_compiles + emits main.tf with aws_s3_bucket
(e) run_spike_e2e.sh exits 0 (full pipeline end-to-end)
(f) confidence band is pass for dev
(g) outbox item present (query DynamoDB by PK)
(h) REQ-28: the adapter is the only substrate-specific code. acdl_platform/
    Python has no aws_s3_bucket; modules-ir/ JSON has no aws_s3_bucket as a
    resource-type value (docs/descriptions excluded — they reference the
    mapping, which is allowed); adapters/terraform/ has aws_s3_bucket (it
    should — it is the substrate-specific code). The IR commitments hold.

VERIFIED - Phase 10: L2 + contract-e2e; IR commitments hold (REQ-28).
2026-07-21 19:38:49 +00:00
Jon Chery 7afaa34b60 phase: 10, status: plan-as-execute, persona: backend-engineer+security-engineer+platform-engineer, task: T-10.8
---ci---
project: acdl
phase: 10
milestone: v1.1
status: plan-as-execute
persona: backend-engineer+security-engineer+platform-engineer
task: T-10.8
requirements.covered: [REQ-27]
---/ci---

Wave 3: the end-to-end spike pipeline orchestrator (capstone).

scripts/run_spike_e2e.sh - 8-step pipeline:
1+2. contract_resolver.py validates + resolves contracts/spike.yaml -> IR
3. adapter.py compiles IR -> terraform/spike/*.tf (regenerated)
4. terraform init -reconfigure -lock=false + validate + plan -lock=false
   (real AWS; 1 to add, 0 to change, 0 to destroy)
5. checkov on terraform/spike/main.tf (6 failed, 5 passed)
6. checkov_adapter.py -> 12 PolicyCheckResult records (incl ACDL_TAG_NAMING SKIPPED)
7. confidence_signal.py compute -> score 0.8, band pass (dev >= 0.50)
8. outbox_writer.py -> DynamoDB outbox put_item (contractId, hash chain GENESIS)

EXECUTE: ran against real AWS via the rotated spike key (D-039).
SPIKE E2E OK - the full pipeline completes end-to-end. Regenerated
terraform/spike/{main.tf,terraform.tf} committed (backend key now
spike/l2-static-asset/terraform.tfstate per D-P10-1; used -reconfigure
because the backend key changed from the Phase 09 l1-s3 spike).
2026-07-21 19:36:41 +00:00
Jon Chery 3936bf460a phase: 9, status: plan-as-execute, persona: lead-developer, task: T-9.8
---ci---
project: acdl
phase: 9
milestone: v1.1
status: plan-as-execute
persona: lead-developer
task: T-9.8
---/ci---

Wave 4: scripts/verify_phase09.sh.

8 checks: all 9 deliverable files exist; spike_instance.json validates
against ir.schema.json; registry has l1-s3@1.0.0; adapter py_compiles +
emits aws_s3_bucket + bucket_arn output; terraform/spike/*.tf match a
fresh adapter run (D-P09-4 reproducibility, diff); no AKIA in committed
files (excluding .terraform/ provider binaries which contain AKIA
bytes - gitignored anyway); secrets + TF working artifacts gitignored;
real terraform plan against AWS succeeds (rotated spike key, plan-only,
-lock=false per D-P09-1).

VERIFIED - Phase 09: IR + l1-s3 + Terraform adapter; real terraform
plan succeeds.
2026-07-21 19:16:33 +00:00
Jon Chery 3070a68e1d phase: 9, status: plan-as-execute, persona: platform-engineer, task: T-9.5..T-9.7+T-9.9
---ci---
project: acdl
phase: 9
milestone: v1.1
status: plan-as-execute
persona: platform-engineer
task: [T-9.5, T-9.6, T-9.7, T-9.9]
requirements.covered: [REQ-26]
---/ci---

Waves 2+3: Terraform adapter + generated spike TF + run script.

- T-9.5: adapters/terraform/adapter.py - compiles an IR instance to a
  Terraform root module. TYPE_MAP {aws:s3:bucket -> aws_s3_bucket}. Thin
  layer; does not own L1 content. Emits main.tf (resource + outputs) +
  terraform.tf (required_version/providers + S3 backend, NO
  dynamodb_table per D-P09-1) + providers.tf (aws provider region from
  the IR). CLI: adapter.py <ir_instance.json> <out_dir>.

- T-9.6: terraform/spike/{main.tf,terraform.tf,providers.tf} - generated
  by running the adapter against modules-ir/l1/l1-s3/spike_instance.json.
  Committed so verify_phase09.sh can validate/plan without regenerating
  (D-P09-4); the verify script will regenerate + diff to prove
  reproducibility.

- T-9.7: scripts/run_spike_plan.sh - loads rotated spike key from
  gitignored .env.secrets, exports AWS env vars, cd terraform/spike,
  terraform init -lock=false, terraform validate, terraform plan
  -lock=false -out=tfplan. Plan-only; no apply.

- T-9.9: .gitignore - add terraform/spike/.terraform/ + tfplan +
  *.tfstate*.

EXECUTE: ran scripts/run_spike_plan.sh against real AWS via the rotated
spike key (D-039). terraform plan succeeded: 1 to add (the S3 bucket),
outputs computed. One non-blocking deprecation warning (aws_s3_bucket
versioning block -> use aws_s3_bucket_versioning in v1.2). No long-lived
credential in the workflow (key loaded from .env.secrets at runtime).
2026-07-21 19:15:10 +00:00
Jon Chery d28630d1f1 phase: 8, status: plan-as-execute, persona: lead-developer, task: T-8.8
---ci---
project: acdl
phase: 8
milestone: v1.1
status: plan-as-execute
persona: lead-developer
task: T-8.8
requirements.covered: [REQ-23]
---/ci---

Wave 5: execute the bootstrap against real AWS + fix verify script.

- Created S3 bucket acdl-tfstate-581513795199-us-east-1 (versioning
  enabled) + DynamoDB table acdl-outbox (PAY_PER_REQUEST, PK contractId,
  SK eventType#eventTs) via create_state_backend.py.
- Created IAM user acdl-spike-runner + scoped inline policy
  (DenyEverythingElse) + initial key via create_iam_user.py.
- Rotated the spike key via rotate_spike_key.sh: old key deleted, new
  key in gitignored .env.secrets (chmod 600).
- verify_phase08.sh fixes: (a) heredoc python instead of -c to avoid
  bash quoting issues; (b) Check 4 uses the bootstrap root key to
  inspect IAM (the spike key is least-privilege and cannot iam:GetUser
  - that itself confirms the policy denies non-granted actions); (c)
  get_user_policy returns PolicyDocument as a dict, not a URL-encoded
  string in this boto3 version - handle both.
- VERIFIED: caller identity is acdl-spike-runner (not root), S3 + DDB +
  IAM user + Deny-everything-else policy all present, .env.secrets +
  .bootstrap_state.json gitignored.

D-034 closure: user must manually rotate the root key in the AWS IAM
console now (the bootstrap root key has served its one-shot purpose).
2026-07-21 19:01:58 +00:00
Jon Chery 1d5c4d2ae7 phase: 8, status: plan-as-execute, persona: platform-engineer+lead-developer, task: T-8.5..T-8.7
---ci---
project: acdl
phase: 8
milestone: v1.1
status: plan-as-execute
persona: platform-engineer+lead-developer
task: [T-8.5, T-8.6, T-8.7]
requirements.covered: [REQ-23]
---/ci---

Waves 3+4: rotation script + verify script + README + .gitignore.

- T-8.5 (platform): scripts/rotate_spike_key.sh - boto3 with bootstrap
  root key from env (ACDL_BOOTSTRAP_AWS_*); creates new key for
  acdl-spike-runner, deactivates+deletes old, writes new to gitignored
  .env.secrets (chmod 600); idempotent (re-run ends with exactly 1
  active key); optional Gitea secret upload if ACDL_GITEA_TOKEN set;
  does NOT rotate the root key (D-034 closure = manual user step).

- T-8.6 (lead): scripts/verify_phase08.sh - loads rotated key from
  .env.secrets, asserts caller identity is acdl-spike-runner (not root),
  S3 bucket + DynamoDB table + IAM user + scoped policy with
  DenyEverythingElse all present, .env.secrets + .bootstrap_state.json
  gitignored. Uses heredoc python to avoid bash quoting issues.

- T-8.7 (lead): terraform/bootstrap/README.md runbook (6 steps incl.
  manual D-034 root-key rotation) + .gitignore (.env.secrets +
  .bootstrap_state.json). Spike vs v1.2 boundary table.

bash -n + gitignore checks pass.
2026-07-21 19:00:08 +00:00