From 65bf3d84e9d14d8b1132a80a5db202ad19944319 Mon Sep 17 00:00:00 2001 From: CIAgent Date: Thu, 20 Aug 2026 13:14:14 +0000 Subject: [PATCH 1/6] =?UTF-8?q?docs(init):=20validate=20specification=20?= =?UTF-8?q?=E2=80=94=20REQ-372=20leadership=20deck=20(v1.30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.30 status: specify ---/ci--- --- .ciagent/CHECKPOINT.json | 8 +- .ciagent/PROJECT.md | 356 ++++++++++++++++++++++++++++++++++++++- .ciagent/REQUIREMENTS.md | 185 +++++++++++++++++++- 3 files changed, 543 insertions(+), 6 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index adfa24f..422262c 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -4,12 +4,12 @@ "milestone": "v1.30", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-20T11:00:00Z", + "updated_at": "2026-08-20T13:15:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.30", - "milestone_branch": null, - "phase_branch": null, + "milestone_branch": "milestone/v1.30-leadership-deck", + "phase_branch": "phase/00-pre-execution", "tag_line": "v1.29.x", "phase_name": "pre-execution", "milestone_type": "feature", @@ -23,5 +23,5 @@ "branches_deleted": true, "releases_created": true }, - "notes": "v1.29 COMPLETE (v1.28.6, merged to main 9dc5669, 8 Gitea releases ids 803-810). Checkpoint cleared per run.md. v1.30 PDLC Phase 0 intake authored (STATE.md updated 2026-08-20, commit 713ad2e). Initiative: Leadership Presentation Deck (≤7 slides, S&P theme, 18-month CDLC→SDLC→PDLC roadmap). Next: /ci-run to execute v1.30 Phase 0 (SPECIFY→CLARIFY→RESEARCH→PLAN→GRILL)." + "notes": "v1.30 Phase 0 SPECIFY complete. REQ-372.1...12 added to REQUIREMENTS.md. v1.30 milestone section + Slide Content Map appended to PROJECT.md. Tags run on v1.29.x line: v1.29.1 (P0), v1.29.2 (P1), v1.29.3 (P2 = milestone release). Next: CLARIFY (D-241..D-243)." } \ No newline at end of file diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index 09ba903..ee8266d 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -662,4 +662,358 @@ New requirements REQ-354..REQ-369 + REQ-371 + REQ-363b — full text in > milestone release). Milestone branch: > `milestone/v1.29-reposplit-identity`. Phase-by-phase task breakdown, > wave ordering, and persona assignments will live in `.ciagent/PLAN.md`. -> Authoritative resume state: `.ciagent/CHECKPOINT.json`. \ No newline at end of file +> Authoritative resume state: `.ciagent/CHECKPOINT.json`. + +## v1.30 — Single-shot Leadership Deck (active, presented August 2026) + +> **Feature milestone — single-shot PPTX leadership deck.** A +> hand-authored Marp markdown deck rendered via the existing +> `scripts/render_pptx.py` pipeline, presented live to Infrastructure +> & Operations leadership (CTO + VP Technology + Product Management) +> in August 2026, securing architecture endorsement and a November +> 2026 runway to demonstrate Nova's next milestone. The deck is a +> **discrete artifact** (D-241: NOT a compression of the existing +> citizen-developer pitch `nova-autonomous-cloud-delivery-marp.md`, +> which remains untouched). +> +> Tags run on the **v1.29.x** line: `v1.29.1` (P0) → `v1.29.2` (P1 +> execution) → `v1.29.3` (P2 final review = milestone release). +> Milestone branch: `milestone/v1.30-leadership-deck`. Single execution +> phase (P1) — this is a single-shot artifact, not a multi-phase +> build. Authoritative resume state: `.ciagent/CHECKPOINT.json`. +> +> **Source spec:** REQ-372 v1.0 (locked 2026-08-20). Full requirement +> text in `.ciagent/REQUIREMENTS.md` §v1.30. Slide Content Map (the +> source-of-truth for REQ-372.7 content traceability) is reproduced +> verbatim below from the locked spec. + +### v1.30 ID allocations (no collisions with shipped history) + +- **Decisions:** `D-241..D-243` (3 decisions, authored in CLARIFY). + Max existing D = D-240 (v1.29). Next free: D-244. +- **Capabilities:** `CAP-042` (1 capability, appended at ship). + Max existing CAP = CAP-041 (v1.29). Next free: CAP-043. + +### v1.30 Scope (CLARIFY-grounded, full autonomy) + +- **In scope:** one hand-authored Marp source + (`docs/presentations/nova-leadership-deck-marp.md`, ≤7 slides); one + rendered PPTX (`docs/presentations/nova-leadership-deck.pptx` via + the existing `scripts/render_pptx.py`, narrowly extended per + D-242); speaker notes per slide meeting the depth discipline + (REQ-372.4); footer `Nova Platform - Infrastructure & Operations` + on all 7 slides (REQ-372.5); S&P theme tokens only (REQ-372.6); + related-artifacts header comment (REQ-372.9); smoke test + `scripts/check_leadership_deck.sh` runnable on demand, NOT a CI + gate (REQ-372.8); vision `[1]` grounding citations in slides 3/5/7 + speaker notes (REQ-372.12); CAP-042 in STATE.md (REQ-372.10); + D-241 record in PROJECT.md (REQ-372.11). +- **Out of scope (explicit exclusions):** compression/modification of + the existing citizen-developer deck; per-milestone refresh / auto- + regeneration; Marp HTML as a primary deliverable; multi-audience + variants; `publish.yml` integration; live AWS cutover of covered- + reference REQs; coverage floor restoration; S3 Object Lock + provisioning; roadmap authoring (PLAN.md remains source of record); + new CI plumbing. + +### v1.30 Requirements + +Full text in `.ciagent/REQUIREMENTS.md` §v1.30. Summary: + +- **REQ-372.1** — Source markdown exists and is parseable (7 slides, + header comment). +- **REQ-372.2** — PPTX render via existing pipeline (7 slides, no + python-pptx exceptions). +- **REQ-372.3** — Slide count is exactly 7. +- **REQ-372.4** — Speaker notes depth per slide (word bands: 1/2/4/6 + 150–300; 3/5 250–400; 7 200–300). +- **REQ-372.5** — Footer `Nova Platform - Infrastructure & Operations` + on every slide (right-aligned). +- **REQ-372.6** — Only S&P theme tokens `#D6002A`, `#1B1B1B`, + `#FFFFFF`, `#F0F0F0`. +- **REQ-372.7** — Slide-by-slide content matches the Slide Content Map + (visual review). +- **REQ-372.8** — Smoke test `scripts/check_leadership_deck.sh` exits + 0 on pass (asserts a–f). Runnable on demand; NOT a CI gate. +- **REQ-372.9** — Related-artifacts comment in source header. +- **REQ-372.10** — CAP-042 appended to STATE.md at ship. +- **REQ-372.11** — D-241 recorded in PROJECT.md at ship. +- **REQ-372.12** — Vision `[1]` citations in slides 3, 5, 7 speaker + notes (ground to `docs/vision.md`). + +### v1.30 Hard constraints + +- **DO NOT modify** `docs/presentations/nova-autonomous-cloud-delivery-marp.md` + (the citizen-developer pitch). Per D-241, the two decks remain + discrete artifacts. +- **DO NOT add `publish.yml` integration** for this deck. Not tagged + or released via the existing pipeline. +- **DO NOT wire `scripts/check_leadership_deck.sh` as a CI gate.** + Runnable on demand. Single-shot artifact. +- **DO NOT extend the deck beyond 7 slides.** Slide count bound by + REQ-372.3. +- **DO NOT auto-derive future leadership decks** from STATE.md / + NORTH_STAR.md. Every leadership artifact is hand-authored. +- **DO NOT compress the deck for a sub-audience.** Multi-audience + variants are out of scope. +- **DO NOT introduce hex colors** outside the 4 S&P theme tokens. + +### v1.30 Authoring conventions + +- **Marp frontmatter:** `marp: true; theme: default; footer: "Nova + Platform - Infrastructure & Operations"; paginate: false; size: 16:9` +- **Theme tokens (only colors in source):** `#D6002A`, `#1B1B1B`, + `#FFFFFF`, `#F0F0F0` +- **Slide separator:** `---` on its own line +- **Speaker notes:** HTML comments `` within the slide + body, before the next `---` +- **Footer:** exact string `Nova Platform - Infrastructure & + Operations` via the Marp `footer:` directive (and rendered as a + right-aligned textbox per D-242, since python-pptx does not read + the Marp footer directive) +- **Per-slide word-count bands:** slides 1/2/4/6 in 150–300; slides + 3/5 in 250–400; slide 7 in 200–300 +- **Vision grounding:** slides 3, 5, 7 speaker notes must contain at + least one `[1]` citation grounding to the principles, anti-goals, + or tenets in `docs/vision.md` + +### v1.30 Render pipeline (existing — narrowly extended per D-242) + +```bash +python3 scripts/render_pptx.py docs/presentations/nova-leadership-deck-marp.md \ + --output docs/presentations/nova-leadership-deck.pptx +``` + +The existing `scripts/render_pptx.py` is extended to accept an +explicit source `.md` path + `--output` filename (D-242). The source +is authored as `nova-leadership-deck-marp.md` to fit the existing +`-marp.md` pipeline convention; the output is +`nova-leadership-deck.pptx` per spec REQ-372.2. The renderer is also +extended to add a right-aligned footer textbox on every slide (the +python-pptx path does not read the Marp `footer:` directive). + +### v1.30 phase status (live — tag `v1.29.3` = the v1.30 release) + +- **P0** pre-execution → `v1.29.1` (in progress). +- **P1** execution (author + render + smoke test) → `v1.29.2`. +- **P2** final review + audit + milestone ship → `v1.29.3` = the + v1.30 release. + +### v1.30 Slide Content Map (REQ-372.7 traceability reference) + +The PPTX content is fully specified by the slide drafts below. Each +slide carries an exact on-slide body + speaker notes fingerprint. +Smoke test does not assert content strings verbatim (brittle); audit +verifies by visual review against this map. Any drift requires +`CLARIFY`. + +#### Slide 1 — The frictions Nova absorbs + +**On-slide body:** + +> **The friction every delivery team lives today** +> +> *Velocity is up; the coordination surface around each change is up +> faster.* +> +> → Infrastructure is authored by people who don't specialize in +> infrastructure. +> → Every change is gated because one misconfiguration can expose the +> entire estate. +> → Compliance, security, and NFRs are checked late — fueling +> remediation cycles that erode delivery cadence and team morale. +> +> *Nova absorbs all three — owned building blocks, separation of +> concerns, attested compliance up front.* + +**Speaker notes (~270 words):** Three-pattern problem frame grounded +in the binding-constraint claim [1]. Closing distinguishes +**infrastructure patching (Nova's lane)** from **AppSec (application +team's lane)** — Nova is not a remediation tool, not a security +blanket. + +#### Slide 2 — Nova in one frame + +**On-slide body:** + +> **Nova in one frame** +> +> *You already recognize this pattern.* +> +> Every Central IT team curates a golden image for Windows, for Linux, +> for macOS. They own it. They patch it. They ship it. Consumers +> consume it without thinking about what's inside. +> +> Nova plays the same role one layer up — for everything that runs +> your cloud. S3 buckets with SSE-KMS posture. RDS instances with +> deletion protection and PITR. Lambda containers with static ABAC +> binaries. ALBs, ECS services, KMS keys, DynamoDB tables. Each one +> is owned by the platform team, patched by the platform team, +> attested by the platform team, and consumed by anyone who declares a +> contract. +> +> The difference: every primitive is versioned, tested across its +> entire lifecycle, and bounded by policy before any consumer ever +> touches it. +> +> *Nova's lane is the infrastructure beneath the application. AppSec, +> dependency review, and runtime application security stay where they +> have always been — with the application team.* + +**Speaker notes (~210 words):** Trade-off pattern (Central IT vs. +Nova both trade per-application control for uniform operability); +platform-begins/ends framing [1]; sovereignty-via-boundary argument. + +#### Slide 3 — Two principles that organize everything else + +**On-slide body:** + +> **Two principles that organize everything else** +> +> *The architecture is principled, not improvised. Two tenets +> discipline every other decision.* +> +> **Sovereign boundary.** Nova governs the delivery lifecycle; it +> does not reach upstream into product or software development [1]. +> Integration with SDLC and PDLC partners happens exclusively through +> the validated, published contract surface. What lives outside the +> contract is not Nova's domain. +> +> **Lower autonomous · higher attested.** Lower environments proceed +> through agentic automation. Promotion to higher environments +> requires deliberate human attestation — not as a rubber stamp, but +> as policy-mandated accountability [1]. The compute the platform +> makes; the choice the human keeps. +> +> *Everything else in the architecture inherits from these two.* + +**Speaker notes (~270 words):** Cross-tenet architecture discipline +argument — how the four-layer model, HITL gates, policy envelope, and +contract schema all inherit from the two tenets [1]. Closes with "The +next slide is what the line looks like in 18 months of milestones." + +#### Slide 4 — Live · Attested · Stays human + +**On-slide body:** + +> **Live today** +> 41 capabilities across 12 domains. Contract ingestor, audit +> outbox, state buckets, and the live pilot run have been operating +> in our AWS estate since v1.7; pilot evidence at v1.26 returned +> confidence 0.800. DORA + adoption + policy-conformance metrics +> flow to PowerBI from the same audit stream as the lineage. Every +> finding carries one owner, one patch state, one audit entry — one +> pane, no second source of truth. A POC is production-grade by +> construction: there is no "POC that became prod" surprise. +> +> **Attested on promotion** +> qa, prod, and dr require a named human approver distinct from the +> PR author. Rubber stamps cannot be silently issued. +> +> **Stays human — by design** +> Confidence below the autonomy threshold at qa, prod, or dr triggers +> human escalation [1]. Some categories of decision are preserved for +> human judgment, and the platform says so out loud. + +**Speaker notes (~230 words):** Three-column claim disambiguation +(real / observable / disciplined). Pilot evidence as record, not +forecast. Single-pane-of-glass via audit lineage [1]. POC-to-prod +discipline [1]. HITL discipline closing [1]. + +#### Slide 5 — The boundary keeps us honest + +**On-slide body:** + +> **The boundary keeps us honest** +> +> *Nova stays where it belongs.* +> +> **In Nova's lane** +> → Infrastructure primitives: S3, RDS, Lambda, ECS, DynamoDB, KMS, +> CloudFront. +> → Operational guardrails: confidence, policy, attestation, audit +> lineage. +> → CVE response at the infrastructure layer. +> +> **Outside Nova's lane** +> → Application business logic. +> → IDE, sprint, author workflows [1]. +> → Application-layer security: AppSec, dependency review, runtime +> threat modeling. +> → VM, bare-metal, OS lifecycles [1]. +> +> *The line is the contract. Everything below the contract is Nova. +> Everything above it stays where it has always been.* + +**Speaker notes (~250 words):** Architecture boundary discipline. +AppSec stays with app team as autonomy-preserving design choice. +Boundary as operating principle, not defensive posture [1]. + +#### Slide 6 — The 18-month shape + +**On-slide body:** + +> **The 18-month shape** +> +> *Where CDLC meets SDLC + PDLC — through the contract surface, not +> above it.* +> +> **α (now → Q4'26) — Operating model + federated governance.** A +> named platform-ops body owns the platform; SLAs on every L2 are +> ratifiable by platform + consumer. The operating model is +> published; integration surfaces for SDLC and PDLC harnesses are +> documented at the contract boundary. +> +> **β (Q1'27) — Auto-published infra observability.** Every consumer +> stack ships with CloudWatch dashboards, uptime-kuma monitors, and +> alert routing on apply — infrastructure primitives publish +> observability as a property, no per-team authoring required. +> +> **γ (Q2'27) — Runbook generation from telemetry.** Every L1 +> primitive ships with an auto-generated incident runbook derived +> from observed patterns. SREs get a starting runbook, not a blank +> page. +> +> **δ (Q3'27 → Q4'27) — Audit ledger, tamper-resistant + externally +> addressable.** The SQLite hash-evidence stream migrates to S3 +> Object Lock + JWS signatures. External counsel verifies any +> production change back to a named human attestation. +> +> *Nova absorbs no IDE, no editor, no sprint tool, no agent harness.* + +**Speaker notes (~250 words):** Boundary-respecting integration +argument. α as unlock + governance discipline [1]. β's infra-vs-app +observability discipline [1]. γ's infra-vs-app runbook discipline +[1]. δ as audit lineage outward, not upstream [1]. + +#### Slide 7 — What we ask · What comes back + +**On-slide body:** + +> **What we ask · What comes back** +> +> **What we ask.** +> Architecture endorsement. Runway to the next milestone. +> +> **Why now.** +> Agentic SDLC is reshaping the delivery curve. What is barely +> keepable today — incident response, compliance reconciliation, +> security remediation — does not compress at the same rate as the +> velocity it has to keep pace with. By the end of 2027, the gap +> between delivery acceleration and operational absorption is the +> structural risk. +> +> **What comes back.** +> The infrastructure foundation that absorbs the velocity. Metrics +> that tell us where to push next. Audit lineage that closes the +> regulatory question. The next milestone, **by November 2026**. +> +> *What we do not ask for: an IDE, a sprint tool, an author workflow, +> an upstream pipeline. Nova stays in its lane [1].* + +**Speaker notes (~256 words):** Opens with "This is presented to +Infrastructure & Operations leadership in August 2026." Asks for +architecture endorsement and runway to next milestone by November +2026. Velocity framing with **60% goal as internal directional +target, not sourced claim**. Closes with "Use the runway to land the +architecture endorsement." \ No newline at end of file diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index 0660fdf..7fa4a9b 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -853,4 +853,187 @@ M1/M1.5/M2 cutover gates documented in the operator guide. > gates in `nova-platform-ops` CI (out-of-band). The operator attests > the results in `docs/operator-guide-platform-ops.md` §18 "Cutover > Gates" Result column. P6 audit verifies the template + Result column -> exist; the live-green attestation is out-of-band (grill CF-1/CF-2). \ No newline at end of file +> exist; the live-green attestation is out-of-band (grill CF-1/CF-2). + +## v1.30 — Single-shot Leadership Deck (active milestone) + +> **Feature milestone — single-shot PPTX leadership deck.** Ships +> REQ-372.1 through REQ-372.12 in one execution phase. Tags run on the +> **v1.29.x** line (milestone v1.30 → tags v1.29.1..v1.29.3). Tag +> `v1.29.3` = the milestone release. The deck is a discrete artifact, +> hand-authored (NOT a compression of the existing citizen-developer +> pitch per D-241), scoped to a single live presentation to +> Infrastructure & Operations leadership in August 2026, securing +> architecture endorsement and a November 2026 runway. +> +> Source: `docs/presentations/nova-leadership-deck-marp.md` (authored +> against the Slide Content Map in `.ciagent/PROJECT.md` §v1.30 spec). +> Rendered via the existing `scripts/render_pptx.py` (narrowly extended +> per D-242 to accept an explicit source path + custom output filename +> and to add a per-slide footer textbox). Smoke test: +> `scripts/check_leadership_deck.sh` (runnable on demand; NOT a CI gate +> per the single-shot constraint). Vision grounding `[1]` citations +> resolve to `docs/vision.md` (the spec's `acdl-vision.md` reference). + +### Decisions (locked in CLARIFY, full autonomy — load-bearing for v1.30) + +- **D-241 (Q3 override):** The leadership deck is a **discrete, + hand-authored artifact** — NOT a compression of the existing + 23-slide citizen-developer pitch + (`nova-autonomous-cloud-delivery-marp.md`). This overrides the + post-v1.29 STATE.md intake assumption 3 ("is a compression, not a + rewrite"). The existing citizen-developer deck remains untouched. + Rationale: the spec §2.2 + cover note forbid compression/mirroring; + the Slide Content Map is hand-authored content, not derived. +- **D-242 (render pipeline):** The existing `scripts/render_pptx.py` + is narrowly extended to (a) accept an explicit source `.md` path + + custom output `.pptx` filename (the cover note's invocation + `scripts/render_pptx.py docs/presentations/nova-leadership-deck.md` + is honoured via a path-aware argv), and (b) render a right-aligned + footer textbox on every slide with the exact string + `Nova Platform - Infrastructure & Operations` (the python-pptx + renderer does not read the Marp `footer:` directive; REQ-372.5 + requires the footer on every rendered slide). This extension is a + non-REQ-372 prerequisite per spec §3.3 Edge 2 ("scope narrowly and + update `render_pptx.py` separately"). The source file is authored as + `nova-leadership-deck-marp.md` to fit the existing `-marp.md` + pipeline convention; the output is `nova-leadership-deck.pptx` per + spec REQ-372.2. +- **D-243 (date anchor):** August 2026 is a month-only presentation + anchor (no specific day); November 2026 is the runway anchor + (~90 days). Slide 7 references "Infrastructure & Operations + leadership" without naming a specific day. Resolves spec §7 Q1. + +### Requirements + +#### REQ-372.1 — Source markdown exists and is parseable + +**Priority:** High · **Journey:** J1 + +**Given** the deck initiative is scoped, **when** +`docs/presentations/nova-leadership-deck-marp.md` is read, **then** the +file exists, parses as valid Marp markdown, contains exactly 7 slides +delimited by `---`, and the file header carries the related-artifacts +comment (per REQ-372.9). + +#### REQ-372.2 — PPTX render via existing pipeline + +**Priority:** High · **Journey:** J1 + +**Given** the source markdown exists (REQ-372.1), **when** +`scripts/render_pptx.py` is invoked against the leadership deck source, +**then** `docs/presentations/nova-leadership-deck.pptx` is written with +7 slides and python-pptx raised no exceptions. + +#### REQ-372.3 — Slide count is exactly 7 + +**Priority:** High · **Journey:** J1 + +**Given** the source markdown, **when** slide boundaries are counted, +**then** the count equals 7. + +#### REQ-372.4 — Speaker notes depth per slide + +**Priority:** High · **Journey:** J1 + +**Given** the source markdown, **when** speaker notes (HTML comments) +are extracted per slide, **then** per-slide word counts fall within: +slides 1/2/4/6 in 150–300; slides 3/5 in 250–400; slide 7 in 200–300. +Smoke test exits non-zero on violation. + +#### REQ-372.5 — Footer on every slide + +**Priority:** High · **Journey:** J1 + +**Given** the source markdown's Marp frontmatter `footer:` directive + +the python-pptx renderer extension (D-242), **when** the PPTX is +rendered, **then** every slide carries the right-aligned footer +`Nova Platform - Infrastructure & Operations`. + +#### REQ-372.6 — S&P theme tokens are the only colors used + +**Priority:** High · **Journey:** J1 + +**Given** the source markdown, **when** color values are extracted +(Marp directives + inline overrides), **then** the only hex colors +present are `#D6002A`, `#1B1B1B`, `#FFFFFF`, `#F0F0F0`. + +#### REQ-372.7 — Slide-by-slide content traceability + +**Priority:** High · **Journey:** J1 + +**Given** the rendered PPTX, **when** any slide N ∈ [1, 7] is opened, +**then** its content matches the **Slide Content Map** in +`.ciagent/PROJECT.md` §v1.30 spec. Any deviation from the map requires +`CLARIFY` before ship. Smoke test does not assert content strings +verbatim (brittle); audit verifies by visual review against the map. + +#### REQ-372.8 — Smoke test exits 0 on pass + +**Priority:** High · **Journey:** J1 + +**Given** `scripts/check_leadership_deck.sh` exists, **when** invoked +from the repo root, **then** the script asserts: (a) source file +exists, (b) slide count = 7, (c) per-slide word counts in band, (d) +footer string present in source, (e) only S&P hex colors used, (f) +PPTX file exists. Exits 0 on pass, non-zero on fail. Runnable on +demand; not wired as a CI gate. + +#### REQ-372.9 — Related-artifacts comment in source header + +**Priority:** Med · **Journey:** J1 + +**Given** the source markdown, **when** the file header is inspected, +**then** a comment exists that (i) names this deck as the leadership +artifact for Infrastructure & Operations, (ii) names August 2026 as +the presentation date, (iii) names +`nova-autonomous-cloud-delivery-marp.md` as a related-but-distinct +artifact and notes that this deck does not compress or modify it. + +#### REQ-372.10 — CAP-042 appended to STATE.md at ship + +**Priority:** Med · **Journey:** J1 + +**Given** the deck has shipped, **when** STATE.md is updated at the +v1.30 milestone ship wave, **then** a CAP-042 row exists capturing +artifact paths (`nova-leadership-deck-marp.md`, +`nova-leadership-deck.pptx`), audience (Infrastructure & Operations +leadership), single-shot intent, presentation month (August 2026). + +#### REQ-372.11 — D-241 recorded in PROJECT.md at ship + +**Priority:** Med · **Journey:** J1 + +**Given** the deck has shipped, **when** PROJECT.md is updated at the +v1.30 milestone ship wave, **then** a `D-241` entry exists capturing: +(a) single-shot nature of the deck, (b) audience (Infrastructure & +Operations leadership), (c) August 2026 anchor + November 2026 runway, +(d) explicit decision not to compress the existing citizen-developer +deck. + +#### REQ-372.12 — Vision grounding citations in architecture-load slides + +**Priority:** Med · **Journey:** J1 + +**Given** the source markdown, **when** the speaker notes are +inspected, **then** at least one `[1]` citation appears in slides 3, +5, and 7 — the three architecture-load slides — grounding the +principles, anti-goals, and integration-boundary claims to +`docs/vision.md` (the spec's `acdl-vision.md` reference [1]). + +### v1.30 Traceability (live — see CHECKPOINT.json for authoritative state) + +| REQ | Phase | Status | +|-----|-------|--------| +| REQ-372.1 | P1 | planned | +| REQ-372.2 | P1 | planned | +| REQ-372.3 | P1 | planned | +| REQ-372.4 | P1 | planned | +| REQ-372.5 | P1 | planned | +| REQ-372.6 | P1 | planned | +| REQ-372.7 | P1 | planned (visual review) | +| REQ-372.8 | P1 | planned | +| REQ-372.9 | P1 | planned | +| REQ-372.10 | P1 | planned | +| REQ-372.11 | P1 | planned | +| REQ-372.12 | P1 | planned | \ No newline at end of file From 6aac523da7599772229bb7514fb92177b87e0f6e Mon Sep 17 00:00:00 2001 From: CIAgent Date: Thu, 20 Aug 2026 13:14:59 +0000 Subject: [PATCH 2/6] =?UTF-8?q?docs(P00):=20clarify=20=E2=80=94=20D-241/D-?= =?UTF-8?q?242/D-243=20+=20STATE.md=20intake=20override?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.30 status: clarify decisions: [D-241, D-242, D-243] ---/ci--- --- .ciagent/CHECKPOINT.json | 6 +- .ciagent/CLARIFY.md | 611 +++++++++++---------------------------- .ciagent/STATE.md | 2 +- 3 files changed, 166 insertions(+), 453 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 422262c..78ca2d4 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "specify", + "stage": "clarify", "milestone": "v1.30", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-20T13:15:00Z", + "updated_at": "2026-08-20T13:25:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.30", @@ -23,5 +23,5 @@ "branches_deleted": true, "releases_created": true }, - "notes": "v1.30 Phase 0 SPECIFY complete. REQ-372.1...12 added to REQUIREMENTS.md. v1.30 milestone section + Slide Content Map appended to PROJECT.md. Tags run on v1.29.x line: v1.29.1 (P0), v1.29.2 (P1), v1.29.3 (P2 = milestone release). Next: CLARIFY (D-241..D-243)." + "notes": "v1.30 Phase 0 CLARIFY complete. D-241 (discrete artifact, overrides STATE.md intake assumption 3), D-242 (narrow render_pptx.py extension), D-243 (month-only date anchor). STATE.md intake assumption 3 overridden. Spec §7 Q1-Q4 auto-resolved at full autonomy. Next: RESEARCH." } \ No newline at end of file diff --git a/.ciagent/CLARIFY.md b/.ciagent/CLARIFY.md index 6cb1a28..c6fbecd 100644 --- a/.ciagent/CLARIFY.md +++ b/.ciagent/CLARIFY.md @@ -1,500 +1,213 @@ -# CLARIFY — v1.28 CLI Canonicalization + Identity Layer +# CLARIFY — v1.30 Single-shot Leadership Deck > **Autonomy:** full. Auto-resolution with assumption logging per -> `config.autonomy.level: "full"`. No human escalation unless confidence -> < 0.60. The user-approved re-mapping plan (v1.18 spec → v1.28) resolved -> the headline discrepancy. This file records the remaining ambiguities -> and the grounding gaps surfaced in pre-flight. +> `config.autonomy.level: "full"`. No human escalation unless +> confidence < 0.60. The user confirmed the 4 framing decisions +> (milestone numbering, render pipeline path, stale intake +> assumption override, smoke test PPTX gate) in the pre-run planning +> conversation. This file records the formal D-IDs and the spec §7 +> open-question resolutions. --- ## Method -The clarify stage identifies ambiguities in the v1.28 specification and -resolves them at full autonomy. The v1.28 spec is the user-provided -"Universal Feature Specification — v1.18 CLI Canonicalization + Identity -Layer," re-mapped to v1.28 (milestone number, tag line, and all -ID namespaces) per the user-approved plan. Each ambiguity gets a -decision ID (D-226+, continuing from v1.27's D-214..D-225), a resolution, -a confidence score, and a rationale. +The clarify stage identifies ambiguities in the v1.30 specification +(REQ-372 v1.0, locked 2026-08-20) and resolves them at full autonomy. +The spec is the user-provided "REQ-372 — Nova Leadership Presentation +Deck." Each ambiguity gets a decision ID (D-241+, continuing from +v1.29's D-232..D-240), a resolution, a confidence score, and a +rationale. --- ## Prior-conversation resolutions (already locked, restated for the record) -These were resolved by the user-approved re-mapping plan in the -conversation that spawned v1.28. They are load-bearing for v1.28 -execution. +These were resolved by the user in the pre-run planning conversation +that spawned v1.30. They are load-bearing for v1.30 execution. -### Q-P1 — The source spec is titled "v1.18" but v1.18 already shipped. What milestone is this? +### Q-M1 — The cover note/spec say "v1.29.x" but the checkpoint says v1.29 is complete and active_milestone is v1.30. What is the milestone number? -**Resolution:** Re-map the spec's *content* (CLI Canonicalization + -Identity Layer) to **v1.28**, the next milestone after v1.27 (complete). -Tags run on the **v1.27.x** line (P0 = `v1.27.0`). Milestone branch: -`milestone/v1.28-cli-identity`. -**Confidence:** 1.0 (user-confirmed — "Re-map to v1.28"). **Decision:** n/a (milestone identity, not a D-ID). +**Resolution:** The milestone is **v1.30**. The cover note's "v1.29.x" +is the **tag line** (per run.md branch strategy, tags run on the +previous minor's patch line: milestone v1.30 → tags v1.29.1, +v1.29.2, v1.29.3). The milestone branch is +`milestone/v1.30-leadership-deck`. v1.29 is complete (merged to main +`9dc5669`, tag `v1.28.6`). +**Confidence:** 1.0 (user-confirmed — "Milestone v1.30, tags v1.29.x"). +**Decision:** n/a (milestone identity, not a D-ID). -### Q-P2 — The spec's "locked inputs" (D-NEW-26, kj engine, Nova-idp, INV-63/64/65, CAP-025..030, REQ-001..031) don't exist in the repo. How to handle? +### Q-M2 — The cover note says `scripts/render_pptx.py docs/presentations/nova-leadership-deck.md` but render_pptx.py expects `{deck}-marp.md` naming. How to resolve? -**Resolution:** Author them fresh in this milestone's CLARIFY/RESEARCH as -**D-226..D-231, INV-12..17, CAP-033..038, REQ-323..353**. The `kj` engine -is mapped to the existing **kyverno-json** engine (INV-4 swappable) — no -new engine is built. CAP/INV/REQ IDs are re-allocated to avoid collisions -with shipped history (CAP-025..032 and INV-1..11 are blockchain/pilot). -**Confidence:** 1.0 (user-confirmed — "Re-map to v1.28"). **Decision:** D-227 (kj→kyverno-json), plus the ID-allocation block in REQUIREMENTS.md. +**Resolution:** Author the source as +`docs/presentations/nova-leadership-deck-marp.md` to fit the existing +`-marp.md` pipeline convention. Narrowly extend `render_pptx.py` to +accept an explicit source `.md` path + `--output` filename, and to +render a right-aligned footer textbox on every slide (python-pptx +does not read the Marp `footer:` directive). The output is +`nova-leadership-deck.pptx` per spec REQ-372.2. Formalized as D-242. +**Confidence:** 1.0 (user-confirmed — "Author source as +nova-leadership-deck-marp.md, extend render_pptx.py"). +**Decision:** D-242. -### Q-P3 — The spec claims a "Cognito drop." No Cognito exists in the repo. What does NFR-5 mean? +### Q-M3 — The post-v1.29 STATE.md intake (assumption 3) says the leadership deck "is a compression, not a rewrite" of the 23-slide citizen-developer deck. The cover note + spec explicitly forbid compression. How to handle? -**Resolution:** NFR-5 (no AWS-managed identity in the path) is a -**greenfield constraint**, not a migration. Nova-idp is built fresh; no -Cognito/IAM Identity Center is *introduced*. The "drop" framing is -aspirational language from the source spec, not a literal removal. -**Confidence:** 1.0. **Decision:** D-226 (recorded below; NFR-5 restated -as a greenfield constraint in INV-15). +**Resolution:** Override the stale intake assumption. The leadership +deck is a **discrete, hand-authored artifact** — NOT a compression. +The existing citizen-developer deck +(`nova-autonomous-cloud-delivery-marp.md`) remains untouched. The +spec §2.2 + cover note forbid compression/mirroring; the Slide +Content Map is hand-authored content, not derived. Update STATE.md +intake assumption 3 to reflect the discrete-artifact decision. +Formalized as D-241. +**Confidence:** 1.0 (user-confirmed — "Override with spec's +discrete-artifact decision"). +**Decision:** D-241. + +### Q-M4 — The smoke test (REQ-372.8f) must assert PPTX file existence. Given the render environment limitations, should the PPTX-existence check be a hard fail or a conditional skip? + +**Resolution:** **Hard fail** if `.pptx` absent. The deck must be +rendered before ship. The render environment is resolved (python-pptx +installed via user-site `pip install --user --break-system-packages`; +no Chromium needed since python-pptx is the render path, not Marp +CLI). If the environment cannot render, that is a ship blocker to +resolve — not a reason to weaken the gate. +**Confidence:** 1.0 (user-confirmed — "Hard fail if .pptx absent"). +**Decision:** n/a (gate severity, not a D-ID — recorded in PLAN.md). --- ## Open questions from the spec's §7 (auto-resolved at full autonomy) -### Q1 — Argon2 native dependency in Lambda runtime +### Q1 — Specific meeting date inside August 2026 -`argon2-cffi` has a C extension that may not build cleanly in the Lambda -Python 3.12 runtime. +**Spec context:** The presentation is in August 2026, but no specific +day is named. Slide 7 references "Infrastructure & Operations +leadership" without naming a day. -**Resolution (D-228):** Use `argon2-cffi` with bundled wheels; if the -extension fails to load, fall back to the pure-Python implementation. If -both fail, document the Fargate migration path for the auth Lambda. -CAP-036 covers end-to-end verification. -**Confidence:** 0.85. **Rationale:** Bundled wheels are the standard -workaround for Lambda native deps; the pure-Python fallback is a safe -degradation. Fargate is the escape hatch if Lambda's runtime is -fundamentally incompatible. RESEARCH will validate wheel availability for -Python 3.12 + the Lambda execution environment. -**Impact if wrong:** Auth Lambda migrates to Fargate, adding ~1 week to P2. +**Resolution:** Anchor to **month-only** (August 2026). No specific +day in the deck text. November 2026 is the runway anchor (~90 days +from August 2026). +**Confidence:** 0.95. **Impact if wrong:** Very low — the meeting is +what it is; the deck text doesn't depend on a specific day. +**Decision:** D-243 (date anchor discipline: month-only). -### Q2 — PAT revocation propagation latency +### Q2 — Explicit non-compression of the existing citizen-developer deck -The 60-second SLO (NFR-4) depends on whether the token-vend Lambda reads -PAT revocation state from DynamoDB on every request (eventually -consistent reads) or via a cached/denylist mechanism. +**Spec context:** The two decks (leadership + citizen-developer) +remain discrete artifacts. The existing 23-slide +`nova-autonomous-cloud-delivery-marp.md` is not compressed or +modified. -**Resolution (D-229):** Read-on-every-request with strongly consistent -reads on the PAT hash table. Cost is acceptable given expected request -volume (token vending is not a hot path — it precedes a deploy, not every -request). REV-351 verifies the SLO in CI. -**Confidence:** 0.90. **Rationale:** Strongly consistent DynamoDB reads -have single-digit-ms latency at expected volume; the 60s SLO has >10x -headroom. A cache layer adds invalidation complexity that the SLO does -not require. -**Impact if wrong:** If read latency exceeds 60s under load, introduce a -DynamoDB TTL + cache layer; SLO must be re-verified. +**Resolution:** Document the discrete-artifact constraint in +REQ-372.9 (related-artifacts header comment) + D-241 (this file) + +D-241 record in PROJECT.md at ship (REQ-372.11). Leave the existing +citizen-developer deck untouched. The cover note's hard scope rules +("Do not modify `nova-autonomous-cloud-delivery-marp.md`") are +binding. +**Confidence:** 1.0. **Impact if wrong:** None for this milestone. +**Decision:** D-241 (restated — the discrete-artifact decision is the +same as Q-M3's override). -### Q3 — JWKS endpoint: Lambda function URL vs. API Gateway +### Q3 — Assumption: existing `scripts/render_pptx.py` accepts S&P theme directives and Marp speaker notes without modification -A function URL is simpler and cheaper but lacks throttling, WAF, and -custom domains out of the box. +**Spec context:** The render pipeline is existing; the spec assumes +it works for the new deck. If a theme limitation forces a renderer +change, scope narrowly and update `render_pptx.py` separately as a +non-REQ-372 task. -**Resolution (D-230):** Start with a Lambda function URL behind a custom -domain; rate limiting configured at the DNS/CDN layer. API Gateway -migration deferred to v1.19+ if throttling requirements grow. -**Confidence:** 0.80. **Rationale:** The JWKS endpoint is public-key -only (no secrets); the threat surface is low. Function URL + CDN rate- -limiting covers the v1.28 volume. API Gateway is over-engineering until -traffic patterns are known. -**Impact if wrong:** If throttling becomes a requirement, API Gateway -migration adds ~3-5 days. +**Resolution (confirmed by research):** The existing `render_pptx.py` +has two gaps for REQ-372: (a) it expects a `{deck}` arg and reads +`{deck}-marp.md` / writes `{deck}-python.pptx` — it does not accept +an explicit source path or custom output filename; (b) it does not +read the Marp `footer:` directive (it skips HTML comments at lines +366-379 and never adds a footer textbox). Speaker notes (HTML +comments) are skipped entirely — acceptable for REQ-372.4 (smoke test +checks source word counts, not PPTX-embedded notes). The narrow +extension per D-242 addresses (a) and (b). No other renderer change +is needed. The extension is a prerequisite, scoped separately from +REQ-372 per spec §3.3 Edge 2. +**Confidence:** 0.92. **Impact if wrong:** Small follow-up; doesn't +change milestone scope. +**Decision:** D-242 (restated). -### Q4 — Mode resolver precedence with invalid `NOVA_CLIENT_MODE` value +### Q4 — Assumption: the 18-month runway shape (α–δ) is acceptable as drafted to I&O leadership -What happens if the env var is set to something other than `agent` or -`interactive` (e.g., `NOVA_CLIENT_MODE=auto`)? +**Spec context:** Slides 6 + 7 rehearse both architecture-load and +political-cover framings. The worked-example granularity was +confirmed by the PO. -**Resolution (D-226):** Invalid env var values are ignored, falling -through to credential type. A warning is logged. Behavior is documented -in the `nova-cli` README. This is a sub-clause of the mode-resolution -priority decision. -**Confidence:** 0.90. **Rationale:** Ignoring + warning is the least -surprising behavior for an operator debugging mode issues. Failing hard -would block legitimate workflows that set a stale/typo'd env var. -**Impact if wrong:** Operators debugging mode issues may be confused; -non-blocking. - -### Q5 — Service-account PAT vs. developer PAT in the same session - -What if both credential types are available (e.g., a developer explicitly -exports a service-account PAT)? - -**Resolution (D-226):** The most recently acquired credential wins. -Documented in `nova auth login` output. The credential type is what -drives mode resolution (INV-14), so the operator sees which mode was -selected and why. -**Confidence:** 0.85. **Rationale:** "Most recent wins" is the simplest -deterministic rule that matches operator mental models of "I just logged -in as X." The audit event records the winning credential type, so the -selection is traceable. -**Impact if wrong:** Mode selection may surprise the operator; non- -blocking, but `nova auth status` must make the active credential explicit. - -### Q6 — ABAC policy ownership and versioning - -`platform/abac/token-vend.policy` is referenced, but who owns changes? -How are policy versions tracked in audit? - -**Resolution (D-231):** Policy changes require PR review; the policy -version (git SHA) is recorded in every token-vend audit event. Owner: -Platform Security. The policy file lives in the platform repo at -`platform/abac/token-vend.policy` and is reviewed like any other -production config. -**Confidence:** 0.90. **Rationale:** Git SHA is the natural version -identifier for a repo-resident policy; recording it in the audit event -makes every allow/deny decision reconstructable to the exact policy text. -**Impact if wrong:** Untracked policy changes could lead to unexpected -allow/deny decisions in production, undermining audit defensibility. +**Resolution:** Accept the α–δ shape as drafted. Slides 6 + 7 are the +only slide-by-slide revisions that might be needed if leadership +pushes back; everything else is locked. No spec change required +unless the architectural claim set shifts (spec §3.3 Edge 3). +**Confidence:** 0.85. **Impact if wrong:** Slide 6 and slide 7 are +the only revisions; everything else is locked. +**Decision:** n/a (acceptance, not a D-ID — the shape is in the +locked Slide Content Map). --- -## Grounding gaps surfaced in pre-flight (auto-resolved) +## Decisions (locked, full autonomy — load-bearing for v1.30) -### G1 — The `kj` engine does not exist; the spec treats it as locked. +### D-241 — Leadership deck is discrete, hand-authored, NOT a compression -**Resolution (D-227):** The token-vend Lambda uses the existing -**kyverno-json** engine (INV-4 swappable) as the ABAC evaluator. The -policy at `platform/abac/token-vend.policy` is a kyverno-json policy. -No new `kj` engine is built in v1.28. If a distinct `kj` engine is -desired later, it is a separate research spike (not this milestone). -**Confidence:** 0.95. **Rationale:** The repo already has a swappable -policy engine (INV-4) implemented as kyverno-json. Building a second -engine to do the same job violates the swappable-engine invariant's -spirit. kyverno-json's `evaluate` semantics cover the spec's ABAC needs -(subject, claims, resource, environment → allow/deny). -**Impact if wrong:** If the user actually wants a new `kj` engine, v1.28 -scope expands significantly (engine design + implementation + migration). -This was flagged as caveat #3 in the approved plan; the recommended path -(kyverno-json) is locked here. +**Q-M3 / Q2.** The leadership deck is a **discrete, hand-authored +artifact** — NOT a compression of the existing 23-slide +citizen-developer pitch +(`nova-autonomous-cloud-delivery-marp.md`). This overrides the +post-v1.29 STATE.md intake assumption 3 ("is a compression, not a +rewrite"). The existing citizen-developer deck remains untouched. +The spec §2.2 + cover note forbid compression/mirroring; the Slide +Content Map is hand-authored content, not derived. Recorded in +PROJECT.md at ship (REQ-372.11). +**Confidence:** 1.0. -### G2 — The spec's INV-18..21, INV-34, INV-63/64/65 don't exist. +### D-242 — Narrow render_pptx.py extension (path arg + custom output + footer textbox) -**Resolution:** Re-allocated as **INV-12..INV-17** (see REQUIREMENTS.md -§v1.28 Invariants). The 1:1 mapping: -- INV-63 (mode observability) → INV-12 -- INV-64 (mode determinism) → INV-13 -- INV-65 (credential type encodes role) → INV-14 -- INV-18..21 (attestation invariants) → INV-15 (no AWS-managed identity), - INV-16 (password storage), INV-17 (ABAC discipline). The spec's - attestation invariants INV-18..21 are partially covered by existing - invariants (INV-6 immutable audit) + INV-17; the JWS-from-PAT behavior - (REQ-332) is a requirement, not a separate invariant, in this mapping. -- INV-34 (MFA enforcement) → deferred to v1.21+ (out of scope per §2.2); - no INV allocated in v1.28. -**Confidence:** 0.85. **Rationale:** The mapping preserves the spec's -intent without colliding with the repo's INV-1..11. INV-34 (MFA) is -explicitly deferred per the spec's own §2.2 out-of-scope table. -**Impact if wrong:** If the user wants the exact INV-18..21 semantics as -separate invariants, INV-12..17 can be re-numbered; non-blocking. +**Q-M2 / Q3.** The existing `scripts/render_pptx.py` is narrowly +extended to: (a) accept an explicit source `.md` path + `--output` +filename (honouring the cover note's invocation pattern), and (b) +render a right-aligned footer textbox on every slide with the exact +string `Nova Platform - Infrastructure & Operations` (python-pptx +does not read the Marp `footer:` directive; REQ-372.5 requires the +footer on every rendered slide). The source is authored as +`nova-leadership-deck-marp.md` to fit the existing `-marp.md` +pipeline convention; the output is `nova-leadership-deck.pptx` per +spec REQ-372.2. This extension is a non-REQ-372 prerequisite per +spec §3.3 Edge 2 ("scope narrowly and update `render_pptx.py` +separately"). No other renderer change (speaker notes are not +embedded in the PPTX — acceptable; smoke test checks source word +counts). +**Confidence:** 0.92. -### G3 — The spec's CAP-025..030 collide with blockchain/pilot CAPs. +### D-243 — Date anchor discipline: month-only (August 2026 present, November 2026 runway) -**Resolution:** Re-allocated as **CAP-033..CAP-038** (see REQUIREMENTS.md -§v1.28 + REQ-352). The 1:1 mapping: -- CAP-025 (CLI subcommand surface) → CAP-033 -- CAP-026 (subcommand delegates to core/) → CAP-034 -- CAP-027 (layer matches wheel) → CAP-035 -- CAP-028 (Nova-idp auth flow) → CAP-036 -- CAP-029 (token-vend signs via KMS) → CAP-037 -- CAP-030 (PAT issuance + revocation) → CAP-038 -**Confidence:** 1.0. **Rationale:** Existing CAP-025..032 are -blockchain/pilot capabilities (STATE.md); re-use would corrupt the -capability registry. The re-allocated IDs are the next available. -**Impact if wrong:** None — this is a numbering decision, not a semantic -one. - -### G4 — The spec's REQ-001..031 collide / don't exist. - -**Resolution:** Re-allocated as **REQ-323..REQ-353** (1:1 with the spec's -REQ-001..031). Full text in REQUIREMENTS.md §v1.28. Max existing REQ = -REQ-322. -**Confidence:** 1.0. **Rationale:** Same as G3 — avoid collision, use -next available range. - -### G5 — `platform/abac/`, `nova/` subcommand dir, `nova-idp-*` Lambdas don't exist. - -**Resolution:** These are **greenfield deliverables** of v1.28 execution -phases, not pre-existing "locked architectures." RESEARCH will design -them; PLAN will sequence them; EXECUTE will build them. The spec's -"Operating Principle 1" (incremental delivery) is honored — v1.28 is -net-new work. -**Confidence:** 1.0. **Rationale:** The spec itself describes these as -new ("introducing Nova-idp"). The mis-framing was in calling them -"locked" — they are locked in *scope*, not in *prior existence*. -**Impact if wrong:** None — this is a framing correction. +**Q1.** August 2026 is a **month-only** presentation anchor (no +specific day). November 2026 is the runway anchor (~90 days from +August 2026). Slide 7 references "Infrastructure & Operations +leadership" without naming a specific day. No spec change required +unless the architectural claim set shifts (spec §3.3 Edge 3). +**Confidence:** 0.95. --- -## Decision ledger (v1.28 — D-226..D-231) +## STATE.md intake assumption override -| ID | Title | Confidence | Load-bearing for | -|----|-------|------------|------------------| -| D-226 | Mode resolution priority + invalid-env + dual-credential | 0.90 | REQ-327, INV-12, INV-13, INV-14 | -| D-227 | ABAC engine = kyverno-json (no `kj` engine built) | 0.95 | REQ-336, REQ-339, INV-17, NFR-9 | -| D-228 | Argon2id in Lambda: bundled wheels + pure-Python fallback + Fargate path | 0.85 | REQ-333, REQ-334, INV-16, NFR-8 | -| D-229 | PAT revocation: strongly-consistent DDB read-on-every-request, 60s SLO | 0.90 | REQ-342, REQ-343, REQ-351, NFR-4 | -| D-230 | JWKS endpoint: Lambda function URL + custom domain + CDN rate-limit | 0.80 | REQ-338, NFR-5 | -| D-231 | ABAC policy ownership: Platform Security, git SHA in audit | 0.90 | REQ-339, NFR-9 | +The post-v1.29 STATE.md intake (line ~526, Agent Assumptions, item 3) +states: "The 23-slide existing deck is the source material — the +≤7-slide leadership deck is a compression, not a rewrite." + +**Override (D-241):** This assumption is **replaced**. The leadership +deck is a discrete, hand-authored artifact — NOT a compression. The +existing citizen-developer deck remains untouched. The override is +recorded in this CLARIFY.md (D-241) and will be reflected in STATE.md +at the v1.30 ship wave (CAP-042 row + intake assumption correction). --- -## Assumptions logged (full autonomy, no human escalation) +## Requirements impact -1. **CodeArtifact is provisionable** in AWS account `581513795199` (the - pilot account). RESEARCH will confirm IAM permissions + repository - creation. If not, v1.28 falls back to a private PyPI server or a - Gitea-hosted wheel index; the CLI subcommand surface (REQ-324) and - identity layer (REQ-333+) are unaffected. -2. **Python 3.12** is the target runtime for both the CLI wheel and the - Lambda functions (spec §4 REQ-004.3). The repo's current Python - version will be confirmed in RESEARCH; if it differs, the CLI pins - 3.12 and Lambda uses the 3.12 runtime regardless. -3. **KMS asymmetric signing** (RSA-2048 or ECDSA P-256) is available in - the target account. RESEARCH will confirm. If only symmetric KMS is - available, the token-vend Lambda uses symmetric signing + a public-key - publication step (less ideal, but functional); INV-15 is unaffected. -4. **The Forge action** (REQ-326) is the existing `nova cli-action` - pattern, extended to both GitHub and Gitea marketplaces. The repo's - current Forge/Gitea workflow conventions (`.gitea/workflows/`, - `deploy.yml@v1.25`) are the baseline. -5. **MFA/TOTP** code path ships in v1.28 (per spec §2.2) but enforcement - for prod/dr is deferred to v1.21+. This is a doc/test-only path in - v1.28 — no enforcement gate. - ---- - -## CLARIFY complete - -All material ambiguities resolved at full autonomy (6 open questions + -5 grounding gaps → D-226..D-231, confidence ≥ 0.80). No human escalation -triggered (all confidences ≥ 0.60 threshold). REQUIREMENTS.md updated -with the decision ledger + invariants. Next: RESEARCH. - ---- - -# CLARIFY — v1.29 Reposplit + Identity Layer Bring-Live - -> **Autonomy:** full. Auto-resolution with assumption logging per -> `config.autonomy.level: "full"`. No human escalation unless confidence -> < 0.60. The v1.29 spec is v1.1 (highly detailed — §7 resolves Q1-6, Q7 -> carried forward as a verification-gate dependency). This file records -> the v1.29 ambiguities and the scope-split grounding. - ---- - -## Method - -The v1.29 spec ("Universal Feature Specification — Reposplit + Identity -Layer Bring-Live", v1.1) is the most detailed spec the project has -received: it includes BDD acceptance criteria, an 8-item M1.5 spike -checklist, 7 decisions pre-drafted (D-232..238), 14 NFRs, and an -explicit §7 resolving Q1-6. Clarify work focuses on (a) the scope split -between `acdl` (CIAgent) and `nova-platform-ops` (out-of-band), (b) the -`kj` identity (Go binary vs. the v1.28 kyverno-json re-mapping), and (c) -the carried-forward Q7. Each ambiguity gets a decision ID (D-232+, -continuing from v1.28's D-226..D-231), a resolution, a confidence score, -and a rationale. - ---- - -## Prior-conversation resolutions (already locked, restated for the record) - -These were resolved by the user-approved execution plan in the -conversation that spawned v1.29. - -### Q-P1 — The spec creates a separate repo `nova-platform-ops`. CIAgent runs inside `acdl`. Where does the Terraform code land? - -**Resolution:** Terraform modules -(`networking`/`kms`/`identity`/`contract-ingest`/`bootstrap`/`edge`) are -authored **out-of-band** in `nova-platform-ops` (operator-owned). CIAgent -in `acdl` delivers only the acdl-side work (publish.yml, Gitea scrub, -CFN archive, operator guide, consumer bump) and tracks the ops-side -REQs as **covered-reference** (verification surface = the M1/M1.5/M2 -cutover gates documented in the operator guide). -**Confidence:** 1.0 (user-confirmed — "Author out-of-band in -nova-platform-ops"). **Decision:** scope split documented in -PROJECT.md §v1.29 + REQUIREMENTS.md §v1.29. - -### Q-P2 — The run scope. How far does this `/ci-run` go? - -**Resolution:** Full milestone through the final phase (P0 → P1..P5 → -P6 final review + audit + milestone ship, tag `v1.28.6`). -**Confidence:** 1.0 (user-confirmed — "Full milestone through final -phase"). **Decision:** n/a (execution scope, not a D-ID). - -### Q-P3 — Edge 8 / REQ-354 footnote: pilot consumer deploy bump. Handle how? - -**Resolution:** Include a cross-project phase (P5) in this CIAgent run -(multi-project mode is active). Bump `nova-blockchain-exchange` -deploy.yml `@v1.25` → `@v1.29` + smoke test. -**Confidence:** 1.0 (user-confirmed — "Cross-project phase in this -run"). **Decision:** n/a (execution scope). - ---- - -## Spec-grounded resolutions (from §7 + §5) - -### Q1 — State bucket bootstrap on day-0 (resolved per spec §7.1) - -**Resolution:** Manual one-time at the operator's secure scratch; Terraform -then adopts it via `terraform import`. Avoids bootstrapping the -bootstrapper. **Confidence:** 1.0 (spec §7.1 explicit). **Decision:** -D-235 (tag-pin handoff) — the state bucket is one of the imported -resources. - -### Q2 — `pyproject.toml` version bump (resolved per spec §7.2) - -**Resolution:** Bump to `1.29.0` in M1 (P2 — Gitea scrub phase) of v1.29 -alongside the Gitea scrub. **Confidence:** 1.0 (spec §7.2 explicit). -**Decision:** n/a (implementation detail, tracked in PLAN.md P2). - -### Q3 — WAF cost (resolved per spec §7.3) - -**Resolution:** Acceptable for the JWKS public surface; documented in -operator-guide cost section (~$5–10/month per WebACL + per-request). -**Confidence:** 1.0 (spec §7.3 explicit). **Decision:** documented in -REQ-OPS-GUIDE AC. - -### Q4 — Coverage 73.8% — does this milestone drive it down further? (resolved per spec §7.4) - -**Resolution:** Accept any further debt as carry-forward to the separate -NFR milestone. New modules have ≥80% coverage; older code paths are -unchanged. YELLOW carried without scope expansion. **Confidence:** 1.0 -(spec §7.4 explicit). **Decision:** n/a (NFR carry-forward, not a v1.29 -D-ID). - -### Q5 — CFN code deletion timing (resolved per spec §7.5) - -**Resolution:** Archive to `docs/archive/nova-idp-cfn-v1.28.md`; deletion -is a follow-up after the next pilot run verifies Terraform parity. -**Confidence:** 1.0 (spec §7.5 explicit). **Decision:** REQ-369 AC (3). - -### Q6 — `acdl-act-runner-role` reuse (resolved per spec §7.6) - -**Resolution:** Reuse the existing role for v1.29 to minimize IAM surface -changes; scope narrow per REQ-360. **Confidence:** 1.0 (spec §7.6 -explicit). **Decision:** covered by REQ-360 (IAM-NARROW). - -### Q7 — `kj` image verification dependency (CARRY-FORWARD per spec §7.7) - -**Resolution (carry-forward):** M1 cutover is conditional on the M1.5 -verification gate. **Recommendation:** Block M1 cutover until M1.5 -passes. If M1.5 fails three consecutive rebuilds, defer to M2a and ship -Nova-idp in read-only partial mode (no token issuance) until `kj` is -verified. **Impact if wrong:** A live token-vend that signs with a -broken ABAC path would let through a denied claim — fails closed only if -`ImageUri` is verified pre-apply. **Confidence:** 0.92 (spec §7.7 -explicit + D-236 cutover shape). **Decision:** D-236 (cutover shape + -rollback procedure). This is the **only** outstanding carry-forward; -CIAgent in acdl builds + publishes the image + the gate tests (P1), but -the live 3-rebuild verification happens in `nova-platform-ops` CI -(out-of-band). CIAgent does not block on it. - ---- - -## Grounding-gap resolutions (surfaced in pre-flight) - -### G1 — The spec's `kj` vs. v1.28's `kj` re-mapping - -**Ambiguity:** v1.28 (D-227) re-mapped the spec's `kj` engine → -kyverno-json (INV-4 swappable), explicitly stating "no new `kj` engine -is built." v1.29 reintroduces `kj` as a compiled Go binary -(`platform/abac/kj-version.txt`, pinned v0.0.3) embedded in an ECR -container image. Is this a contradiction? - -**Resolution:** No contradiction. v1.28's `kj` was a *policy engine* -reference; v1.29's `kj` is a *compiled Go binary* (a distinct artifact). -The kyverno-json engine remains the policy engine (INV-4). The v1.29 -`kj` binary is invoked via `subprocess.run(['/opt/kj/kj', 'apply', ...])` -by the Lambda handler — it is a **substrate** binary, not a policy -engine. The two coexist: kyverno-json evaluates ABAC policy; `kj` is the -container image's static binary that the Lambda runtime executes. No -collision. -**Confidence:** 0.95 (spec §3.3 Edge 5 item 4 explicit + v1.28 D-227 -scope). **Decision:** documented in PROJECT.md §v1.29 ID allocations + -KJ-STATIC NFR. - -### G2 — `REQ-363b` sub-requirement numbering - -**Ambiguity:** The spec uses `REQ-363b` for the Fargate defensive -fallback. The repo's REQ namespace is `REQ-NNN` (numeric). How to -record `363b`? - -**Resolution:** Keep `REQ-363b` as-is (sub-requirement of REQ-363). It -is a distinct requirement (Fargate fallback, KJ-LOCKSTEP) but logically -paired with REQ-363 (production substrate). The `b` suffix is -unambiguous and matches the spec. No collision with any existing REQ. -**Confidence:** 0.98 (spec explicit + no collision). **Decision:** n/a -(naming convention). - -### G3 — `REQ-370` gap - -**Ambiguity:** The spec jumps from REQ-369 to REQ-371. Is REQ-370 -missing or intentionally unused? - -**Resolution:** Intentionally unused per the source spec. REQ-370 is a -gap in the spec's numbering (likely a deleted/renumbered item during -spec v1.0 → v1.1). v1.29 does not allocate REQ-370; it remains a -reserved gap. **Confidence:** 0.90 (spec explicit gap, no content). -**Decision:** n/a (spec fidelity). - -### G4 — Covered-reference REQs and CIAgent verification - -**Ambiguity:** REQ-355, 356, 357, 358, 359, 360, 361, 362, 363, 363b, -364, 365, 366, 371 are authored in `nova-platform-ops` (out-of-band). -How does CIAgent verify them? Are they `human_needed`? - -**Resolution:** They are **covered-reference**, NOT `human_needed`. The -verification surface is the M1/M1.5/M2 cutover gates documented in the -operator guide (`docs/operator-guide-platform-ops.md`). The operator -guide lists each covered-reference REQ with its cutover gate entry -(M1/M1.5/M2). CIAgent verify marks them `covered-reference` and the -final-phase audit confirms the operator guide documents all gates. -**Confidence:** 0.94 (scope-split decision + spec §2.3 milestone -gates). **Decision:** documented in REQUIREMENTS.md §v1.29 + REQ-OPS- -GUIDE AC. - ---- - -## Assumptions (logged, not escalated — confidence ≥ 0.80) - -1. **`kj` v0.0.3** is available at the pinned SHA in - `platform/abac/kj-version.txt` and compiles with `CGO_ENABLED=0 - GOOS=linux GOARCH=amd64`. RESEARCH will confirm the source repository - + build commands. If the binary is not available, P1 (publish - pipeline) cannot produce the ECR image; M1.5 gate fails by - construction → M2a (Fargate toggle, same image) also fails → escalate - (but this is a spec dependency, not a CIAgent ambiguity). -2. **ECR repository** exists or is creatable in account `581513795199` - for the `kj` image. RESEARCH will confirm. The repo name is not - specified in the spec; the operator guide will document it. -3. **GitHub Releases** is the artifact distribution channel (per - REQ-354). The `acdl/acdl` repo is already on GitHub (the Gitea scrub - in REQ-367 standardizes on GitHub). NOVA_FORGE_TOKEN (Gitea) is - retained for `nova-platform-ops` releases only. -4. **The `nova idp setup --apply` terraform-delegation** (REQ-369 AC 2) - requires `terraform` to be on the operator's PATH. The CLI detects - terraform via `which terraform`; if absent, it falls back to the CFN - path with a deprecation warning (the CFN archive remains read-only - reference, but the delegation is the preferred path). -5. **The M1.5 8-item spike** (spec §3.3 Edge 5) is the verification - gate. CIAgent in acdl authors the *tests* (test_idp_auth, - test_kms_roundtrip, ABAC E2E) in P1; the *live 3-rebuild run* - happens in `nova-platform-ops` CI. This is the Q7 carry-forward - surface. - ---- - -## CLARIFY complete - -All material ambiguities resolved at full autonomy (3 prior-conversation -+ 7 spec-grounded + 4 grounding-gap → D-232..D-238, confidence ≥ 0.80). -Q7 is the only carry-forward (verification-gate dependency, not a -blocking ambiguity). No human escalation triggered (all confidences ≥ -0.60 threshold). REQUIREMENTS.md updated with the decision ledger + -invariants + NFR constraints. Next: RESEARCH. \ No newline at end of file +No requirements are added, removed, or re-scoped by these decisions. +D-241–D-243 are load-bearing context for executing REQ-372.1–.12 as +written. The spec is locked (v1.0, 2026-08-20); no spec text changes. \ No newline at end of file diff --git a/.ciagent/STATE.md b/.ciagent/STATE.md index aaeb83b..5275aee 100644 --- a/.ciagent/STATE.md +++ b/.ciagent/STATE.md @@ -523,7 +523,7 @@ Known Tensions: (1) nova-platform-ops repo not yet created — the 14 covere Missing Context: (1) The 18-month roadmap specifics — NORTH_STAR.md §Future Horizons has the strategic direction (CDLC→SDLC→PDLC integration, AI-Agent Intent Share ≥40%) but the PO needs to define the concrete milestone sequence for the deck. (2) Target audience specifics — "Technology Leadership" is the stated audience but the deck needs to know if this is CTO-level, VP-level, or Director-level (affects depth + framing). (3) Live AWS verification of covered-reference REQs — nova-platform-ops not yet created; M1/M1.5/M2 cutover gates not yet run. -Agent Assumptions: (1) The PDLC trigger is the post-v1.29 state intake + the PO's new initiative (leadership deck). (2) The deck uses the existing S&P theme (`docs/presentations/assets/nova-sp-theme.css`, palette `#D6002A`/`#1B1B1B`/`#FFFFFF`/`#F0F0F0`) + the existing Marp + python-pptx render pipeline (`workflows-src/slides.yml`, `scripts/render_pptx.py`). (3) The 23-slide existing deck is the source material — the ≤7-slide leadership deck is a compression, not a rewrite. (4) Coverage 73.8% is reported as YELLOW system health (below 80% floor) but is not a blocker for the deck initiative — it's quality debt for a future NFR milestone. (5) The covered-reference REQs are reported as tensions, not blockers — they have acdl-side deliverables complete + documented cutover gates. +Agent Assumptions: (1) The PDLC trigger is the post-v1.29 state intake + the PO's new initiative (leadership deck). (2) The deck uses the existing S&P theme (`docs/presentations/assets/nova-sp-theme.css`, palette `#D6002A`/`#1B1B1B`/`#FFFFFF`/`#F0F0F0`) + the existing Marp + python-pptx render pipeline (`workflows-src/slides.yml`, `scripts/render_pptx.py`). (3) **OVERRIDDEN by D-241 (v1.30 CLARIFY):** the leadership deck is a **discrete, hand-authored artifact — NOT a compression** of the 23-slide existing citizen-developer deck (`nova-autonomous-cloud-delivery-marp.md`), which remains untouched. The Slide Content Map in PROJECT.md §v1.30 is hand-authored content, not derived. (4) Coverage 73.8% is reported as YELLOW system health (below 80% floor) but is not a blocker for the deck initiative — it's quality debt for a future NFR milestone. (5) The covered-reference REQs are reported as tensions, not blockers — they have acdl-side deliverables complete + documented cutover gates. --- From 18b403fcd849228c62deff26f593806f4e79c246 Mon Sep 17 00:00:00 2001 From: CIAgent Date: Thu, 20 Aug 2026 13:16:33 +0000 Subject: [PATCH 3/6] docs(P00): research findings + persona assessment ---ci--- project: acdl phase: 0 milestone: v1.30 status: research ---/ci--- --- .ciagent/CHECKPOINT.json | 6 +- .ciagent/PERSONAS.md | 298 ++++----------- .ciagent/RESEARCH.md | 793 +++++++++++++-------------------------- 3 files changed, 328 insertions(+), 769 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 78ca2d4..29faaba 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "clarify", + "stage": "research", "milestone": "v1.30", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-20T13:25:00Z", + "updated_at": "2026-08-20T13:35:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.30", @@ -23,5 +23,5 @@ "branches_deleted": true, "releases_created": true }, - "notes": "v1.30 Phase 0 CLARIFY complete. D-241 (discrete artifact, overrides STATE.md intake assumption 3), D-242 (narrow render_pptx.py extension), D-243 (month-only date anchor). STATE.md intake assumption 3 overridden. Spec §7 Q1-Q4 auto-resolved at full autonomy. Next: RESEARCH." + "notes": "v1.30 Phase 0 RESEARCH complete. R1-R8: render pipeline behavior+limits, smoke-test conventions, Marp frontmatter/footer/notes, theme enforcement, python-pptx install (resolved), vision grounding, CAP-024 non-collision, slides.yml non-interference. PERSONAS.md: lead-developer + backend-engineer + ci-doc-writer (phase-specific) + ci-cli-engineer. frontend/data/security deactivated. Next: PLAN." } \ No newline at end of file diff --git a/.ciagent/PERSONAS.md b/.ciagent/PERSONAS.md index eb1f6a0..ba44a6f 100644 --- a/.ciagent/PERSONAS.md +++ b/.ciagent/PERSONAS.md @@ -1,267 +1,111 @@ --- project: acdl -milestone: v1.28 -generated_at: 2026-08-19 -generator: lead-developer -verification_toolchain: - typecheck: "python3 -m py_compile core/mode_resolver.py nova/cli.py 2>&1 | head -5 || true" - test: "pytest tests/test_mode_resolver.py tests/test_cli_subcommands.py -q 2>&1 | tail -15 || true" - lint: "ruff check nova/ core/lambda/nova_idp_*.py 2>/dev/null || true" - note: | - v1.28 is a feature milestone (CLI Canonicalization + Identity Layer). - Four active personas: backend-engineer (Lambda/DynamoDB/KMS/CodeArtifact), - security-engineer (Argon2id/KMS/ABAC/threat model), cli-engineer - (subcommand surface/mode_resolver/argparse/CAP-034), lead-developer - (plan/review/ship/capability gate). frontend-engineer + data-engineer - deactivated (no UI, no data pipelines). The kj-binary-in-Lambda-layer - risk (D-227, RESEARCH §7) is the highest-risk item; P2 spike confirms. ---- - -# Personas — v1.28 CLI Canonicalization + Identity Layer - -## Roster - -### backend-engineer -```yaml -active: true -domain: "Lambda functions, DynamoDB, KMS integration, dual-use packaging, CodeArtifact publish, CloudFormation generation" -frameworks: ["Python 3.12", "boto3", "argparse", "pytest", "moto[dynamodb]", "CloudFormation"] -constraints: ["INV-15", "INV-16", "INV-17", "D-228", "D-229", "D-230", "NFR-5", "NFR-6", "NFR-7", "NFR-8"] -territory: - - "core/lambda/**" - - "core/metrics/**" - - "core/env.py" - - "core/outbox_writer.py" - - "terraform/bootstrap/**" - - ".gitea/workflows/publish.yml" - - ".github/workflows/publish.yml" - - ".github/actions/nova-cli/**" -``` - -### security-engineer -```yaml -active: true -domain: "Argon2id hashing, KMS asymmetric signing (ECDSA P-256 / ES256), ABAC policy, JWKS exposure, PAT lifecycle, threat model, DER→raw ECDSA conversion" -frameworks: ["argon2-cffi", "cryptography", "pyjwt", "kyverno-json", "JMESPath", "KMS Sign/Verify/GetPublicKey"] -constraints: ["INV-15", "INV-16", "INV-17", "NFR-5", "NFR-8", "NFR-9", "D-227", "D-231"] -territory: - - "platform/abac/**" - - "core/policy_engine.py" - - "adapters/kyverno-json/**" - - "core/lambda/nova_idp_auth.py" - - "core/lambda/nova_idp_token_vend.py" - - "core/lambda/nova_idp_jwks.py" - - "docs/threat-model.md" -``` - -### cli-engineer -```yaml -active: true -domain: "CLI subcommand surface, mode_resolver, argparse, [project.scripts] entry-point, CAP-034 AST scan, nova auth/idp subgroups, property tests" -frameworks: ["Python 3.12", "argparse", "setuptools [project.scripts]", "hypothesis", "pkgutil"] -constraints: ["INV-12", "INV-13", "INV-14", "D-226", "NFR-1", "NFR-2", "NFR-3"] -territory: - - "nova/**" - - "core/mode_resolver.py" - - "pyproject.toml" - - "tests/test_mode_resolver.py" - - "tests/test_cli_subcommands.py" -``` - -### lead-developer -```yaml -active: true -domain: "Phase plan, persona roster, review gates, milestone ship, capability gate (CAP-033..038), ROADMAP/STATE/PROJECT wiring" -frameworks: ["git", "Gitea Actions", "semver tagging", ".ciagent/ discipline"] -constraints: ["INV-1..17 (cross-cutting)", "v1.28 hard constraints", "NFR-6", "NFR-11"] -territory: - - ".ciagent/**" - - "PLAN.md" - - "CHECKPOINT.json" - - "STATE.md" - - "REQUIREMENTS.md" - - "ROADMAP.md" -``` - -### frontend-engineer -```yaml -active: false -phase_specific: false -reason: "No UI in v1.28 (CLI + JSON endpoints only). JWKS serves application/json; no HTML/CSS/JS surface." -``` - -### data-engineer -```yaml -active: false -phase_specific: false -reason: "No data pipelines / metrics / PowerBI work in v1.28. The metrics layer is v1.17-complete; v1.28 adds audit events but no new fact/dim tables." -``` - -## Territory overlap notes - -- `core/lambda/contract_ingestor.py` (dual-use refactor, REQ-329) = - backend-engineer territory. `core/lambda/nova_idp_auth.py` + - `nova_idp_token_vend.py` are **co-owned** by backend-engineer (Lambda - plumbing, DynamoDB, function URLs) + security-engineer (crypto, ABAC, - Argon2id logic inside). -- `core/mode_resolver.py` = cli-engineer. `core/policy_engine.py` = - security-engineer (the ABAC evaluation path). -- `nova/idp/setup.py` = cli-engineer (the subcommand + arg parsing) + - backend-engineer (the CloudFormation generation + deploy). -- `nova/auth/*` = cli-engineer (subcommands) + security-engineer (the - token exchange + credential storage logic). - -## Phase-specific personas - -None. All four active personas span the full milestone. The -security-engineer is heaviest in P2 (identity layer) + P3 (threat model); -the cli-engineer is heaviest in P1 (CLI substrate); the backend-engineer -spans P1 (CodeArtifact/layer) + P2 (Lambdas/DynamoDB). - ---- - -# Personas — v1.29 Reposplit + Identity Layer Bring-Live - -```yaml -project: acdl -milestone: v1.29 +milestone: v1.30 generated_at: 2026-08-20 generator: lead-developer verification_toolchain: - typecheck: "python3 -m py_compile nova/idp/setup.py core/lambda/nova_idp_setup.py 2>&1 | head -5 || true" - test: "pytest tests/test_idp_auth.py tests/test_kms_roundtrip.py -q 2>&1 | tail -15 || true" - lint: "ruff check nova/idp/ core/lambda/nova_idp_setup.py 2>/dev/null || true" + typecheck: "python3 -m py_compile scripts/render_pptx.py 2>&1 | head -5 || true" + test: "bash scripts/check_leadership_deck.sh 2>&1 | tail -20; echo \"exit=$?\"" + lint: "python3 -c \"import pptx; print('python-pptx', pptx.__version__)\" 2>&1" note: | - v1.29 is a feature milestone (Reposplit + Identity Layer Bring-Live). - Pure ops/devops focus — Terraform modules are authored out-of-band in - nova-platform-ops; CIAgent in acdel delivers publish.yml, Gitea scrub, - CFN archive + CLI terraform-delegation, operator guide, consumer bump. - Five active personas: backend-engineer (publish.yml ECR image, Lambda - zip, GitHub Releases), security-engineer (kj static build verification, - KMS round-trip tests, ABAC E2E, M1.5 gate), cli-engineer (nova idp - setup --apply terraform delegation, CFN archive), data-engineer - (DynamoDB import references, outbox bootstrap docs), lead-developer - (plan/review/ship, Gitea scrub, decisions, operator guide, milestone - wiring). frontend-engineer deactivated (no UI). -``` + v1.30 is a single-shot presentation artifact milestone (Leadership + Deck). Four active personas: lead-developer (coordination + STATE.md + CAP-042 + PROJECT.md D-241), backend-engineer (render_pptx.py + extension + PPTX render + python-pptx install), ci-doc-writer + (custom, phase-specific — Marp markdown deck authoring), ci-cli- + engineer (custom — smoke-test script). frontend-engineer + + data-engineer + security-engineer deactivated (no UI, no data + pipelines, no runtime security surface — the deck is a static + artifact). The render_pptx.py extension (D-242) is the only code + change; it is a narrow prerequisite, not a REQ-372 deliverable. +--- + +# Personas — v1.30 Single-shot Leadership Deck ## Roster ### lead-developer ```yaml active: true -domain: "Milestone plan, persona roster, Gitea scrub (REQ-367), decisions D-232..240 (REQ-368), operator guide (P4), milestone ship, STATE/ROADMAP/PROJECT wiring, covered-reference REQ tracking" -frameworks: ["git", "Gitea Actions", "GitHub Actions", "semver tagging", ".ciagent/ discipline", "Terraform (reference only)"] -constraints: ["D-232 (forge parity abandoned)", "D-235 (tag-pin handoff)", "D-236 (cutover shape)", "D-238 (KJ-LOCKSTEP)", "OPER-PRIV", "TFM-HITL", "v1.29 hard constraints"] +domain: "Milestone coordination, STATE.md CAP-042, PROJECT.md D-241 record, ship discipline" +frameworks: [] +constraints: ["pragmatic", "battle-tested defaults", "D-241", "D-242", "D-243"] territory: - - ".ciagent/**" - - "PLAN.md" - - "CHECKPOINT.json" - - "STATE.md" - - "REQUIREMENTS.md" - - "ROADMAP.md" - - "PROJECT.md" - - "CLARIFY.md" - - "RESEARCH.md" - - "docs/operator-guide-platform-ops.md" - - ".github/workflows/ci.yml" - - "scripts/sync_workflows.py" - - "pyproject.toml" - - "README.md" + - ".ciagent/STATE.md" + - ".ciagent/PROJECT.md" + - ".ciagent/CHECKPOINT.json" + - ".ciagent/REQUIREMENTS.md" + - ".ciagent/ROADMAP.md" +reason: "Owns the ship-wave records (CAP-042, D-241) and milestone coordination. The deck is a single-shot artifact; the lead-developer ensures the STATE.md/PROJECT.md records are appended correctly at ship." ``` ### backend-engineer ```yaml active: true -domain: "publish.yml ECR container image build (CGO_ENABLED=0 static kj), Lambda zip + layer wheel + Python wheel attach to GitHub Releases, ECR push with tag v1.29.x-kj-, kj-version.txt read, Dockerfile for lambda:3.12-al2023 base" -frameworks: ["Python 3.12", "GitHub Actions", "Docker", "ECR", "Go (CGO_ENABLED=0 build)", "file(1)", "sha256sum"] -constraints: ["KJ-STATIC", "D-239 (ECR tag format)", "D-235 (tag-pin handoff)", "REQ-354 criteria 1-4"] +domain: "scripts/render_pptx.py extension (path arg + custom output + footer textbox), PPTX render, python-pptx install" +frameworks: ["Python 3.11", "python-pptx 1.0.2", "pip"] +constraints: ["D-242", "narrow extension only", "no new renderer", "S&P theme tokens only in source"] territory: - - ".github/workflows/publish.yml" - - "platform/abac/kj-version.txt" - - "core/lambda/nova_idp_token_vend.py" - - "core/lambda/nova_idp_auth.py" - - "core/lambda/nova_idp_jwks.py" - - "tests/test_idp_auth.py" - - "tests/test_kms_roundtrip.py" + - "scripts/render_pptx.py" + - "docs/presentations/nova-leadership-deck.pptx" +reason: "Owns the narrow render_pptx.py extension (D-242) and the PPTX render. Frameworks overridden from fastify/hono (default) to python-pptx (actual project dependency for this milestone). The extension is a non-REQ-372 prerequisite per spec §3.3 Edge 2." ``` -### security-engineer +### ci-doc-writer ```yaml active: true -domain: "kj static-link audit (file(1) asserts statically linked + no shared library), KMS round-trip test against alias/nova-oidc-signing, ABAC E2E (sign-up→sign-in→token-vend→verify, INV-17 fail-closed), M1.5 verification gate tests (8-item spike), KJ-LOCKSTEP digest-equality verification" -frameworks: ["KMS Sign/Verify/GetPublicKey", "kyverno-json", "jose", "file(1)", "readelf", "pytest", "moto[dynamodb]"] -constraints: ["KJ-STATIC", "KJ-LOCKSTEP", "INV-17 (ABAC fail-closed)", "INV-18 (JWKS-EDGE-ONLY)", "ABAC-FAIL-CLOSED", "ARGON", "KF (KMS asymmetric)"] +phase_specific: true +domain: "Marp markdown deck authoring (7 slides, speaker notes, [1] citations, S&P theme)" +frameworks: ["Marp", "Markdown"] +constraints: ["REQ-372.1", "REQ-372.3", "REQ-372.4", "REQ-372.6", "REQ-372.7", "REQ-372.9", "REQ-372.12", "D-241", "D-243"] territory: - - "platform/abac/**" - - "platform/abac/kj-version.txt" - - "adapters/kyverno-json/policies/token-vend.policy" - - "tests/test_kms_roundtrip.py" - - "tests/test_idp_auth.py" - - "tests/test_abac_e2e.py" - - "docs/threat-model.md" + - "docs/presentations/nova-leadership-deck-marp.md" +reason: "Custom persona for presentation authoring. Created for P1 (the deck is the primary deliverable). Removed after P1 ships. The deck is hand-authored against the Slide Content Map in PROJECT.md §v1.30 — NOT a compression (D-241)." ``` -### cli-engineer +### ci-cli-engineer ```yaml active: true -domain: "nova idp setup --apply terraform delegation (REQ-369 AC 2), CFN archive to docs/archive/nova-idp-cfn-v1.28.md (REQ-369 AC 3), which terraform detection + CFN fallback deprecation warning" -frameworks: ["Python 3.12", "argparse", "subprocess", "importlib", "shutil.which"] -constraints: ["REQ-369", "D-235 (tag-pin handoff)"] +domain: "Smoke-test script (bash, runnable on demand, NOT a CI gate)" +frameworks: ["Bash", "grep", "awk", "wc"] +constraints: ["REQ-372.8", "not a CI gate", "exit 0 on pass", "non-zero on fail"] territory: - - "nova/idp/setup.py" - - "core/lambda/nova_idp_setup.py" - - "docs/archive/nova-idp-cfn-v1.28.md" - - "nova/idp/__init__.py" + - "scripts/check_leadership_deck.sh" +reason: "Custom persona for the smoke-test script. Owns the 6 assertions (a–f): file exists, slide count=7, word bands, footer string, S&P colors only, PPTX exists. Pure bash — no python dependency (keeps it runnable without the python-pptx install)." ``` -### data-engineer -```yaml -active: true -phase_specific: false -domain: "DynamoDB table import references (nova-contracts, nova-change-requests, nova-outbox, nova-users, nova-sessions, nova-pats) documented in operator guide, PITR restore procedure, audit outbox bootstrap" -frameworks: ["DynamoDB", "AWS CLI (reference)"] -constraints: ["REQ-361 (import idempotency, covered-reference)", "JWKS-ROTATION"] -territory: - - "docs/operator-guide-platform-ops.md" - - ".ciagent/ARCHITECTURE.md" -reason: | - Re-activated for v1.29: the operator guide (P4) documents DynamoDB PITR - restore, table imports, and the audit outbox bootstrap — data-engineer - owns the data-layer sections of the guide. The Terraform import itself - is out-of-band (nova-platform-ops), but the operator-facing docs are - in-acdl. -``` +## Deactivated ### frontend-engineer ```yaml active: false -phase_specific: false -reason: "No UI in v1.29 (pure ops/devops focus). JWKS serves application/json via CloudFront; no HTML/CSS/JS surface." +reason: "ACDL has no frontend (no package.json); the deck is markdown (ci-doc-writer territory). Already deactivated in config.json personas[3]." ``` -## Territory overlap notes +### data-engineer +```yaml +active: false +reason: "No schema/migration/data-pipeline work in v1.30. The milestone is a single-shot presentation artifact." +``` -- `.github/workflows/publish.yml` (REQ-354) = backend-engineer (ECR - image build, Dockerfile, Lambda zip) + lead-developer (Gitea scrub - removes the `.gitea/workflows/publish.yml` mirror in P2, D-232). -- `nova/idp/setup.py` (REQ-369) = cli-engineer (the `--apply` delegation - + `which terraform` detection) + backend-engineer (the CFN archive - content — the CFN template is backend-engineer territory from v1.28). -- `platform/abac/kj-version.txt` = security-engineer (KJ-STATIC audit - reads + verifies the SHA) + backend-engineer (publish.yml reads the - SHA to embed in the ECR tag). -- `docs/operator-guide-platform-ops.md` (P4) = lead-developer (cutover - gates, cost section, artifact-mirror fallback) + data-engineer (PITR - restore, DynamoDB imports) + security-engineer (KMS rotation, JWKS - reachability, PAT revocation). +### security-engineer +```yaml +active: false +reason: "No runtime security surface in v1.30. The deck is a static artifact; the existing security posture (ABAC, KMS, JWKS) is referenced in slide content, not modified. Security review of the deck content is handled by the verify stage (no secrets, no publish.yml integration)." +``` -## Phase-specific personas +## Phase-specific persona lifecycle -None. All five active personas span the full milestone. The -backend-engineer is heaviest in P1 (publish pipeline); the -lead-developer is heaviest in P2 (Gitea scrub + decisions) + P4 -(operator guide) + P6 (final ship); the cli-engineer is heaviest in P3 -(CFN archive + TF delegation); the security-engineer is heaviest in P1 -(M1.5 gate tests) + P4 (operator guide security sections); the -data-engineer is heaviest in P4 (operator guide data sections). \ No newline at end of file +- **ci-doc-writer**: created for P1, removed after P1 ships. The deck + source is the deliverable; no further presentation authoring in P2 + (final review only). +- All other personas persist through P2 (final review + ship). + +## Territory enforcement + +- **Mode:** `warn` (per `config.json personas.territory_enforcement`). +- **Note:** v1.30 has a small, non-overlapping territory surface. + `lead-developer` owns `.ciagent/STATE.md` + `.ciagent/PROJECT.md`; + `backend-engineer` owns `scripts/render_pptx.py` + the PPTX; + `ci-doc-writer` owns the markdown source; `ci-cli-engineer` owns + the smoke-test script. No territory conflicts expected. \ No newline at end of file diff --git a/.ciagent/RESEARCH.md b/.ciagent/RESEARCH.md index c1060e3..2931da2 100644 --- a/.ciagent/RESEARCH.md +++ b/.ciagent/RESEARCH.md @@ -1,590 +1,305 @@ -# Nova — v1.28 Research Findings +# RESEARCH — v1.30 Single-shot Leadership Deck -> Phase: research (pre-execution). Milestone: v1.28 (CLI Canonicalization -> + Identity Layer). Status: research. Researcher: ci-researcher. -> Autonomy: full. -> -> Research delegated to the ci-researcher subagent (full domain/ecosystem -> research with web citations). This file is the curated summary; the -> full 868-line research document is preserved in git history (the -> subagent's task output). Key findings + recommendations are below. +> **Autonomy:** full. Research findings load-bearing for v1.30 PLAN. +> The research scope is narrow: this is a single-shot presentation +> artifact, not a runtime feature. The research covers (1) the +> existing render pipeline's behavior + limits, (2) the smoke-test +> script conventions, (3) the Marp frontmatter/footer/speaker-notes +> handling, (4) the theme-token enforcement strategy, (5) the +> python-pptx install path in this environment, (6) the vision +> document grounding for `[1]` citations. --- -## §1 — Codebase Inventory (grounding) +## R1 — Existing render pipeline (`scripts/render_pptx.py`) -### 1.1 `core/` modules (the REQ-324 subcommand surface) +**Source:** `scripts/render_pptx.py` (688 lines, REQ-269 v1.23). -19 Python files under `core/` (plus `core/lambda/`, `core/metrics/`). -Two already have `_cli.py` companions (`contract_resolver_cli.py` 40 -lines, `regression_verify_cli.py` 32 lines) — the thin-delegate -precedent for `nova/.py`. **No `nova/` dir, no `bin/`, no -`[project.scripts]` entry exists today.** The CLI is greenfield. +**Behavior:** +- Argv: `render_pptx.py [deck-name]` → reads + `docs/presentations/{deck}-marp.md`, writes + `docs/presentations/{deck}-python.pptx` (lines 677-680). **Does + not accept a full path or non-`-marp.md` filename.** +- Frontmatter: stripped (lines 62-67) — the Marp `footer:`, + `paginate:`, `theme:`, `size:`, `style:` directives are NOT read + by the python-pptx path. They are source-only (smoke test checks + source; the Marp CLI path in `render_slides.sh` reads them, but + that path needs Chromium which is unavailable here). +- Slide splitting: `re.split(r"\n---\s*\n", ...)` after frontmatter + strip (line 69). Exactly 7 `---`-delimited slides required. +- Body parsing (`parse_slide`, lines 360-498): + - HTML comments (``) are **skipped entirely** (lines + 366-379). **Speaker notes are NOT embedded in the PPTX.** + Acceptable for REQ-372.4 (smoke test checks source word counts, + not PPTX-embedded notes). + - Headings `#`/`##` → title (first) or lead (subsequent). + - Bold lead `**...**` (own line, exactly 2 `**`) → `lead` block + (red, bold). + - Blockquotes `>` → `quote` block (grey, italic). + - Unordered list `[-*+]\s+...` → `bullet` (level by indent). + **`*italic*` (no space after `*`) does NOT match** — safe as + plain text. + - Ordered list `\d+\.\s+...` → `ordered`. + - Tables `| ... |` + separator → `table`. + - `→`-prefixed lines → `plain` text (not bullets). Content + preserved. + - `_strip_inline_emphasis` (lines 209-220): `**bold**`, `*italic*`, + `` `code` `` markers are collapsed to plain text in the PPTX. + Content is preserved; emphasis styling is lost (acceptable — the + PPTX is an editable comparison artifact; REQ-372.7 content match + is by visual review). +- Theme: hardcoded S&P constants (lines 37-43): `RED=#D6002A`, + `BLACK=#1B1B1B`, `WHITE=#FFFFFF`, `GREY_HEADER=#F0F0F0`, + `GREY_TEXT=#2E2E2E`, `BODY_TEXT=#1B1B1B`. **Note: `GREY_TEXT=#2E2E2E` + is a 5th color used internally for blockquote/body text.** This is + a renderer-internal color, NOT a source hex color — REQ-372.6 + scopes to "color values extracted from the source markdown (Marp + directives + inline overrides)", so `#2E2E2E` in the renderer does + not violate REQ-372.6. The smoke test checks the *source* file for + hex colors. +- Footer: **NOT rendered.** No footer textbox is added by the + existing renderer. **D-242 extension required** to add a + right-aligned footer textbox on every slide. +- Title slide: `render_title_slide` (line 501) — black bg, red top + bar, white title. Triggered when `idx==0` + (`title_is_h1` or + `is_title_class`). The leadership deck's slide 1 uses a bold lead + (`**The friction...**`) as the first line — this is an H1 (`# The + friction...`) in the source, so slide 1 renders as a title slide + (black bg). **Decision for PLAN:** author slide 1 with `#` H1 + title (title slide, black bg, red bar — strong opener) OR author + as `##` H2 (content slide, white bg). The Slide Content Map shows + slide 1 with a bold title + italic subtitle + arrows + italic + closing — a content-rich slide. **Recommend: `##` H2 title for all + 7 slides → all render as content slides (white bg, red title bar) + for visual consistency.** Slide 1 as a black-bg title slide would + hide the `→` arrows in white-on-black, which is fine but differs + from the map's framing. The map doesn't specify background; visual + review accepts either. **Final call in PLAN:** all `##` content + slides for consistency + readability of the 3-pattern frame. -### 1.2 Existing Lambda pattern (`core/lambda/contract_ingestor.py`) - -521 lines. Function URL + IAM auth (D-051). DynamoDB via lazy -module-global `boto3.resource`. Secrets Manager for tokens. Schema -validation in-Lambda. **`__main__` block already does CLI dispatch** -(`--check-readiness` → `core.submission_readiness.cli_main`) — this is -the dual-use precedent for REQ-329. Local testing via -`core/local_emulators.py:LocalLambdaStub`. - -### 1.3 `core/env.py` — getter, not synthesizer - -31 lines. `get_env(name, default)` reads `NOVA_` from `os.environ`. -**REQ-330 needs a NEW `synthesize_local_env()` function** added here. -The closest existing pattern is `core/onboarding.py:generate_env_file()`. - -### 1.4 `PolicyEngine` Protocol + `KyvernoJsonEngine` (the ABAC substrate) - -`core/policy_engine.py`: `PolicyEngine` Protocol with `evaluate(payload, -policy_dir, contract_id) -> list[dict]`. `KyvernoJsonEngine` shells to -`kj scan --policy --payload --output json`. Policy shape = -`ValidatingPolicy` (`apiVersion: json.kyverno.io/v1alpha1`) with -`spec.rules[].assert.all[].check` using JMESPath. Severity from -`metadata.annotations["nova.cloudinit.dev/severity"]`. **The payload -can be ANY JSON** — not just contracts (the v1.25 design point). This -is what makes kyverno-json usable for ABAC token vending (D-227). - -### 1.5 `pyproject.toml` state - -name `nova`, version `1.14.0`, requires-python `>=3.10` (spec wants -3.12 — bump needed for REQ-326). setuptools build backend. No -`[project.scripts]`, no `[tool.setuptools.packages.find]` — both needed. -Deps: `boto3`, `jsonschema`, `pyyaml`. No `argon2-cffi`, `cryptography`, -`pyjwt`, `click`/`typer` — **argparse-only** is the repo convention. - -### 1.6 Forge conventions - -`.github/workflows/` + `.gitea/workflows/` kept byte-identical. Python -3.12 already pinned via `actions/setup-python@v5`. No composite action -exists yet — `nova cli-action` (REQ-326) is greenfield. - -### 1.7 IAM baseline (load-bearing for REQ-340) - -`.ciagent/IAM_POLICY.md` + `terraform/bootstrap/spike_runner_policy.json`. -The `nova-spike-runner` principal already has KMS (incl. `CreateKey`, -`Sign`, `GetPublicKey`), Lambda (incl. `PublishLayerVersion`), DynamoDB -grants. **New grants needed:** `cloudformation:*` (for `nova idp setup ---apply`) + `codeartifact:*` (for the wheel publish pipeline). Flagged -for P1/P2. +**Gaps for v1.30 (D-242 extension):** +1. Accept explicit source `.md` path + `--output` filename. +2. Add right-aligned footer textbox on every slide with exact string + `Nova Platform - Infrastructure & Operations`. --- -## §2 — CodeArtifact + Lambda Layer Pipeline (REQ-323) +## R2 — Smoke-test script conventions -**Recommendation:** single CI job on merge to `main` affecting -`core/**`/`adapters/**`/`nova/**`/`pyproject.toml`. Build wheel -(`python -m build --wheel`) → `twine upload` to CodeArtifact → build -layer (`pip install --target layer/python/ dist/nova-*.whl argon2-cffi -cryptography pyjwt`) → `aws lambda publish-layer-version` → record -version mapping in SSM `/nova/layer/nova-cli/version` (CAP-035). If -either publish fails, the job fails (merge blocked, REQ-323 AC). +**Source:** `scripts/check_north_star_diff.sh` (REQ-204), other +`scripts/check_*.sh` / `scripts/run_*.sh`. -**Atomicity:** wheel publish is idempotent (pin version to -`+`); layer publish retries on failure. CAP-035 reads the -SSM parameter to verify layer-version ↔ wheel-version match. +**Conventions:** +- Shebang `#!/usr/bin/env bash` +- Header comment with purpose + Usage + Returns +- `set -euo pipefail` +- Exit 0 on pass, non-zero (1) on fail +- `echo "WARN: ..."` / `echo "ERROR: ..."` to stderr +- Runnable from repo root: `bash scripts/check_*.sh` -**Risks:** CodeArtifact not yet provisioned in `581513795199` (CLARIFY -assumption #1); `codeartifact:*` grant missing. Fallback: Gitea-hosted -wheel index. Layer `--compatible-architectures`: build x86_64 only for -v1.28 (aarch64 only if Graviton Lambda needed). +**v1.30 smoke test (`scripts/check_leadership_deck.sh`) assertions +(REQ-372.8 a–f):** +- (a) `docs/presentations/nova-leadership-deck-marp.md` exists +- (b) slide count = 7 (count `---` separators on own line, excluding + frontmatter) +- (c) per-slide speaker-note word counts in band (extract HTML + comments per slide; slides 1/2/4/6: 150–300; 3/5: 250–400; 7: + 200–300) +- (d) footer string `Nova Platform - Infrastructure & Operations` + present in source (frontmatter `footer:` directive) +- (e) only S&P hex colors `#D6002A`, `#1B1B1B`, `#FFFFFF`, `#F0F0F0` + in source (grep for `#[0-9A-Fa-f]{6}` and diff against the allow- + list) +- (f) `docs/presentations/nova-leadership-deck.pptx` exists (hard + fail per Q-M4) + +**Implementation approach:** pure bash + `grep`/`awk`/`wc`. No +python dependency for the smoke test (keeps it runnable on demand +without the python-pptx install). Slide count: count lines matching +`^---\s*$` after the frontmatter, +1. Speaker notes: per slide, +extract content between ``, strip HTML comment markers, +`wc -w`. Color scan: `grep -oiE '#[0-9A-Fa-f]{6}'` on the source, +sort -u, compare to allow-list. --- -## §3 — CLI Subcommand Architecture (REQ-324) +## R3 — Marp frontmatter / footer / speaker-notes handling -**Recommendation:** three-layer. `nova/__init__.py` (marker) → -`nova/cli.py` (~80 lines, auto-discovers `nova/.py` via -`pkgutil.iter_modules`, dispatches, emits `cli.invocation` audit event) -→ `nova/.py` (≤50 lines each, exports `add_parser(subparsers)` -+ `run(args) -> int`, delegates to `core/`). Entry point: -`[project.scripts] nova = "nova.cli:main"`. **argparse-only** (no -click/typer — repo convention). +**Source:** `docs/presentations/nova-autonomous-cloud-delivery-marp.md` +(lines 1-27), Marp CLI v4.5.0 (available via npx). -**CAP-034 AST scan:** ≤50 lines; ≤3 function defs; every `ast.Call` -resolves to a `core.` import; no conditionals beyond `if __name__`. +**Existing deck frontmatter:** +```yaml +marp: true +theme: default +paginate: true +size: 16x9 +footer: 'Nova — The Autonomous Cloud Delivery Platform' +style: | + section { ... color: #1B1B1B; ... } + h1 { color: #D6002A; ... } + ... +``` -**Subcommand groups:** `nova auth`, `nova idp`, `nova metrics` = -nested subparsers (same pattern, one level deeper). +**v1.30 leadership deck frontmatter (per cover note + spec):** +```yaml +marp: true +theme: default +footer: "Nova Platform - Infrastructure & Operations" +paginate: false +size: 16x9 +style: | + section { font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif; font-size: 22px; color: #1B1B1B; padding: 48px 56px 40px; overflow: auto; } + h1 { color: #D6002A; font-size: 34px; margin-bottom: 0.3em; } + h2 { color: #D6002A; font-size: 26px; margin-bottom: 0.2em; } + blockquote { border-left: 4px solid #D6002A; color: #1B1B1B; font-size: 20px; padding-left: 12px; } + strong { color: #D6002A; } + ... +``` -**setuptools:** add `[tool.setuptools.packages.find]` including `nova`, -`nova.*`, `core`, `core.*`, `adapters.*`. +**Key differences from the existing deck:** +- `paginate: false` (existing: `true`) — per cover note. +- `footer: "Nova Platform - Infrastructure & Operations"` (existing: + different string) — per cover note + REQ-372.5. +- The `style:` block uses only the 4 S&P tokens. The existing deck's + `style:` uses `#2E2E2E` for blockquote color — **this must be + changed to `#1B1B1B`** in the leadership deck's `style:` block to + satisfy REQ-372.6 (only 4 hex colors in source). The renderer's + internal `GREY_TEXT=#2E2E2E` is not in the source, so it doesn't + violate REQ-372.6 — but the *source* `style:` block must not + contain `#2E2E2E`. + +**Speaker notes:** HTML comments `` within the slide +body, before the next `---`. The Marp CLI renders these as speaker +notes in the HTML/PPTX; the python-pptx path skips them. The smoke +test extracts them from the *source* for word-count checking. --- -## §4 — Argon2id in Lambda Python 3.12 (REQ-334, D-228) +## R4 — Theme-token enforcement strategy -**Findings:** `argon2-cffi-bindings` v25.1.0 ships `cp39-abi3` -manylinux x86_64 + aarch64 wheels — **ABI-stable, compatible with -Python 3.9..3.13**. Lambda Python 3.12 runs Amazon Linux 2023 (glibc -2.34 ≥ 2.28 required). **The abi3 manylinux wheel loads cleanly.** -Confidence: 0.92. +**REQ-372.6:** only `#D6002A`, `#1B1B1B`, `#FFFFFF`, `#F0F0F0` as hex +colors in the source. -**D-228 AMENDMENT:** the "pure-Python fallback" clause is **weaker than -stated** — there is no maintained pure-Python Argon2 implementation. A -pure-Python crypto fallback is a **liability** (weaker hashing, -violates INV-16's spirit). Revised recommendation: -1. **Primary:** bundled manylinux abi3 wheel in the `nova-cli` Lambda - layer. Works. Confidence 0.92. -2. **Fallback:** detect `ImportError` at Lambda cold-start → **fail - closed** (503, refuse sign-ups). The Lambda health check reports - C-extension status. **Do NOT ship a pure-Python fallback.** -3. **Escape hatch:** Fargate (~1 week, per CLARIFY Q1). - -Lambda memory ≥ 512 MB (Argon2id memory_cost ~20 MB + overhead). +**Enforcement:** +1. **Source `style:` block:** use only the 4 tokens. Replace the + existing deck's `#2E2E2E` (blockquote color) with `#1B1B1B`. +2. **No inline `color:` overrides** in slide bodies — the slides use + no inline HTML/color spans. +3. **Smoke test (8e):** `grep -oiE '#[0-9A-Fa-f]{6}'` on the source, + `sort -u`, compare to the 4-token allow-list. Any other hex color + → fail. --- -## §5 — KMS Asymmetric Signing for OIDC Tokens (REQ-337) +## R5 — python-pptx install path (this environment) -**Recommendation: key spec = `ECC_NIST_P256`, alg = `ECDSA_SHA_256` -(JWS `ES256`).** RSA-2048 is larger + slower; P-256 is RFC 7518's -recommended JWT alg. Signature size 64 bytes (vs RSA 256). JWKS -compactness matters (fetched often). +**Environment:** Debian/Ubuntu, Python 3.11.2, no system pip, no +root, no `python3-venv`/`python3-pip` packages, no `ensurepip`. -**The #1 gotcha:** KMS returns DER-encoded ECDSA signatures; **JWS -requires raw r‖s concatenation** (RFC 7515 §3.1.3). The token-vend -Lambda converts via `cryptography.hazmat.primitives.asymmetric.utils. -decode_dss_signature` → `r.to_bytes(32) + s.to_bytes(32)`. ~5 lines. -Flagged for the threat model (REQ-347) + KMS round-trip test (REQ-350). +**Resolved install path:** +1. `curl -sS https://bootstrap.pypa.io/get-pip.py -o /home/opencode/tmp/get-pip.py` +2. `python3 get-pip.py --user --break-system-packages` +3. `/home/opencode/.local/bin/pip install --user --break-system-packages "python-pptx>=0.6.23"` +4. `pip install --user --break-system-packages "pytest>=8.0"` (for + verify stage) -**Flow:** validate PAT → ABAC eval → build JWT header/payload → -`kms.sign(Message=signing_input, MessageType="RAW", SigningAlgorithm= -"ECDSA_SHA_256")` → DER→raw → JWT. `kid` = KMS key alias. +**Result:** python-pptx 1.0.2 + pytest 9.1.1 installed to user-site. +`python3 -c "import pptx"` succeeds. No Chromium needed (python-pptx +is the render path, not Marp CLI PPTX). -**Verification:** use `pyjwt` (`jwt.decode` handles JWK→key natively); -`cryptography` only for SPKI→JWK in the JWKS Lambda. - -**Rotation:** manual, 90 days (matches D-069 CMK cadence). New key + -re-point alias + JWKS serves both `kid`s during overlap. +**Confirmed in RESEARCH execution:** all commands ran successfully +in this session. --- -## §6 — JWKS Endpoint (REQ-338, D-230) +## R6 — Vision document grounding for `[1]` citations -**D-230 confirmed.** Lambda function URL (`AuthType: NONE` — JWKS is -public-key only) + reserved concurrency 10 (max 100 RPS, JWKS is -cached client-side). `Cache-Control: max-age=3600`. Separate tiny -`nova-idp-jwks` Lambda (separation of concerns). +**Source:** `docs/vision.md` (the spec's `acdl-vision.md` / `[1]` +reference). -**Custom domain + WAF = OPTIONAL** via `--public-jwks-domain ` -flag on `nova idp setup`. Without it, raw function URL (acceptable for -v1.28 pilot). With it: CloudFront + ACM + WAF rate-based rule (>100 -req/5min per IP) + Route53 ALIAS. Adds ~8 CloudFormation resources. +**Key tenets for slide grounding:** +- **§1 The Friction** (slide 1): "Software delivery scales with the + coordination surface around it, not the engineering inside it." + Grounds the three-pattern problem frame + binding-constraint + claim. +- **§3 Core Tenets** (slides 3, 5, 7): + - "The Delivery Lifecycle is a Sovereign Boundary" — grounds + slide 3's Sovereign boundary tenet + slide 5's boundary + discipline + slide 7's "Nova stays in its lane." + - "Lower Environments are Autonomous; Higher Environments are + Attested" — grounds slide 3's Lower autonomous · higher attested + tenet + slide 4's HITL discipline. + - "Infrastructure is Consumed, Not Maintained" — grounds slide 5's + "VM, bare-metal, OS lifecycles" exclusion. +- **§4 Domain Boundaries** (slides 2, 5, 6): "The platform begins + where the artifact is compiled and ends where it runs in + production." "Out of scope: Application business logic, IDE + workflows, product backlog management, sprint planning, compute + requiring node-level or OS-level management." Grounds slide 5's + in-lane/out-of-lane split + slide 6's "Nova absorbs no IDE, no + editor, no sprint tool, no agent harness." -**Defer API Gateway** (D-230) — $3.50/M + complexity for no benefit at -v1.28 volume. +**Citation convention:** `[1]` in speaker notes, resolving to +`docs/vision.md`. The spec §citation-references confirms `[1]` → +`acdl-vision.md` (vision document, source [1]). --- -## §7 — kyverno-json ABAC Policy (REQ-339, D-227) +## R7 — CAP-024 regression policy (collision check) -**D-227 confirmed.** Policy at `platform/abac/token-vend.policy` = -`ValidatingPolicy` with JMESPath checks against a payload of -`{subject, requested_claims, target_resource, environment, pat_jti, -policy_version}`. Decision logic: any `fail` PCR with severity -`critical` → deny (403 + audit); all pass → allow → KMS sign. +**Source:** `adapters/kyverno-json/policies/regression/cap-024-deck-structure.json` ++ `tests/test_regression_policies.py`. -**`policy_version` (D-231):** git SHA of the policy file, baked into -the Lambda layer, recorded in every `token.vend.allowed/denied` audit -event. - -**BIGGEST PACKAGING RISK:** the token-vend Lambda needs the `kj` Go -binary (~40 MB) on PATH. Bundle it in the `nova-cli` Lambda layer -(`wget` the Linux amd64 release into `layer/bin/kj`). `KyvernoJsonEngine -.is_configured()` checks `which kj` → `/opt/bin/kj` (layer mount). P2 -spike confirms it runs in AL2023 Lambda. Fallback: Fargate. Confidence -0.75 — needs the spike. +**Finding:** CAP-024 validates the citizen-developer deck's 4-beat +arc (Problem/Solution/Proof/Roadmap+Ask) against fixture files +(`clean.json`/`drifted.json` in `tests/fixtures/`), NOT against the +actual deck markdown files. The leadership deck +(`nova-leadership-deck-marp.md`) does NOT pass through this policy. +No collision risk. The leadership deck's 7-slide structure is a +different artifact (CAP-042, not CAP-024). --- -## §8 — PAT Lifecycle (REQ-342, REQ-343, REQ-344) +## R8 — `slides.yml` CI (non-interference check) -**PAT = signed JWT** (KMS-signed, `typ: "developer_pat"` distinguishes -from `nova_oidc_token` per INV-14). Claims: `iss, sub, typ, jti, iat, -exp, roles, owner`. +**Source:** `workflows-src/slides.yml`. -**`nova-pats` DynamoDB table** (4th table): PK=`jti`, GSI1=`sub` (list -PATs for user), GSI2=`pat_hash` (lookup by hash). Only the hash stored -(not raw PAT). Revoked PATs retained for audit. - -**Revocation (D-229 CLARIFIED):** GSIs don't support strongly-consistent -reads. The token-vend Lambda extracts `jti` from the PAT JWT (decode -without verifying — signature verified separately) → -`GetItem(PK=jti, ConsistentRead=True)` on the main table. Satisfies the -60s SLO. Confidence 0.90. - -**CLI:** `nova auth login` (session→OIDC token, store locally), -`nova auth revoke --pat `, `nova auth status` (active credential, -mode, selection_reason). Local file `~/.nova/credentials.json` (0600, -never to stdout, in `.gitignore`). "Most recent wins" (D-226 Q5) = -`active_credential_jti` field. +**Finding:** The CI workflow triggers on `docs/presentations/**` +path changes, but `scripts/render_slides.sh` defaults to +`DECK="nova-autonomous-cloud-delivery"` and only renders that one +deck. Adding `nova-leadership-deck-marp.md` to +`docs/presentations/` will trigger the CI, but it will only re- +render the citizen-developer deck (no-op if that deck is unchanged). +The leadership deck is NOT rendered by CI (per spec: no CI gate, no +`publish.yml` integration). **No interference.** The bot commit from +CI (if any) will be a no-op re-render of the unchanged citizen- +developer deck. --- -## §9 — `nova idp setup` CloudFormation (REQ-340, REQ-341) - -**Template (raw dict → JSON, no troposphere dep):** 2-3 Lambdas, 4 -DynamoDB tables (`nova-users`, `nova-sessions`, `nova-password-resets`, -`nova-pats`), KMS key `alias/nova-oidc-signing` (ECC_NIST_P256), -function URLs, IAM roles, optional CloudFront/WAF/ACM. - -**`--check`:** validates prerequisites (AWS creds, CFN perms, KMS perms, -layer exists via CAP-035). Prints required IAM policy delta. -**`--apply`:** generate → print to temp file + resource summary → -`$PAGER` → `Apply? [y/N]` → `cloudformation deploy --capabilities -CAPABILITY_IAM`. NFR-10 satisfied by the explicit prompt. -**`--dry-run`:** resource list only, no write. -**`--verify`:** runs the KMS round-trip test (REQ-350). - -**New IAM grants needed:** `cloudformation:*`, `iam:CreateRole`/`PassRole`, -`lambda:CreateFunction`/`CreateFunctionUrlConfig`, -`dynamodb:CreateTable`, `kms:CreateKey`/`CreateAlias`, `ssm:PutParameter`. - ---- - -## §10 — GitHub + Gitea Marketplace Composite Action (REQ-326) - -**Single `action.yml`** at `.github/actions/nova-cli/action.yml`, -referenced by both GitHub + Gitea via `uses: continuous-intelligence/ -acdl/.github/actions/nova-cli@v1.28`. Composite action: `setup-python@v5` -(python 3.12) → CodeArtifact login + `pip install nova` → `nova -${{ inputs.command }}`. `NOVA_CLIENT_MODE` env from input. - -**Byte-identical test (REQ-326 AC2):** CI matrix runs the action on -GitHub `ubuntu-latest` + Gitea `act_runner` with same inputs; assert -same stdout/exit code. - -**Risk:** Gitea `actions/checkout`/`setup-python` may need Gitea -mirrors (`https://gitea.com/actions/...`). P1 test on the actual Gitea -instance. Confidence 0.70. - ---- - -## §11 — `mode_resolver` Priority (REQ-327, D-226) - -**TTY detection: check `sys.stdin.isatty()`** (NOT stdout). Edge 3 -(`nova apply | tee log.txt`): stdout piped, stdin is TTY → user is -present → `interactive` (correct). `sys.stdout.isatty()` would -misresolve to `agent`. **`stdin` answers "is a human at a terminal?"** - -**Credential type detection:** read `~/.nova/credentials.json` → -`active_credential_jti`'s `type` (`developer_pat`/`nova_oidc_token`). -Both + TTY → `interactive`; + no TTY → `agent` (INV-14). - -**Property tests (REQ-349):** `hypothesis` with strategies for -flag/env/cred/tty. Properties: deterministic (INV-13), flag-wins, -invalid-env-ignored, no-silent-fallback (every resolution has a -non-empty `selection_reason`). - -**`mode_resolver.py` lives in `core/`** (not `nova/`) so Lambdas could -import it, but **it's CLI-only** — the token-vend Lambda doesn't resolve -modes. - ---- - -## §12 — Persona Assessment - -See `.ciagent/PERSONAS.md` for the full YAML roster. Summary: -- **Deactivate** frontend-engineer (no UI) + data-engineer (no data - pipelines in v1.28). -- **Activate** backend-engineer (Lambda/DynamoDB/KMS/CodeArtifact) + - lead-developer (plan/review/ship). -- **Add** security-engineer (Argon2id/KMS/ABAC/threat model) + - cli-engineer (subcommand surface/mode_resolver/argparse/CAP-034). - ---- - -## §13 — Architecture Sketch (ARCHITECTURE.md §12.10) - -See `.ciagent/ARCHITECTURE.md` §12.10 (appended this stage). New -greenfield files: `nova/` CLI package, `platform/abac/token-vend.policy`, -`core/mode_resolver.py`, `core/env.py:+synthesize_local_env()`, -`core/lambda/nova_idp_{auth,token_vend,jwks}.py`, `tests/test_*`, -`docs/{operator-guide-idp,developer-guide-auth,threat-model}.md`. - ---- - -## Decisions re-validated / amended - -| Decision | Status | Change | -|---|---|---| -| D-226 | re-validated + refined | `sys.stdin.isatty()` is the TTY check (not stdout) | -| D-227 | re-validated | `kj` Go binary bundled in Lambda layer — packaging risk flagged | -| D-228 | **amended** | Pure-Python fallback → fail-closed + Fargate (pure-Python crypto is a liability) | -| D-229 | re-validated + clarified | Strong read on main table PK (`jti`), not GSI (GSIs don't support strong reads) | -| D-230 | re-validated | CloudFront/WAF/ACM made optional via `--public-jwks-domain` flag | -| D-231 | re-validated | `policy_version` (git SHA) in the ABAC payload | - -**New recommendations for PLAN/GRILL to formalize (no D-ID yet):** -- KMS key spec = `ECC_NIST_P256`, alg `ES256`; DER→raw ECDSA conversion required. -- `nova-cli` Lambda layer bundles the `kj` Go binary (~40 MB). -- `nova-pats` = 4th DynamoDB table; PK=`jti`, GSI1=`sub`, GSI2=`pat_hash`. -- `sys.stdin.isatty()` is the TTY heuristic. -- `[project.scripts] nova = "nova.cli:main"`; argparse-only. -- `cloudformation:*` + `codeartifact:*` = new IAM baseline grants (P1/P2). - ---- - -## RESEARCH complete - -All 11 research questions answered with cited findings + concrete -recommendations + risks. D-228 amended (fail-closed, not pure-Python -fallback). The `kj` binary packaging is the highest-risk item (P2 -spike). Next: PLAN. - ---- - -# Nova — v1.29 Research Findings - -> Phase: research (pre-execution). Milestone: v1.29 (Reposplit + Identity -> Layer Bring-Live). Status: research. Researcher: ci-researcher. -> Autonomy: full. -> -> Research delegated to the ci-researcher subagent (10 topics — Terraform -> import idempotency, `data.aws_ecr_image` digest resolution, -> `lifecycle.precondition`, CloudFront OAC for Lambda Function URL, WAF -> on CloudFront, ACM DNS validation + Route53 alias, `kj` Go binary -> static build, ECR tag format, codebase inspection, Gitea Actions HITL). -> This file is the curated summary. Key findings + recommendations below. - ---- - -## §1 — Terraform `import` idempotency (REQ-361) - -- `terraform import ` reads an existing cloud resource into - state without modifying it; the resource must have a matching - `resource` block in config. -- Re-importing an address already in state fails with **`Error: Resource - already managed by Terraform`** (non-zero exit). The CI import step - must treat this specific error as idempotent success (grep the - message, not just exit code) — this is the IMPORT-IDEMPOTENT contract. -- `importable-resources.tf` is a convention (not built-in): a dedicated - file listing resource addresses imported from the live account (S3 - state bucket, DynamoDB tables, IAM OIDC role, KMS keys) so the import - surface is enumerable + reviewable. -- Drift detection: `terraform plan -detailed-exitcode` (exit 2 = drift) - fails the apply; the state bucket is bootstrapped manually then - imported (never created by Terraform — avoids bootstrapping the - bootstrapper, Q1/§7.1, D-235). - -**Recommendation:** `nova-platform-ops` maintains an -`importable-resources.tf` map; CI import treats "already managed" as -idempotent success; `plan -detailed-exitcode` asserts zero drift. - -## §2 — `data.aws_ecr_image` digest resolution (REQ-355, REQ-371) - -- `data "aws_ecr_image" "kj_image" { repository_name = …; image_tag = … }` - resolves the tag to an **immutable `sha256:` digest** via - `image_digest`. -- ECR tags are mutable by default (a re-push moves a tag → different - digest). KJ-LOCKSTEP pins on `image_digest`, never the tag. -- `image_uri` = `${data.aws_ecr_repository.kj.repository_url}@${data.aws_ecr_image.kj_image.image_digest}` - — pinning by `@digest`, not `:tag`. Both Lambda and Fargate reference - the same data source → same digest by construction. -- `data.aws_ecr_image` reads at plan time; if the tag doesn't exist - (engineering hasn't published), the data source fails the plan (Q7 - fail-closed). - -**Recommendation:** Both image-bearing resources reference a single -`data.aws_ecr_image.kj_image`; `image_uri` = `repo@digest`; LOCKSTEP is -true by construction + the precondition (§3) is a verification. - -## §3 — `lifecycle.precondition` — the KJ-LOCKSTEP mechanism (REQ-371) - -- **Version correction (D-240):** preconditions introduced in - **Terraform v1.2.0 (May 2022)**, NOT v1.4+ as the spec implies. The - ops repo `required_version = ">= 1.2.0"` suffices. -- Syntax: `precondition` block inside `lifecycle { … }` for resources. - Evaluated **before** the resource action (during planning); a failing - precondition aborts the **plan** with the custom `error_message`. -- `error_message` is a string expression — can interpolate values: - `error_message = "KJ-LOCKSTEP: Fargate='${aws_ecs_task_definition.kj.image}' canonical='${data.aws_ecr_image.kj_image.image_digest}'"`. -- Asserting two attributes resolve to the same value: - ```hcl - lifecycle { - precondition { - condition = self.image_uri == "${data.aws_ecr_repository.kj.repository_url}@${data.aws_ecr_image.kj_image.image_digest}" - error_message = "KJ-LOCKSTEP: Lambda image does not match the resolved ECR digest" - } - } - ``` - -**Pitfalls:** precondition blocks cannot reference `count`/`for_each` -unexpanded resources; both resources must depend on the same data source -(explicit `depends_on` if `image_uri` is computed indirectly). - -**Recommendation:** Add `lifecycle { precondition { … } }` to **both** -the Lambda and Fargate task; set `required_version = ">= 1.2.0"`. - -## §4 — CloudFront OAC pinning to Lambda Function URL (D-233, REQ-364) - -- **Critical:** CloudFront OAC for a Lambda Function URL origin requires - `AuthType: AWS_IAM` on the Function URL (NOT `AuthType: NONE`). With - `AWS_IAM`, direct access returns 403 unless SigV4-signed; CloudFront + - OAC signs requests on the viewer's behalf → CloudFront 200, direct 403 - (INV-18 JWKS-EDGE-ONLY). -- OAC resource: `OriginAccessControlOriginType = "lambda"`, - `SigningBehavior = "always"`, `SigningProtocol = "sigv4"`. Attach via - `OriginAccessControlId` on the origin block; HTTPS only. -- Resource-based permission: `aws lambda add-permission --action - lambda:InvokeFunctionUrl --principal cloudfront.amazonaws.com - --source-arn ` — binds the Function URL to the - specific distribution. -- OAC replaces the deprecated S3-origin OAI; for Lambda origins, OAC is - the only signing mechanism. - -**Pitfall:** if `AuthType: NONE` is left on the Function URL, OAC signing -is ignored and the URL stays public — the 403 guarantee evaporates. - -**Recommendation:** JWKS Function URL `authorization_type = "AWS_IAM"`, -`lambda`-type OAC (`SigningBehavior: always`), `lambda:InvokeFunctionUrl` -permission scoped to the distribution ARN. - -## §5 — WAF WebACL rate-limit + AWS Managed Rules on CloudFront (REQ-365) - -- Rate-based rule: `RateBasedStatement` with `Limit: 3000`, - `AggregateKeyType: "IP"`, `EvaluationWindowSec: 300` (5-min window; - accepted values 60/120/300/600). WAF checks ~every 10s. -- AWS Managed Rules Common Rule Set = managed rule group - `AWSManagedRulesCommonRuleSet` (vendor `AWS`), attached as a separate - priority from the rate rule. -- CloudFront WebACLs **must** be created in `us-east-1` with - `Scope = "CLOUDFRONT"` (regional WebACLs cannot associate with - CloudFront). -- CloudWatch metrics: per-rule `VisibilityConfig.CloudWatchMetricsEnabled - = true`; S3 access logs via `aws_cloudfront_distribution.logging_config`. - -**Recommendation:** WebACL in `us-east-1` `Scope=CLOUDFRONT`; rate rule -(3000/5min/IP) + Common Rule Set; associate to JWKS distribution; -CloudWatch metrics + S3 access logs. - -## §6 — ACM cert DNS validation + Route53 alias (REQ-366) - -- ACM DNS validation: `aws_acm_certificate` with - `validation_method = "DNS"`; create `aws_route53_record` for each - `domain_validation_options` CNAME; `aws_acm_certificate_validation` - waits on `ISSUED`. For CloudFront, the cert **must** be in - `us-east-1`. -- Route53 alias: `type = "A"`, `alias { name = - aws_cloudfront_distribution.jwks.domain_name; zone_id = - aws_cloudfront_distribution.jwks.hosted_zone_id; - evaluate_target_health = false }`. -- `route53_record_not_resolvable` failure mode: the alias doesn't - resolve until CloudFront `status = Deployed` AND ACM cert `ISSUED`. If - the validation CNAME is mis-created or Route53 is not authoritative, - the CNAME never validates → cert stays `PENDING_VALIDATION` → alias - NXDOMAIN. - -**Recommendation:** ACM cert in `us-east-1` DNS validation; validation -CNAMEs in the authoritative Route53 zone; `aws_acm_certificate_validation` -gates on `ISSUED`; Route53 A-alias to the distribution. Operator guide -documents the `route53_record_not_resolvable` → check-cert-status -debugging path. - -## §7 — `kj` Go binary static build for AL2023 Lambda (KJ-STATIC, REQ-354, REQ-363) - -- Build: `CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s - -w" -o kj ./…`. `CGO_ENABLED=0` is load-bearing — no cgo, no dynamic - libc link. -- `file(1)` must report `ELF 64-bit LSB executable, x86-64, statically - linked` + absence of `shared library`/`interpreter`. Secondary: - `readelf -d kj` shows no `NEEDED` entries. -- Base image `public.ecr.aws/lambda/python:3.12-al2023`; copy binary to - `/opt/kj/kj` `chmod 0555` owned by `sbx_user:1051` (Lambda sandbox - user, uid/gid 1051 in AL2023). `0555` + immutable-owned prevents - runtime tampering. -- Lambda handler invokes `subprocess.run(['/opt/kj/kj', 'apply', …], - capture_output=True, check=True)` — `kj` is a substrate binary, not a - library; the Python handler is a thin shim. kyverno-json (INV-4) is - separate + unaffected. - -**Pitfall:** `CGO_ENABLED=1` (default on systems with gcc) produces a -dynamically-linked binary; AL2023 glibc mismatch → runtime -`GLIBC_X not found`. `CGO_ENABLED=0` eliminates this. - -**Recommendation:** `publish.yml` P1 builds with `CGO_ENABLED=0 -GOOS=linux GOARCH=amd64`, asserts `file` reports `statically linked` + -no `shared library` (fail build otherwise), copies to `/opt/kj/kj` -`chmod 0555`, handler calls `subprocess.run(['/opt/kj/kj', 'apply', …])`. - -## §8 — ECR image tag format (REQ-354 AC 3) — SPEC CORRECTION (D-239) - -- **ECR image tags do NOT allow `+`.** The ECR tag regex is - `^[a-zA-Z0-9]+(?:[._-][a-zA-Z0-9]+)*$` — permitted chars - `[a-zA-Z0-9._-]` only; `+` is rejected by `PutImage`/`BatchGetImage` - with `InvalidParameterException`. -- The spec's tag format `v1.29.x+kj-` is **invalid** as written. - Correct format: **`v1.29.x-kj-`** (replace `+` with `-`). -- The digest is the immutable trust surface regardless of the tag string - — a re-tag is detectable only via digest mismatch. The tag is a human - hint, not a security boundary. - -**Decision D-239 (spec correction):** REQ-354 AC 3 tag format corrected -to `v1.29.x-kj-`. Confidence 0.95. Applied to REQUIREMENTS.md -§v1.29 REQ-354 AC (3). - -## §9 — Codebase inspection (actual file paths) - -| Target | Path | Summary | -|---|---|---| -| `publish.yml` | `.github/workflows/publish.yml` (165 lines) + `.gitea/workflows/publish.yml` mirror | Currently publishes wheel + Lambda layer on `push: branches: [main]` (NOT tag-triggered). P1 must change trigger to `on: push: tags: ['v1.29.*']` + attach Lambda zip + ECR image to GitHub Releases. | -| `nova/idp/setup.py` CFN | `nova/idp/setup.py` (40 lines, thin CLI dispatcher) + `core/lambda/nova_idp_setup.py` (actual CFN logic, importlib-loaded because `lambda` is reserved) | REQ-369 archives to `docs/archive/nova-idp-cfn-v1.28.md`; `--apply` delegates to `terraform apply`. | -| `platform/abac/kj-version.txt` | `platform/abac/kj-version.txt` (2 lines: `v0.0.3` + SHA `4ebb9a19...`) | Already pins `kj` v0.0.3 + source SHA from v1.28 P4. P1 reads this SHA to embed in the ECR tag + verify the build. | -| `.gitea/` scrub targets | `.gitea/workflows/` (7 files) + `scripts/sync_workflows.py` (line 26: `GITEA_DIR`), `scripts/sync_to_nova.sh`, `scripts/rotate_spike_key.sh`, `terraform/bootstrap/`, ~100 `.ciagent/` doc matches | REQ-367 P2 removes `.gitea/`, scrubs `gitea` from `.github/` `docs/` `pyproject.toml` `README.md` `.ciagent/`, asserts `forge_parity_disabled` in CI (D-232). `sync_workflows.py` is the central removal target. | -| Consumer `deploy.yml` | NOT in `acdl/.github/workflows/deploy.yml` (that's the platform reusable workflow). Consumer's deploy.yml is in the `nova-blockchain-exchange` project — documented at `.ciagent/nova-blockchain-exchange/REQUIREMENTS.md` (REQ-314) + `.ciagent/nova-blockchain-exchange/README.md`. | P5 bumps consumer's `uses:` ref `@v1.25` → `@v1.29` in both `.github/workflows/deploy.yml` + `.gitea/workflows/deploy.yml` (consumer's `.gitea/` is out of scope for REQ-367 — that scrub is `acdl/acdl` only) + smoke test. | - -## §10 — Gitea Actions HITL approval (REQ-357, TFM-HITL) - -- Gitea Actions has **no Environments API** with required reviewers. The - approval signal is `gitea.actor` (triggering user) + - `gitea.triggering_actor` (may differ on re-run — the re-dispatcher). -- PR author: `${{ gitea.event.pull_request.user.login }}`. INV-3 check: - `${{ gitea.triggering_actor }} != ${{ gitea.event.pull_request.user.login }}` - (use `triggering_actor` for re-run safety). -- Gitea scoped-workflows (v1.27+) supports **required workflows** that - gate PR merges via status checks — but this gates *merge*, not *apply*. -- The `workflow_dispatch` approve-input pattern (D-042) is the mechanism: - plan runs automatically on PR; apply is a separate `workflow_dispatch` - with `approve_apply` input; the apply job asserts INV-3 + fails closed. -- **Codebase precedent:** `core/hitl_gates.py` + `core/separation_of_duties.py` - (D-042) — `hitl_gates.attest(env, approver)` reads - `GITHUB_ACTOR`/`FORGE_ACTOR`, writes to DynamoDB outbox; - `separation_of_duties.check` compares approvers. This is the production - pattern to extend for `nova-platform-ops` `terraform apply`. - -**Pitfalls:** scoped-workflow required-check enforcement needs branch -protection on `main`; a re-run changes `gitea.actor` to the re-dispatcher -— use `gitea.triggering_actor` for the effective approver. - -**Recommendation:** `nova-platform-ops` uses `workflow_dispatch` -approve-input pattern (extending `hitl_gates.py`/`separation_of_duties.py`); -plan auto-runs on PR, apply is `workflow_dispatch` with `approve_apply`; -apply job asserts `${{ gitea.triggering_actor }} != ${{ gitea.event.pull_request.user.login }}`; -branch protection on `main` + required scoped-workflow status check. - ---- - -## New decisions for the decision ledger (research-derived) - -| D-ID | Title | Confidence | Source | -|---|---|---|---| -| **D-239** | ECR tag format `v1.29.x+kj-` invalid (`+` not in ECR tag regex) → corrected to `v1.29.x-kj-` | 0.95 | §8 ECR API PutImage character class | -| **D-240** | `lifecycle.precondition` introduced in Terraform v1.2.0 (not v1.4+); ops repo `required_version = ">= 1.2.0"` suffices | 0.98 | §3 Terraform v1.2.0 CHANGELOG | - -Both are spec-vs-reality corrections logged at full autonomy (confidence -≥ 0.60 threshold). D-239 is applied to REQUIREMENTS.md §v1.29 REQ-354 -AC (3). D-240 is documented in the operator guide (P4) for the -`nova-platform-ops` `required_version` floor. - ---- - -## RESEARCH complete - -All 10 research questions answered with cited findings + concrete -recommendations + risks. Two spec corrections (D-239 ECR tag, D-240 -Terraform precondition floor). The highest-risk item is the M1.5 -verification gate (Q7 carry-forward — `kj` static build + 3 consecutive -rebuilds in `nova-platform-ops` CI). Next: PLAN. \ No newline at end of file +## Persona assessment (lead-developer) + +**Active personas for v1.30:** +- **lead-developer** (coordination) — owns STATE.md CAP-042, PROJECT.md + D-241, milestone coordination. Territory: `.ciagent/STATE.md`, + `.ciagent/PROJECT.md`. +- **backend-engineer** (backend) — owns `scripts/render_pptx.py` + extension + PPTX render + python-pptx install. Territory: + `scripts/render_pptx.py`, `docs/presentations/nova-leadership-deck.pptx`. + Framework override: python-pptx (not fastify/hono — the default + frameworks don't match this project's Python stack). +- **ci-doc-writer** (custom, phase-specific) — owns the Marp markdown + deck source. Territory: + `docs/presentations/nova-leadership-deck-marp.md`. Created for this + phase (presentation authoring); removed after P1. +- **ci-cli-engineer** (custom) — owns the smoke-test script. + Territory: `scripts/check_leadership_deck.sh`. + +**Deactivated personas:** +- **frontend-engineer** — already `active: false` in config (no UI). + Confirmed. +- **data-engineer** — no schema/migration work in this milestone. + Deactivate for v1.30. + +**Territory enforcement:** `warn` (per config). \ No newline at end of file From e560adacb60c628d59943637f3a69e0358ae517d Mon Sep 17 00:00:00 2001 From: CIAgent Date: Thu, 20 Aug 2026 13:17:16 +0000 Subject: [PATCH 4/6] =?UTF-8?q?docs(P00):=20create=20phase=20plans=20?= =?UTF-8?q?=E2=80=94=20P1=20leadership-deck=20(4=20waves)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.30 status: plan ---/ci--- --- .ciagent/CHECKPOINT.json | 6 +- .ciagent/PLAN.md | 1236 +++++++------------------------------- 2 files changed, 229 insertions(+), 1013 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 29faaba..2682cc6 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "research", + "stage": "plan", "milestone": "v1.30", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-20T13:35:00Z", + "updated_at": "2026-08-20T13:45:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.30", @@ -23,5 +23,5 @@ "branches_deleted": true, "releases_created": true }, - "notes": "v1.30 Phase 0 RESEARCH complete. R1-R8: render pipeline behavior+limits, smoke-test conventions, Marp frontmatter/footer/notes, theme enforcement, python-pptx install (resolved), vision grounding, CAP-024 non-collision, slides.yml non-interference. PERSONAS.md: lead-developer + backend-engineer + ci-doc-writer (phase-specific) + ci-cli-engineer. frontend/data/security deactivated. Next: PLAN." + "notes": "v1.30 Phase 0 PLAN complete. 1 execution phase (P1) — single-shot artifact. 4 waves: W1 render_pptx.py extension, W2 deck source, W3 smoke test, W4 render+records. MVP/UX checklist: User-Facing Surface (PPTX+source+smoke test), Happy Path (J1), UX Acceptance Criteria (8 items). Next: GRILL." } \ No newline at end of file diff --git a/.ciagent/PLAN.md b/.ciagent/PLAN.md index 19eb629..7e007af 100644 --- a/.ciagent/PLAN.md +++ b/.ciagent/PLAN.md @@ -1,1059 +1,275 @@ -# PLAN — v1.28 CLI Canonicalization + Identity Layer +# PLAN — v1.30 Single-shot Leadership Deck -> **Milestone:** v1.28 (feature — CLI substrate + Nova-idp identity -> layer). Tags on the **v1.27.x** line: `v1.27.0` (P0) → -> `v1.27.1..v1.27.6` (P1..P6) → `v1.27.7` (P7 final = milestone -> release). The final phase's patch IS the milestone release. -> **Branch:** `milestone/v1.28-cli-identity`. Phase branches: -> `phase/00-pre-execution`, `phase/01-cli-substrate`, -> `phase/02-lambda-packaging`, `phase/03-idp-auth`, -> `phase/04-token-vend-pat`, `phase/05-docs-integration`, -> `phase/06-final-review-ship`. +> **Milestone:** v1.30 (feature — single-shot PPTX leadership deck). +> Tags on the **v1.29.x** line: `v1.29.1` (P0) → `v1.29.2` (P1 +> execution) → `v1.29.3` (P2 final = milestone release). The final +> phase's patch IS the milestone release. +> **Branch:** `milestone/v1.30-leadership-deck`. Phase branches: +> `phase/00-pre-execution`, `phase/01-leadership-deck`, +> `phase/02-final-review-ship`. > -> **Tags:** `v1.27.0` (P0) → `v1.27.1..v1.27.5` (P1..P5) → -> `v1.27.6` (P6 final = milestone release). 6 execution phases -> (P5 idp-setup folded into P4 Wave 8 per grill C-2.1). +> **Tags:** `v1.29.1` (P0) → `v1.29.2` (P1) → `v1.29.3` (P2 final = +> milestone release). **1 execution phase** (P1) — this is a +> single-shot artifact, not a multi-phase build. ## Milestone goal -The Nova CLI is installable from internal PyPI (CodeArtifact); every -`core/` module is reachable as a `nova `; the CLI and -Lambda functions share a single `core/` source tree; and Nova owns its -identity layer end-to-end (Nova-idp: `nova-idp-auth` + -`nova-idp-token-vend` Lambdas, KMS-signed OIDC tokens, kyverno-json -ABAC token vending, PAT lifecycle). No AWS-managed identity services -in the path (INV-15). +A single-shot, 7-slide PPTX leadership deck for Infrastructure & +Operations leadership (CTO + VP Technology + Product Management), +presented live in August 2026, securing architecture endorsement and +a November 2026 runway. Authored as Marp markdown, rendered via the +existing `scripts/render_pptx.py` (narrowly extended per D-242), +verified by `scripts/check_leadership_deck.sh`. The deck is discrete +from the existing citizen-developer pitch (D-241: NOT a compression). ## Requirements -31 requirements: REQ-323..REQ-353 (full text in -`.ciagent/REQUIREMENTS.md` §v1.28). 6 capabilities: CAP-033..CAP-038. -6 invariants: INV-12..INV-17. 6 decisions: D-226..D-231 (CLARIFY) + -RESEARCH amendments (D-228 fail-closed, D-229 strong-read-on-PK). +12 requirements: REQ-372.1..REQ-372.12 (full text in +`.ciagent/REQUIREMENTS.md` §v1.30). 1 capability: CAP-042. 3 +decisions: D-241..D-243 (CLARIFY). Vision grounding: `[1]` → +`docs/vision.md`. ## Phase breakdown -### Phase P1 — cli-substrate (REQ-323..REQ-328) +### Phase P1 — leadership-deck (REQ-372.1..REQ-372.12) -**Goal:** CodeArtifact wheel + Lambda layer pipeline; `nova/` CLI -package with a subcommand per `core/` module; `nova init`; `nova -cli-action` composite action; `core/mode_resolver.py`; audit emission -with `mode` + `selection_reason`. The CLI is installable and every -`core/` module is reachable. +**Goal:** Author the Marp markdown deck source, extend the render +pipeline, render the PPTX, author the smoke test, and append the +ship-wave records (CAP-042, D-241). The deck is a single-shot +artifact; all 12 REQs ship in this one phase. -**Exit criterion:** CAP-033 + CAP-034 + CAP-035 Verified + all REQ-323..328 -tests pass. CodeArtifact provisioned (Wave 0 gate). +**Personas:** lead-developer, backend-engineer, ci-doc-writer +(phase-specific), ci-cli-engineer. -#### Wave 0 — CodeArtifact provisioning (backend-engineer) [C-3.2/C-8.1] -- **Task 0.1** (backend-engineer): provision CodeArtifact domain - (`nova`) + repository (`nova-pypi`) in `581513795199`. Verify - `codeartifact:*` IAM grant on `nova-spike-runner`. **Binary go/no-go - gate for Wave 4.** If fail: activate Gitea wheel index fallback - (CLARIFY assumption #1) and document in PLAN.md. +**Territory:** `docs/presentations/nova-leadership-deck-marp.md` +(ci-doc-writer), `scripts/render_pptx.py` + +`docs/presentations/nova-leadership-deck.pptx` (backend-engineer), +`scripts/check_leadership_deck.sh` (ci-cli-engineer), +`.ciagent/STATE.md` + `.ciagent/PROJECT.md` (lead-developer). -#### Wave 1 — pyproject + entry point (cli-engineer) -- **Task 1.1** (cli-engineer): `pyproject.toml` — add - `[project.scripts] nova = "nova.cli:main"`; add - `[tool.setuptools.packages.find]` including `nova`, `nova.*`, `core`, - `core.*`, `adapters.*`; bump `requires-python` to `>=3.12`; add - `argon2-cffi`, `cryptography`, `pyjwt`, `hypothesis` to deps/test-deps. - Verify `pip install -e .` produces a `nova` executable. +#### Wave 1 — render pipeline prerequisite (backend-engineer) -#### Wave 2 — CLI dispatch + subcommands (cli-engineer) -- **Task 2.1** (cli-engineer): `nova/__init__.py` + `nova/cli.py` - (~80 lines, auto-discovers `nova/.py` via `pkgutil.iter_modules`, - dispatches, emits `cli.invocation` audit event stub with INV-12 fields). -- **Task 2.2** (cli-engineer): `nova/.py` for each `core/` - module (≤50 lines, `add_parser` + `run` delegates to `core/`). Cover: - `resolve`, `decommission`, `env-transition`, `env-check`, `hitl`, - `onboard`, `outbox`, `publish-outputs`, `policy`, `regression`, `sod`, - `readiness`, `attestation-matrix`, `confidence`. Skip internal-only - (`env`, `local_emulators`, `output_publisher` if not user-facing). -- **Task 2.3** (cli-engineer): `nova/init.py` (REQ-325) — scaffolds - `.nova/`, `.nova/contract.yml.attestations/`, `.gitignore` (excludes - secrets, `~/.nova/credentials.json`). +**Task P1.W1.T1:** Extend `scripts/render_pptx.py` per D-242: +- Accept an explicit source `.md` path as argv[1] (if it ends in + `.md` and contains a `/`, treat as a path; else treat as a deck + name per the existing convention — backward compatible). +- Accept `--output ` for the custom output filename. Default: + derive from the source name (strip `-marp.md` → add `.pptx`) for + backward compatibility. +- Add a `_add_footer(slide, text)` helper that adds a right-aligned + textbox at the bottom of every slide with the exact string + `Nova Platform - Infrastructure & Operations` (grey, small). Call + it in both `render_title_slide` and `render_content_slide`. +- The footer text is read from the Marp frontmatter `footer:` + directive if present; else default to the existing deck's footer + (backward compatible). Parse the frontmatter to extract the + `footer:` value (the existing code strips frontmatter without + reading it — add a frontmatter parser). +- **No other renderer change.** Speaker notes remain skipped + (acceptable per RESEARCH R1). -#### Wave 3 — mode_resolver + audit (cli-engineer) -- **Task 3.1** (cli-engineer): `core/mode_resolver.py` — - `resolve_mode(flag, env_var, credential_type, stdin_isatty)` per D-226. - `sys.stdin.isatty()` is the TTY check (RESEARCH §11). Invalid env → - warn + fall through. Returns `(mode, selection_reason)`. -- **Task 3.2** (cli-engineer): wire `mode_resolver` into `nova/cli.py` - — resolve mode before dispatch, emit `cli.invocation` with `mode`, - `selection_reason`, `credential_type`, `command`, `args` (INV-12, - REQ-328). -- **Task 3.3** (cli-engineer): `tests/test_mode_resolver.py` — - `hypothesis` property tests (REQ-349): deterministic, flag-wins, - invalid-env-ignored, no-silent-fallback. Edge cases: TTY + piped - stdout, missing credential, conflicting flag/env, invalid env value. +**Must-haves:** +- `python3 scripts/render_pptx.py docs/presentations/nova-leadership-deck-marp.md --output docs/presentations/nova-leadership-deck.pptx` works. +- `python3 scripts/render_pptx.py nova-autonomous-cloud-delivery` still works (backward compatible — renders `{deck}-marp.md` → `{deck}-python.pptx`). +- Every rendered slide has a right-aligned footer textbox. +- `python3 -m py_compile scripts/render_pptx.py` exits 0. -#### Wave 4 — CodeArtifact + layer pipeline (backend-engineer) -- **Task 4.1** (backend-engineer): `.gitea/workflows/publish.yml` + - `.github/workflows/publish.yml` (byte-identical) — build wheel → - CodeArtifact `twine upload` → build layer (`pip install --target - layer/python/` + `argon2-cffi` + `cryptography` + `pyjwt`) → - `lambda publish-layer-version` → SSM `/nova/layer/nova-cli/version` - mapping (CAP-035). Fail either → job fails (merge blocked, REQ-323). - Pin version to `+` for idempotent re-runs. +**REQs covered:** (prerequisite, not REQ-372 directly — per spec §3.3 +Edge 2 + D-242). -#### Wave 5 — composite action (cli-engineer + backend-engineer) -- **Task 5.1** (cli-engineer): `.github/actions/nova-cli/action.yml` — - composite action, `setup-python@v5` (3.12), CodeArtifact login + - `pip install nova`, `nova ${{ inputs.command }}`. `NOVA_CLIENT_MODE` - from input. -- **Task 5.2** (backend-engineer): byte-identical integration test — - CI matrix runs the action on GitHub `ubuntu-latest` + Gitea - `act_runner`; assert same stdout/exit code (REQ-326 AC2, NFR-11). +#### Wave 2 — deck source (ci-doc-writer) -#### Wave 6 — CAP-033/034 gate (cli-engineer) -- **Task 6.1** (cli-engineer): `tests/test_cli_subcommands.py` — - CAP-033 (`nova --help` lists a subcommand for every `core/` module) - + CAP-034 (AST scan: ≤50 lines, ≤3 defs, all calls resolve to `core.`, - no conditionals beyond `if __name__`). Wire into CI merge gate. +**Task P1.W2.T1:** Author +`docs/presentations/nova-leadership-deck-marp.md`: +- **Header comment (REQ-372.9):** an HTML comment at the top (before + frontmatter) naming this deck as the leadership artifact for + Infrastructure & Operations, August 2026 presentation date, and + naming `nova-autonomous-cloud-delivery-marp.md` as a related-but- + distinct artifact that this deck does not compress or modify. +- **Frontmatter (cover note):** `marp: true; theme: default; footer: + "Nova Platform - Infrastructure & Operations"; paginate: false; + size: 16:9` + a `style:` block using ONLY the 4 S&P tokens + (`#D6002A`, `#1B1B1B`, `#FFFFFF`, `#F0F0F0`). **Replace the + existing deck's `#2E2E2E` blockquote color with `#1B1B1B`** to + satisfy REQ-372.6. +- **7 slides** delimited by `---` on its own line (REQ-372.3). All + slides use `##` H2 titles (content slides, white bg, red title bar + — per RESEARCH R1 final call for visual consistency). +- **On-slide body** per the Slide Content Map in PROJECT.md §v1.30 + (REQ-372.7). Use `>` blockquotes for the italic callouts, `**...**` + bold lead for the slide titles' sub-headings, `-` bullets with `→` + prefix for the arrow lines (so they render as proper bullets). +- **Speaker notes** per slide as HTML comments `` within + the slide body before the next `---` (REQ-372.4). Word counts: + slides 1/2/4/6 in 150–300; slides 3/5 in 250–400; slide 7 in + 200–300. +- **`[1]` citations** (REQ-372.12): at least one `[1]` in speaker + notes of slides 3, 5, 7 (the architecture-load slides), grounding + to `docs/vision.md` tenets/anti-goals/boundaries. +- **No hex colors** outside the 4 S&P tokens anywhere in the source + (REQ-372.6). -### Phase P2 — lambda-packaging (REQ-329, REQ-330, REQ-331) +**Must-haves:** +- File exists, parses as valid Marp, exactly 7 `---`-delimited slides. +- Header comment present with all 3 elements (REQ-372.9). +- Frontmatter has the exact footer string + `paginate: false`. +- Per-slide speaker-note word counts in band. +- `[1]` present in slides 3, 5, 7 speaker notes. +- `grep -oiE '#[0-9A-Fa-f]{6}'` returns only the 4 S&P tokens. -**Goal:** Dual-use `core/lambda/contract_ingestor.py` (Lambda + CLI -paths share ≥80% code); `core/env.py:+synthesize_local_env()` for -`nova apply --local`; `.nova/contract.yml.attestations/` scaffolded; -JWS-from-PAT key derivation (C-5.2). +**REQs covered:** REQ-372.1, REQ-372.3, REQ-372.4, REQ-372.6, +REQ-372.7, REQ-372.9, REQ-372.12. -**Exit criterion:** all REQ-329..331 tests pass + JWS-from-PAT KDF -specified. +#### Wave 3 — smoke test (ci-cli-engineer) -#### Wave 1 — dual-use refactor (backend-engineer) -- **Task 1.1** (backend-engineer): refactor - `core/lambda/contract_ingestor.py` — extract the shared logic into - importable functions; the Lambda handler + the CLI `__main__` block - both call them. The `__main__` block already exists (the dual-use - precedent per RESEARCH §1.2). Verify ≥80% code share (CAP-034 / code - review). Local path via `core/local_emulators.py:LocalLambdaStub`. +**Task P1.W3.T1:** Author `scripts/check_leadership_deck.sh`: +- Shebang `#!/usr/bin/env bash`, `set -euo pipefail`, header comment + with Usage + Returns. +- Assertions (REQ-372.8 a–f): + - (a) `docs/presentations/nova-leadership-deck-marp.md` exists. + - (b) slide count = 7 (count `^---\s*$` lines after frontmatter + end, +1; or count `---` separators — careful with frontmatter). + - (c) per-slide speaker-note word counts in band (extract `` content per slide, `wc -w`; slides 1/2/4/6: 150–300; 3/5: + 250–400; 7: 200–300). Exit non-zero on violation. + - (d) footer string `Nova Platform - Infrastructure & Operations` + present in source (frontmatter `footer:` directive). + - (e) only S&P hex colors in source (`grep -oiE '#[0-9A-Fa-f]{6}'`, + `sort -u`, compare to 4-token allow-list). + - (f) `docs/presentations/nova-leadership-deck.pptx` exists (hard + fail per Q-M4). +- Exit 0 on pass, non-zero (1) on fail. Runnable from repo root. +- NOT wired as a CI gate (no `.github/workflows/` or + `workflows-src/` integration). -#### Wave 2 — local env synthesizer + JWS KDF (backend-engineer) -- **Task 2.1** (backend-engineer): `core/env.py:+synthesize_local_env() - ` — produces a local env dict (account_id placeholder, region local, - no real AWS) from a contract + `--local` flag. Mirrors - `core/onboarding.py:generate_env_file()`. -- **Task 2.2** (cli-engineer): `nova/apply.py` (≤50 lines) — `nova - apply --local` delegates to `core.env.synthesize_local_env()` + - `core.contract_resolver.resolve()`. -- **Task 2.3** (security-engineer): JWS-from-PAT key derivation - (C-5.2). HKDF-SHA256(PAT_bytes, salt='nova-local-attestation', - info='jws-signing-key') → 32-byte symmetric key. The JWS is - HMAC-SHA256 (symmetric, not asymmetric). The "public key derivable - from the PAT" AC (REQ-332) is re-interpreted: the *verification key* - is derived from the PAT via the same KDF (the PAT is the shared - secret). Document in `docs/developer-guide-auth.md`. Update REQ-332 - AC accordingly. +**Must-haves:** +- `bash scripts/check_leadership_deck.sh` exits 0 after the deck + + PPTX are authored/rendered. +- Exits non-zero if any assertion fails (test by temporary + mutation). -#### Wave 3 — attestations dir (cli-engineer) -- **Task 3.1** (cli-engineer): verify `nova init` (P1 Wave 2 Task 2.3) - creates `.nova/contract.yml.attestations/` (empty). REQ-331 test. +**REQs covered:** REQ-372.8. -### Phase P3 — idp-auth (REQ-333, REQ-334, REQ-335) +#### Wave 4 — render + ship-wave records (backend-engineer + lead-developer) -**Goal:** `nova-idp-auth` Lambda (sign-up, sign-in, session) with -Argon2id hashing + DynamoDB tables. CAP-036 target. +**Task P1.W4.T1 (backend-engineer):** Render the PPTX: +- `python3 scripts/render_pptx.py docs/presentations/nova-leadership-deck-marp.md --output docs/presentations/nova-leadership-deck.pptx` +- Verify: PPTX written with 7 slides, python-pptx raised no + exceptions, footer textbox present on every slide. +- Run `bash scripts/check_leadership_deck.sh` → exits 0. -**Exit criterion:** CAP-036 Verified (E2E sign-up → sign-in → session -passes in CI). +**Task P1.W4.T2 (lead-developer):** Append CAP-042 to STATE.md: +- CAP-042 row in the capability table: artifact paths + (`nova-leadership-deck-marp.md`, `nova-leadership-deck.pptx`), + audience (Infrastructure & Operations leadership), single-shot + intent, presentation month (August 2026), milestone v1.30 / tag + `v1.29.3`. -#### Wave 1 — DynamoDB schema (backend-engineer) -- **Task 1.1** (backend-engineer): define the 4 DynamoDB table schemas - (`nova-users`, `nova-sessions`, `nova-password-resets`, `nova-pats`) - in a CloudFormation snippet (reused by P4 Wave 8 `nova idp setup`). - PITR enabled on each (REQ-335). +**Task P1.W4.T3 (lead-developer):** Record D-241 in PROJECT.md: +- D-241 entry in the decisions section: single-shot nature, audience, + August 2026 anchor + November 2026 runway, explicit decision not + to compress the existing citizen-developer deck. -#### Wave 2 — Argon2id (security-engineer) [C-1.2/C-7.2] -- **Task 2.1** (security-engineer): `core/lambda/nova_idp_auth.py` — - Argon2id password hashing via `argon2-cffi` (D-228: bundled abi3 - wheel; **fail-closed on `ImportError` → 503, no pure-Python - fallback**). **Parameters: t=3, m=65536 KiB, p=1** (OWASP-recommended - minimum). Lambda memory ≥512 MB (m=64 MiB + Python overhead fits). - Raw passwords never in logs/traces/env/DDB (INV-16, REQ-334). -- **Task 2.2** (security-engineer): `tests/test_argon2_fail_closed.py` - — mock `argon2.low_level` import failure → assert auth Lambda - returns 503 (not a crash, not a weak hash). C-1.2. +**Must-haves:** +- PPTX exists with 7 slides. +- Smoke test exits 0. +- CAP-042 row in STATE.md. +- D-241 record in PROJECT.md. -#### Wave 3 — auth Lambda (backend-engineer + security-engineer) -- **Task 3.1** (backend-engineer): `nova-idp-auth` Lambda handler — - sign-up, sign-in, session creation endpoints. Function URL + IAM - auth. DynamoDB via lazy `boto3.resource` (the existing pattern). -- **Task 3.2** (security-engineer): session token issuance + session - storage in `nova-sessions` (TTL `expires_at`). Password reset flow - in `nova-password-resets` (TTL 15m). +**REQs covered:** REQ-372.2, REQ-372.5, REQ-372.8, REQ-372.10, +REQ-372.11. -#### Wave 4 — CAP-036 E2E (backend-engineer) -- **Task 4.1** (backend-engineer): `tests/test_idp_auth.py` — sign-up - → sign-in → session round-trip (moto[dynamodb] for local; deployed - for CI). CAP-036 verification. +### Phase P2 — final-review-ship (review + audit + milestone ship) -### Phase P4 — token-vend-pat (REQ-336..REQ-344, REQ-340, REQ-341) [was P4+P5] +**Goal:** Multi-persona review of the milestone changes, project- +health audit, and milestone ship (merge to main, tag `v1.29.3` = +milestone release, delete milestone branches). -**Goal:** `nova-idp-token-vend` Lambda (KMS-signed OIDC, kyverno-json -ABAC), JWKS endpoint, PAT lifecycle, `nova auth` commands, **and** -`nova idp setup` (folded from P5 per C-2.1). CAP-037 + CAP-038 target. -**Highest-risk phase — critical-path.** The kj-binary spike (Wave 1) -is the single highest-probability schedule slip; Fargate fallback adds -~1 week (D-227). This is a **double-length phase** (8 waves). +**Personas:** lead-developer (review + audit + ship coordination). -**Exit criterion:** CAP-037 + CAP-038 Verified + `nova idp setup ---check/--apply/--verify` works against a fresh AWS account. +**Tasks:** +- Review all v1.30 changes (deck source, render extension, smoke + test, STATE.md/PROJECT.md records). Auto-apply P0 fixes; flag P1+ + for post-hoc review. +- Audit: reconstruction test (git log matches `.ciagent/` files), + file discipline, branch hygiene, commit discipline. +- Ship: merge `phase/02` → `milestone/v1.30-leadership-deck` → + `main`, tag `v1.29.3`, create release, delete milestone branches. +- Complete: mark REQ-372.1..12 complete in REQUIREMENTS.md, mark + v1.30 complete in ROADMAP.md. -#### Wave 1 — kj-binary spike (backend-engineer + security-engineer) [C-8.2] -- **Task 1.1** (backend-engineer): confirm the `kj` Go binary - (~40 MB Linux amd64) runs in the Lambda Python 3.12 runtime on - AL2023. Bundle it in the `nova-cli` layer (`wget` a **pinned - release** (e.g. `kj@v1.x.y`) + record SHA256 into `layer/kj.sha256` - — C-8.2, supply-chain safety) into `layer/bin/kj`, `chmod +x`. - Verify `KyvernoJsonEngine.is_configured()` finds `/opt/bin/kj`. - **If this fails:** fall back to Fargate for the token-vend Lambda - (D-227 risk, RESEARCH §7). Escalate to user only if both fail (full - autonomy: log assumption + proceed with Fargate). +## Wave dependency graph -#### Wave 2 — ABAC policy (security-engineer) [C-5.1] -- **Task 2.1** (security-engineer): `platform/abac/token-vend.policy` - — kyverno-json `ValidatingPolicy` (D-227). Payload: - `{subject, requested_claims, target_resource, environment, pat_jti, - policy_version}`. **`requested_claims` = list of claim names** (the - policy asserts the subject is *allowed* to request those claims; the - values are assigned by the Lambda, not the requestor — C-5.1). - JMESPath checks for role/scope/env/owner. Severity `critical` = deny - on fail. -- **Task 2.2** (security-engineer): `policy_version` = git SHA of the - policy file, baked into the Lambda layer (D-231). Recorded in every - `token.vend.allowed/denied` audit event. +``` +W1 (render_pptx.py extension) ─┐ + ├─→ W4.T1 (render PPTX) ─→ W4.T2/T3 (records) +W2 (deck source) ──────────────┤ │ + │ ↓ +W3 (smoke test) ───────────────┴────────────────────────→ P1 VERIFY + │ + ↓ + P1 SHIP (v1.29.2) + │ + ↓ + P2 (v1.29.3) +``` -#### Wave 3 — KMS signing (security-engineer) [C-1.1] -- **Task 3.1** (security-engineer): **verify KMS asymmetric key - support** before implementation: `aws kms create-key --key-spec - ECC_NIST_P256 --key-usage SIGN_VERIFY` in the target account - (C-1.1). If fail: fall back to RSA-2048 (also supported, larger - tokens) or escalate. Do not discover this mid-Wave. -- **Task 3.2** (security-engineer): KMS key `alias/nova-oidc-signing` - (ECC_NIST_P256, SIGN_VERIFY). Token-vend Lambda signs via - `kms.sign(SigningAlgorithm="ECDSA_SHA_256")` → DER→raw ECDSA - conversion (`decode_dss_signature` → `r.to_bytes(32) + s.to_bytes(32)`, - RESEARCH §5). JWT header `{"alg":"ES256","typ":"JWT","kid":"..."}`. - -#### Wave 4 — token-vend Lambda (backend-engineer + security-engineer) [C-6.1/C-7.1 ABAC FAIL-CLOSED] -- **Task 4.1** (backend-engineer): `core/lambda/nova_idp_token_vend.py` - — accepts PAT/session, validates revocation (`nova-pats.GetItem(jti, - ConsistentRead=True)` — D-229), evaluates ABAC (Wave 2), signs (Wave - 3), returns OIDC JWT. Audit at every step. -- **Task 4.2** (security-engineer): token claims `sub, aud, iss, exp, - iat, jti, roles` (REQ-336). -- **Task 4.3** (security-engineer) 🔴: **ABAC fail-closed.** If - `KyvernoJsonEngine.is_configured()` returns false or `evaluate()` - raises, return 403 + audit `token.vend.denied` (reason: - `abac_eval_failed`). **Never fail open.** This is INV-17's runtime - enforcement (C-6.1/C-7.1 — the grill's #1 finding). Test: - `tests/test_abac_fail_closed.py` — mock `kj` absent → assert 403 + - audit event. - -#### Wave 5 — JWKS endpoint (backend-engineer) -- **Task 5.1** (backend-engineer): `core/lambda/nova_idp_jwks.py` — - function URL `AuthType: NONE`, `Cache-Control: max-age=3600`. - `kms.get_public_key` → DER SPKI → JWK via `cryptography`. Returns - `{"keys":[...]}`. Custom domain + WAF = optional (D-230). - -#### Wave 6 — PAT lifecycle (security-engineer + cli-engineer) [C-7.3] -- **Task 6.1** (security-engineer): PAT issuance — signed JWT - (`typ: "developer_pat"`, INV-14), `nova-pats` PutItem (jti, pat_hash, - status=active). Only hash stored (REQ-343). Revoked PATs retained. - **Max TTL: ≤24h for developer PATs, ≤1h for service-account PATs** - (C-6.2 threat model). -- **Task 6.2** (cli-engineer): `nova/auth/{login,revoke,status}.py` — - `nova auth login` (session→OIDC token, store in - `~/.nova/credentials.json` 0600), `nova auth revoke --pat `, - `nova auth status` (active credential, mode, selection_reason). - All emit audit events (REQ-344). **C-7.3: `~/.nova/credentials.json` - stores the OIDC token + PAT metadata (jti, exp, type) ONLY — NOT the - raw PAT.** The raw PAT is entered once at `nova auth login` and not - persisted (reduces filesystem-compromise blast radius). - -#### Wave 7 — CAP-037/038 (security-engineer) -- **Task 7.1** (security-engineer): `tests/test_kms_roundtrip.py` - (REQ-350, CAP-037) — sign test JWT via token-vend, fetch JWKS, - verify with `pyjwt`. `tests/test_pat_revocation.py` (REQ-351, - CAP-038) — issue → vend → revoke → assert 403 within 60s P95. - -#### Wave 8 — nova idp setup (cli-engineer + backend-engineer) [folded from P5 per C-2.1] - -**Goal:** `nova idp setup` command with `--check/--apply/--verify` -modes; CloudFormation template generation + review (REQ-340, REQ-341). - -- **Task 8.1** (backend-engineer): `nova/idp/setup.py` (+ backend - helper) — generates the Nova-idp CloudFormation template (raw dict → - JSON): 2-3 Lambdas, 4 DDB tables, KMS key, function URLs, IAM roles, - optional CloudFront/WAF/ACM (`--public-jwks-domain` flag). -- **Task 8.2** (cli-engineer): `--check` (prerequisites + IAM policy - delta), `--apply` (generate → `$PAGER` → `y/N` → `cloudformation - deploy --capabilities CAPABILITY_IAM`, NFR-10), `--dry-run` (resource - list only), `--verify` (KMS round-trip, delegates to REQ-350 test). -- **Task 8.3** (backend-engineer): IAM policy delta computation — - compares current `nova-spike-runner` grants to required - `cloudformation:*` + `codeartifact:*` + `kms:*` + `lambda:*` + - `dynamodb:*` + `ssm:*`. - -### Phase P5 — docs-integration (REQ-345..REQ-351) - -**Goal:** Operator guide, developer guide, threat model; E2E -integration test; property tests; KMS round-trip; PAT revocation SLO. - -**Exit criterion:** all REQ-345..351 tests pass + docs published + -threat model reviewed. - -#### Wave 1 — docs (lead-developer + security-engineer) [C-6.2/C-6.3/C-9.2] -- **Task 1.1** (lead-developer): `docs/operator-guide-idp.md` (REQ-345) - — `nova idp setup --check/--apply/--verify`, prerequisite IAM policy, - CloudFormation review flow. **C-6.3 additions:** KMS key rotation - procedure (90 days), Lambda layer update procedure, DDB PITR restore - procedure, emergency PAT revocation (DDB-level, not CLI). -- **Task 1.2** (lead-developer): `docs/developer-guide-auth.md` - (REQ-346) — signup, signin, login, mode resolution, TTY vs piped - stdout behavior, JWS-from-PAT KDF (P2 Wave 2 Task 2.3). -- **Task 1.3** (security-engineer): `docs/threat-model.md` (REQ-347) — - Argon2id storage, KMS signing, JWKS exposure, PAT revocation SLO, - ABAC token vending, no-AWS-managed-identity (INV-15), DER→raw ECDSA - gotcha. **C-6.2 additions:** (a) JWKS unauthenticated endpoint DDoS - surface + reserved-concurrency mitigation; (b) PAT theft + max TTL - (≤24h dev, ≤1h service-account); (c) ABAC fail-closed guarantee - (C-6.1). **C-9.2 addition:** INV-18..21 compression audit — verify - the spec's attestation invariant semantics are fully captured by - INV-15/16/17 + REQ-332. - -#### Wave 2 — integration tests (backend-engineer + security-engineer) -- **Task 2.1** (backend-engineer): `tests/test_e2e_idp.py` (REQ-348) — - sign-up → sign-in → token-vend → apply → audit. Verifiable audit - chain. Runs in CI against deployed Nova-idp. -- **Task 2.2** (security-engineer): verify REQ-349 (mode_resolver - property tests, P1 Wave 3 Task 3.3) + REQ-350 (KMS round-trip, P4 - Wave 7 Task 7.1) + REQ-351 (PAT revocation SLO, P4 Wave 7 Task 7.1) - pass in CI. - -### Phase P6 — final-review-ship (Final Phase) - -**Goal:** Multi-persona code review across P1..P5; project-health -audit; milestone ship to main; CAP-033..038 Verified. - -#### Wave 1 — review (lead-developer) -- **Task 1.1** (lead-developer): `ciagent-review` across all phases. - Auto-fix P0; flag P1+ for post-hoc. If P1+ found, fix in this phase. - -#### Wave 2 — audit (lead-developer) -- **Task 2.1** (lead-developer): `ciagent-audit` — reconstruction test - (git log ↔ `.ciagent/`), file/branch/commit discipline. Fix critical - issues in this phase. - -#### Wave 3 — milestone ship (lead-developer) -- **Task 3.1** (lead-developer): `ciagent-ship` — merge `phase/06` → - `milestone/v1.28-cli-identity` → `main`; tag `v1.27.6` (= the v1.28 - release); Gitea release with full milestone summary; delete all - milestone branches. Update REQUIREMENTS.md (mark REQ-323..353 - complete), ROADMAP.md (mark v1.28 complete), STATE.md (append - CAP-033..038 + INV-12..17), NORTH_STAR.md. - ---- +W1, W2, W3 are independent (no cross-dependencies at author time). +W4 depends on W1 + W2 (render needs the extension + the source) + +W3 (smoke test validates the render). W4.T2/T3 (records) depend on +W4.T1 (render confirms ship readiness). ## User-Facing Surface -> MVP/UX CHECK §1 (REQ-MVP-UX-001). - -1. **CLI flag:** `nova --help` lists every subcommand; `nova init` - scaffolds a project; `nova auth login` authenticates; `nova apply - --local` runs locally; `nova idp setup` deploys the identity stack. -2. **README quickstart:** `docs/developer-guide-auth.md` (REQ-346) - documents signup → signin → login → `nova apply` in a quickstart. -3. **`.feature` Scenario:** `tests/test_e2e_idp.py` (REQ-348) is the - E2E happy path (sign-up → sign-in → token-vend → apply → audit). +- **The PPTX deck** (`docs/presentations/nova-leadership-deck.pptx`) + — the primary leadership-facing artifact, presented live in August + 2026. +- **The Marp markdown source** + (`docs/presentations/nova-leadership-deck-marp.md`) — the source- + of-truth, reproducible via `scripts/render_pptx.py`. +- **The smoke test** (`scripts/check_leadership_deck.sh`) — runnable + on demand by the PO/presenter to verify deck integrity before + presentation. ## Happy Path -> MVP/UX CHECK §2 (REQ-MVP-UX-001). End-to-end scenario written BEFORE -> execute. +**J1 — PO presents the deck live** (from spec §3.2): -**Journey 2 — Dev authenticates and deploys locally:** -1. `nova auth signup` → `nova-idp-auth` Lambda → Argon2id hash → - `nova-users` PutItem → session token. -2. `nova auth signin` → `nova-idp-auth` → Argon2id verify → session. -3. `nova auth login` → `nova-idp-token-vend` (exchanges session for - Nova OIDC token; stores in `~/.nova/credentials.json` 0600). -4. `nova init` in a project dir → `.nova/`, `.gitignore`, - `.nova/contract.yml.attestations/`. -5. `nova apply --local --sign-local-review` → - `core.env.synthesize_local_env()` → `core.contract_resolver.resolve()` - → JWS attestation signed with a key derived from the PAT → local - ledger entry. - -The E2E test (`tests/test_e2e_idp.py`, REQ-348) verifies this chain + -the audit event chain in CI against a deployed Nova-idp. +1. PO authors `nova-leadership-deck-marp.md` against the Slide + Content Map; `bash scripts/check_leadership_deck.sh` exits 0 + (verifies content). _(REQ-372.1, .4, .6, .7, .8, .12.)_ +2. PO renders the markdown to PPTX via + `python3 scripts/render_pptx.py docs/presentations/nova-leadership-deck-marp.md --output docs/presentations/nova-leadership-deck.pptx`; + visual inspection confirms 7 slides + footer. _(REQ-372.2, .5.)_ +3. PO presents live to Infrastructure & Operations leadership; + speaker notes carry architecture depth. _(REQ-372.4.)_ +4. PO updates STATE.md with CAP-042 and PROJECT.md with D-241 at the + v1.30 ship wave. _(REQ-372.10, .11.)_ ## UX Acceptance Criteria -> MVP/UX CHECK §3 (REQ-MVP-UX-001). - -1. `nova --help` exits 0 and lists a subcommand for every `core/` - module (CAP-033). -2. `nova init` in an empty dir creates `.nova/`, - `.nova/contract.yml.attestations/`, `.gitignore` (secrets excluded). -3. `nova auth login` at a TTY resolves `mode=interactive, - selection_reason=credential:developer_pat` (INV-12, INV-14). -4. `nova apply --local` produces a JWS attestation verifiable with the - public key derived from the PAT (REQ-332). -5. `nova idp setup --check` reports prerequisites + IAM policy delta; - `--apply` presents the CloudFormation template for review before any - resource is created (NFR-10); `--verify` confirms the KMS round-trip. -6. The Forge action (`nova cli-action`) runs `nova apply` in - `mode=agent, selection_reason=credential:service_account_pat` with - no TTY dependency (Journey 3, INV-12). -7. PAT revocation takes effect within 60s P95 (NFR-4, CAP-038). - ---- - -## Capability gate (CAP-033..CAP-038) - -| CAP | Name | Phase | Gate rule | -|-----|------|-------|-----------| -| CAP-033 | CLI subcommand surface exists | P1 | `nova --help` lists a subcommand for every `core/` module | -| CAP-034 | Subcommand delegates to `core/` | P1 | Every `nova/.py` ≤50 lines, no business logic, AST scan | -| CAP-035 | Layer matches wheel | P1 | Lambda layer ARN version matches `nova-cli` wheel version (SSM mapping) | -| CAP-036 | Nova-idp auth flow works | P3 | E2E test (sign-up → sign-in → session) passes in CI | -| CAP-037 | Token-vend signs via KMS | P4 | KMS round-trip test (REQ-350) passes in CI | -| CAP-038 | PAT issuance + revocation | P4 | Issue → vend → revoke → 403 within 60s P95 (REQ-351) passes in CI | -**Release gate (§6 of the spec):** CAP-001..CAP-032 remain Verified; -CAP-033..CAP-038 are Verified; all v1.28 release-gate criteria met. - ---- - -## Test evidence required for v1.28 release - -- [ ] Code coverage ≥ 80% on new modules (`mode_resolver.py`, - `nova-idp-auth`, `nova-idp-token-vend`, PAT lifecycle). -- [ ] CI/CD pipeline GREEN: wheel + Lambda layer publish on every merge - (REQ-323, CAP-035). -- [ ] QA sign-off: all four happy-path journeys (J1–J4) pass integration - tests in CI. -- [ ] Security/compliance review: threat model published, Argon2id - verified, ABAC policy reviewed. -- [ ] Capability gate GREEN: CAP-001..032 remain Verified; CAP-033..038 - Verified. -- [ ] Mode resolver property tests pass (all four priority levels + edge - cases; REQ-349). -- [ ] KMS round-trip test passes against deployed JWKS (REQ-350). -- [ ] PAT revocation SLO verified: ≤60s P95 in CI (REQ-351, NFR-4). -- [ ] Operator + developer guides published. -- [ ] `nova idp setup` succeeds in a fresh AWS account. -- [ ] Byte-identical Forge action on GitHub + Gitea (REQ-326, NFR-11). - ---- - -## Plan completeness checklist - -- [x] Every REQ-323..353 mapped to a phase + wave + task. -- [x] Every CAP-033..038 mapped to a phase + gate rule. -- [x] Every INV-12..17 referenced in persona constraints. -- [x] Every D-226..231 referenced in task rationale. -- [x] Vertical slices: each phase ships independently (P1 CLI substrate - is useful before P2 packaging; P2 before P3 auth; etc.). -- [x] Wave ordering within phases (no wave N+1 depends on wave N work - in the same phase). -- [x] Persona assignments per task (4 active personas). -- [x] MVP/UX CHECK: 3 sections present (User-Facing Surface, Happy Path, - UX Acceptance Criteria). -- [x] Highest-risk item flagged (P4 Wave 1 kj-binary spike). -- [x] Grill conditions applied (3 critical + 16 tracked; see GRILL.md). - ---- - -## Cost envelope (C-3.1) - -Monthly estimate for the default (no CloudFront) Nova-idp deployment in -account `581513795199`: - -| Resource | Quantity | Pricing | Est. monthly | -|----------|----------|---------|-------------| -| DynamoDB (on-demand) | 4 tables | $1.25/1M write, $0.25/1M read | ~$1 (pilot volume) | -| DynamoDB PITR | 4 tables | $0.20/GB-month | ~$1 (small tables) | -| KMS asymmetric key | 1 key | $1/key-month + $0.03/10k signs | ~$1 | -| Lambda invocations | 3 Lambdas | $0.20/1M req + $0.000016/GB-s | ~$2 (low volume) | -| Lambda layer storage | ~50 MB | $0.02/GB-month | <$1 | -| CodeArtifact | 1 domain + 1 repo | $1/domain + $1/repo | $2 | -| SSM Parameter | 1 | $0.05/param (advanced) | <$1 | -| **Total (default)** | | | **~$9/month** | - -Optional CloudFront + WAF + ACM (if `--public-jwks-domain`): +~$3/month -at pilot volume. ACM is free for CloudFront-attached certs. - -This is a pilot-scale cost envelope. Production scale (100x volume) -would still be <$50/month. No hidden costs identified. - ---- - -# PLAN — v1.29 Reposplit + Identity Layer Bring-Live - -> **Milestone:** v1.29 (feature — reposplit + identity layer bring-live). -> Tags on the **v1.28.x** line: `v1.28.0` (P0) → `v1.28.1..v1.28.5` -> (P1..P5) → `v1.28.6` (P6 final = milestone release). The final phase's -> patch IS the milestone release. -> **Branch:** `milestone/v1.29-reposplit-identity`. Phase branches: -> `phase/00-pre-execution` (complete), `phase/01-publish-pipeline`, -> `phase/02-gitea-scrub-decisions`, `phase/03-cfn-archive-tf-delegation`, -> `phase/04-operator-guide-reference-tracking`, -> `nova-blockchain-exchange/phase/05-consumer-deploy-bump` (cross-project), -> `phase/06-final-review-ship`. -> -> **Scope split (CLARIFY-grounded):** Terraform modules authored -> out-of-band in `nova-platform-ops`. CIAgent in `acdl` authors only the -> acdl-side REQs (354, 367, 368, 369, REQ-OPS-GUIDE, REQ-CONSUMER-BUMP). -> Covered-reference REQs (355-366, 371) verified via cutover gates -> documented in the operator guide (P4). - -## Milestone goal - -v1.29 makes platform operations a Terraform-controlled discipline that -lives outside the engineering repo, with a narrow-IAM `kj` substrate -shared by the primary runtime and its defensive fallback. `acdl/acdl` -standardizes on GitHub (Gitea scrub); Nova-idp is brought live in -account `581513795199` (code complete since v1.28, unverified in-account -at Phase 0); `kj` has exactly one identity (one ECR image digest) shared -by both substrates (KJ-LOCKSTEP, REQ-371). - -## Requirements - -17 requirements: REQ-354..REQ-369 + REQ-371 + REQ-363b + REQ-OPS-GUIDE -+ REQ-CONSUMER-BUMP (full text in `.ciagent/REQUIREMENTS.md` §v1.29). -1 invariant: INV-18 (JWKS-EDGE-ONLY). 10 NFR constraints: KJ-STATIC, -KJ-LOCKSTEP, KJ-WARMUP-HEALTH, OPER-PRIV, IAM-NARROW, DRIFT-DETECT, -IMPORT-IDEMPOTENT, TFM-HITL, JWKS-SLO, JWKS-ROTATION. 9 decisions: -D-232..D-238 (CLARIFY) + D-239/D-240 (RESEARCH spec corrections). - -## Phase breakdown - -### Phase P1 — publish-pipeline (REQ-354) - -**Goal:** `publish.yml` attaches Lambda zip + layer wheel + Python wheel -+ ECR container image (static `kj`, `CGO_ENABLED=0`, tag -`v1.29.x-kj-`) to GitHub Release for each tag, with matching -SHA-256 in the body. The M1.5 verification gate tests -(`test_idp_auth`, `test_kms_roundtrip`, ABAC E2E) are authored. - -**Exit criterion:** REQ-354 criteria 1-4 pass; KJ-STATIC audit (file(1) -asserts `statically linked`) runs in CI; ECR image pushed with tag -`v1.29.x-kj-` (D-239); GitHub Release body lists image URI + digest -alongside wheel + layer + Lambda zip; M1.5 gate tests exist + pass in -moto-DDB (live KMS round-trip is covered-reference, runs in -nova-platform-ops CI). - -**Branch:** `phase/01-publish-pipeline`. **Tag:** `v1.28.1`. - -#### Wave 0 — publish.yml trigger model (backend-engineer) -- **Task 0.1** (backend-engineer): change `.github/workflows/publish.yml` - trigger from `push: branches: [main]` to `push: tags: ['v1.29.*']`. - Preserve the existing wheel + Lambda layer publish steps (REQ-323/ - CAP-035). Add the Lambda zip packaging step - (`nova-lambda-token-vend-v1.29.x.zip`). Verify the trigger fires on - `git tag v1.29.0 && git push --tags`. - -#### Wave 1 — kj source confirmation + static build + ECR image (backend-engineer, security-engineer) -- **Task 1.0** (backend-engineer): **kj source-fetch confirmation - (grill CF-4/G-4 — binary go/no-go gate before Wave 1).** Confirm the - `kj` Go source repo URL + commit at SHA `4ebb9a19...` (read from - `platform/abac/kj-version.txt`). Record the repo URL as a 3rd line - in `platform/abac/kj-version.txt`. If unfetchable → P1 fails closed - → escalate (this is a spec dependency, not a CIAgent ambiguity). The - source repo is the `kyverno-json/kj` Go binary project (distinct - from the kyverno-json Python engine adapter in `adapters/kyverno- - json/`). -- **Task 1.1** (backend-engineer): add a `build-kj-image` job to - `publish.yml` that: - (a) reads `platform/abac/kj-version.txt` (v0.0.3 + SHA - `4ebb9a19...`); - (b) fetches the `kj` Go source at the pinned SHA (RESEARCH §7 — - source repo confirmed in P1 RESEARCH); - (c) builds with `CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build - -ldflags="-s -w" -o kj ./…`; - (d) runs `file kj` and asserts output contains `statically linked` - AND does NOT contain `shared library` (KJ-STATIC — fail build - otherwise); - (e) builds the container image from - `public.ecr.aws/lambda/python:3.12-al2023`, copying `kj` to - `/opt/kj/kj` with `chmod 0555` owned by `sbx_user:1051`; - (f) pushes the image to ECR with tag `v1.29.x-kj-` - (D-239 — assert tag matches `^[a-zA-Z0-9._-]+$` before push); - (g) records the image URI + digest for the GitHub Release body. -- **Task 1.2** (security-engineer): add a KJ-STATIC audit step that - runs `file(1)` + `readelf -d kj` (assert no `NEEDED` entries) as a - CI gate. If either fails, the publish job fails closed. This is the - mechanical enforcement of KJ-STATIC (not just a human review). - -#### Wave 2 — GitHub Release body + SHA-256 (backend-engineer) -- **Task 2.1** (backend-engineer): extend the `publish.yml` release step - to attach: (a) `nova-lambda-token-vend-v1.29.x.zip`; (b) - `nova-cli-layer-v1.29.x.zip`; (c) `nova-1.29.x-py3-none-any.whl`; (d) - the ECR image URI + digest. Compute SHA-256 for each artifact + list - in the release body. Verify REQ-354 criteria 1, 2, 4 (artifacts - appear, independent per tag, image URI + digest listed). - -#### Wave 3 — M1.5 verification gate tests (security-engineer) -- **Task 3.1** (security-engineer): author `tests/test_idp_auth.py` — - sign-up → sign-in → session flow against moto-DDB (covers Edge 5 - item 5). Skip live-KMS assertions (covered-reference — runs in - nova-platform-ops CI). -- **Task 3.2** (security-engineer): author - `tests/test_kms_roundtrip.py` — sign/verify round-trip against - `alias/nova-oidc-signing`. Mark as `@pytest.mark.live_aws` (skipped in - acdl CI; runs in nova-platform-ops CI against the live key, REQ-362). -- **Task 3.3** (security-engineer): author - `tests/test_abac_e2e.py` — known PAT → ABAC-allowed action → signed - OIDC token → `jose` verification → green; known PAT + ABAC-denied - action → 403 with deny reason logged (INV-17 fail-closed, Edge 5 - item 7). Uses moto-DDB + mock KMS. - -#### Wave 4 — regression + ship (lead-developer) -- **Task 4.1** (lead-developer): run full test suite; verify 1000+ - tests still pass (no regressions from publish.yml changes). Verify - CAP-001..038 regression gate green. **Push a `v1.29.0` intermediate - tag at P1 ship** (grill CF-3/G-3) to trigger `publish.yml` + produce - the v1.29 artifacts (Lambda zip + layer wheel + Python wheel + ECR - image). The milestone release tag remains `v1.28.6`; the `v1.29.0` - artifact tag is a P1 intermediate to produce publish artifacts for - P5's smoke test. Ship P1 → `v1.28.1`. - -### Phase P2 — gitea-scrub-decisions (REQ-367, REQ-368) - -**Goal:** Hard scrub of all Gitea references in `acdl/acdl`; `.gitea/` -removed; `forge_parity_disabled` CI assertion; pyproject → 1.29.0; -decisions D-232..238 recorded in PROJECT.md + CLARIFY (already done in -P0; this phase adds the CI assertion + the actual file scrub). - -**Exit criterion:** `grep -rni gitea .github/ docs/ pyproject.toml -README.md .ciagent/` returns zero matches outside the spec archive -section; `find .gitea` returns nothing; CI `forge_parity_disabled` -assertion passes; pyproject.toml version = 1.29.0. - -**Branch:** `phase/02-gitea-scrub-decisions`. **Tag:** `v1.28.2`. - -#### Wave 0 — pyproject bump (lead-developer) -- **Task 0.1** (lead-developer): bump `pyproject.toml` version → - `1.29.0` (spec §7.2). Verify `nova --version` reports `1.29.0`. - -#### Wave 1 — .gitea/ removal (lead-developer) -- **Task 1.1** (lead-developer): `rm -rf .gitea/` (7 workflow files + - README.md, RESEARCH §9d). Remove `scripts/sync_workflows.py` (the - byte-identical-forges generator — central removal target, D-232). - Remove Gitea references from `scripts/sync_to_nova.sh` (line 201: - `--exclude=/.gitea`) + `scripts/rotate_spike_key.sh` (Gitea API - secret upload). Scrub `terraform/bootstrap/` Gitea OIDC references - (the OIDC role for act_runner moves to nova-platform-ops; the - bootstrap here becomes archived reference). - -#### Wave 2 — Gitea reference scrub (lead-developer) -- **Task 2.1** (lead-developer): `grep -rni gitea .github/ docs/ - pyproject.toml README.md .ciagent/` — scrub all matches outside the - spec archive section (`.ciagent/REQUIREMENTS.md` §v1.29 + CLARIFY §v1.29 - + RESEARCH §v1.29 retain "Gitea" as historical/reference text; these - are the "spec archive section" exemption per REQ-367 AC 1). Update - `.github/workflows/ci.yml` to remove any Gitea-specific steps. - -#### Wave 3 — forge_parity_disabled CI assertion (lead-developer) -- **Task 3.1** (lead-developer): add a CI step to `.github/workflows/ci.yml` - that asserts `forge_parity_disabled` — the step runs - `test ! -d .gitea/` and `! grep -rqi gitea .github/workflows/` and - exits 0 on success, non-zero with `forge_parity_disabled` message on - failure (REQ-367 AC 3, D-232). This is the deliberate CI failure that - documents the abandoned parity. - -#### Wave 4 — decisions verification + ship (lead-developer) -- **Task 4.1** (lead-developer): verify D-232..238 + D-239/240 are - present in PROJECT.md + CLARIFY.md + REQUIREMENTS.md (REQ-368 AC 1-2, - already authored in P0; this task is a verification, not re-authoring). - Run full test suite; ship P2 → `v1.28.2`. - -### Phase P3 — cfn-archive-tf-delegation (REQ-369) - -**Goal:** Archive the CFN template in `nova/idp/setup.py` + -`core/lambda/nova_idp_setup.py` to `docs/archive/nova-idp-cfn-v1.28.md` -(read-only reference); `nova idp setup --apply` delegates to `terraform -apply` (the CLI detects terraform via `which terraform`; if absent, -falls back to the CFN path with a deprecation warning). - -**Exit criterion:** `docs/archive/nova-idp-cfn-v1.28.md` exists + -contains the CFN template as read-only reference; `nova idp setup ---apply` invokes `terraform apply` when terraform is on PATH (tested -with a mock terraform binary); the CFN path emits a deprecation warning -when terraform is absent. - -**Branch:** `phase/03-cfn-archive-tf-delegation`. **Tag:** `v1.28.3`. - -#### Wave 0 — CFN archive (cli-engineer, backend-engineer) -- **Task 0.1** (backend-engineer): extract the CFN template from - `core/lambda/nova_idp_setup.py` + write it to - `docs/archive/nova-idp-cfn-v1.28.md` as a fenced code block with a - read-only header ("Archived at v1.29.0 — the active path is - `terraform apply` in `nova-platform-ops`. Deletion is a follow-up - after Terraform parity is verified."). -- **Task 0.2** (cli-engineer): mark the CFN generation code path in - `core/lambda/nova_idp_setup.py` as deprecated (add a - `DeprecationWarning` when the CFN path is invoked + a docstring - pointing to the archive + the terraform delegation path). - -#### Wave 1 — terraform delegation (cli-engineer) -- **Task 1.1** (cli-engineer): modify `nova/idp/setup.py` `--apply` to - detect terraform via `shutil.which("terraform")`. If terraform is on - PATH: delegate to `subprocess.run(["terraform", "apply", - "-auto-approve"])` in the `nova-platform-ops` checkout (the operator - runs this from the ops repo root). If terraform is absent: fall back - to the CFN path with a `DeprecationWarning` ("CFN path is archived; - install terraform or use nova-platform-ops. See - docs/archive/nova-idp-cfn-v1.28.md."). -- **Task 1.2** (cli-engineer): add `nova idp setup --verify` delegation - to `terraform plan` (same `which terraform` detection). The verify - path runs `terraform plan` + reports the diff. - -#### Wave 2 — tests (cli-engineer) -- **Task 2.1** (cli-engineer): author - `tests/test_idp_setup_tf_delegation.py` — test the `--apply` path - with a mock terraform binary on PATH (assert `subprocess.run` called - with `["terraform", "apply", "-auto-approve"]`); test the fallback - path with terraform absent (assert `DeprecationWarning` raised + CFN - path invoked); test `--verify` delegates to `terraform plan`. - -#### Wave 3 — ship (lead-developer) -- **Task 3.1** (lead-developer): run full test suite; ship P3 → - `v1.28.3`. - -### Phase P4 — operator-guide-reference-tracking (REQ-OPS-GUIDE) - -**Goal:** `docs/operator-guide-platform-ops.md` covering KMS rotation, -JWKS reachability via CloudFront edge, PITR restore, PAT revocation, -edge configuration, Fargate standby health, cost section, artifact- -mirror fallback, and the M1/M1.5/M2 cutover gates as release-gate -entries for the covered-reference REQs. ARCHITECTURE.md §12.9. STATE.md -v1.29 CAPs + invariants. REQUIREMENTS.md covered-reference markers. - -**Exit criterion:** operator guide exists + covers all sections per -REQ-OPS-GUIDE AC; ARCHITECTURE.md §12.9 added; STATE.md updated with -v1.29 rows; covered-reference REQs in REQUIREMENTS.md marked with their -cutover gate. - -**Branch:** `phase/04-operator-guide-reference-tracking`. **Tag:** -`v1.28.4`. - -#### Wave 0 — operator guide (lead-developer, data-engineer, security-engineer) -- **Task 0.1** (lead-developer): author - `docs/operator-guide-platform-ops.md` sections: (a) Overview + the - reposplit rationale (Vision §4); (b) Day-0 cutover procedure (M1 - steps from spec §3.2 Journey 2); (c) M1.5 verification gate (8-item - spike, 3 consecutive rebuilds); (d) M2 operational handoff loop - (tag-pin bump → plan → HITL approval → apply); (e) M2a Fargate - activation (conditional on M1.5 failure); (f) Rollback procedure - (D-236 — revert `nova_platform_version` pin); (g) cost section (WAF - ~$5-10/month + Fargate ~$15-20/month, REQ-363b AC 4); (h) artifact- - mirror fallback (operator-local mirror by SHA-256 when Gitea - act_runner cannot reach GitHub Releases, Edge 6). -- **Task 0.2** (data-engineer): author the operator guide data - sections: (a) DynamoDB PITR restore procedure (per-table); (b) - DynamoDB import addresses (nova-contracts, nova-change-requests, - nova-outbox, nova-users, nova-sessions, nova-pats — the - `importable-resources.tf` map, REQ-361 covered-reference); (c) audit - outbox bootstrap; (d) JWKS-ROTATION (24-hour overlap window on key - rotation). -- **Task 0.3** (security-engineer): author the operator guide security - sections: (a) KMS rotation (90-day cadence, `alias/nova-oidc- - signing`, `ECC_NIST_P256`, D-234); (b) JWKS reachability via - CloudFront edge (OAC pinning, `AuthType: AWS_IAM`, direct Function - URL → 403, INV-18); (c) PAT revocation (60s SLO, D-229); (d) edge - configuration (CloudFront + WAF + ACM + Route53 — REQ-364/365/366 - covered-reference); (e) Fargate standby health checks (`GET /health` - every 10s, `KJ-WARMUP-HEALTH`, 3 consecutive probe failures → alert + - token-vend fails closed, REQ-363b AC 2); (f) Fargate sunset - discipline (D-237 — ≥30 consecutive days green before deletion + - architecture review); (g) IAM scope (IAM-NARROW, REQ-360 covered- - reference — no `Action: "*"` or `Resource: "*"`); (h) the - `route53_record_not_resolvable` debugging path (ACM cert status - check). - -#### Wave 1 — covered-reference cutover gates (lead-developer) -- **Task 1.1** (lead-developer): add a "Cutover Gates" section to the - operator guide listing each covered-reference REQ (355, 356, 357, - 358, 359, 360, 361, 362, 363, 363b, 364, 365, 366, 371) with its - gate entry (M1/M1.5/M2) + the verification command + a **"Result" - column** (grill CF-2/G-5). P6 audit verifies every covered-reference - REQ has a non-empty, green Result. Empty/red → P6 blocks. The Result - column is populated by the operator attestation (the operator runs - the verification command in `nova-platform-ops` CI + records the - outcome). This is the acdl-side evidence surface for covered- - reference REQs. -- **Task 1.2** (lead-developer): update REQUIREMENTS.md §v1.29 traceability - table — mark each covered-reference REQ with its cutover gate in the - Status column (e.g., `planned (M1 gate: nova-platform-ops)`). - -#### Wave 2 — ARCHITECTURE.md + STATE.md (lead-developer) -- **Task 2.1** (lead-developer): add ARCHITECTURE.md §12.9 (Platform - Ops Reposplit) — the domain boundary (engineering ends at the - compiled artifact; operations begins at the live platform under - guardrails), the `kj` substrate (one ECR image digest, KJ-LOCKSTEP), - the covered-reference REQ tracking pattern, the operator guide - pointer. -- **Task 2.2** (lead-developer): update STATE.md — append v1.29 - capability rows (CAP-039: platform-ops-reposplit, CAP-040: - kj-substrate-lockstep, CAP-041: jwks-edge-only) + bump invariants - (INV-18 JWKS-EDGE-ONLY + the 10 NFR constraints). Bump "Last - milestone ship" to v1.29 (pending). - -#### Wave 3 — ship (lead-developer) -- **Task 3.1** (lead-developer): run full test suite; ship P4 → - `v1.28.4`. - -### Phase P5 — consumer-deploy-bump (REQ-CONSUMER-BUMP, cross-project) - -**Goal:** Bump `nova-blockchain-exchange` deploy.yml `@v1.25` → `@v1.29` -in both `.github/workflows/deploy.yml` + `.gitea/workflows/deploy.yml` -+ smoke test (sign-up → sign-in → token-vend → apply → audit against -v1.29 publish artifacts). - -**Exit criterion:** both deploy.yml files reference `@v1.29`; smoke -test passes (the chain completes against v1.29 publish artifacts). - -**Branch:** `nova-blockchain-exchange/phase/05-consumer-deploy-bump` -(cross-project, multi-project branch naming per branch-strategy.md). -**Tag:** `v1.28.5`. - -#### Wave 0 — deploy.yml bump (lead-developer) -- **Task 0.1** (lead-developer): in the `nova-blockchain-exchange` - project, update `.github/workflows/deploy.yml` + `.gitea/workflows/ - deploy.yml` `uses:` ref from `acdl/.github/workflows/deploy.yml@v1.25` - → `@v1.29` (RESEARCH §9e — the consumer's `.gitea/` is out of scope - for the acdl REQ-367 scrub; the consumer may keep its Gitea mirror or - follow suit — this is a consumer-repo decision, not an acdl one). - -#### Wave 1 — smoke test (lead-developer, security-engineer) -- **Task 1.1** (security-engineer): author - `nova-blockchain-exchange/tests/test_v1.29_smoke.py` — sign-up → - sign-in → token-vend → apply → audit chain against the v1.29 publish - artifacts (the consumer's contract → `deploy.yml@v1.29` mode=full → - apply → attest → record against `581513795199`). Uses the existing - CAP-025 round-trip assertion (v1.26). -- **Task 1.2** (lead-developer): run the smoke test; verify the chain - completes against the real v1.29.0 publish artifacts (produced by - P1's intermediate tag, grill CF-3/G-3). **No hedge** — the smoke - test MUST run against the published v1.29.x artifacts or P5 fails - closed. If the artifacts are not available (P1 did not push the - intermediate tag), P5 blocks until P1 re-ships. - -#### Wave 2 — ship (lead-developer) -- **Task 2.1** (lead-developer): ship P5 → `v1.28.5`. The consumer - project ships independently (merge to the consumer's main, not - acdl's milestone branch). - -### Phase P6 — final-review-ship (Final Phase) - -**Goal:** Multi-persona code review across P1..P5; audit (reconstruction -test, branch hygiene, commit discipline, file discipline); milestone -ship (merge `phase/06` → `milestone/v1.29-reposplit-identity` → `main`; -tag `v1.28.6` = the v1.29 release; Gitea release; delete all milestone -branches); mark all v1.29 REQs complete in REQUIREMENTS.md + ROADMAP.md. - -**Exit criterion:** review P0 issues auto-fixed, P1+ flagged; audit -PASS; milestone merged to main; tag `v1.28.6` created; Gitea release -published; milestone branches deleted; REQUIREMENTS.md + ROADMAP.md -marked complete. - -**Branch:** `phase/06-final-review-ship`. **Tag:** `v1.28.6` = -milestone release. - -#### Wave 0 — review (lead-developer) -- **Task 0.1** (lead-developer): delegate to `ciagent-review` — - multi-persona review (lead-developer, backend-engineer, security- - engineer, data-engineer, cli-engineer) across P1..P5. Auto-apply P0 - fixes; flag P1+ for post-hoc review. If P1+ issues found: fix them - in this phase. - -#### Wave 1 — audit (lead-developer) -- **Task 1.1** (lead-developer): delegate to `ciagent-audit` — - reconstruction test (git log ↔ `.ciagent/`), branch hygiene, commit - discipline, file discipline. If critical issues found: fix them in - this phase. - -#### Wave 2 — milestone ship (lead-developer) -- **Task 2.1** (lead-developer): delegate to `ciagent-ship` — merge - `phase/06` → `milestone/v1.29-reposplit-identity` → `main`; tag - `v1.28.6`; Gitea release with full milestone summary; delete all - milestone branches (phase/00..06 + milestone/v1.29-reposplit- - identity). - -#### Wave 3 — milestone completion (lead-developer) -- **Task 3.1** (lead-developer): update REQUIREMENTS.md (all v1.29 REQs - → complete), ROADMAP.md (v1.29 → complete), NORTH_STAR.md (note - Strategic Objective — platform operations as a Terraform-controlled - discipline), STATE.md (bump "Last milestone ship" to v1.29, tag - `v1.28.6`). Commit `docs(milestone): complete v1.29-reposplit- - identity`. - ---- - -## User-Facing Surface - -1. **CLI flag:** `nova idp setup --apply` now delegates to `terraform - apply` (REQ-369 AC 2) — the operator runs this from the - `nova-platform-ops` checkout. `nova idp setup --verify` delegates to - `terraform plan`. -2. **GitHub Release artifacts page:** each `v1.29.x` tag's GitHub - Release page lists the Lambda zip + layer wheel + Python wheel + ECR - image URI/digest with SHA-256 (REQ-354) — this is the engineering- - to-ops handoff surface (D-235 tag-pin handoff). -3. **Operator guide:** `docs/operator-guide-platform-ops.md` — the - operator-facing runbook covering KMS rotation, JWKS reachability, - PITR restore, PAT revocation, edge config, Fargate standby, cost, - artifact-mirror fallback, and the M1/M1.5/M2 cutover gates. -4. **CI assertion:** `forge_parity_disabled` — the deliberate CI - failure documenting the abandoned byte-identical-forges parity - (D-232, REQ-367 AC 3). - -## Happy Path - -**M1.5 verification gate (spec §3.3 Edge 5, 12-item spike — written -BEFORE execute, extended per grill CF-1):** - -1. `kj` v0.0.3 (pinned SHA in `platform/abac/kj-version.txt`) compiles - with `CGO_ENABLED=0 GOOS=linux GOARCH=amd64`. -2. Resulting binary reports `file kj → ELF 64-bit LSB executable, - x86-64, statically linked, no shared library` (KJ-STATIC). -3. Container image built from - `public.ecr.aws/lambda/python:3.12-al2023` with the binary copied - to `/opt/kj/kj`, `chmod 0555`, owned by `sbx_user:1051`. -4. Lambda runtime `python3.12` executes - `nova_idp_token_vend.handler`; the handler invokes - `subprocess.run(['/opt/kj/kj', 'apply', ...])` and parses stdout - JSON. -5. `tests/test_idp_auth.py` passes against the live image in moto-DDB. -6. `tests/test_kms_roundtrip.py` passes against the live KMS key - (REQ-362 path — covered-reference, runs in nova-platform-ops CI). -7. End-to-end: known PAT → known ABAC-allowed action → signed OIDC - token → `jose` verification → green. Known PAT + ABAC-denied action - → 403 with deny reason logged (INV-17). -8. Image URI is recorded in Terraform state and in the operator guide. -9. **(grill CF-1)** Direct JWKS Function URL → 403 / via-CloudFront → - 200 (INV-18, JWKS-EDGE-ONLY — `AuthType: AWS_IAM` verified, not - prose). -10. **(grill CF-1)** IAM-NARROW: no `Action: "*"` or `Resource: "*"` - in the Gitea OIDC role effective permissions (REQ-360). -11. **(grill CF-1)** TFM-HITL: self-approval rejected — - `gitea.triggering_actor == pull_request.user.login` → apply fails - closed (REQ-357, INV-3). -12. **(grill CF-1)** Rollback drill — revert `nova_platform_version` - pin → prior digest runs (D-236 cutover shape + rollback procedure). - -If items 1-7 fail three consecutive rebuilds, M2a activates REQ-363b -(Fargate toggle) with the same image — no warmup hit because the -standby is always running the same digest. - -**HARD P6 SHIP GATE (grill CF-1/G-2.1):** P6 must not ship `v1.28.6` -until the operator guide contains an operator-attested "M1.5 -Verification Gate Result" row (3 consecutive green rebuilds, run -IDs/SHAs, attestor identity). P6 audit verifies the row exists. The -M1.5 gate is verified in `nova-platform-ops` CI (out-of-band); the -operator attestation in the guide is the acdl-side evidence surface. - -## UX Acceptance Criteria - -1. **M1 acceptance gate (spec §2.3):** `terraform apply` from `main` - brings the live AWS account to a state where Nova-idp identity - tables exist, JWT-issuing paths are wired but not yet consuming - container images, JWKS infrastructure is in place, WAF + OAC pinning - the CloudFront edge; `acdl/acdl v1.29.0` ships with zero `.gitea/` - references and zero platform-infra files; D-232..238 recorded in - PROJECT.md/CLARIFY. -2. **M1.5 acceptance gate:** items 1-12 of the Edge 5 spike all green - on three consecutive rebuilds; image digest resolvable via - `data.aws_ecr_image.kj_image`; sign/verify round-trip passes; ABAC - fail-closed path verified against live policy; JWKS-EDGE-ONLY - verified (item 9); IAM-NARROW verified (item 10); TFM-HITL - self-approval rejected (item 11); rollback drill passes (item 12). - **HARD P6 ship gate** — operator-attested "M1.5 Verification Gate - Result" row in the operator guide (grill CF-1/G-2.1). -3. **M2 acceptance gate:** Bumping `local.nova_platform_version` in a - PR and merging it results in `terraform apply` updating both - `aws_lambda_function.nova_idp_token_vend.image_uri` and - `aws_ecs_task_definition.kj.container_definitions[0].image` to the - same digest (KJ-LOCKSTEP, REQ-371), with zero diff on KMS, DDB, - IAM, edge. - -## Test evidence required for v1.29 release - -- [ ] Code coverage ≥ 80% on new modules (the acdl-side files: - `publish.yml` changes, `nova/idp/setup.py` terraform delegation, - `docs/operator-guide-platform-ops.md` is docs — no coverage - requirement; the M1.5 gate tests). -- [ ] CI/CD pipeline GREEN for `acdl/acdl` (the `nova-platform-ops` - pipeline is out-of-band). -- [ ] M1.5 verification gate green: items 1-12 of §3.3 Edge 5 spike - pass on three consecutive rebuilds (covered-reference — verified - in nova-platform-ops CI; acdl authors the tests in P1; operator - attests in the guide, P4; P6 audit verifies the attestation row, - grill CF-1/G-2.1). -- [ ] Covered-reference REQs (355-366, 371) have non-empty, green - Result in the operator guide "Cutover Gates" section (grill - CF-2/G-5 — P6 audit verifies). -- [ ] `lifecycle.precondition` enforced on both image-bearing resources - (REQ-371 mechanical proof — covered-reference in - nova-platform-ops). -- [ ] Live KMS sign/verify round-trip verified in account - `581513795199` (covered-reference). -- [ ] Live ABAC sign/verify round-trip verified against the production - policy (covered-reference). -- [ ] Pilot consumer (`nova-blockchain-exchange`) smoke test green: - sign-up → sign-in → token-vend → apply → audit chain (P5). -- [ ] All existing capabilities (CAP-001..038) still pass the - regression gate. -- [ ] Drift-detection baseline: `terraform plan` exit 0 against live - AWS state, captured at cutover (covered-reference). -- [ ] `kj` standby Fargate task health `READY` before M1 cutover - (covered-reference, KJ-WARMUP-HEALTH). -- [ ] Fargate standby sunset discipline documented in operator-guide - (D-237, P4). -- [ ] `forge_parity_disabled` CI assertion passes (P2, REQ-367 AC 3). -- [ ] `grep -rni gitea .github/ docs/ pyproject.toml README.md - .ciagent/` returns zero matches outside the spec archive section - (P2, REQ-367 AC 1). - -## Plan completeness checklist - -- [x] Every REQ mapped to a phase + wave + task. -- [x] Covered-reference REQs identified + their verification surface - documented (operator guide P4, cutover gates). -- [x] Decisions D-232..240 referenced in the plan. -- [x] Invariants + NFR constraints referenced (KJ-STATIC, KJ-LOCKSTEP, - INV-18, etc.). -- [x] Personas assigned to every task (lead-developer, backend-engineer, - security-engineer, cli-engineer, data-engineer). -- [x] User-Facing Surface section (3 surfaces named). -- [x] Happy Path section (M1.5 8-item spike, written before execute). -- [x] UX Acceptance Criteria section (M1, M1.5, M2 gates). -- [x] Test evidence checklist. -- [x] Phase boundaries + tags (v1.28.0 → v1.28.6). -- [x] Cross-project phase (P5, nova-blockchain-exchange) identified. - -## Cost envelope (v1.29) - -Monthly estimate for the `nova-platform-ops` live platform (documented -in the operator guide, P4): - -| Resource | Quantity | Est. monthly | -|----------|----------|-------------| -| WAF WebACL (CloudFront-scoped) | 1 | ~$5-10/month (+ per-request) | -| Fargate standby (0.25 vCPU, 512 MB) | 1 task | ~$15-20/month (REQ-363b AC 4) | -| KMS asymmetric key | 1 | ~$1/month | -| DynamoDB (on-demand, 7 tables) | 7 | ~$2/month (pilot volume) | -| DynamoDB PITR | 7 tables | ~$2/month | -| Lambda invocations (3 Lambdas) | 3 | ~$2/month | -| ECR image storage | ~100 MB | <$1/month | -| S3 state bucket + access logs | 1 | <$1/month | -| CloudFront + ACM + Route53 | 1 distribution | ~$1/month (ACM free) | -| **Total** | | **~$30-40/month** | - -This is the pilot-scale ops cost envelope. The Fargate standby -(~$15-20/month) is the largest line item + is explicitly documented in -the operator guide (REQ-363b AC 4) with the D-237 sunset discipline -(≥30 consecutive days green before deletion + architecture review). \ No newline at end of file +1. `bash scripts/check_leadership_deck.sh` exits 0 (all 6 assertions + a–f pass). +2. `docs/presentations/nova-leadership-deck.pptx` exists, has 7 + slides, and python-pptx raised no exceptions during render. +3. Visual review: each slide N (1–7) matches the Slide Content Map + in PROJECT.md §v1.30 (on-slide body + speaker notes fingerprint). +4. Footer `Nova Platform - Infrastructure & Operations` is visible + (right-aligned) on every rendered slide. +5. Only S&P theme colors appear in the source markdown. +6. `[1]` citations present in slides 3, 5, 7 speaker notes. +7. CAP-042 row in STATE.md; D-241 record in PROJECT.md. +8. `nova-autonomous-cloud-delivery-marp.md` is unmodified (D-241 + discrete-artifact constraint). + +## Risks (from RESEARCH + GRILL) + +| Risk | Mitigation | +|---|---| +| python-pptx render fails on the new frontmatter/style block | The python-pptx path strips frontmatter without reading it; the `style:` block is source-only (Marp CLI). No render risk. | +| Footer textbox overlaps content | Place footer at `SLIDE_H - 0.3"` (bottom margin); content area tops out at ~6.5". No overlap. | +| Speaker notes word-count band violation | ci-doc-writer counts words per slide during authoring; smoke test (8c) is the gate. | +| `→` lines render as plain text (not bullets) | Use `- → ...` bullets so the renderer treats them as bullet blocks with the arrow in the text. | +| `*italic*` in source matches unordered-list regex | Verified in RESEARCH R1: `*italic*` (no space after `*`) does NOT match `[-*+]\s+`. Safe. | +| CAP-024 regression policy collides | Verified in RESEARCH R7: CAP-024 validates fixtures, not deck files. No collision. | +| `slides.yml` CI interferes | Verified in RESEARCH R8: CI only renders the citizen-developer deck (hardcoded DECK). No interference. | \ No newline at end of file From 48657eb81604ad33cf9d47bf6f23cc674093becc Mon Sep 17 00:00:00 2001 From: CIAgent Date: Thu, 20 Aug 2026 13:17:55 +0000 Subject: [PATCH 5/6] =?UTF-8?q?docs(P00):=20grill=20=E2=80=94=20PROCEED=20?= =?UTF-8?q?(0.88),=20G-1..G-4=20binding=20decisions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.30 status: grill ---/ci--- --- .ciagent/CHECKPOINT.json | 6 +- .ciagent/GRILL.md | 439 ++++++++++----------------------------- 2 files changed, 112 insertions(+), 333 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 2682cc6..7eccebd 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "plan", + "stage": "grill", "milestone": "v1.30", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-20T13:45:00Z", + "updated_at": "2026-08-20T13:50:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.30", @@ -23,5 +23,5 @@ "branches_deleted": true, "releases_created": true }, - "notes": "v1.30 Phase 0 PLAN complete. 1 execution phase (P1) — single-shot artifact. 4 waves: W1 render_pptx.py extension, W2 deck source, W3 smoke test, W4 render+records. MVP/UX checklist: User-Facing Surface (PPTX+source+smoke test), Happy Path (J1), UX Acceptance Criteria (8 items). Next: GRILL." + "notes": "v1.30 Phase 0 GRILL complete. Verdict: PROCEED (confidence 0.88). No critical conditions. 6 tracked conditions (all advisory). 4 binding decisions (G-1..G-4): H2 content slides, → bullets, #1B1B1B for blockquote, minimal frontmatter parse. Next: MVP/UX CHECK." } \ No newline at end of file diff --git a/.ciagent/GRILL.md b/.ciagent/GRILL.md index 059f929..f52fd7b 100644 --- a/.ciagent/GRILL.md +++ b/.ciagent/GRILL.md @@ -1,359 +1,138 @@ -# GRILL — v1.28 CLI Canonicalization + Identity Layer +# GRILL — v1.30 Single-shot Leadership Deck -> Adversarial review of the v1.28 SPECIFY + CLARIFY + RESEARCH + PLAN. -> Griller: ci-griller subagent. Autonomy: full. All 9 axes reviewed; -> every claim verified against the live codebase. +> Adversarial review of the v1.30 SPECIFY + CLARIFY + RESEARCH + +> PLAN. Griller: lead-developer (acting as ci-griller at full +> autonomy). All 9 axes reviewed; every claim verified against the +> live codebase. --- -## Overall verdict: **PROCEED-WITH-CONDITIONS** · Confidence 0.76 +## Overall verdict: **PROCEED** · Confidence 0.88 -The plan is fundamentally sound — architecture correct, re-mapping -clean (no ID collisions), technical depth accurate (DER→raw, strong- -read revocation, stdin TTY), highest-risk item (kj binary) has a -Fargate fallback. Not unfeasible, not over-scoped beyond an agent-driven -repo's capacity, not security-broken by design. +The plan is sound — this is a low-complexity, single-shot +presentation artifact milestone. The scope is narrow (1 execution +phase, 4 waves, no runtime code), the render pipeline extension is +minimal (D-242), the discrete-artifact discipline is clear (D-241), +and the environment prerequisites are resolved (python-pptx +installed). No critical conditions. 4 tracked conditions (all +advisory, none block P1). -**3 critical conditions (must-fix before P1) + 16 tracked conditions.** -No escalations (all axes ≥ 0.70 confidence). +The lower confidence vs. a "clean 0.95" reflects two residual +risks: (1) the python-pptx user-site install is environment-fragile +(it works now but is not reproducible in a fresh CI runner without +the same `--break-system-packages` path); (2) the PPTX footer +textbox is a new renderer behavior that needs visual confirmation. +Both are mitigated — (1) by the smoke-test hard-fail gate (8f) which +forces render success before ship, and (2) by the verify stage's +visual review (REQ-372.7). --- ## Axis verdicts -| Axis | Verdict | Confidence | Critical condition | +| Axis | Verdict | Confidence | Tracked condition | |------|---------|-----------|-------------------| -| §1 Feasibility | PROCEED-WITH-CONDITIONS | 0.82 | C-1.1 KMS asym verify; C-1.2 Argon2 fail-closed test | -| §2 Scope | PROCEED-WITH-CONDITIONS | 0.74 | C-2.1 fold P5 into P4; C-2.2 P4 overload | -| §3 Cost | PROCEED-WITH-CONDITIONS | 0.70 | C-3.1 cost estimate; C-3.2 CodeArtifact P1 task | -| §4 Schedule | PROCEED-WITH-CONDITIONS | 0.76 | C-4.1 P4 critical path; C-4.2 per-phase exit | -| §5 Technical Depth | PROCEED-WITH-CONDITIONS | 0.80 | C-5.1 ABAC shape; **C-5.2 JWS KDF** | -| §6 Operational Readiness | PROCEED-WITH-CONDITIONS | 0.72 | **C-6.1 ABAC fail-closed**; C-6.2 threat model; C-6.3 ops guide | -| §7 Security Posture | PROCEED-WITH-CONDITIONS | 0.73 | **C-7.1 ABAC fail-closed**; C-7.2 Argon2 params; C-7.3 cred file | -| §8 Dependency Risk | PROCEED-WITH-CONDITIONS | 0.83 | C-8.1 CodeArtifact P1; C-8.2 pin kj version | -| §9 Re-mapping Integrity | PROCEED-WITH-CONDITIONS | 0.84 | **C-9.1 traceability fix**; C-9.2 INV audit | +| §1 Feasibility | PROCEED | 0.90 | T-1.1 footer textbox overlap | +| §2 Scope | PROCEED | 0.92 | T-2.1 single-shot discipline enforcement | +| §3 Cost | PROCEED | 0.95 | (none — smallest milestone in project history) | +| §4 Schedule | PROCEED | 0.93 | (none — 1 execution phase) | +| §5 Technical Depth | PROCEED | 0.86 | T-5.1 speaker notes word-band parsing; T-5.2 `→` bullet rendering | +| §6 Operational Readiness | PROCEED | 0.90 | T-6.1 render env reproducibility | +| §7 Security Posture | PROCEED | 0.95 | (none — static artifact, no runtime surface) | +| §8 Dependency Risk | PROCEED | 0.84 | T-8.1 python-pptx user-site install | +| §9 Re-mapping Integrity | PROCEED | 0.92 | T-9.1 STATE.md intake override applied | --- -## Critical conditions (the 3 must-fix-before-P1) +## Tracked conditions (advisory — none block P1) -### 🔴 C-6.1 / C-7.1 — ABAC fail-closed -The token-vend Lambda's behavior on `kj` absence/error is unspecified. -Without fail-closed, INV-17 is documentation, not a runtime guarantee — -a `kj` load failure would bypass the ABAC gate (every PAT gets a token). -**Fix applied to PLAN.md P4 Wave 4 Task 4.1:** "If -`KyvernoJsonEngine.is_configured()` returns false or `evaluate()` -raises, return 403 + audit `token.vend.denied` (reason: -`abac_eval_failed`). Never fail open. Test: `tests/test_abac_fail_closed.py`." +### T-1.1 — Footer textbox overlap with content -### 🔴 C-5.2 — JWS-from-PAT key derivation -REQ-332's AC ("public key derivable from the PAT") is unimplementable -without a specified KDF. A PAT is a JWT, not a keypair. -**Fix applied to PLAN.md P2 Wave 2 Task 2.3 + REQ-332 AC:** the JWS -uses HMAC-SHA256 with a key derived via -`HKDF-SHA256(PAT_bytes, salt='nova-local-attestation', info='jws-signing-key')` -→ 32-byte symmetric key. The "public key derivable" AC is re-interpreted: -the *verification key* is derived from the PAT via the same KDF (the -PAT is the shared secret). This is a symmetric scheme, not asymmetric. +**Claim:** The footer textbox at `SLIDE_H - 0.3"` (7.2") won't +overlap content (content area tops out at ~6.5"). -### 🔴 C-9.1 — Traceability drift -REQUIREMENTS.md §v1.28 traceability table mapped 16 REQs to P2; -PLAN.md splits them across P2/P3/P4/P5/P6. **Fix applied to -REQUIREMENTS.md** — traceability table updated to match PLAN.md phase -structure. +**Verification:** python-pptx test rendered a textbox at +`Inches(7.2)` on a 7.5" slide — succeeds, no overlap with content +ending at ~6.5". The `render_content_slide` accumulates `cur_top` +per body block; a 7-slide deck with the Slide Content Map's body +volume (titles + 3-5 body blocks per slide) tops out at ~5.5-6.0". +**Verdict:** Safe. The verify stage visual review (REQ-372.7) is the +backstop. + +### T-2.1 — Single-shot discipline enforcement + +**Claim:** The deck is not wired as a CI gate, not integrated with +`publish.yml`, not auto-regenerated. + +**Verification:** `workflows-src/slides.yml` triggers on +`docs/presentations/**` but `render_slides.sh` hardcodes +`DECK="nova-autonomous-cloud-delivery"` — the leadership deck is +NOT rendered by CI. No `publish.yml` reference to the leadership +deck. The smoke test is a standalone script (no workflow +integration). **Verdict:** Discipline enforced by absence — no CI +plumbing references the new artifact. + +### T-5.1 — Speaker notes word-band parsing in bash + +**Claim:** The smoke test extracts `` per slide and +counts words with `wc -w`. + +**Verification:** Bash `awk`/`sed` can extract HTML comment content +per slide (split on `---`, then extract `` within each +slide block). Multi-line comments are supported by the spec +convention ("placed within the slide body, before the next `---`"). +**Verdict:** Feasible. The ci-cli-engineer implements + tests this in +W3. + +### T-5.2 — `→` bullet rendering + +**Claim:** Use `- → ...` bullets so the renderer treats `→` lines as +bullet blocks. + +**Verification:** The renderer's unordered-list regex +`^(\s*)([-*+])\s+(.*)` matches `- → ...` → bullet level 0, text +`→ ...`. The `→` is preserved in the rendered text. **Verdict:** +Correct. The ci-doc-writer uses `- → ...` for the arrow lines. + +### T-6.1 / T-8.1 — Render environment reproducibility + +**Claim:** python-pptx is installed via user-site +`pip install --user --break-system-packages`. + +**Verification:** Confirmed in this session: python-pptx 1.0.2 + +pytest 9.1.1 installed. `python3 -c "import pptx"` succeeds. The +install path is environment-specific (Debian/Ubuntu without system +pip/venv). In a fresh CI runner, the `slides.yml` workflow uses +`pip install -e ".[slides]"` (system pip in the runner image) — +reproducible there. For local on-demand renders, the user-site +install is the documented path. **Verdict:** Acceptable. The +smoke-test hard-fail gate (8f) forces render success before ship; +if the environment can't render, ship blocks until resolved. + +### T-9.1 — STATE.md intake override applied + +**Claim:** D-241 overrides the stale STATE.md intake assumption 3. + +**Verification:** STATE.md line ~526 assumption 3 was edited in +CLARIFY to read "OVERRIDDEN by D-241 (v1.30 CLARIFY): the leadership +deck is a discrete, hand-authored artifact — NOT a compression." +The override is recorded in CLARIFY.md (D-241) + this grill. **Verdict:** +Applied + verified. --- -## Tracked conditions (16 — applied to PLAN.md as amendments) - -- **C-1.1** KMS asymmetric key verification before P4 Wave 3 (one - `aws kms create-key --key-spec ECC_NIST_P256` call). -- **C-1.2** Argon2 fail-closed test in P3 Wave 2 (Lambda returns 503 - on `ImportError`, not a crash or pure-Python hash). -- **C-2.1** Fold P5 (idp-setup) into P4 as P4 Wave 8 → **reduces to 6 - execution phases** (P1..P6, P7 = final). Applied. -- **C-2.2** P4 is a double-length phase; acknowledged in P4 header. -- **C-3.1** Cost envelope subsection added to PLAN.md. -- **C-3.2 / C-8.1** CodeArtifact provisioning = P1 Wave 0 task with - binary go/no-go gate; Gitea wheel index fallback documented. -- **C-4.1** P4 flagged as critical-path phase (kj spike = highest- - probability schedule slip; Fargate = +1 week). -- **C-4.2** Per-phase exit criteria added to PLAN.md. -- **C-5.1** `requested_claims` = list of claim names (the policy - asserts the subject is *allowed* to request those claims). -- **C-6.2** Threat model (REQ-347) adds: JWKS DDoS surface, PAT theft - + max TTL (≤24h dev, ≤1h service-account), ABAC fail-closed, - INV-18..21 compression audit. -- **C-6.3** Operator guide (REQ-345) adds: KMS rotation, layer update, - PITR restore, emergency PAT revocation. -- **C-7.2** Argon2id parameters: t=3, m=65536 KiB, p=1 (OWASP min). -- **C-7.3** `~/.nova/credentials.json` stores OIDC token + PAT metadata - (jti, exp, type), NOT the raw PAT. -- **C-8.2** `kj` pinned to a specific release + SHA256 recorded. -- **C-9.2** Threat model includes INV-18..21 compression audit - (verify spec's attestation invariant semantics are captured by - INV-15/16/17 + REQ-332). - ---- - -## Escalations - -None. All 9 axes resolved at confidence ≥ 0.70. No human escalation -required (full autonomy). - ---- - -## Grill complete - -The plan proceeds with the 3 critical fixes and 16 tracked conditions -applied to PLAN.md + REQUIREMENTS.md. The binding decisions above are -the authoritative grill record. Next: MVP/UX CHECK → SHIP phase 0. - ---- - -# GRILL — v1.29 Reposplit + Identity Layer Bring-Live - -> Adversarial red-team review of the v1.29 SPECIFY + CLARIFY + -> RESEARCH + PLAN. Griller: CIAgent griller (red-team persona). -> Autonomy: full. All 9 review axes grilled; every claim verified -> against the live codebase (`publish.yml`, `kj-version.txt`, -> `nova/idp/setup.py`, existing v1.28 test files). -> Date: 2026-08-20. - ---- - -## Overall verdict: **PROCEED-WITH-CONDITIONS** · Confidence 0.72 - -The plan is architecturally sound and the in-acdl scope is well-bounded. -The scope split (Terraform out-of-band in `nova-platform-ops`, acdl -authors publish/scrub/archive/guide/consumer-bump) is the correct -boundary per Vision §4. The technical depth is accurate (D-239 ECR tag -correction, D-240 Terraform precondition floor, CloudFront OAC pitfall, -ECR tag mutability → pin-by-digest). The cost envelope is realistic. - -**However**, the covered-reference pattern — as currently structured — -is a **deferred-trust assertion** for 14 of 17 requirements. The plan -ships REQ-355..366 + 371 as "complete" on the strength of a markdown -pointer (the operator guide's cutover-gate section) to CI in a repo -that does not yet exist and has no CIAgent presence. The M1.5 -verification gate, the one surface acdl genuinely owns, can be -authored-but-never-run-green and the milestone still ships. Four -critical fixes convert "documented" into "evidenced-by-operator- -attestation-in-the-guide-which-acdl-audits-at-P6." - -**4 critical fixes (must apply before EXECUTE) + 6 tracked conditions.** -No escalations (all axes resolved at confidence ≥ 0.60; the user -confirmed the binding verdict on the covered-reference pattern). - ---- - -## Axis verdicts - -| Axis | Verdict | Confidence | Forcing finding | -|------|---------|-----------|----------------| -| §1 Feasibility | PROCEED-WITH-CONDITIONS | 0.70 | KJ-SOURCE: `kj` v0.0.3 source repo unverified by RESEARCH (CF-1) | -| §2 Scope | PROCEED-WITH-CONDITIONS | 0.74 | Covered-reference = deferred-trust for 14/17 REQs (G-1 + CF-2) | -| §3 Cost | PROCEED | 0.82 | $30-40/month realistic at pilot volume; no hidden budget shock | -| §4 Requirements coverage | PROCEED-WITH-CONDITIONS | 0.76 | All REQs mapped; covered-reference verification surface weak (CF-2) | -| §5 Technical risks | PROCEED-WITH-CONDITIONS | 0.72 | KJ-STATIC mitigation sound; KJ-LOCKSTEP by-construction good; M1.5 gate not enforced (CF-1) | -| §6 Testability | REJECT-AS-WRITTEN → PROCEED-WITH-CONDITIONS | 0.66 | "Verified via cutover gates in operator guide" is a punt absent CF-1/CF-2/CF-3/CF-4 | -| §7 Security | PROCEED-WITH-CONDITIONS | 0.68 | INV-18 (AuthType=AWS_IAM), TFM-HITL, IAM-NARROW unverifiable from acdl (CF-2) | -| §8 Timeline/sequencing | PROCEED | 0.80 | P1→P2 ordering safe (acdl-local scrub); P5 smoke hedges (CF-3) | -| §9 Adversarial | PROCEED-WITH-CONDITIONS | 0.70 | Dominant silent-failure = M1.5 never runs green (CF-1 addresses) | - ---- - -## Critical fixes (must apply before EXECUTE) - -### 🔴 CF-1 — M1.5 green is a HARD P6 milestone-ship gate; spike extended - -**Finding:** P1 authors the M1.5 gate tests (Wave 3) but P1's exit -criterion explicitly marks the live KMS round-trip as "covered- -reference, runs in nova-platform-ops CI." P6 ships the milestone with -no requirement that M1.5 ever ran green. The dominant silent-failure -path (user-confirmed): M1.5 never runs green → 14 REQs ship "complete" -on paper while Nova-idp is not live. - -**Fix (binding):** -1. P6 Wave 2 (`ciagent-ship`) MUST NOT ship `v1.28.6` until the operator - guide (`docs/operator-guide-platform-ops.md`) contains an - operator-attested "M1.5 Verification Gate Result" row recording: - (a) the 8-item spike all-green on **3 consecutive rebuilds** in - `nova-platform-ops` CI; (b) the rebuild run IDs / commit SHAs; (c) - the operator attestor identity. The P6 audit step (Wave 1) verifies - this row exists + is non-empty. Absent the row → P6 blocks → escalate. -2. The M1.5 8-item spike (PLAN Happy Path §3.3 Edge 5) is EXTENDED from - 8 to **12 items** by adding: - - **Item 9 (JWKS-EDGE-ONLY):** direct JWKS Function URL GET (bypassing - CloudFront) returns **403**; via-CloudFront GET returns 200. Proves - `AuthType: AWS_IAM` + OAC pinning (INV-18). Without this, the - `AuthType: NONE` pitfall (RESEARCH §4) is undetected. - - **Item 10 (IAM-NARROW):** `aws iam get-role-policy` on the OIDC - role asserts no `Action: "*"` and no `Resource: "*"` (REQ-360). - - **Item 11 (TFM-HITL):** a `terraform apply` `workflow_dispatch` - triggered by the PR author is **rejected** (exit non-zero, - `gitea.triggering_actor == PR author`); a dispatch by a distinct - user proceeds (REQ-357, RESEARCH §10). - - **Item 12 (rollback drill):** revert `nova_platform_version` pin → - `terraform apply` → assert the prior ECR digest runs (proves D-236 - rollback; guards against ECR tag mutability, RESEARCH §2). - -**Binding decision G-2.1:** the covered-reference pattern is accepted -as a verification surface **only** with CF-1 applied. M1.5 green -(evidenced by operator attestation in the guide) is the ship gate. - -### 🔴 CF-2 — Covered-reference REQs gated by operator-attested evidence rows - -**Finding:** 14 of 17 REQs (355..366, 371) are "verified via cutover -gates in the operator guide" (CLARIFY G4). This is a deferred-trust -assertion: if `nova-platform-ops` is never built, or builds the wrong -thing, or its CI silently passes, the REQs ship "complete" on the -strength of a markdown pointer. The user confirmed this is a -deferred-trust assertion, not a verification. - -**Fix (binding):** The operator guide (P4 Wave 1 Task 1.1) "Cutover -Gates" section MUST list each covered-reference REQ with: -(a) the gate entry (M1/M1.5/M2); (b) the verification command; (c) a -placeholder "Result" column. The P6 audit step (Wave 1) verifies that -every covered-reference REQ has a non-empty, green "Result" entry -(operator-attested). A REQ with an empty or red Result → P6 blocks. -This converts "documented" to "evidenced-by-operator-attestation- -audited-by-acdl-at-P6." - -**Binding decision G-1:** the covered-reference pattern is **accepted -as a verification surface** with CF-1 + CF-2 applied. Without them, it -is a punt and the grill would REJECT. - -### 🔴 CF-3 — P5 smoke test must run against a real v1.29.x tag (no hedge) - -**Finding:** P5 bumps the consumer deploy.yml `@v1.25` → `@v1.29` and -runs a smoke test "against the v1.29 publish artifacts." But -`publish.yml` triggers on `v1.29.*` tags (P1 Wave 0), and the milestone -release tag is `v1.28.6`. P5 Wave 1 Task 1.2 hedges: "If the v1.29 -publish artifacts are not yet available... mark as covered-reference: -requires v1.29.0 tag." This hedge lets P5 ship green without the -smoke test ever running against real artifacts — a second silent- -failure path. - -**Fix (binding):** -1. P1 Wave 4 (regression + ship) MUST push a `v1.29.0` tag (or the - first `v1.29.x` tag) as part of P1 ship, triggering `publish.yml` - and producing the v1.29 artifacts. Document this in PLAN P1. -2. P5 Wave 1 Task 1.2's hedge clause is REMOVED. The P5 smoke test - MUST run against the published v1.29.x artifacts. If the artifacts - are absent (P1 failed to publish), P5 fails closed — no hedge to - "covered-reference." -3. The milestone release tag remains `v1.28.6` (the v1.28.x line per - the tagging convention); the `v1.29.0` artifact tag is a P1 - intermediate tag, not the release. This resolves the tag-semantics - ambiguity the grill surfaced. - -### 🔴 CF-4 — kj v0.0.3 source-fetch path confirmed before P1 Wave 1 - -**Finding:** P1 Wave 1 Task 1.1b says "fetches the `kj` Go source at -the pinned SHA" citing "RESEARCH §7 — source repo confirmed in P1 -RESEARCH." RESEARCH §7 confirms the build command (`CGO_ENABLED=0`) -but is **silent on the source repository**. Assumption ledger item #1 -says "RESEARCH will confirm the source repository + build commands" -— RESEARCH did NOT confirm the source repo. `kj-version.txt` pins -`v0.0.3` + SHA `4ebb9a19...` but the grill cannot determine whether -this is a source commit SHA or a binary digest, or what repo it lives -in. P1 Wave 1 is built on an open assumption. - -**Fix (binding):** Before P1 Wave 1 starts (P1 Wave 0 or a new Wave -0.5), the backend-engineer MUST confirm: (a) the `kj` source repo URL -+ the commit at SHA `4ebb9a19...`; (b) `go build` reproduces a binary -whose SHA-256 matches the recorded one (or the SHA is a source commit, -in which case the build is the verification); (c) the fetched source -compiles `CGO_ENABLED=0` to a statically-linked binary (KJ-STATIC). If -the source is not fetchable at the pinned SHA → P1 fails closed → -escalate (this is a spec dependency, not a CIAgent ambiguity per -assumption #1). Document the confirmed repo URL + commit in -`platform/abac/kj-version.txt` (add a third line: the source repo URL). - ---- - -## Tracked conditions (apply during execution) - -- **TC-1 (KJ-STATIC audit, P1 Wave 1 Task 1.2):** `file(1)` asserts - `statically linked` + `readelf -d` asserts no `NEEDED` entries, as a - CI gate. Already in PLAN; tracked for enforcement. -- **TC-2 (KJ-LOCKSTEP by construction, covered-reference):** both - image-bearing resources reference a single `data.aws_ecr_image.kj_image`; - `image_uri = repo@digest`. Verified via CF-1 item 12 (rollback drill) - + CF-2 (operator-attested result row for REQ-371). -- **TC-3 (CloudFront OAC pitfall, P4 operator guide):** the guide MUST - document the `AuthType: NONE` → OAC-ignored pitfall (RESEARCH §4) as - a callout. CF-1 item 9 mechanically verifies it. Already in PLAN P4 - Wave 0 Task 0.3b; tracked. -- **TC-4 (ECR tag format, P1 Wave 1 Task 1.1f):** assert tag matches - `^[a-zA-Z0-9._-]+$` before push (D-239). Already in PLAN; tracked. -- **TC-5 (import idempotency, covered-reference REQ-361):** CI import - treats "Resource already managed by Terraform" as idempotent success - (grep the message, not just exit code). Documented in RESEARCH §1; - tracked for the ops repo (operator-attested via CF-2). -- **TC-6 (Fargate sunset discipline, P4 operator guide):** D-237 — - ≥30 consecutive days green + architecture review before deletion. - Already in PLAN P4 Wave 0 Task 0.3f; tracked. - ---- - -## Binding decisions (this grill session) +## Binding decisions (grill-level, full autonomy) | ID | Decision | Rationale | Confidence | |----|----------|-----------|-----------| -| **G-1** | The covered-reference pattern is accepted as a verification surface, but ONLY with CF-1 (M1.5 green = hard P6 gate + spike extended to 12 items) + CF-2 (operator-attested result rows for every covered-reference REQ, audited at P6). Without these, it is a deferred-trust assertion (punt) and the grill would REJECT. | User-confirmed: covered-reference is a deferred-trust assertion; M1.5 must be a hard gate; TFM-HITL/IAM-NARROW/JWKS-EDGE-ONLY are unverifiable from acdl absent the extended spike. | 0.78 | -| **G-2.1** | M1.5 green (3 consecutive rebuilds of the 12-item spike) is a binding P6 milestone-ship gate, evidenced by an operator-attested row in the operator guide. The P6 audit verifies the row exists + is green. | Dominant silent-failure path = M1.5 never runs green → 14 REQs false-"complete." User-confirmed. | 0.85 | -| **G-2.2** | The M1.5 spike is extended 8 → 12 items, adding: JWKS-EDGE-ONLY direct-URL-403 check, IAM-NARROW no-wildcard assertion, TFM-HITL self-approval-rejection check, rollback drill. | INV-18, REQ-360, REQ-357 are otherwise unverifiable from acdl. Rollback is untested (D-236). | 0.80 | -| **G-3** | P1 MUST push a `v1.29.0` (or first `v1.29.x`) intermediate tag at P1 ship to produce publish artifacts; P5's "covered-reference: requires v1.29.0 tag" hedge is REMOVED; the smoke test must run against real artifacts or P5 fails closed. | P5's hedge is a second silent-failure path. User-confirmed. | 0.82 | -| **G-4** | The `kj` v0.0.3 source-fetch path (repo URL + commit at SHA `4ebb9a19...`) must be confirmed before P1 Wave 1; the confirmed repo URL is recorded as a third line in `platform/abac/kj-version.txt`. If unfetchable → P1 fails closed → escalate. | RESEARCH §7 is silent on the source repo; P1 Wave 1 is built on an open assumption. User-confirmed. | 0.80 | -| **G-5** | The covered-reference REQs (355..366, 371) are NOT marked "complete" at P6 unless their operator-guide cutover-gate row is non-empty + green (CF-2). An empty/red row blocks the milestone ship. | Converts "documented" → "evidenced-by-operator-attestation-audited-by-acdl." | 0.78 | +| G-1 | All 7 slides use `##` H2 titles (content slides, white bg) — slide 1 is NOT a title-class slide. | The Slide Content Map's slide 1 is content-rich (3 friction patterns + closing). A black-bg title slide would hide the arrows in white-on-black, differing from the map's framing. White-bg content slides give visual consistency across all 7. The map doesn't specify background; visual review accepts either. | 0.82 | +| G-2 | The `→` arrow lines are authored as `- → ...` bullets (not bare `→` plain text). | The renderer parses `[-*+]` as bullets (proper indentation + bullet glyphs). Bare `→` lines parse as plain paragraphs (no bullet formatting). The Slide Content Map shows `→` as distinct arrow lines — bullets with the arrow glyph preserve the visual intent in the PPTX. | 0.88 | +| G-3 | The `style:` block in the leadership deck frontmatter replaces `#2E2E2E` (blockquote color in the existing deck) with `#1B1B1B`. | REQ-372.6 allows only 4 hex colors in the source. The existing deck's `style:` uses `#2E2E2E` for blockquote text — this must not appear in the leadership deck source. `#1B1B1B` is the closest S&P token (black). | 1.0 | +| G-4 | The render_pptx.py extension parses the Marp frontmatter to extract the `footer:` value (for the footer textbox), but does NOT parse `paginate:`, `theme:`, `size:`, or `style:`. | Minimal extension scope per D-242. Only the footer is needed for REQ-372.5. The other directives are source-only (smoke test checks source; the python-pptx path ignores them). | 0.90 | --- ## Escalations -None. All 9 axes resolved at confidence ≥ 0.66. The user confirmed the -binding verdict (G-1: accepted with 4 conditions). No human escalation -required (full autonomy). The kj source-fetch (CF-4) has a fail-closed -path: if RESEARCH's open assumption is wrong, P1 fails closed and -escalates at that point — but the grill does not pre-escalate a -spec dependency the plan already flags. - ---- - -## Evidence verified against the live codebase - -- `.github/workflows/publish.yml` line 47-55: trigger is - `push: branches: [main]` (P1 Wave 0 changes to `tags: ['v1.29.*']` — - matches PLAN). -- `.gitea/workflows/publish.yml` exists (P2 removes it — matches PLAN). -- `platform/abac/kj-version.txt`: 2 lines (`v0.0.3` + SHA - `4ebb9a19...`) — matches PLAN; RESEARCH §7 silent on source repo - (CF-4). -- `nova/idp/setup.py`: 50 lines, `--check/--apply/--verify/--dry-run` - (P3 adds terraform delegation — matches PLAN). -- `core/lambda/nova_idp_setup.py` exists (P3 archives its CFN — matches). -- `tests/test_idp_auth.py` + `tests/test_kms_roundtrip.py` EXIST (from - v1.28); `tests/test_abac_e2e.py` does NOT exist (P1 Wave 3 authors it - — matches PLAN). -- `pyproject.toml` version = `1.14.0` (P2 bumps to `1.29.0` — matches - PLAN; note: v1.28 did not bump it, a v1.28 carry-over the grill - flags as minor but does not block on). - ---- - -## Grill complete - -The v1.29 plan proceeds with **4 critical fixes** (CF-1 M1.5 hard gate -+ spike extension; CF-2 operator-attested result rows; CF-3 P5 live -smoke no-hedge; CF-4 kj source confirmation) and **6 tracked -conditions**. The covered-reference pattern is accepted as a -verification surface **only** because CF-1 + CF-2 convert -"documented" into "evidenced-by-operator-attestation-audited-by-acdl- -at-P6." Without those fixes, the grill would REJECT: 14 of 17 REQs -would ship "complete" on the strength of a markdown pointer to a -nonexistent repo's CI. - -Next: apply the 4 critical fixes to PLAN.md + REQUIREMENTS.md, then -MVP/UX CHECK → SHIP phase 0. \ No newline at end of file +None. All axes ≥ 0.84 confidence. No human escalation required at +full autonomy. \ No newline at end of file From 8ba9981743ac6c1c97a66d097d65427c20859de4 Mon Sep 17 00:00:00 2001 From: CIAgent Date: Thu, 20 Aug 2026 13:18:04 +0000 Subject: [PATCH 6/6] =?UTF-8?q?decision(P00):=20mvp/ux=20gate=20=E2=80=94?= =?UTF-8?q?=20auto-generated=20(3=20sections=20present)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.30 status: mvp_ux_check ---/ci--- --- .ciagent/CHECKPOINT.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 7eccebd..45f2d57 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "grill", + "stage": "mvp_ux_check", "milestone": "v1.30", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-20T13:50:00Z", + "updated_at": "2026-08-20T13:52:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.30", @@ -23,5 +23,5 @@ "branches_deleted": true, "releases_created": true }, - "notes": "v1.30 Phase 0 GRILL complete. Verdict: PROCEED (confidence 0.88). No critical conditions. 6 tracked conditions (all advisory). 4 binding decisions (G-1..G-4): H2 content slides, → bullets, #1B1B1B for blockquote, minimal frontmatter parse. Next: MVP/UX CHECK." + "notes": "v1.30 Phase 0 MVP/UX CHECK passed. PLAN.md has all 3 sections: User-Facing Surface (PPTX+source+smoke test), Happy Path (J1), UX Acceptance Criteria (8 items). Auto-generated at full autonomy. Next: PHASE 0 SHIP." } \ No newline at end of file