Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e7866fda84 | |||
| 2efed26bb6 | |||
| 5c07e29b90 | |||
| aa868c97ef | |||
| e4a9915891 | |||
| 0ca383dae6 | |||
| ed5ea90654 | |||
| 2273009b95 | |||
| 0d2cbdb423 | |||
| b418d429b5 | |||
| dcba380b52 | |||
| f0bc3be92c | |||
| 0b79b16715 | |||
| 90624be63f |
@@ -0,0 +1,66 @@
|
||||
# Nova — The Autonomous Cloud Delivery Platform: Autonomy Defensibility Brief
|
||||
|
||||
> Strategic direction, leadership metrics & unified story
|
||||
> Last refined: v1.21 — reframe from "no-humans" to "autonomous operations"
|
||||
|
||||
## The thesis
|
||||
|
||||
Nova is the autonomous infrastructure layer that lets product teams
|
||||
ship without engaging an operator, and lets executives trust the
|
||||
platform not because it never fails but because every decision is
|
||||
captured, scored, and accountable.
|
||||
|
||||
**Autonomy in operations; human at stage gates.** Normal operations —
|
||||
provisioning, healing, remediation — run without an operator in the
|
||||
loop. Human attestation remains required at stage gates: QA signs off
|
||||
for production, SRE greenlights based on operational readiness. The
|
||||
absence of an operator in the loop is never the absence of a record.
|
||||
|
||||
## Grounded proof (measurable today)
|
||||
|
||||
| Proof | Source | Status |
|
||||
|-------|--------|--------|
|
||||
| Capabilities verified, none broken (live-AWS caps honestly skipped, resources torn down to zero-cost steady state) | regression report | grounded |
|
||||
| Decision Ledger captures 100% of automated decisions with outcome backfill | decision ledger store | grounded |
|
||||
| Attestation coverage: 100% of prod/dr promotions attested by a human | attestation gates + outbox | grounded |
|
||||
| Confidence-gated policy engine (deterministic, not an LLM) — weighted inputs, band outcome | confidence signal | grounded |
|
||||
| Attestation matrix with separation-of-duties on prod | attestation matrix + separation-of-duties | grounded |
|
||||
| Pre-apply cost estimates (offline) | cost adapter | grounded |
|
||||
| Test suite passes | test results | grounded |
|
||||
|
||||
## Deferred proof (measurable when blocking work lifts)
|
||||
|
||||
| Proof | Blocking work | Unblock requirement |
|
||||
|-------|----------------|---------------------|
|
||||
| Touchless resolution rate across production estates | 0 consumers today | Pilot estate activation |
|
||||
| Live infrastructure health (ECS, ALB, RPS) | Live AWS torn down | Live AWS re-provisioning |
|
||||
| Onboarding funnel: requested → granted | Auto-grant not built | Auto-grant implementation |
|
||||
| Drift auto-reversal rate | No drift scheduler | Drift detection scheduler |
|
||||
| Predictive vs reactive ratio | No emitter | ML anomaly-forecasting service |
|
||||
| Tamper-evident ledger checkpoints (S3 Object Lock + JWS) | Audit ledger build-out | Audit ledger build-out |
|
||||
|
||||
## Anti-claims (what Nova is NOT)
|
||||
|
||||
1. **Nova's decisions are NOT made by an LLM.** They are made by a
|
||||
confidence-gated policy engine: deterministic scripts calculate a
|
||||
score, and a band outcome gates the action. The platform functions
|
||||
without AI. The Decision Ledger captures this real decision path —
|
||||
not a fabricated "AI agent." When an LLM planner is added, it will
|
||||
emit richer `alternatives_considered` without schema breakage.
|
||||
2. **Nova does NOT remove humans from accountability.** Only from
|
||||
normal operations. Every stage-gate promotion (qa/prod/dr) requires
|
||||
a human attestation recorded with approver identity,
|
||||
separation-of-duties check, and the evidence matrix.
|
||||
3. **Nova is NOT for legacy, untagged, or freeform infrastructure.** It
|
||||
requires Terraform-managed, policy-aligned, fully-tagged inputs.
|
||||
4. **Nova does NOT fabricate metrics.** Every metric is grounded (cites
|
||||
a source), derived (documented formula), or deferred (cites the
|
||||
blocking work). No fabricated numbers in any deck slide or metrics
|
||||
entry (the "no fabrication" hard constraint).
|
||||
|
||||
## What "won" looks like
|
||||
|
||||
By month 18, Nova is the layer enterprise leadership points to when
|
||||
they say *"we don't have an infrastructure ops team anymore, and the
|
||||
audit trail is stronger than it ever was"* — and it is the layer their
|
||||
AI engineering teams reach for first when an agent needs to deploy.
|
||||
@@ -1,13 +1,11 @@
|
||||
{
|
||||
"phase": 1,
|
||||
"stage": "complete",
|
||||
"milestone": "v1.19",
|
||||
"phase_role": "execution",
|
||||
"phase": 0,
|
||||
"stage": "plan",
|
||||
"milestone": "v1.21",
|
||||
"phase_role": "pre_execution",
|
||||
"attempts": 0,
|
||||
"updated_at": "2026-08-06T20:00:00Z",
|
||||
"updated_at": "2026-08-11T00:01:00Z",
|
||||
"milestone_complete": false,
|
||||
"tag": "v1.18.0",
|
||||
"release_id": 530,
|
||||
"requirements": ["REQ-229"],
|
||||
"notes": "v1.19 P1 SHIP complete: tag v1.18.0 (first patch on v1.18.x line), Gitea release id 530 created. 4-layer verify PASS. Next: P2 final-review-ship (review + audit + milestone complete)."
|
||||
"requirements": ["REQ-245","REQ-246","REQ-247","REQ-248","REQ-249","REQ-250","REQ-251","REQ-252","REQ-253"],
|
||||
"notes": "v1.21 P0 plan stage complete. PLAN.md v1.21 section written. 5 execution phases (P1 strategic-docs, P2 slides, P3 marp+talking-points+README, P4 pipeline-hardening, P5 render+verify) + P6 final-review-ship. Wave 1 (P1/P2/P4 parallelizable), Wave 2 (P3), Wave 3 (P5), Wave 4 (P6). CLARIFY+RESEARCH minimal at full autonomy — domain known, requirements confirmed with user. Proceeding to P0 ship then execution."
|
||||
}
|
||||
+57
-36
@@ -1,7 +1,7 @@
|
||||
# NORTH_STAR — Nova
|
||||
|
||||
> **Status:** Draft (pending interactive GRILL → final)
|
||||
> **Milestone:** v1.17 — Strategic Direction, Leadership Metrics & Unified Story
|
||||
> **Milestone:** v1.21 — Nova Deck Refinement & Pipeline Hardening
|
||||
> **Owner:** Product Owner
|
||||
> **Purpose:** Durable strategic intent. Read by CIAgent in every future
|
||||
> `/ci-run` so the platform's direction survives across milestones. This
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
## Vision
|
||||
|
||||
> **Infrastructure operations become invisible. Every environment
|
||||
> **Infrastructure operations become visible. Every environment
|
||||
> provisioned, every incident healed, every risk remediated — by an
|
||||
> autonomous system whose trustworthiness is provable, not promised.
|
||||
> Human attestation remains required at stage gates — QA signs off for
|
||||
@@ -22,9 +22,12 @@
|
||||
> operator is never in the loop of normal operations.**
|
||||
|
||||
Nova is the autonomous infrastructure layer that lets product teams ship
|
||||
without engaging an operator, and lets executives trust the AI not because
|
||||
it never fails but because every decision is captured, scored, and
|
||||
accountable.
|
||||
without engaging an operator, and lets executives trust the platform not
|
||||
because it never fails but because every decision is captured, scored,
|
||||
and accountable. The recurring theme across the platform is that
|
||||
**infrastructure operations become visible** — security posture,
|
||||
remediation velocity, reliability, and lead time are surfaced as
|
||||
queryable signals rather than hidden in tribal knowledge.
|
||||
|
||||
---
|
||||
|
||||
@@ -38,46 +41,64 @@ human by design; operational escalations (AI confidence too low to
|
||||
proceed) are the failure mode we drive toward zero. Everything else
|
||||
collapses if autonomy isn't real.
|
||||
|
||||
**2. Establish provable trust in AI decisions.**
|
||||
Build the audit substrate — Decision Ledger, confidence scoring, circuit
|
||||
breakers, blast-radius controls — that turns "autonomous" from a
|
||||
marketing claim into a defensible one. Trust is the moat. Features can be
|
||||
copied; an immutable, queryable decision history cannot.
|
||||
**2. Establish provable trust in automated decisions.**
|
||||
Trust is established by deterministic scripts that calculate a score and
|
||||
a band outcome that gates the action — the platform functions without AI.
|
||||
"AI decisions" are really automated decisions. The audit substrate —
|
||||
Decision Ledger, confidence scoring, circuit breakers, blast-radius
|
||||
controls — turns "autonomous" from a marketing claim into a defensible
|
||||
one. Trust is the moat. Features can be copied; an immutable, queryable
|
||||
decision history cannot.
|
||||
|
||||
**3. Deliver compounding, quantifiable ROI for customers.**
|
||||
Each quarter on Nova must reduce cloud spend, free engineering hours, and
|
||||
avoid downtime measurably. If the CFO can't point to a number that
|
||||
improves quarter-over-quarter, Nova fails its commercial test, regardless
|
||||
of how clever the AI is.
|
||||
Each quarter on Nova must show measurable improvement on four CTO-grade
|
||||
metrics, all of which flow into PowerBI views and are captured by the
|
||||
telemetry pipeline:
|
||||
|
||||
**4. Become the default substrate for agentic infrastructure consumption.**
|
||||
AI agents are already becoming the largest consumers of cloud
|
||||
infrastructure. Nova must be the platform through which those agents
|
||||
declare, deploy, and verify infrastructure — not a vendor scrambling into
|
||||
that market two quarters late.
|
||||
- **Lead Time** — from PR merge to production deployment (downward trend).
|
||||
- **Infrastructure Vulnerability Count** — open findings on deployed
|
||||
resources (downward trend, demonstrating that proactive scanning +
|
||||
remediation keeps up with the AI-era 0-day pace).
|
||||
- **MTTR** — for platform-detected and platform-remediated incidents.
|
||||
- **Cloud Spend Reduction** — on pilot estates vs. the pre-Nova
|
||||
baseline.
|
||||
|
||||
If leadership cannot point to a number that improves quarter-over-quarter
|
||||
on these four axes, Nova fails its commercial test, regardless of how
|
||||
clever the automation is.
|
||||
|
||||
**4. Integrate with externally owned development platforms — regardless of source.**
|
||||
Nova integrates with externally owned PDLC, SDLC, Agentic, and Citizen
|
||||
Developer platforms with no regard for the source of the intent. Nova
|
||||
provides a set of skills and MCP endpoints that help the developer or AI
|
||||
agent make their application production-grade. Regardless of the source,
|
||||
all intents to deploy to production go through the same rigorous
|
||||
controls, quality gates, attestation, and evidence stream. Nova is the
|
||||
layer any of those platforms reach for first when an agent needs to
|
||||
deploy — not a vendor arriving late to that market.
|
||||
|
||||
---
|
||||
|
||||
## Anti-Goals (5 — what Nova is fundamentally NOT)
|
||||
## Anti-Goals (4 — what Nova is fundamentally NOT)
|
||||
|
||||
1. **Not a Terraform, Kubernetes, or hyperscaler competitor.** We
|
||||
orchestrate them. Replacing them is the most expensive possible
|
||||
distraction from the value we create.
|
||||
2. **Not a general-purpose AI agent platform.** We are purpose-built for
|
||||
1. **Not a general-purpose AI agent platform.** We are purpose-built for
|
||||
infrastructure operations. Breadth here produces shallow tools; depth
|
||||
here wins the category.
|
||||
3. **Not a system that removes humans from accountability.** Only from
|
||||
operations. Every AI decision lands in an immutable ledger. Every
|
||||
stage-gate promotion (qa/prod/dr) requires a human attestation recorded
|
||||
with approver identity, separation-of-duties check, and the 8-concern
|
||||
evidence matrix. The absence of an operator is never the absence of a
|
||||
record.
|
||||
4. **Not for legacy, untagged, or freeform infrastructure.** Nova requires
|
||||
Terraform-managed, policy-aligned, fully-tagged inputs. We optimize for
|
||||
the disciplined 95%, not the chaotic 5%.
|
||||
5. **Not sold to operators.** Nova is sold to leadership on outcomes —
|
||||
cost, velocity, risk. Selling to operators inverts the incentive and
|
||||
breaks the autonomy thesis.
|
||||
2. **Not a system that removes humans from accountability.** Only from
|
||||
normal operations. Every automated decision lands in an immutable
|
||||
ledger. Every stage-gate promotion (qa/prod/dr) requires a human
|
||||
attestation recorded with approver identity, separation-of-duties
|
||||
check, and the evidence matrix. The absence of an operator in the
|
||||
loop is never the absence of a record.
|
||||
3. **Not an upstream development platform.** Nova does not own the
|
||||
product backlog, IDE workflows, code authorship, or application
|
||||
business logic. The PDLC is upstream; Nova integrates with it through
|
||||
a validated contract boundary — Nova never penetrates it.
|
||||
4. **Not a replacement for the Product Development Lifecycle (PDLC).**
|
||||
Nova governs infrastructure + delivery only. Product lifecycle
|
||||
decisions (what to build, when to ship, for whom) remain with the
|
||||
product team. Nova makes their intent production-grade; it does not
|
||||
own the intent.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,3 +1,157 @@
|
||||
# Nova — Phase Plan v1.21 (Nova Deck Refinement & Pipeline Hardening)
|
||||
|
||||
> **Milestone:** v1.21 — Nova Deck Refinement & Pipeline Hardening
|
||||
> **Branch:** `milestone/v1.21-deck-refinement` (flat workflow: commits on
|
||||
> main, tags on the v1.20.x line per branch-strategy)
|
||||
> **Tag line:** `v1.20.x` patch line — `v1.20.0` (P0) → `v1.20.1..v1.20.5`
|
||||
> (P1–P5) → `v1.20.6` (P6 final = milestone release). v1.21 is an NFR
|
||||
> milestone (all phases are docs/test/chore/refactor) → progressive patches.
|
||||
> **Phase count:** 7 (P0 pre-execution [DONE] + 5 execution + 1 final).
|
||||
> **Source of truth for requirements:** `.ciagent/REQUIREMENTS.md` §v1.21
|
||||
> (REQ-245..253, 9 requirements).
|
||||
> **Source of truth for decisions:** the 33 review notes in the v1.21
|
||||
> run context (encoded as REQ-245..253).
|
||||
> **Source of truth for research:** existing deck + pipeline + strategic
|
||||
> docs (the domain is known; no new research needed at full autonomy).
|
||||
|
||||
## Wave Ordering
|
||||
|
||||
All 5 execution phases are **sequenced** (flat workflow). The theoretical
|
||||
parallelism is documented for future parallelization-enabled runs.
|
||||
|
||||
| Wave | Phases | Rationale |
|
||||
|------|--------|-----------|
|
||||
| Wave 1 | P1, P2, P4 (**parallelizable**) | P1 (strategic docs: NORTH_STAR, AUTONOMY_THESIS, PROJECT, scope, raci), P2 (slides source-of-truth rewrite + rename), P4 (pipeline hardening: Checkov/Wiz flow). Zero file overlap: P1 touches `.ciagent/` + `docs/scope.md` + `docs/raci.md`; P2 touches `docs/presentations/*.md`; P4 touches `scripts/run_*.sh` + `adapters/wiz/` + `tests/test_pipeline*.py`. In a parallelization-enabled run these three could execute concurrently. |
|
||||
| Wave 2 | P3 | Marp deck + talking points + README synthesis. Depends on P2's updated source-of-truth. Re-renders HTML+PPTX via `render_slides.sh`. Also fixes theme CSS A1 table + footer cleanup (REQ-251). |
|
||||
| Wave 3 | P5 | Render + verify. Depends on P2 (source), P3 (marp), P4 (pipeline). Re-renders mermaid PNGs (slide 1 new diagram, slide 9 expand, Atelier split), HTML, PPTX. Runs `test_slides_pipeline.py`, `test_no_forge_mentions.py`, full `pytest`, `run_platform.sh --check-only`. |
|
||||
| Wave 4 | P6 | Final review + audit + milestone ship. Merge to main, tag `v1.20.6`, create release, attach PPTX. |
|
||||
|
||||
## Phase Summaries
|
||||
|
||||
### Phase P0 — pre-execution (DONE)
|
||||
SPECIFY → CLARIFY → RESEARCH → PLAN. Validated v1.21 requirements
|
||||
(REQ-245..253). Established `active_milestone: "v1.21"`. Synced
|
||||
PROJECT.md strategic-direction pillar. No new research (domain known).
|
||||
|
||||
### Phase P1 — strategic-docs (Wave 1)
|
||||
- `NORTH_STAR.md`: vision polish (item 11); obj #2 deterministic-scoring
|
||||
reword (item 13); obj #3 four CTO metrics (item 14); obj #4 replaced
|
||||
with integration objective (item 17); drop anti-goals 1,4,5; add 2 new
|
||||
anti-goals (item 16); anti-goal #3 reworded (item 7).
|
||||
- `git mv .ciagent/NO_HUMANS_THESIS.md .ciagent/AUTONOMY_THESIS.md` +
|
||||
reframe content (items 7, 8).
|
||||
- `PROJECT.md`: mission/scope sync for item 17 (already partially done
|
||||
in P0; finalize here).
|
||||
- `docs/scope.md`: light sync.
|
||||
- `docs/raci.md`: rename Release Mgmt → SRE; add Quality Engineering role.
|
||||
- **REQs:** REQ-246, REQ-247 (partial).
|
||||
|
||||
### Phase P2 — slides source-of-truth (Wave 1)
|
||||
- `git mv` all 5 deck files `nova-no-humans-platform*` →
|
||||
`nova-autonomous-cloud-delivery*`.
|
||||
- Rewrite `nova-autonomous-cloud-delivery.md` (source of truth):
|
||||
- Slide 1 "The Problem" (items 3,4,5,7,9): broader problem (devs writing
|
||||
terraform, destructive changes, AI-era 0-day pace, bandwidth gaps,
|
||||
tribal knowledge/rockstar operator); no arc; no "18 capabilities
|
||||
verified"; not "humans are the problem".
|
||||
- Slide 2 "Nova's Vision" (item 11): polish for technical audience;
|
||||
"infrastructure operations become visible" as recurring theme.
|
||||
- Slide 3 "Strategic Objectives + Anti-Goals" (items 12,13,14,15,16,17,
|
||||
18): only Obj+Anti-Goals; provable trust = deterministic scripts
|
||||
(functions without AI); ROI = Lead Time + Vuln Trend + MTTR + Spend;
|
||||
drop anti-goals 1,4,5; add "not upstream dev platform", "not PDLC
|
||||
replacement"; replace obj #4 with integration objective; reword benefit.
|
||||
- Slide 4 "Scope" (item 29): refine (moved up).
|
||||
- Slide 5 "RACI" (item 30): add QE column; reassign A from Platform →
|
||||
QA/SRE; rename Release Mgmt → SRE; split release attestation (SRE =
|
||||
Production Readiness); shrink to fit (moved up).
|
||||
- Slide 6 "Pipeline" (item 20): Checkov on static code before plan;
|
||||
Wiz on plan; no Wiz → Checkov on plan; never both.
|
||||
- Slide 7 "Decision Ledger" (items 21,22): drop D-121/122/132; "AI
|
||||
decisions = automated decisions"; focus on value (immutable,
|
||||
queryable, accountable), not sqlite/hash-chain implementation.
|
||||
- Slide 8 "Attestation Matrix" (item 23): drop bullets below table;
|
||||
add Description column per concern; rethink "operator-supplied"
|
||||
label; reword benefit.
|
||||
- Slide 9 "Telemetry & Live Ops" (item 25): expand on value; keep
|
||||
metric flow; drop D-120/125/126; expand on PowerBI live ops
|
||||
dashboard; reword benefit.
|
||||
- Slide 10 "Decision Ledger + Attestation Coverage" (item 27):
|
||||
mandatory by design; no prod change without ledger + human
|
||||
attestation; queryable for auditing; full traceability; improve
|
||||
benefit.
|
||||
- Slide 11 "Cost & ROI": minor polish.
|
||||
- Slide 12 "What's Deferred — and Why" (items 10,19): remove all D-IDs;
|
||||
plain-language blockers.
|
||||
- Slide 13 "Roadmap to the North Star" (items 10,19): drop D-IDs; no
|
||||
status column; roadmap with timelines.
|
||||
- Slide 14 "12-Month Product Roadmap" (item 24): drop `planned` badges.
|
||||
- Slide 15 "Quarter-by-Quarter Outcomes" (item 24): drop badges.
|
||||
- Slide 16 "Production-Grade Guidance via Atelier (1/2)" (item 31):
|
||||
split — Skills + MCP server overview.
|
||||
- Slide 17 "Production-Grade Guidance via Atelier (2/2)" (item 31):
|
||||
split — agentic validation beyond deterministic scanners + vendoring.
|
||||
- Slide 18 "Recap + Ask": refresh recap to match new structure.
|
||||
- Appendix A1 "Metrics Glossary" (item 32): table readability fixed
|
||||
in P3 theme CSS.
|
||||
- Global (items 6,10,24,2): tech-leadership benefits; no D-###/REQ-###/
|
||||
.py paths in audience slides; no badges; no version in footer; final
|
||||
"less is more / no fluff" prose pass.
|
||||
- **REQs:** REQ-245, REQ-248, REQ-249, REQ-252 (partial).
|
||||
|
||||
### Phase P3 — marp deck + talking points + README (Wave 2)
|
||||
- `nova-autonomous-cloud-delivery-marp.md`: synthesize from updated
|
||||
source; frontmatter — title "Nova — The Autonomous Cloud Delivery
|
||||
Platform", footer without version + without "Act N/5", title-slide
|
||||
subtitle "Product Development & Citizen Developer Overview", no badges.
|
||||
- `nova-autonomous-cloud-delivery-talking-points.md`: re-distill to
|
||||
18-slide structure.
|
||||
- `docs/presentations/README.md`: update deck title, audience, slide
|
||||
count (18 main + 1 appendix), directory layout, remove badge docs,
|
||||
update deck table + render commands + filenames.
|
||||
- `docs/presentations/assets/nova-sp-theme.css`: fix Appendix A1 table
|
||||
background (item 32); footer chrome no version.
|
||||
- Update `scripts/render_slides.sh`, `scripts/render_deck.sh`,
|
||||
`workflows-src/slides.yml`, `.github/workflows/slides.yml`,
|
||||
`tests/test_slides_pipeline.py` filename refs.
|
||||
- **REQs:** REQ-251, REQ-252 (partial).
|
||||
|
||||
### Phase P4 — pipeline hardening (Wave 1)
|
||||
- `scripts/run_platform.sh` + `scripts/run_postapply.sh`: item 20 flow —
|
||||
1. Checkov on static code (`main.tf`/TF dir) **before** `terraform
|
||||
plan` → fail-fast dev feedback.
|
||||
2. After plan: if `WIZ_API_TOKEN`+`WIZ_API_URL` → **Wiz against plan**;
|
||||
else **Checkov against plan** (drop-in). **Never both.**
|
||||
- `adapters/wiz/wiz_adapter.py`: support plan-mode input if needed.
|
||||
- Tests: `tests/test_pipeline.py`, `tests/test_pipeline_contract.py`,
|
||||
`tests/test_slides_pipeline.py`, checkov/wiz tests.
|
||||
- `docs/scope.md` policy-enforcement line + slide 6 reflect new flow.
|
||||
- `docs/METRICS.md` policy-stage description if changed.
|
||||
- **REQs:** REQ-250.
|
||||
|
||||
### Phase P5 — render + verify (Wave 3)
|
||||
- Re-render changed/new mermaid diagrams (slide 1 new diagram, slide 9
|
||||
expand, Atelier split) via `scripts/render_slides.sh`.
|
||||
- Render HTML + PPTX.
|
||||
- `tests/test_slides_pipeline.py` passes: 18 main + 1 appendix; no badges;
|
||||
no version in footer; no D-###/REQ-###/.py paths in audience slides;
|
||||
filename refs updated.
|
||||
- `tests/test_no_forge_mentions.py` passes.
|
||||
- Full `pytest` passes (pipeline-hardening tests green).
|
||||
- `run_platform.sh --check-only` passes.
|
||||
- **REQs:** REQ-253 (partial).
|
||||
|
||||
### Phase P6 — final-review-ship (Final Phase, Wave 4)
|
||||
- Multi-persona code review across P1–P5.
|
||||
- Audit: git log vs `.ciagent/` discipline.
|
||||
- Ship: merge to main, tag `v1.20.6` (final patch = milestone release),
|
||||
create release, attach PPTX.
|
||||
- Update `REQUIREMENTS.md` (v1.21 REQs complete) + `ROADMAP.md` (v1.21
|
||||
complete). Clear `CHECKPOINT.json`.
|
||||
- **REQs:** REQ-253 (complete).
|
||||
|
||||
---
|
||||
|
||||
# Nova — Phase Plan v1.18 (Citizen Developer & Production-Grade Guidance)
|
||||
|
||||
> **Milestone:** v1.18 — Citizen Developer & Production-Grade Guidance
|
||||
|
||||
+17
-4
@@ -1266,16 +1266,29 @@ P7 review+audit+ship). Tags on the v1.16.x line: `v1.16.0` (P0) →
|
||||
|
||||
- **Pillar A — Strategic Direction.** A durable, PO-authored
|
||||
`.ciagent/NORTH_STAR.md` encodes the platform's vision, 4 strategic
|
||||
objectives, 5 anti-goals, v1.17 non-goals, 12–18mo targets (with a
|
||||
objectives, anti-goals, v1.17 non-goals, 12–18mo targets (with a
|
||||
grounding column), and success criteria. CIAgent reads it in every
|
||||
future `/ci-run` so the direction survives across milestones. The
|
||||
attestation clarification is reflected: human attestation required at
|
||||
stage gates (QA for production, SRE for operational readiness); autonomy
|
||||
in operations, not in accountability.
|
||||
in operations, not in accountability. **v1.21 refinement:** Strategic
|
||||
Objective #4 reframed from "default substrate for agentic consumption" to
|
||||
integrating with externally owned PDLC/SDLC/Agentic/Citizen Developer
|
||||
platforms regardless of source (Nova provides skills + MCP endpoints;
|
||||
all prod intents go through the same controls). Objective #2 reworded:
|
||||
trust is established by deterministic scripts that calculate a score —
|
||||
the platform functions without AI. Objective #3 reworded with four
|
||||
CTO-grade metrics (Lead Time PR→Prod, Infrastructure Vulnerability
|
||||
Count trend, MTTR, Cloud Spend Reduction) all flowing into PowerBI.
|
||||
Anti-goals #1, #4, #5 removed; replaced with "not an upstream
|
||||
development platform" and "not a replacement for the PDLC".
|
||||
|
||||
- **Pillar B — Leadership Metrics + PowerBI.** Instrument Nova to
|
||||
collect, aggregate, and surface leadership-grade metrics that prove the
|
||||
"no-humans" autonomous-infrastructure value proposition. Nova-native
|
||||
"no-humans" autonomous-infrastructure value proposition (reframed in
|
||||
v1.21 to "autonomous cloud delivery" — professional framing; the
|
||||
platform delivers safe production deployment without an operator in
|
||||
the loop of normal operations). Nova-native
|
||||
minimal tech (CloudEvents 1.0 envelope, JSONL event log, SQLite cold
|
||||
store, hash-chained Decision Ledger via `outbox_writer.py` extension)
|
||||
+ Infracost for pre-apply cost estimates. Hybrid model: existing
|
||||
@@ -1334,7 +1347,7 @@ constraints or user-directed scope). New v1.18 decisions:
|
||||
| D-140 | MCP server extensibility = plugin-registry (`plugins/<name>.py` implementing `register(mcp)`). | Future capabilities (new scanners, policy evaluators, cost tools) drop in as new plugin files — no `server.py` edits. `server.py` scans `plugins/` and calls `register` on each. This is the extensibility insurance: plugins are decoupled from the server entrypoint. | P5 implements the plugin-registry; initial plugins are `principles.py` + `validation.py`. |
|
||||
| D-141 | PPTX storage = commit binary directly to `docs/presentations/` (no LFS). | Decks are small (~1-5 MiB); git handles binary blobs. LFS requires server-side support (unverified for git.cloudinit.dev) + client config. Committing directly is simplest and works without any repo/server config. Binary diffs are not delta-friendly, but deck changes are infrequent. | P1/P2/P6 commit .pptx directly. |
|
||||
| D-142 | Deck render trigger = any phase modifying `docs/presentations/*-marp.md` or `docs/presentations/assets/` must re-render HTML + PPTX, commit PPTX, and attach to the Gitea release. | PPTX was previously manual + release-only (not committed). v1.18 makes it a first-class artifact: committed (history) + attached (download), both always, not optional. Automated via `scripts/render_deck.sh` + `scripts/attach_release_asset.py`. | P1/P2/P6 run the render+commit+attach pipeline. |
|
||||
## Objective for Milestone v1.19 (active — Nova 2nd-Release Sync)
|
||||
## Objective for Milestone v1.19 (complete — Nova 2nd-Release Sync)
|
||||
|
||||
> **NFR-only chore milestone.** Ships a patch on the v1.18.x line (tag
|
||||
> `v1.18.0`). Single execution phase. Establishes the manual-only "2nd
|
||||
|
||||
@@ -1395,3 +1395,324 @@ with documented schemas.
|
||||
| REQ | Phase | Status |
|
||||
|-----|-------|--------|
|
||||
| REQ-229 | P1 | complete |
|
||||
|
||||
## v1.20 — Consumer Cleanup + Transparent Terraform + Slide Pipeline
|
||||
|
||||
> **Multi-concern milestone.** Four user-directed inputs spanning consumer
|
||||
> cleanup, infrastructure transparency, and presentation automation. Tags
|
||||
> run on the v1.19.x line (milestone v1.20 → tags v1.19.0, v1.19.1, …).
|
||||
>
|
||||
> **Input 1 — Gitea/GitLab removal:** Remove all mentions of `gitea` / `gitlab`
|
||||
> (case-insensitive) from every file synced to `~/nova`. The platform team
|
||||
> (consumer of `~/nova`) must never know about the dev forge or the GitLab
|
||||
> mirror. Genericize forge-detection code to `forge` / `generic_forge`.
|
||||
>
|
||||
> **Input 2 — Documentation simplification:** Radically simplify all synced
|
||||
> documentation. Anything the CIAgent needs to reference for itself lives in
|
||||
> `.ciagent/`. Everything else is tailored to the Platform Team audience.
|
||||
> Strip ciagent-internal provenance (REQ-/D-/P-/CAP- IDs, milestone headers,
|
||||
> `.ciagent/PROJECT.md` citations) from synced docs. Delete completed
|
||||
> migration guides. Move internal artifacts to `.ciagent/`.
|
||||
>
|
||||
> **Input 3 — Transparent terraform:** Move terraform `init` / `validate` /
|
||||
> `plan` / `apply` / `output` into native workflow steps (transparent, visible
|
||||
> in CI logs). Split `run_platform.sh` into `run_codegen.sh` (pre-TF) +
|
||||
> `run_postapply.sh` (post-TF). Add `var.enabled` feature flags to every L1
|
||||
> module + L2 composition toggles. Wire forge repo variables as per-client
|
||||
> feature flags — different clients test different functionality without
|
||||
> version upgrades.
|
||||
>
|
||||
> **Input 4 — Slide pipeline + product roadmap:** The slides have not adopted
|
||||
> the S&P Global theme fully. Create a dedicated render pipeline that builds
|
||||
> the slides (mermaid PNGs + Marp HTML/PPTX) with the S&P theme applied to all
|
||||
> slide chrome. Add a 12-month product roadmap (high-level, product-oriented
|
||||
> vs the technical roadmap in `.ciagent/ROADMAP.md`) to the deck.
|
||||
|
||||
- **REQ-230** — No `gitea` / `gitlab` string literal (case-insensitive) appears
|
||||
in any file synced to `~/nova`. Verified by
|
||||
`tests/test_no_forge_mentions.py` which scans the synced subset (same
|
||||
path rules as `sync_to_nova.sh`'s `DOMAINS` / `EXCLUDES`). Forge-detection
|
||||
code (`contract_ingestor.py`, `hitl_gates.py`, `run_platform.sh`) is
|
||||
genericized: `gitea` → `forge` / `generic_forge`, `GITEA_ACTOR` →
|
||||
`FORGE_ACTOR` (with `GITHUB_ACTOR` primary). (Phase P1)
|
||||
|
||||
- **REQ-231** — Synced documentation is tailored to the Platform Team
|
||||
audience. Ciagent-internal provenance (`v1.XX — Strategic Direction` headers,
|
||||
`REQ-NNN` / `D-NNN` / `P-NNN` / `CAP-NNN` IDs, `.ciagent/PROJECT.md`
|
||||
"source of truth" citations) is stripped from synced docs. (Phase P1)
|
||||
|
||||
- **REQ-232** — Completed/historical migration docs
|
||||
(`docs/NOVA_MIGRATION.md`, `docs/NOVA_AWS_MIGRATION.md`) removed from the
|
||||
synced tree. `docs/NO_HUMANS_THESIS.md` moved to `.ciagent/` (internal
|
||||
thesis-defense artifact). (Phase P1)
|
||||
|
||||
- **REQ-233** — Terraform `init` / `validate` / `plan` / `apply` / `output`
|
||||
run as native workflow steps in `deploy.yml` (transparent, named steps
|
||||
visible in CI logs), not buried inside `run_platform.sh`. (Phase P4)
|
||||
|
||||
- **REQ-234** — `run_platform.sh` is split: `run_codegen.sh` (pre-TF: env
|
||||
check, validate, resolve, adapt) + `run_postapply.sh` (post-TF: Checkov,
|
||||
confidence, HITL, outbox, SSM, comment, uptime). A thin `run_platform.sh`
|
||||
shim preserves backward compat for local-dev usage. (Phase P4)
|
||||
|
||||
- **REQ-235** — Every L1 module has `variable "enabled" { type = bool,
|
||||
default = true }` + `count = var.enabled ? 1 : 0` on its primary
|
||||
resource(s); declared in `interface.json`. The `uptime` module's
|
||||
`feature_flag_enabled` is renamed to `enabled` (with backward-compat alias).
|
||||
(Phase P4)
|
||||
|
||||
- **REQ-236** — L2 `composition.json` supports per-child `enabled` toggles
|
||||
driven by contract `inputs.enable_<child>`. The resolver skips children
|
||||
with `enabled: false`. (Phase P4)
|
||||
|
||||
- **REQ-237** — `deploy.yml` reads feature flags from forge repository
|
||||
variables (`vars.ENABLE_*`) and passes them as `-var` flags to terraform,
|
||||
enabling per-client feature toggles without version upgrades. (Phase P4)
|
||||
|
||||
- **REQ-238** — Stale artifact path `/tmp/acdl_platform_run_v18` in
|
||||
`deploy.yml` fixed to use `NOVA_WORK_DIR`. (Phase P4)
|
||||
|
||||
- **REQ-239** — A dedicated S&P Global theme CSS file
|
||||
(`docs/presentations/assets/nova-sp-theme.css`) is the Marp theme for all
|
||||
Nova presentation decks. The theme applies the S&P Red/Black/White palette
|
||||
(`#D6002A`, `#1B1B1B`, `#FFFFFF`) to all slide chrome (background,
|
||||
header/footer, pagination, tables, blockquotes), not just headings. (Phase P2)
|
||||
|
||||
- **REQ-240** — A dedicated render pipeline (`scripts/render_slides.sh`)
|
||||
builds the presentation deck end-to-end: (1) renders all
|
||||
`assets/mmd/*.mmd` → `assets/png/*.png` via `mermaid-cli --configFile
|
||||
sp-theme.json`; (2) renders the Marp deck → HTML + PPTX via `marp-cli`;
|
||||
(3) stages all rendered artifacts to git. Supersedes `render_deck.sh`.
|
||||
(Phase P2)
|
||||
|
||||
- **REQ-241** — A CI workflow (`workflows-src/slides.yml` +
|
||||
`.github/workflows/slides.yml`) runs `render_slides.sh` on any change to
|
||||
`docs/presentations/**` and commits the rendered HTML/PPTX/PNGs back. No
|
||||
manual re-render step; no artifact drift. (Phase P2)
|
||||
|
||||
- **REQ-242** — `tests/test_slides_pipeline.py` validates: (1) the Marp
|
||||
deck frontmatter references `nova-sp-theme.css`; (2) the CSS contains the
|
||||
S&P colors; (3) every `.mmd` has a corresponding `.png`; (4) the HTML
|
||||
exists and is newer than the Marp `.md`. (Phase P2)
|
||||
|
||||
- **REQ-243** — `docs/presentations/README.md` directory layout is updated
|
||||
to remove retired decks (`how-the-platform-works-*`,
|
||||
`the-developer-experience-*`) and document the render pipeline + theme CSS.
|
||||
(Phase P2)
|
||||
|
||||
- **REQ-244** — A 12-month product roadmap (4 quarters, product-outcome
|
||||
oriented, grounded in NORTH_STAR strategic objectives + deferred-metric
|
||||
candidate milestones) is added to the presentation deck as Slide 20 +
|
||||
Slide 21. The roadmap is distinct from Slide 15's deferred-metric unblock
|
||||
paths. A matching talking-points section is added. (Phase P3)
|
||||
|
||||
### Out of Scope (v1.20)
|
||||
|
||||
- **Multi-cloud (Azure/GCP) implementation** — deferred; only the product
|
||||
roadmap references it as a Q4 aspiration.
|
||||
- **ML anomaly-forecasting service** — deferred; only the product roadmap
|
||||
references it as a Q4 aspiration.
|
||||
- **Actual pilot estate activation** — deferred (requires live AWS
|
||||
re-provisioning, D-096 lift); the product roadmap references it as Q1.
|
||||
- **Token rotation for `NOVA_GITEA_TOKEN`** — out of scope; the `.env` files
|
||||
are correctly excluded from sync. Flagged for awareness only.
|
||||
|
||||
### v1.20 Traceability
|
||||
|
||||
| REQ | Phase | Status |
|
||||
|-----|-------|--------|
|
||||
| REQ-230 | P1 | complete |
|
||||
| REQ-231 | P1 | complete |
|
||||
| REQ-232 | P1 | complete |
|
||||
| REQ-233 | P4 | complete |
|
||||
| REQ-234 | P4 | complete |
|
||||
| REQ-235 | P4 | complete |
|
||||
| REQ-236 | P4 | complete |
|
||||
| REQ-237 | P4 | complete |
|
||||
| REQ-238 | P4 | complete |
|
||||
| REQ-239 | P2 | complete |
|
||||
| REQ-240 | P2 | complete |
|
||||
| REQ-241 | P2 | complete |
|
||||
| REQ-242 | P2 | complete |
|
||||
| REQ-243 | P2 | complete |
|
||||
| REQ-244 | P3 | complete |
|
||||
|
||||
## v1.21 — Nova Deck Refinement & Pipeline Hardening
|
||||
|
||||
> Leadership-deck refinement based on 33 review notes on the v1.20 deck
|
||||
> (v1.20 shipped as `nova-no-humans-platform*`). This milestone renames the
|
||||
> deck to the professional "Autonomous Cloud Delivery Platform" framing,
|
||||
> restructures the narrative (Problem → Solution → Proof → Roadmap + Ask),
|
||||
> removes internal provenance from audience-facing slides, hardens the
|
||||
> policy pipeline (Checkov before plan, Wiz-or-Checkov on plan), and moves
|
||||
> the strategic integration objective into the North Star.
|
||||
>
|
||||
> Tags run on the v1.20.x line (milestone v1.21 → tags v1.20.0, v1.20.1, …).
|
||||
|
||||
### REQ-245 — Deck rename + restructure
|
||||
|
||||
The deck files are renamed from `nova-no-humans-platform*` to
|
||||
`nova-autonomous-cloud-delivery*` across all five artifacts
|
||||
(source `.md`, `-marp.md`, `.html`, `.pptx`, `-talking-points.md`).
|
||||
The in-deck title becomes "Nova — The Autonomous Cloud Delivery Platform"
|
||||
(professional, conveys autonomy without the provocative "no-humans"
|
||||
wording). The narrative restructures to 18 main + 1 appendix slides:
|
||||
|
||||
1. The Problem (merged old 1+2; broader problem framing; no "arc"; no
|
||||
"18 capabilities verified"; not "humans are the problem"; add tribal
|
||||
knowledge / rockstar-operator framing)
|
||||
2. Nova's Vision
|
||||
3. Strategic Objectives + Anti-Goals
|
||||
4. Scope: Downstream of PDLC (moved up)
|
||||
5. RACI: Who Owns What (moved up)
|
||||
6. The Platform Pipeline
|
||||
7. The Decision Ledger
|
||||
8. The Attestation Matrix
|
||||
9. Telemetry & Live Ops
|
||||
10. Decision Ledger + Attestation Coverage
|
||||
11. Cost & ROI
|
||||
12. What's Deferred — and Why
|
||||
13. Roadmap to the North Star
|
||||
14. 12-Month Product Roadmap
|
||||
15. Quarter-by-Quarter Outcomes
|
||||
16. Production-Grade Guidance via Atelier (1/2)
|
||||
17. Production-Grade Guidance via Atelier (2/2)
|
||||
18. Recap + Ask
|
||||
A1. Metrics Glossary
|
||||
|
||||
Removed: old Slide 10 (Capability Health), old Slide 12 (Zero-Touch
|
||||
Efficiency), old Appendix A2 (Operating Model & Cost). Slide 5's first
|
||||
table removed.
|
||||
|
||||
### REQ-246 — Thesis rename + reframe
|
||||
|
||||
`.ciagent/NO_HUMANS_THESIS.md` is renamed (git mv) to
|
||||
`.ciagent/AUTONOMY_THESIS.md`. Content reframes from "removing humans" to
|
||||
"autonomy in operations, human at stage gates" — professional, not
|
||||
provocative. The operator-bottleneck framing is softened; the attestation
|
||||
model + provable trust are emphasized. Anti-claims are retained and
|
||||
reworded for a tech-leadership audience. All references across the repo
|
||||
are updated to the new filename + framing.
|
||||
|
||||
### REQ-247 — Strategic-docs sync (NORTH_STAR + PROJECT)
|
||||
|
||||
`NORTH_STAR.md` is updated:
|
||||
- Vision polished for a technical audience concerned about security,
|
||||
security remediation velocity, and reliability; "infrastructure
|
||||
operations become visible" is preserved as a recurring theme.
|
||||
- Strategic Objective #2 (provable trust) is reworded: trust is
|
||||
established by deterministic scripts that calculate a score, not by
|
||||
AI. The platform functions without AI. "AI decisions" are really
|
||||
automated decisions.
|
||||
- Strategic Objective #3 (ROI) is reworded with four CTO-grade metrics:
|
||||
Lead Time (PR → Production), Infrastructure Vulnerability Count
|
||||
(downward trend), MTTR, Cloud Spend Reduction. All flow into PowerBI
|
||||
views and are captured by the telemetry pipeline.
|
||||
- Strategic Objective #4 is replaced: integrate with externally owned
|
||||
PDLC, SDLC, Agentic, and Citizen Developer platforms regardless of
|
||||
source; Nova provides skills + MCP endpoints to make applications
|
||||
production-grade; all intents to deploy to production go through the
|
||||
same rigorous controls and quality gates.
|
||||
- Anti-goals #1 (hyperscaler competitor), #4 (legacy untagged), and #5
|
||||
(sold to operators) are removed. Two new anti-goals added: not an
|
||||
upstream development platform; not a replacement for the Product
|
||||
Lifecycle (PDLC).
|
||||
- Anti-goal #3 reworded to remove the "removes humans" framing.
|
||||
|
||||
`PROJECT.md` mission statement + scope are synchronized with the
|
||||
integration objective and the reworded strategic objectives.
|
||||
|
||||
### REQ-248 — RACI restructure (Quality Engineering + SRE)
|
||||
|
||||
The RACI matrix (slide + `docs/raci.md`) is restructured:
|
||||
- A **Quality Engineering** column is added.
|
||||
- The Platform column no longer holds the **A** for release attestation;
|
||||
accountability is reassigned to QA or SRE as appropriate.
|
||||
- "Release Management" is renamed to **SRE**.
|
||||
- "Release attestation" is split into two rows: the SRE part is
|
||||
**Production Readiness** (operational readiness sign-off).
|
||||
- The slide is sized to fit (text shrunk / low-impact rows dropped).
|
||||
|
||||
### REQ-249 — Atelier split (2 slides)
|
||||
|
||||
Slide 19 (Production-Grade Guidance via Atelier) is split into two slides:
|
||||
- **16 (1/2):** Skills + MCP server overview (the 9 skills, the 4 MCP
|
||||
tools, the plugin-registry + stdio surface).
|
||||
- **17 (2/2):** Agentic validation beyond deterministic scanners +
|
||||
vendored Atelier for audit reproducibility.
|
||||
The benefit wording is improved; the same spirit is retained.
|
||||
|
||||
### REQ-250 — Pipeline hardening (Checkov before plan; Wiz-or-Checkov on plan)
|
||||
|
||||
`scripts/run_platform.sh` (and `scripts/run_postapply.sh` where
|
||||
relevant) implement the two-stage policy scan:
|
||||
1. **Checkov runs on static code** (the generated `main.tf` / TF
|
||||
directory) **before** `terraform plan` — fail-fast, quick developer
|
||||
feedback on policy violations in the authored code.
|
||||
2. **After `terraform plan`:** if `WIZ_API_TOKEN` + `WIZ_API_URL` are
|
||||
set, run **Wiz against the plan**; otherwise run **Checkov against
|
||||
the plan** as a drop-in replacement. **Wiz and Checkov are never
|
||||
both run on the plan.**
|
||||
`adapters/wiz/wiz_adapter.py` is updated if needed for plan-mode
|
||||
input. Slide 6 + `docs/scope.md` reflect the new flow. Tests
|
||||
(`tests/test_pipeline.py`, `tests/test_pipeline_contract.py`, and
|
||||
any checkov/wiz tests) are updated and pass.
|
||||
|
||||
### REQ-251 — Theme CSS fix (Appendix A1) + footer cleanup
|
||||
|
||||
`docs/presentations/assets/nova-sp-theme.css` is fixed so the Appendix
|
||||
A1 Metrics Glossary table is readable (the table background color is
|
||||
corrected). The Marp footer no longer shows the version (`v1.20`) or
|
||||
the `Act %{page}/5` artifact. The title-slide subtitle no longer shows
|
||||
`v1.18 — Citizen Developer & Production-Grade Guidance`; it becomes
|
||||
"Product Development & Citizen Developer Overview" (or similar) to
|
||||
convey the audience for the platform.
|
||||
|
||||
### REQ-252 — Global citation + badge + version removal
|
||||
|
||||
Across all audience-facing slides (the Marp deck, the source-of-truth
|
||||
markdown, and the talking points):
|
||||
- All internal citations are removed: `D-###` decision IDs,
|
||||
`REQ-###` requirement IDs, and internal file paths
|
||||
(e.g. `outbox_writer.py`, `confidence_signal.py`).
|
||||
- All `<span class="badge planned">Planned</span>` badges are removed.
|
||||
- The version is removed from the footer and the title slide.
|
||||
Every benefit callout is rewritten for a tech-leadership audience
|
||||
(security, remediation velocity, reliability, lead time). A "less is
|
||||
more / no fluff" final prose pass is applied; the story stays clear.
|
||||
|
||||
### REQ-253 — Render + verify + ship
|
||||
|
||||
Changed/new mermaid diagrams are re-rendered (slide 1 new diagram, slide
|
||||
9 expand, Atelier split). HTML + PPTX are re-rendered via
|
||||
`scripts/render_slides.sh`. `tests/test_slides_pipeline.py` passes:
|
||||
asserts 18 main + 1 appendix slides, no badge spans, no version in the
|
||||
footer, no `D-###`/`REQ-###`/`.py` paths in audience-facing slides, and
|
||||
filename refs updated in render scripts + CI workflow + README.
|
||||
`tests/test_no_forge_mentions.py` passes. Full `pytest` passes
|
||||
(pipeline-hardening tests green). `run_platform.sh --check-only` passes.
|
||||
Milestone ship: tag the final phase on the v1.20.x line; create a
|
||||
release; attach the PPTX.
|
||||
|
||||
### Out of Scope (v1.21)
|
||||
|
||||
- **Live pilot estate activation** — still deferred (D-096).
|
||||
- **ML anomaly-forecasting service** — still deferred.
|
||||
- **Multi-cloud (Azure/GCP) implementation** — still deferred.
|
||||
- **Tamper-evident ledger (S3 Object Lock + JWS)** — still deferred
|
||||
(D-083); the deck describes it as a roadmap item without citing the
|
||||
decision ID in the audience-facing slides.
|
||||
|
||||
### v1.21 Traceability
|
||||
|
||||
| REQ | Phase | Status |
|
||||
|-----|-------|--------|
|
||||
| REQ-245 | P2 | pending |
|
||||
| REQ-246 | P1 | pending |
|
||||
| REQ-247 | P1 | pending |
|
||||
| REQ-248 | P2 | pending |
|
||||
| REQ-249 | P2 | pending |
|
||||
| REQ-250 | P4 | pending |
|
||||
| REQ-251 | P3 | pending |
|
||||
| REQ-252 | P2 | pending |
|
||||
| REQ-253 | P5 | pending |
|
||||
|
||||
+98
-2
@@ -1756,7 +1756,7 @@ locked (D-133..D-142).
|
||||
Ship tag at milestone COMPLETE: `v1.17.7` (feature milestone; final patch
|
||||
IS the release). **DONE.**
|
||||
|
||||
## v1.19 (active — Nova 2nd-Release Sync, tag line `v1.18.x`)
|
||||
## v1.19 (complete — Nova 2nd-Release Sync, tag line `v1.18.x`)
|
||||
|
||||
> **NFR-only chore milestone.** Single execution phase. Establishes the
|
||||
> manual-only "2nd release" pipeline `~/acdl → ~/nova` (GitLab
|
||||
@@ -1787,7 +1787,7 @@ IS the release). **DONE.**
|
||||
### Phase P2 — final-review-ship (Final Phase)
|
||||
- **Description:** Final review + audit + milestone ship. Merge to main, tag
|
||||
`v1.18.0` (first patch on the v1.18.x line), create Gitea release.
|
||||
- **Status:** pending
|
||||
- **Status:** complete
|
||||
- **Depends on:** [P1]
|
||||
- **Requirements:** REQ-229
|
||||
- **Success Criteria:**
|
||||
@@ -1796,3 +1796,99 @@ IS the release). **DONE.**
|
||||
`main`.
|
||||
- Tag `v1.18.0` created; release notes summarize REQ-229.
|
||||
- Milestone branches deleted; CHECKPOINT cleared.
|
||||
|
||||
Ship tag at milestone COMPLETE: `v1.18.1` (NFR milestone; final patch IS the
|
||||
release). **DONE.**
|
||||
|
||||
---
|
||||
|
||||
## v1.20 — Consumer Cleanup + Transparent Terraform + Slide Pipeline
|
||||
|
||||
> **Multi-concern milestone.** Four user-directed inputs: (1) remove all
|
||||
> gitea/gitlab from synced files — the platform team must never know about
|
||||
> the dev forge; (2) radically simplify documentation for the Platform Team
|
||||
> audience; (3) make terraform runs transparent in workflows with feature-flag
|
||||
> client differentiation; (4) dedicated S&P-themed slide render pipeline +
|
||||
> 12-month product roadmap slides.
|
||||
>
|
||||
> Tags run on the v1.19.x line (milestone v1.20 → tags v1.19.x).
|
||||
|
||||
### Phase P0 — pre-execution
|
||||
- **Description:** Specify → clarify → research → plan. Validate v1.20
|
||||
requirements (REQ-230..244). Establish milestone version in config.json.
|
||||
- **Status:** complete
|
||||
- **Requirements:** REQ-230..244
|
||||
- **Success Criteria:**
|
||||
- `.ciagent/REQUIREMENTS.md` has v1.20 section with all 15 requirements.
|
||||
- `.ciagent/config.json` has `active_milestone: "v1.20"`.
|
||||
- Checkpoint written.
|
||||
|
||||
### Phase P1 — consumer-cleanup (gitea removal + doc simplification)
|
||||
- **Description:** Remove all gitea/gitlab mentions from synced files.
|
||||
Genericize forge-detection code. Drop `.gitea/` byte-identity test
|
||||
assertions. Add `test_no_forge_mentions.py` guard test. Simplify
|
||||
documentation: delete completed migration docs, move thesis to `.ciagent/`,
|
||||
strip ciagent-internal provenance from synced docs.
|
||||
- **Status:** complete
|
||||
- **Requirements:** REQ-230, REQ-231, REQ-232
|
||||
- **Success Criteria:**
|
||||
- `tests/test_no_forge_mentions.py` passes — zero gitea/gitlab mentions in
|
||||
synced subset.
|
||||
- `pytest` passes — all existing tests green after genericization.
|
||||
- Synced docs stripped of REQ-/D-/P- IDs, milestone headers, `.ciagent/`
|
||||
citations.
|
||||
- `docs/NOVA_MIGRATION.md` + `docs/NOVA_AWS_MIGRATION.md` deleted.
|
||||
- `docs/NO_HUMANS_THESIS.md` moved to `.ciagent/`.
|
||||
|
||||
### Phase P2 — slide-pipeline (S&P theme + render automation)
|
||||
- **Description:** Create dedicated S&P theme CSS, render_slides.sh pipeline,
|
||||
CI workflow, tests. Update Marp frontmatter to use dedicated theme. Fix
|
||||
README directory layout.
|
||||
- **Status:** complete
|
||||
- **Requirements:** REQ-239, REQ-240, REQ-241, REQ-242, REQ-243
|
||||
- **Success Criteria:**
|
||||
- `docs/presentations/assets/nova-sp-theme.css` exists with S&P colors.
|
||||
- Marp deck frontmatter references the theme CSS.
|
||||
- `scripts/render_slides.sh` renders mermaid PNGs + HTML + PPTX.
|
||||
- `workflows-src/slides.yml` + `.github/workflows/slides.yml` exist.
|
||||
- `tests/test_slides_pipeline.py` passes.
|
||||
- `docs/presentations/README.md` updated (no retired decks).
|
||||
|
||||
### Phase P3 — product-roadmap (12-month slides)
|
||||
- **Description:** Add 12-month product roadmap as Slide 20 + Slide 21 to the
|
||||
deck. Add matching talking-points sections. Render via new pipeline.
|
||||
- **Status:** complete
|
||||
- **Requirements:** REQ-244
|
||||
- **Success Criteria:**
|
||||
- Slide 20 + 21 in `nova-no-humans-platform-marp.md` + source-of-truth +
|
||||
talking-points.
|
||||
- HTML + PPTX re-rendered via `render_slides.sh`.
|
||||
- 4-quarter product arc grounded in NORTH_STAR + deferred metrics.
|
||||
|
||||
### Phase P4 — transparent-terraform (workflow refactor + feature flags)
|
||||
- **Description:** Split run_platform.sh → run_codegen.sh + run_postapply.sh.
|
||||
Rewrite deploy.yml with native terraform steps. Add var.enabled to all L1
|
||||
modules + L2 composition toggles. Wire forge repo variables as feature
|
||||
flags. Fix stale artifact path.
|
||||
- **Status:** complete
|
||||
- **Requirements:** REQ-233, REQ-234, REQ-235, REQ-236, REQ-237, REQ-238
|
||||
- **Success Criteria:**
|
||||
- `scripts/run_codegen.sh` + `scripts/run_postapply.sh` exist.
|
||||
- `deploy.yml` has native terraform init/validate/plan/apply steps.
|
||||
- Every L1 module has `variable "enabled"` + `count = var.enabled ? 1 : 0`.
|
||||
- L2 `composition.json` supports per-child `enabled`.
|
||||
- `deploy.yml` reads `vars.ENABLE_*` as `-var` flags.
|
||||
- Stale `/tmp/acdl_platform_run_v18` path fixed to `NOVA_WORK_DIR`.
|
||||
- `pytest` passes; `run_platform.sh` shim backward-compat verified.
|
||||
|
||||
### Phase P5 — final-review-ship (Final Phase)
|
||||
- **Description:** Final review + audit + milestone ship. Merge to main,
|
||||
tag `v1.19.4` (final patch = milestone release), create release.
|
||||
- **Status:** complete
|
||||
- **Depends on:** [P1, P2, P3, P4]
|
||||
- **Requirements:** REQ-230..244
|
||||
- **Success Criteria:**
|
||||
- Review + audit clean (no P0).
|
||||
- Milestone branches merged to main.
|
||||
- Tag `v1.19.4` created; release notes summarize all 15 requirements.
|
||||
- CHECKPOINT cleared; milestone branches deleted.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
],
|
||||
"active_project": "acdl",
|
||||
"active_projects": ["acdl"],
|
||||
"active_milestone": "v1.19",
|
||||
"active_milestone": "v1.21",
|
||||
"autonomy": {
|
||||
"level": "full",
|
||||
"escalation_hooks": ["deploy", "delete_data", "merge_to_main"],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ACDL CI Pipeline — Gitea Actions (dev environment)
|
||||
# Nova CI Pipeline (dev environment)
|
||||
#
|
||||
# This workflow implements the central pipeline contract:
|
||||
# pipelines/ci.yml (validated against schemas/pipeline.schema.json)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ACDL Reusable Deploy Workflow — Gitea Actions (dev environment)
|
||||
# Nova Reusable Deploy Workflow (dev environment)
|
||||
#
|
||||
# This reusable workflow implements the central deployment pipeline contract:
|
||||
# pipelines/contract.yml (validated against schemas/deploy-pipeline.schema.json)
|
||||
@@ -8,7 +8,7 @@
|
||||
# declared difference is the forge/runtime, not the stages or commands.
|
||||
#
|
||||
# Consumer repos invoke this workflow via a versioned tag (floating MAJOR + MINOR):
|
||||
# uses: acdl/.gitea/workflows/deploy.yml@v1.9 (Gitea)
|
||||
# uses: nova/.github/workflows/deploy.yml@v1.19
|
||||
# uses: acdl/.github/workflows/deploy.yml@v1.9 (GitHub)
|
||||
#
|
||||
# Unversioned references (@main, bare) are discouraged — the consumer's setup
|
||||
@@ -38,8 +38,8 @@
|
||||
# that matches repo:org/consumer-repo:ref:refs/heads/main, and the session
|
||||
# policy restricts view/update to resources tagged acdl:owner=<consumer-repo>.
|
||||
#
|
||||
# Override (where OIDC is unavailable, e.g. Gitea pending
|
||||
# go-gitea/gitea#36988): set NOVA_AWS_ACCESS_KEY_ID + NOVA_AWS_SECRET_ACCESS_KEY
|
||||
# Override (where OIDC is unavailable, e.g. pending
|
||||
# upstream forge OIDC support): set NOVA_AWS_ACCESS_KEY_ID + NOVA_AWS_SECRET_ACCESS_KEY
|
||||
# as repository secrets. The platform-managed scheduled pipeline rotates
|
||||
# the key on a daily cadence. When .env.secrets is used locally instead,
|
||||
# rotating the key out of band is the consumer's responsibility.
|
||||
@@ -155,7 +155,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nova-terraform
|
||||
path: /tmp/acdl_platform_run_v18/tf/*.tf
|
||||
path: /tmp/nova_platform_run/tf/*.tf
|
||||
if-no-files-found: warn
|
||||
|
||||
- name: Upload platform log
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ACDL Modules Lifecycle Pipeline — Gitea Actions (dev environment)
|
||||
# Nova Modules Lifecycle Pipeline (dev environment)
|
||||
#
|
||||
# Matrix-runs each L1 module's examples/{simple,complex}.yml contracts through
|
||||
# apply→modify→destroy against live AWS. No per-module Python. The "test" =
|
||||
@@ -9,7 +9,7 @@
|
||||
# terraform files); the composition must be deterministic.
|
||||
#
|
||||
# This workflow implements pipelines/modules-lifecycle.yml (byte-identical
|
||||
# in .gitea/workflows/ and .github/workflows/).
|
||||
# in .github/workflows/).
|
||||
#
|
||||
# Lifecycle mode (REQ-134, v1.12): the `lifecycle_mode` input defaults to
|
||||
# "plan" — the lifecycle scripts run `run_platform.sh --plan-only` (fast,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Nova Slides Render — re-renders presentation deck when source files change.
|
||||
name: Nova Slides Render
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'docs/presentations/**'
|
||||
- 'scripts/render_slides.sh'
|
||||
- 'assets/nova-sp-theme.css'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
render:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with: { fetch-depth: 0 }
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: '20' }
|
||||
- name: Install Chrome
|
||||
run: |
|
||||
npx --yes @marp-team/marp-cli@latest --version
|
||||
npx --yes @mermaid-js/mermaid-cli --version
|
||||
- name: Render slides
|
||||
run: bash scripts/render_slides.sh
|
||||
- name: Commit rendered artifacts
|
||||
run: |
|
||||
git config user.name "nova-slides-bot"
|
||||
git config user.email "bot@nova.local"
|
||||
git add docs/presentations/*.html docs/presentations/*.pptx docs/presentations/assets/png/*.png
|
||||
git diff --cached --quiet || git commit -m "chore(slides): re-render deck [skip ci]"
|
||||
git push
|
||||
+10
-15
@@ -1,35 +1,30 @@
|
||||
# GitHub Workflows — Nova Platform CI/CD Catalog
|
||||
|
||||
This directory contains the 7 GitHub Actions workflows for the Nova
|
||||
platform. 3 are byte-identical Gitea mirrors (generated from
|
||||
`workflows-src/` by `scripts/sync_workflows.py`, P8/REQ-172); 4 are
|
||||
GitHub-only (Gitea act_runner feature gaps).
|
||||
This directory contains the GitHub Actions workflows for the Nova
|
||||
platform. 3 are generated from `workflows-src/<name>`; 4 are GitHub-only.
|
||||
|
||||
## Shared workflows (byte-identical Gitea + GitHub)
|
||||
## Shared workflows (generated from source)
|
||||
|
||||
These 3 are generated from `workflows-src/<name>` by
|
||||
`scripts/sync_workflows.py`; the `.gitea/workflows/<name>` mirror is kept
|
||||
byte-identical. Run `python3 scripts/sync_workflows.py --check` to verify
|
||||
These 3 are generated from `workflows-src/<name>`. Run `python3 scripts/sync_workflows.py --check` to verify
|
||||
no drift.
|
||||
|
||||
| Workflow | Trigger | Inputs | Required Secrets | Purpose |
|
||||
|----------|---------|--------|------------------|---------|
|
||||
| `ci.yml` | `pull_request: [main]` | — | — | Lint + test + check-only (runs on every PR) |
|
||||
| `deploy.yml` | `workflow_call` (reusable) + `push: [main]` | `contract` (string, required), `mode` (string, default `deploy`), `changeRequestId` (string), `environment` (string) | `NOVA_AWS_ACCESS_KEY_ID`, `NOVA_AWS_SECRET_ACCESS_KEY`, `NOVA_AWS_DEFAULT_REGION`, `NOVA_KMS_KEY_ID`, `NOVA_LAMBDA_URL` | Reusable deploy workflow (invoked by consumer repos via `uses: acdl/.github/workflows/deploy.yml@v1.15`) |
|
||||
| `deploy.yml` | `workflow_call` (reusable) + `push: [main]` | `contract` (string, required), `mode` (string, default `deploy`), `changeRequestId` (string), `environment` (string) | `NOVA_AWS_ACCESS_KEY_ID`, `NOVA_AWS_SECRET_ACCESS_KEY`, `NOVA_AWS_DEFAULT_REGION`, `NOVA_KMS_KEY_ID`, `NOVA_LAMBDA_URL` | Reusable deploy workflow (invoked by consumer repos via `uses: nova/.github/workflows/deploy.yml@v1.19`) |
|
||||
| `modules-lifecycle.yml` | `pull_request: [main]` + `workflow_dispatch` | `lifecycle_mode` (string, default `plan` — `plan` or `full`) | `NOVA_AWS_ACCESS_KEY_ID`, `NOVA_AWS_SECRET_ACCESS_KEY`, `NOVA_AWS_DEFAULT_REGION`, `NOVA_AWS_ACCOUNT_ID` | L1 + L2 module lifecycle pipeline (plan-only default; full apply/modify/destroy on override) |
|
||||
|
||||
## GitHub-only workflows (no Gitea mirror)
|
||||
## GitHub-only workflows
|
||||
|
||||
These 4 have no Gitea counterpart (Gitea act_runner lacks the features
|
||||
they require — reusable workflows, matrix `needs`, release API). See
|
||||
`.gitea/workflows/README.md` for the limitation rationale.
|
||||
These 4 have no counterpart (the dev forge lacks the features
|
||||
they require — reusable workflows, matrix `needs`, release API).
|
||||
|
||||
| Workflow | Trigger | Inputs | Required Secrets | Purpose |
|
||||
|----------|---------|--------|------------------|---------|
|
||||
| `platform-test.yml` | `pull_request: [main]` | — | — | Lint + unit + integration + schema-validation (replaces `ci.yml` for PRs) |
|
||||
| `primitives-plan.yml` | `pull_request: [main]` | — | `NOVA_AWS_*` | Plan-only for all L1 primitives (matrix) |
|
||||
| `patterns-plan.yml` | `pull_request: [main]` | — | `NOVA_AWS_*` | Plan-only for all L2 modules (matrix) |
|
||||
| `release.yml` | `push: [main]` | — | `NOVA_GITEA_TOKEN` (for Gitea release API) | Semver tag + MAJOR.MINOR/MAJOR floating-tag maintenance + release creation on merge to main |
|
||||
| `release.yml` | `push: [main]` | — | `NOVA_RELEASE_TOKEN` | Semver tag + MAJOR.MINOR/MAJOR floating-tag maintenance + release creation on merge to main |
|
||||
|
||||
## Reusable deploy workflow (`deploy.yml`)
|
||||
|
||||
@@ -38,7 +33,7 @@ Consumer repos invoke the deploy workflow via a versioned tag:
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.15
|
||||
uses: nova/.github/workflows/deploy.yml@v1.19
|
||||
with:
|
||||
contract: .nova/contract.yml
|
||||
environment: dev
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ACDL CI Pipeline — Gitea Actions (dev environment)
|
||||
# Nova CI Pipeline (dev environment)
|
||||
#
|
||||
# This workflow implements the central pipeline contract:
|
||||
# pipelines/ci.yml (validated against schemas/pipeline.schema.json)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ACDL Reusable Deploy Workflow — Gitea Actions (dev environment)
|
||||
# Nova Reusable Deploy Workflow (dev environment)
|
||||
#
|
||||
# This reusable workflow implements the central deployment pipeline contract:
|
||||
# pipelines/contract.yml (validated against schemas/deploy-pipeline.schema.json)
|
||||
@@ -8,7 +8,7 @@
|
||||
# declared difference is the forge/runtime, not the stages or commands.
|
||||
#
|
||||
# Consumer repos invoke this workflow via a versioned tag (floating MAJOR + MINOR):
|
||||
# uses: acdl/.gitea/workflows/deploy.yml@v1.9 (Gitea)
|
||||
# uses: nova/.github/workflows/deploy.yml@v1.19
|
||||
# uses: acdl/.github/workflows/deploy.yml@v1.9 (GitHub)
|
||||
#
|
||||
# Unversioned references (@main, bare) are discouraged — the consumer's setup
|
||||
@@ -38,8 +38,8 @@
|
||||
# that matches repo:org/consumer-repo:ref:refs/heads/main, and the session
|
||||
# policy restricts view/update to resources tagged acdl:owner=<consumer-repo>.
|
||||
#
|
||||
# Override (where OIDC is unavailable, e.g. Gitea pending
|
||||
# go-gitea/gitea#36988): set NOVA_AWS_ACCESS_KEY_ID + NOVA_AWS_SECRET_ACCESS_KEY
|
||||
# Override (where OIDC is unavailable, e.g. pending
|
||||
# upstream forge OIDC support): set NOVA_AWS_ACCESS_KEY_ID + NOVA_AWS_SECRET_ACCESS_KEY
|
||||
# as repository secrets. The platform-managed scheduled pipeline rotates
|
||||
# the key on a daily cadence. When .env.secrets is used locally instead,
|
||||
# rotating the key out of band is the consumer's responsibility.
|
||||
@@ -155,7 +155,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nova-terraform
|
||||
path: /tmp/acdl_platform_run_v18/tf/*.tf
|
||||
path: /tmp/nova_platform_run/tf/*.tf
|
||||
if-no-files-found: warn
|
||||
|
||||
- name: Upload platform log
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ACDL Modules Lifecycle Pipeline — Gitea Actions (dev environment)
|
||||
# Nova Modules Lifecycle Pipeline (dev environment)
|
||||
#
|
||||
# Matrix-runs each L1 module's examples/{simple,complex}.yml contracts through
|
||||
# apply→modify→destroy against live AWS. No per-module Python. The "test" =
|
||||
@@ -9,7 +9,7 @@
|
||||
# terraform files); the composition must be deterministic.
|
||||
#
|
||||
# This workflow implements pipelines/modules-lifecycle.yml (byte-identical
|
||||
# in .gitea/workflows/ and .github/workflows/).
|
||||
# in .github/workflows/).
|
||||
#
|
||||
# Lifecycle mode (REQ-134, v1.12): the `lifecycle_mode` input defaults to
|
||||
# "plan" — the lifecycle scripts run `run_platform.sh --plan-only` (fast,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Nova Slides Render — re-renders presentation deck when source files change.
|
||||
name: Nova Slides Render
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'docs/presentations/**'
|
||||
- 'scripts/render_slides.sh'
|
||||
- 'assets/nova-sp-theme.css'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
render:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with: { fetch-depth: 0 }
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: '20' }
|
||||
- name: Install Chrome
|
||||
run: |
|
||||
npx --yes @marp-team/marp-cli@latest --version
|
||||
npx --yes @mermaid-js/mermaid-cli --version
|
||||
- name: Render slides
|
||||
run: bash scripts/render_slides.sh
|
||||
- name: Commit rendered artifacts
|
||||
run: |
|
||||
git config user.name "nova-slides-bot"
|
||||
git config user.email "bot@nova.local"
|
||||
git add docs/presentations/*.html docs/presentations/*.pptx docs/presentations/assets/png/*.png
|
||||
git diff --cached --quiet || git commit -m "chore(slides): re-render deck [skip ci]"
|
||||
git push
|
||||
@@ -41,3 +41,4 @@ metrics/lifecycle/
|
||||
*.crt
|
||||
*.jks
|
||||
*.keystore.coverage
|
||||
.coverage
|
||||
|
||||
@@ -219,23 +219,9 @@ bash scripts/run_ci.sh --quiet # suppress per-stage banners
|
||||
|
||||
### Reusable deploy workflow
|
||||
|
||||
The deployment pipeline is defined by a **central deployment pipeline
|
||||
contract** (`pipelines/contract.yml`, validated against
|
||||
`schemas/deploy-pipeline.schema.json`) and exposed to consumer repos as a
|
||||
**reusable workflow**:
|
||||
|
||||
- `.github/workflows/deploy.yml` — GitHub Actions (production)
|
||||
|
||||
The workflow implements the same stages as `pipelines/contract.yml`
|
||||
(validate-contract → resolve-stack → security checks → infrastructure plan
|
||||
→ policy checks → confidence → evidence event → apply). A consumer repo
|
||||
invokes the reusable workflow via a **versioned tag** (floating MAJOR +
|
||||
MINOR, e.g. `acdl/.github/workflows/deploy.yml@v1.13`). The workflow checks
|
||||
out the consumer repo, then checks out the Nova platform repo into the
|
||||
runner workspace, and runs `scripts/run_platform.sh` against the consumer's
|
||||
contract — the consumer never clones the platform repo or invokes its
|
||||
scripts locally. See the [Consumer guide](docs/consumer-guide.md) for the
|
||||
end-to-end happy path.
|
||||
Consumer repos invoke the deploy pipeline via `.github/workflows/deploy.yml`
|
||||
(a reusable GitHub Actions workflow, versioned tag `nova/.github/workflows/deploy.yml@v1.19`).
|
||||
See the [Consumer guide](docs/consumer-guide.md) for the end-to-end happy path.
|
||||
|
||||
### Output streaming (run_platform.sh)
|
||||
|
||||
@@ -310,12 +296,6 @@ documented alternative:
|
||||
runs, or in **`.env.secrets`** (gitignored, chmod 600) for local testing.
|
||||
- The platform rotates platform-runner keys on a **daily cadence** —
|
||||
rotation is not the consumer's burden in the platform-runner path.
|
||||
- **When `.env.secrets` is used locally**, rotating the key **out of band is
|
||||
the consumer's responsibility**. The platform guarantees daily rotation
|
||||
for platform-runner runs; it does not guarantee rotation for
|
||||
locally-held copies. The consumer must rotate a local key via
|
||||
`scripts/rotate_spike_key.sh` (or equivalent) on their own cadence.
|
||||
|
||||
No long-lived credential is permitted persistently — the platform-runner
|
||||
key's useful lifetime is one workflow run, and the local alternative is
|
||||
rotated at least daily (platform-runner) or out of band (local).
|
||||
@@ -62,7 +62,7 @@ path above remains the v1.9 production audit record.
|
||||
**platform-level KMS key** (not per-contract — a per-contract key would
|
||||
explode the key-management surface), rotated **quarterly**. The `jws`
|
||||
field is added to the event shape when this ships.
|
||||
- **Async worker + DLQ:** a Lambda (or a Gitea Actions scheduled workflow)
|
||||
- **Async worker + DLQ:** a Lambda (or a forge Actions scheduled workflow)
|
||||
reads the outbox, writes to S3 Object Lock, signs with KMS. DLQ = an
|
||||
SQS dead-letter queue for failed writes. RTO = DLQ replay.
|
||||
- **Daily checkpoints (§9):** a daily job reads the last event hash and
|
||||
@@ -86,7 +86,7 @@ log" anti-goal requires.
|
||||
D-083 ships).
|
||||
- `prev_event_hash` (chain link; `GENESIS` for the first event).
|
||||
- `hash` (this event's SHA-256 over canonical JSON).
|
||||
- `approver_qa` (Gitea/GitHub username of the QA approver; populated on
|
||||
- `approver_qa` (CI username of the QA approver; populated on
|
||||
qa-promotion by v1.9's `hitl_gates.attest` — D-042).
|
||||
- `approver_prod` (SRE username; populated on prod-promotion by v1.9's
|
||||
`hitl_gates.attest`).
|
||||
@@ -112,7 +112,7 @@ log" anti-goal requires.
|
||||
- **D-042** — approver identities (`approver_qa`, `approver_prod`,
|
||||
`approver_dr`) live in the outbox; the separation-of-duties check
|
||||
(`core/separation_of_duties.py`) reads `approver_qa` and compares
|
||||
to the prod-dispatch `gitea.actor` / `github.actor`. v1.9's
|
||||
to the prod-dispatch CI actor. v1.9's
|
||||
`hitl_gates.attest` populates these attributes.
|
||||
- **D-083** (v1.9) — S3 Object Lock + JWS + async worker + DLQ + daily
|
||||
checkpoints deferred to a future milestone. Requires non-offline-
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
"""HITL pre-execution attestation gates (REQ-108, D-084).
|
||||
|
||||
Records the approver identity (`gitea.actor` / `github.actor`) to the
|
||||
Records the approver identity (the CI actor (GITHUB_ACTOR or FORGE_ACTOR)) to the
|
||||
DynamoDB outbox for the contractId (attribute `approver_qa` /
|
||||
`approver_prod` / `approver_dr`), runs the separation-of-duties check on
|
||||
prod, invokes the 8-concern attestation matrix for the target env, and
|
||||
@@ -29,7 +29,7 @@ def attest(contract_id: str, env: str, approver: str,
|
||||
Args:
|
||||
contract_id: the contract UUID.
|
||||
env: dev/qa/prod/dr.
|
||||
approver: the approver's username (`gitea.actor` / `github.actor`).
|
||||
approver: the approver's username (the CI actor (GITHUB_ACTOR or FORGE_ACTOR)).
|
||||
evidence: optional operator-supplied evidence artifacts (for the
|
||||
attestation matrix operator-supplied concerns).
|
||||
outbox_client: optional moto-mocked DynamoDB outbox client for tests.
|
||||
@@ -41,7 +41,7 @@ def attest(contract_id: str, env: str, approver: str,
|
||||
return (True, "dev autonomous (no HITL gate)")
|
||||
|
||||
if not approver:
|
||||
return (False, f"no approver identity for {env} (GITHUB_ACTOR/GITEA_ACTOR unset)")
|
||||
return (False, f"no approver identity for {env} (GITHUB_ACTOR/FORGE_ACTOR unset)")
|
||||
|
||||
attr = _approver_attr(env)
|
||||
if not attr:
|
||||
@@ -88,7 +88,7 @@ def attest(contract_id: str, env: str, approver: str,
|
||||
|
||||
def approver_from_env() -> Optional[str]:
|
||||
"""Read the approver identity from the environment."""
|
||||
return os.environ.get("GITHUB_ACTOR") or os.environ.get("GITEA_ACTOR")
|
||||
return os.environ.get("GITHUB_ACTOR") or os.environ.get("FORGE_ACTOR")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+15
-15
@@ -18,32 +18,32 @@ gates. No partial deployment to roll back on rejection (qa, prod); dr is
|
||||
a separate deployment against a separate cluster/region. The
|
||||
canary/deployment-rollback model is explicitly not in scope for v1.
|
||||
|
||||
## Gitea-specific gate mechanics (D-042)
|
||||
## Forge-specific gate mechanics (D-042)
|
||||
|
||||
Gitea has **no Environments API** and ignores `environment:` blocks
|
||||
The dev forge has **no Environments API** and ignores `environment:` blocks
|
||||
(v1.0 D-013; re-confirmed in RESEARCH TARGET 1). The pre-execution gate
|
||||
is modeled as a `workflow_dispatch` with approval inputs:
|
||||
|
||||
- **qa gate:** `workflow_dispatch` with `approve_qa: true`; the dispatch
|
||||
run's `gitea.actor` is the QA approver.
|
||||
run's `CI actor` is the QA approver.
|
||||
- **prod gate:** `workflow_dispatch` with `approve_prod: true`;
|
||||
`gitea.actor` is the SRE approver.
|
||||
`CI actor` is the SRE approver.
|
||||
- **dr gate:** `workflow_dispatch` with `approve_dr: true`; same.
|
||||
|
||||
The approver identity of record = `gitea.actor` of the dispatch run
|
||||
(D-042). There is no other approval-identity signal in Gitea. The real
|
||||
OIDC path (blocked on go-gitea/gitea#36988) does not change this —
|
||||
The approver identity of record = `CI actor` of the dispatch run
|
||||
(D-042). There is no other approval-identity signal in the dev forge. The real
|
||||
OIDC path (blocked on upstream forge OIDC support) does not change this —
|
||||
OIDC authorizes the *runner* to AWS, it does not change how the platform
|
||||
records the *human* approver.
|
||||
|
||||
On GitHub, the equivalent is `github.actor` of the `workflow_dispatch`
|
||||
On GitHub, the equivalent is `CI actor` of the `workflow_dispatch`
|
||||
run; GitHub Environments with required reviewers are the native gate,
|
||||
but the `workflow_dispatch` approval-input fallback is used for
|
||||
byte-identical Gitea + GitHub workflows.
|
||||
byte-identical across forges.
|
||||
|
||||
## Reviewer routing (ARCHITECTURE.md §10.2)
|
||||
|
||||
Gitea CODEOWNERS routes the right reviewer to the right gate:
|
||||
CODEOWNERS routes the right reviewer to the right gate:
|
||||
|
||||
- qa → QA team
|
||||
- prod → SRE team
|
||||
@@ -105,7 +105,7 @@ concern is missing or expired for prod/dr.
|
||||
| 1 business day | PENDING_ATTESTATION_WARNING | Notify team + platform on-call (elevated path); emit `PENDING_ATTESTATION_TIMEOUT_WARNING` event |
|
||||
| 2 business days | PENDING_ATTESTATION_AUTO_FREEZE | Auto-freeze; require re-submission; emit `PENDING_ATTESTATION_AUTO_FREEZE` event; new submission linked via `supersedes` |
|
||||
|
||||
**Implementation:** a Gitea `on: schedule` workflow (runs hourly) that
|
||||
**Implementation:** an `on: schedule` workflow (runs hourly) that
|
||||
scans the DynamoDB outbox for `PENDING_ATTESTATION` events with `ts`
|
||||
older than 1/2 business days and emits the warn/freeze events. Not
|
||||
implemented in v1.9 (roadmap item; the attestation gates themselves are
|
||||
@@ -126,11 +126,11 @@ The identity-distinctness check is platform-internal, not GitHub-native,
|
||||
not Kyverno (in v1). Sequence:
|
||||
|
||||
1. On promotion dev → qa, the platform reads the QA approver's identity
|
||||
from the `workflow_dispatch` run's `gitea.actor` (or `github.actor`)
|
||||
from the `workflow_dispatch` run's `CI actor`
|
||||
and writes it to the DynamoDB outbox keyed by `contractId` (attribute
|
||||
`approver_qa`).
|
||||
2. On promotion qa → prod, the platform reads the stored `approver_qa`
|
||||
from the outbox and the new SRE approver's `gitea.actor` from the
|
||||
from the outbox and the new SRE approver identity from the
|
||||
prod-dispatch run.
|
||||
3. If `approver_qa == approver_prod`, the platform blocks the prod
|
||||
promotion, writes a `SEPARATION_OF_DUTIES_VIOLATION` event to the
|
||||
@@ -163,8 +163,8 @@ v1.9 (Phase 41 + Phase 42) wires the gates end-to-end:
|
||||
|
||||
## Decision trail
|
||||
|
||||
- **D-042** — approver identity = `gitea.actor` of the `workflow_dispatch`
|
||||
run; no Environments API in Gitea. On GitHub, `github.actor`.
|
||||
- **D-042** — approver identity = `CI actor` of the `workflow_dispatch`
|
||||
run; no Environments API in the dev forge.
|
||||
- **D-013** (v1.0) — the `workflow_dispatch` approval-input fallback,
|
||||
re-used for the real platform's pre-execution gate model.
|
||||
- **D-084** (v1.9) — 8-concern attestation matrix: offline-testable
|
||||
|
||||
@@ -27,7 +27,7 @@ CHANGE_REQUESTS_TABLE = os.environ.get("CHANGE_REQUESTS_TABLE", "nova-change-req
|
||||
GITHUB_TOKEN_SECRET_ID = os.environ.get("GITHUB_TOKEN_SECRET_ID", "nova/github-token")
|
||||
PLATFORM_REPO = os.environ.get("PLATFORM_REPO", "nova/acdl")
|
||||
# P1-9: Forge-agnostic API base URL. Defaults to GitHub; set GITHUB_API_BASE
|
||||
# to a Gitea API root (e.g. https://git.cloudinit.dev/api/v1) for Gitea.
|
||||
# to a compatible forge API root (e.g. https://forge.example.com/api/v1).
|
||||
GITHUB_API_BASE = os.environ.get("GITHUB_API_BASE", "https://api.github.com")
|
||||
|
||||
# P11 (REQ-175): consistent cap for error/stackTrace fields (was 10k vs 2k).
|
||||
@@ -96,22 +96,22 @@ def _iso8601_now():
|
||||
|
||||
|
||||
def _forge_type():
|
||||
"""P1-9: Detect whether the API base is GitHub or Gitea.
|
||||
"""Detect whether the API base is GitHub or a compatible forge.
|
||||
|
||||
Gitea API roots contain '/api/v1'; GitHub's is 'api.github.com'.
|
||||
Compatible forge API roots contain '/api/v1'; GitHub's is 'api.github.com'.
|
||||
"""
|
||||
if "/api/v1" in GITHUB_API_BASE:
|
||||
return "gitea"
|
||||
return "generic_forge"
|
||||
return "github"
|
||||
|
||||
|
||||
def _issues_search_url(owner, repo, encoded_query):
|
||||
"""P1-9: Build the issue search URL based on forge type.
|
||||
"""Build the issue search URL based on forge type.
|
||||
|
||||
GitHub uses /search/issues?q=...; Gitea uses /repos/{owner}/{repo}/issues?...
|
||||
GitHub uses /search/issues?q=...; compatible forges use /repos/{owner}/{repo}/issues?...
|
||||
with query params (no /search/issues endpoint).
|
||||
"""
|
||||
if _forge_type() == "gitea":
|
||||
if _forge_type() == "generic_forge":
|
||||
return (
|
||||
f"{GITHUB_API_BASE}/repos/{owner}/{repo}/issues"
|
||||
f"?state=open&type=issues&q={encoded_query}"
|
||||
@@ -123,7 +123,7 @@ def _issues_search_url(owner, repo, encoded_query):
|
||||
|
||||
|
||||
def _issues_create_url(owner, repo):
|
||||
"""URL for creating an issue (same pattern for both GitHub + Gitea)."""
|
||||
"""URL for creating an issue (same pattern across forges)."""
|
||||
return f"{GITHUB_API_BASE}/repos/{owner}/{repo}/issues"
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Check that qaApprover != prodApprover for a contract (ARCHITECTURE.md
|
||||
§10.3, D-042). Reads `approver_qa` from the DynamoDB outbox for the
|
||||
contractId, compares to the prod-dispatch `gitea.actor` / `github.actor`.
|
||||
contractId, compares to the prod-dispatch the CI actor.
|
||||
Blocks on equality, emits `SEPARATION_OF_DUTIES_VIOLATION`, routes a halt
|
||||
artifact to SRE on-call.
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Nova Metrics Catalog
|
||||
|
||||
> v1.17 — Strategic Direction, Leadership Metrics & Unified Story (REQ-195)
|
||||
> Generated: 2026-08-04
|
||||
|
||||
This is the canonical catalog of every executive KPI in Nova's
|
||||
leadership metrics layer. Each metric carries a **status**:
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Nova Deferred Metrics Activation Roadmap
|
||||
|
||||
> v1.17 — Strategic Direction, Leadership Metrics & Unified Story (REQ-210)
|
||||
> Generated: 2026-08-04
|
||||
|
||||
This document lists all 8 deferred metrics + the onboarding-funnel
|
||||
"granted" half, with their blocking decisions, unblock requirements,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Nova Metrics Views — PowerBI Data Dictionary
|
||||
|
||||
> v1.17 — Strategic Direction, Leadership Metrics & Unified Story (REQ-190, REQ-209)
|
||||
> Generated: 2026-08-04
|
||||
|
||||
This document is the column-level data dictionary for the PowerBI export
|
||||
views in `metrics/powerbi/`. Each fact/dimension table and placeholder
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
# Nova AWS Resource Migration Runbook (REQ-163, P4)
|
||||
|
||||
> **Milestone:** v1.15-Nova (Wave 4, P4). Renames every `acdl-*` AWS
|
||||
> resource name → `nova-*` via Terraform. This is the heaviest Terraform
|
||||
> phase of the rebrand and requires a **maintenance window**.
|
||||
>
|
||||
> **Plan-validated only.** Per A1, `NOVA_LIFECYCLE_MODE` defaults to
|
||||
> `plan` (no live AWS mutation from CI). `terraform validate` passes; the
|
||||
> live apply steps below are executed by a platform operator during the
|
||||
> scheduled maintenance window. Each step has a verification + rollback.
|
||||
|
||||
## Scope (renamed resources)
|
||||
|
||||
| AWS resource | Before | After | Strategy |
|
||||
|---|---|---|---|
|
||||
| KMS alias | `alias/acdl-platform` | `alias/nova-platform` | cheap rename |
|
||||
| SNS topic | `acdl-sod-halt` | `nova-sod-halt` | recreate |
|
||||
| Security group | `acdl-ecs-sg` | `nova-ecs-sg` | recreate |
|
||||
| Lambda (role/policy/function) | `acdl-contract-ingestor` | `nova-contract-ingestor` | recreate |
|
||||
| DynamoDB contracts | `acdl-contracts` | `nova-contracts` | scan + copy |
|
||||
| DynamoDB change-requests | `acdl-change-requests` | `nova-change-requests` | scan + copy |
|
||||
| Secrets Manager secret | `acdl/github-token` | `nova/github-token` | recreate + re-store |
|
||||
| ECR repo | `acdl-microservice` | `nova-microservice` | re-push |
|
||||
| ECS cluster/service/task/role | `acdl-microservice` | `nova-microservice` | recreate |
|
||||
| IAM user + policy | `acdl-spike-runner` (+ `-policy`) | `nova-spike-runner` (+ `-policy`) | re-bootstrap |
|
||||
| IAM act-runner role | `acdl-act-runner-role` | `nova-act-runner-role` | re-bootstrap |
|
||||
| IAM deploy role | `acdl-deploy-<repo>` | `nova-deploy-<repo>` | re-bootstrap |
|
||||
| S3 state bucket | `acdl-tfstate-581513795199-us-east-1` | `nova-tfstate-581513795199-us-east-1` | `-migrate-state` |
|
||||
| DynamoDB outbox | `acdl-outbox` | `nova-outbox` | scan + copy |
|
||||
| Platform VPC/subnet/IGW/RT | `acdl-shared*` | `nova-shared*` | recreate (brief downtime) |
|
||||
| CI VPC/subnet/SG/cluster | `acdl-ci-*` | `nova-ci-*` | recreate (CI-only) |
|
||||
| ALB name prefix | `acdl-alb` | `nova-alb` | recreate (brief downtime, LAST) |
|
||||
|
||||
## Migration ordering (binding)
|
||||
|
||||
Order: **KMS alias → SNS/SG → Lambda → DynamoDB → ECR → IAM → state bucket → ALB**.
|
||||
Each step is independently rollback-able. The ALB is last because it
|
||||
requires the briefest downtime window.
|
||||
|
||||
---
|
||||
|
||||
## Pre-flight
|
||||
|
||||
1. **Announce the maintenance window** (consumers are notified via the
|
||||
P1 migration guide `docs/NOVA_MIGRATION.md`).
|
||||
2. **Back up state** for every stack (see §State bucket — back up the
|
||||
state JSON *before* `-migrate-state`).
|
||||
3. Confirm `NOVA_LIFECYCLE_MODE=plan` (default) so CI does not mutate
|
||||
AWS during the window.
|
||||
4. Confirm the new `nova-*` destination tables/repos will be created by
|
||||
the same Terraform apply (no manual pre-creation needed).
|
||||
|
||||
## Step 1 — KMS alias (`alias/acdl-platform` → `alias/nova-platform`)
|
||||
|
||||
- **Command (in `terraform/platform/`):**
|
||||
```bash
|
||||
terraform init -upgrade
|
||||
terraform apply -replace=aws_kms_alias.nova_platform
|
||||
```
|
||||
(Terraform destroys the old alias + creates the new one — aliases are
|
||||
cheap; the underlying key ID is unchanged.)
|
||||
- **Verify:** `aws kms list-aliases --query 'Aliases[?AliasName==`alias/nova-platform`]'` returns the new alias; `alias/acdl-platform` is gone.
|
||||
- **Rollback:** `terraform apply -replace=aws_kms_alias.nova_platform` against the prior revision (re-creates `alias/acdl-platform`). Resources encrypted by the key are unaffected (key ID unchanged).
|
||||
|
||||
## Step 2 — SNS topic + Security group (recreate)
|
||||
|
||||
- **Command:** `terraform apply` in `terraform/platform/`.
|
||||
- SNS `acdl-sod-halt` → `nova-sod-halt` (the topic ARN changes; update `NOVA_SOD_HALT_TOPIC_ARN` wherever it is set).
|
||||
- SG `acdl-ecs-sg` → `nova-ecs-sg` (the security group is re-attached to running ECS tasks; brief task restart).
|
||||
- **Verify:** `aws sns list-topics` shows `nova-sod-halt`; `aws ec2 describe-security-groups` shows `nova-ecs-sg`.
|
||||
- **Rollback:** `terraform apply` the prior revision re-creates the `acdl-*` names. The SNS topic has no message backlog (halt artifacts are fire-and-forget); the SG drift resolves on next task deploy.
|
||||
|
||||
## Step 3 — Lambda (recreate)
|
||||
|
||||
- **Command:** `terraform apply` in `terraform/platform/`.
|
||||
- Lambda function `acdl-contract-ingestor` → `nova-contract-ingestor`.
|
||||
- Execution role `acdl-contract-ingestor-role` → `nova-contract-ingestor-role`.
|
||||
- Inline policy `acdl-contract-ingestor-policy` → `nova-contract-ingestor-policy`.
|
||||
- The Lambda env vars (`CONTRACTS_TABLE`, `GITHUB_TOKEN_SECRET_ID`) now resolve to `nova-*` defaults.
|
||||
- **Verify:** `aws lambda list-functions` shows `nova-contract-ingestor`; the Function URL returns 200 on a SigV4-signed invoke. The `consumer_invoke_policy.json` rendered output (Terraform `consumer_invoke_policy_rendered`) now references `function:nova-contract-ingestor` — re-distribute to consumer deploy roles.
|
||||
- **Rollback:** `terraform apply` the prior revision re-creates `acdl-contract-ingestor`. Consumer deploy roles must point back at the old Function ARN (re-distribute the prior `consumer_invoke_policy.json`).
|
||||
|
||||
## Step 4 — DynamoDB (scan + copy)
|
||||
|
||||
DynamoDB table names are immutable post-creation, so the migration is a
|
||||
**scan + copy** (not a rename). The new `nova-*` tables are created by
|
||||
the same Terraform apply (Step 3). The data-migration script copies
|
||||
every item and verifies row counts.
|
||||
|
||||
- **Command (from repo root):**
|
||||
```bash
|
||||
# Dry-run first (no writes):
|
||||
python3 scripts/migrate_dynamodb_data.py
|
||||
# Execute the copy:
|
||||
python3 scripts/migrate_dynamodb_data.py --apply
|
||||
# A single table:
|
||||
python3 scripts/migrate_dynamodb_data.py --table contracts --apply
|
||||
```
|
||||
The script scans `acdl-contracts` → copies to `nova-contracts`, and
|
||||
`acdl-change-requests` → `nova-change-requests`, then verifies the
|
||||
destination row count == source row count (re-scan, not
|
||||
`DescribeTable.ItemCount` which lags ~6h).
|
||||
- **Verify:**
|
||||
```bash
|
||||
# Row counts must match (printed by the script). Manual cross-check:
|
||||
aws dynamodb scan --table-name nova-contracts --select COUNT
|
||||
aws dynamodb scan --table-name acdl-contracts --select COUNT
|
||||
```
|
||||
Then **point consumers at the new tables** (the Lambda already reads
|
||||
`nova-*` defaults; any direct DynamoDB consumers update their env).
|
||||
- **Keep the old tables** (`acdl-contracts`, `acdl-change-requests`)
|
||||
until consumers are verified reading from `nova-*`. **Deletion is a
|
||||
manual post-verification step:**
|
||||
```bash
|
||||
aws dynamodb delete-table --table-name acdl-contracts
|
||||
aws dynamodb delete-table --table-name acdl-change-requests
|
||||
```
|
||||
Only delete after a full soak period confirms `nova-*` reads succeed.
|
||||
- **Rollback:** Re-point consumers at `acdl-*` (the old tables are
|
||||
retained). The copy is additive (no data loss). To roll back a partial
|
||||
copy, re-run `--apply` (idempotent — `PutItem` overwrites).
|
||||
|
||||
### Outbox table (`acdl-outbox` → `nova-outbox`)
|
||||
|
||||
The evidence outbox table follows the same scan+copy pattern (it is
|
||||
created by `terraform/bootstrap/create_state_backend.py`).
|
||||
- **Command:** `python3 scripts/migrate_dynamodb_data.py --source acdl-outbox --dest nova-outbox --apply`
|
||||
- The `core/outbox_writer.py` default + `core/regression_verify.py`
|
||||
CAP-015 probe now reference `nova-outbox` (P4 updated both). The
|
||||
regression gate's live-AWS CAP-015 will return `Verified` once the
|
||||
`nova-outbox` table exists live; until then it is `Decayed` (the gate
|
||||
is re-run at milestone complete after the live migration).
|
||||
|
||||
## Step 5 — ECR (re-push)
|
||||
|
||||
- **Command:** `terraform apply` in `terraform/microservice/` creates
|
||||
the new `nova-microservice` ECR repo. Re-push the image:
|
||||
```bash
|
||||
python3 scripts/push_consumer_image.py # creates nova-microservice + prints docker tag/push
|
||||
```
|
||||
(The script's `ECR_REPO_NAME` is now `nova-microservice`.)
|
||||
- **Verify:** `aws ecr describe-repositories` shows `nova-microservice`; `docker pull <acct>.dkr.ecr.us-east-1.amazonaws.com/nova-microservice:latest` succeeds.
|
||||
- **Rollback:** The old `acdl-microservice` repo is retained until the
|
||||
soak passes. Re-push to it if a rollback is needed. Delete it manually:
|
||||
`aws ecr delete-repository --repository-name acdl-microservice --force`.
|
||||
|
||||
## Step 6 — IAM (re-bootstrap)
|
||||
|
||||
- **Command:**
|
||||
```bash
|
||||
export NOVA_BOOTSTRAP_AWS_ACCESS_KEY_ID="<root key>"
|
||||
export NOVA_BOOTSTRAP_AWS_SECRET_ACCESS_KEY="<root secret>"
|
||||
python3 terraform/bootstrap/create_state_backend.py # creates nova-outbox (idempotent)
|
||||
python3 terraform/bootstrap/create_iam_user.py # creates nova-spike-runner
|
||||
python3 terraform/bootstrap/apply_iam_baseline.py # creates nova-spike-runner-policy + nova-act-runner-role
|
||||
bash scripts/rotate_spike_key.sh # rotates the nova-spike-runner key
|
||||
```
|
||||
The deploy role `acdl-deploy-<repo>` → `nova-deploy-<repo>` is
|
||||
created by the bootstrap (the deploy workflow
|
||||
`.gitea/.github/workflows/deploy.yml` now references
|
||||
`role/nova-deploy-{1}`).
|
||||
- **Verify:** `aws iam get-user --user-name nova-spike-runner`;
|
||||
`aws iam list-attached-user-policies --user-name nova-spike-runner`
|
||||
shows `nova-spike-runner-policy`;
|
||||
`aws iam get-role --role-name nova-act-runner-role`.
|
||||
- **Rollback:** Re-run the prior bootstrap scripts (they create
|
||||
`acdl-spike-runner` + `acdl-act-runner-role`). The deploy workflow's
|
||||
`role-to-assume` must be reverted to `acdl-deploy-` (prior revision).
|
||||
|
||||
## Step 7 — State bucket (`acdl-tfstate-*` → `nova-tfstate-*`, `-migrate-state`)
|
||||
|
||||
The S3 state backend is renamed. Terraform's `-migrate-state` copies the
|
||||
state objects to the new bucket. **Back up the state JSON first.**
|
||||
|
||||
- **Back up state (per stack):**
|
||||
```bash
|
||||
for stack in platform microservice ci-vpc; do
|
||||
aws s3 cp s3://acdl-tfstate-581513795199-us-east-1/$stack/terraform.tfstate \
|
||||
./backup-$stack.tfstate
|
||||
done
|
||||
```
|
||||
- **Command (per stack):** the backend config in each
|
||||
`terraform/*/terraform.tf` now points at `nova-tfstate-...`.
|
||||
```bash
|
||||
cd terraform/platform
|
||||
terraform init -migrate-state # copies state acdl-tfstate → nova-tfstate
|
||||
cd ../microservice
|
||||
terraform init -migrate-state
|
||||
cd ../ci-vpc
|
||||
terraform init -migrate-state
|
||||
```
|
||||
- **Verify:** `aws s3 ls s3://nova-tfstate-581513795199-us-east-1/`
|
||||
shows the state keys; `terraform state list` in each dir lists the
|
||||
expected resources.
|
||||
- **Rollback:** Point the backend back at `acdl-tfstate-*` and re-run
|
||||
`terraform init -migrate-state` (restores from the backup bucket). The
|
||||
old `acdl-tfstate-*` bucket is retained until the soak passes. Delete
|
||||
it manually:
|
||||
`aws s3 rb s3://acdl-tfstate-581513795199-us-east-1 --force`.
|
||||
|
||||
## Step 8 — ALB (recreate, brief downtime, LAST)
|
||||
|
||||
The ALB is last because its recreation requires the briefest downtime
|
||||
window (the ECS service is re-attached to the new target group).
|
||||
|
||||
- **Command:** `terraform apply` in `terraform/microservice/`. The ALB
|
||||
`acdl-microservice` / `acdl-alb` → `nova-microservice` / `nova-alb`.
|
||||
- **Verify:** `aws elbv2 describe-load-balancers` shows the new ALB;
|
||||
`curl http://<new-alb-dns>/` returns 200.
|
||||
- **Rollback:** `terraform apply` the prior revision re-creates the
|
||||
`acdl-*` ALB (brief downtime again). The old ALB DNS is retained until
|
||||
consumers are re-pointed.
|
||||
|
||||
---
|
||||
|
||||
## Post-migration
|
||||
|
||||
1. **Soak:** run consumers against `nova-*` for a full verification
|
||||
window (deploy a test contract end-to-end).
|
||||
2. **Delete old resources** (manual, only after soak):
|
||||
- DynamoDB: `acdl-contracts`, `acdl-change-requests`, `acdl-outbox`
|
||||
- ECR: `acdl-microservice`
|
||||
- IAM: `acdl-spike-runner` (+ policy), `acdl-act-runner-role`,
|
||||
`acdl-deploy-<repo>`
|
||||
- S3: `acdl-tfstate-581513795199-us-east-1`
|
||||
- SNS: `acdl-sod-halt`
|
||||
- SG: `acdl-ecs-sg`
|
||||
- Secrets Manager: `acdl/github-token`
|
||||
- KMS alias: `alias/acdl-platform`
|
||||
- ALB: `acdl-alb` / `acdl-microservice`
|
||||
3. **Regression gate:** re-run `bash scripts/run_regression.sh`. The
|
||||
live-AWS CAP-013..016 probes should return `Verified` (the `nova-*`
|
||||
tables + state bucket exist). CAP-015 (outbox) flips from `Decayed`
|
||||
→ `Verified` once `nova-outbox` is live.
|
||||
|
||||
## What P5 owns (not P4)
|
||||
|
||||
- **Remove dual-read fallback:** `core/env.py` `get_env()` drops the
|
||||
`ACDL_*` fallback; shell scripts drop `:-$ACDL_X`. P4 keeps the
|
||||
dual-read (deployments don't break mid-window).
|
||||
- **`nova_tagging.py` hard-fail on `acdl:*`:** P3 set hard mode (no
|
||||
`acdl:*`-only tags); P5 tightens to fail on any `acdl:*` presence. P4
|
||||
leaves P3's behavior.
|
||||
- **Delete `ACDL_*` Gitea secrets:** the `NOVA_*` aliases created in P2
|
||||
are now the only source.
|
||||
- **Finalize `docs/NOVA_MIGRATION.md`:** mark the migration complete
|
||||
(cutoff passed).
|
||||
- **Milestone ship:** tag `v1.15.4`, merge to `main`, Gitea release.
|
||||
|
||||
## Files touched in P4
|
||||
|
||||
- `terraform/platform/main.tf`, `terraform/microservice/main.tf`,
|
||||
`terraform/ci-vpc/main.tf` — resource renames + backend bucket.
|
||||
- `terraform/{platform,microservice,ci-vpc}/terraform.tf` — state bucket.
|
||||
- `terraform/platform/consumer_invoke_policy.json` — Lambda ARN.
|
||||
- `terraform/bootstrap/{create_state_backend,create_iam_user,apply_iam_baseline}.py`,
|
||||
`spike_runner_policy.json`, `.bootstrap_state.json`, `README.md` —
|
||||
IAM/outbox/state-bucket renames.
|
||||
- `modules/l1/*/terraform/**` + `modules/l1/alb/instance.json` — L1
|
||||
resource-name defaults.
|
||||
- `modules/l2/microservice/composition.json` — `nova-app-role` default.
|
||||
- `core/lambda/contract_ingestor.py` — default table names (D-111).
|
||||
- `core/outbox_writer.py`, `core/regression_verify.py`,
|
||||
`core/local_emulators.py` — outbox table consistency (cross-territory,
|
||||
minimal).
|
||||
- `.gitea/workflows/deploy.yml` + `.github/workflows/deploy.yml` —
|
||||
`nova-deploy-` role ARN + artifact names.
|
||||
- `scripts/migrate_dynamodb_data.py` (NEW), `scripts/rotate_spike_key.sh`,
|
||||
`scripts/push_consumer_image.py`.
|
||||
- `tests/**` — fixtures updated to assert `nova-*`.
|
||||
@@ -1,177 +0,0 @@
|
||||
# Nova Migration Guide — What Consumers Must Know
|
||||
|
||||
> **STATUS: COMPLETE (milestone v1.15.4, 2026-07-30).** The Nova rebrand
|
||||
> is fully rolled out. The dual-read / parallel-write grace period has
|
||||
> ended (P5 cutoff passed). All `ACDL_*` env var fallbacks, `.acdl/`
|
||||
> consumer-path fallbacks, `/acdl/` SSM-path fallbacks, `acdl:*` tag-key
|
||||
> fallbacks, and `acdl-*` AWS resource names are removed. Consumers must
|
||||
> use the `NOVA_*` / `.nova/` / `/nova/` / `nova:*` / `nova-*` names
|
||||
> exclusively. If you have not yet migrated, follow the steps below.
|
||||
|
||||
> **Nova** is the new product brand for the platform formerly known as
|
||||
> **ACDL** (Agentic Cloud Delivery Platform). This guide documents the
|
||||
> breaking changes from the rebrand rollout (Phases P2–P4, cutoff P5)
|
||||
> and tells you exactly what to do.
|
||||
|
||||
## What is NOT changing
|
||||
|
||||
- **The Gitea repository name** (`continuous-intelligence/acdl`) is **not**
|
||||
changing. Only the product brand is changing. The `uses:` reference
|
||||
(`acdl/.github/workflows/deploy.yml@vX.Y`) and the GitHub `acdl/acdl` repo
|
||||
path are unchanged for the duration of the rebrand; the workflow
|
||||
`uses:` reference will be migrated in a later, separately-announced step.
|
||||
- **The platform behavior** is unchanged. Same pipeline stages, same
|
||||
contract schema, same confidence model, same evidence stream, same
|
||||
modules. Only the brand, the on-disk path, the env var names, the SSM
|
||||
path, the AWS tag keys, and the AWS resource names are changing.
|
||||
|
||||
## The 5 breaking changes
|
||||
|
||||
Five things that consumers may reference are being renamed. Each is
|
||||
scheduled into a phase, ships with a grace period, and has a cutoff.
|
||||
|
||||
### 1. Consumer contract path — Phase P2
|
||||
|
||||
- **Old:** `.acdl/contract.yml`
|
||||
- **New:** `.nova/contract.yml`
|
||||
- **Phase:** P2 (env vars + consumer path)
|
||||
- **Grace period:** during P2–P4 the deploy workflow reads **both** paths
|
||||
(`.nova/contract.yml` first, falling back to `.acdl/contract.yml` if the
|
||||
new path is absent). Your existing contracts keep working until P5.
|
||||
- **Cutoff:** P5 removes the `.acdl/` fallback. Move your contract file
|
||||
before P5.
|
||||
- **What you must do:** rename the directory in your consumer repo from
|
||||
`.acdl/` to `.nova/` and update any `contract:` workflow input that
|
||||
points at the old path. Nothing else changes in the contract content.
|
||||
|
||||
### 2. Environment variables — Phase P2
|
||||
|
||||
- **Old:** `ACDL_*` (e.g. `ACDL_LIFECYCLE_MODE`, `ACDL_AWS_ACCOUNT_ID`,
|
||||
`ACDL_BOOTSTRAP_AWS_ACCESS_KEY_ID`, …)
|
||||
- **New:** `NOVA_*` (e.g. `NOVA_LIFECYCLE_MODE`, `NOVA_AWS_ACCOUNT_ID`,
|
||||
`NOVA_BOOTSTRAP_AWS_ACCESS_KEY_ID`, …)
|
||||
- **Phase:** P2 (env vars + consumer path)
|
||||
- **Grace period — dual-read fallback:** during P2–P4 the platform reads
|
||||
**`NOVA_*` first, then falls back to `ACDL_*`** if the Nova variable is
|
||||
unset. This means your CI secrets, workflow env blocks, and local
|
||||
`.env.secrets` keep working unchanged through P4. You do not need to
|
||||
rename everything in one shot — rename a variable and the dual-read picks
|
||||
it up; leave one old and it still resolves.
|
||||
- **Cutoff:** P5 removes the `ACDL_*` fallback. After P5, only `NOVA_*`
|
||||
is read.
|
||||
- **What you must do:** rename your `ACDL_*` CI secrets, workflow `env:`
|
||||
blocks, and any local `.env.secrets` entries to `NOVA_*`. Because of the
|
||||
dual-read, you can do this incrementally across P2–P4 — but it must be
|
||||
complete before P5.
|
||||
|
||||
### 3. SSM parameter path — Phase P3 (DONE)
|
||||
|
||||
- **Old:** `/acdl/{env}/{contractId}/{output}`
|
||||
- **New:** `/nova/{env}/{contractId}/{output}`
|
||||
- **Phase:** P3 (SSM paths + tag keys) — **shipped in P3**
|
||||
- **Grace period — parallel-write:** during P3–P4 the platform **writes
|
||||
every output to both** the `/acdl/…` and `/nova/…` SSM paths, and reads
|
||||
from `/nova/…` first (falling back to `/acdl/…`). Any hardcoded SSM path
|
||||
reads in your application code keep resolving through P4. The P3
|
||||
migration script (`scripts/migrate_ssm_paths.py`) copies existing
|
||||
`/acdl/…` parameters to `/nova/…`, verifies the copy, and deletes the
|
||||
old ones.
|
||||
- **Cutoff:** P5 stops writing to `/acdl/…` and removes the read fallback.
|
||||
After P5 only `/nova/…` exists.
|
||||
- **What you must do:** if your application code or runbooks read deploy
|
||||
outputs from SSM by hardcoded path, update the path prefix from `/acdl/`
|
||||
to `/nova/`. If you consume outputs only via the PR-comment / GitHub
|
||||
issue surface, you do nothing — the platform republishes under the new
|
||||
path automatically.
|
||||
|
||||
### 4. AWS tag keys — Phase P3 (DONE)
|
||||
|
||||
- **Old:** `acdl:owner`, `acdl:environment`, `acdl:contract`,
|
||||
`acdl:cost-center`, `acdl:ref`
|
||||
- **New:** `nova:owner`, `nova:environment`, `nova:contract`,
|
||||
`nova:cost-center`, `nova:ref`
|
||||
- **Phase:** P3 (SSM paths + tag keys) — **shipped in P3**
|
||||
- **Grace period — parallel-tag period:** during P3–P4 the platform
|
||||
**tags every resource with both** the `acdl:*` and `nova:*` keys (same
|
||||
values). The ABAC session policy matches on **either** key set, so your
|
||||
existing scoped permissions keep working. The default cost-center value
|
||||
moves from `acdl-default` to `nova-default` (both written during the
|
||||
parallel-tag period). Terraform now emits `nova:*` keys; old `acdl:*`
|
||||
tags on pre-P3 live resources are removed by the P4 runbook's
|
||||
`scripts/untag_acdl_keys.py` step after the `nova:*` tags are applied
|
||||
live.
|
||||
- **Cutoff:** P5 stops writing the `acdl:*` keys and the ABAC policy matches
|
||||
only on `nova:*`. After P5, resources created before P5 still carry the
|
||||
old `acdl:*` tags (tags are not retroactively rewritten) but **new**
|
||||
resources are tagged `nova:*` only, and the policy no longer grants
|
||||
access via `acdl:*`.
|
||||
- **What you must do:** if you have IAM policies, Cost Explorer filters,
|
||||
or billing groupings that key off `acdl:*` tag keys, add a parallel
|
||||
`nova:*` condition (or migrate to `nova:*`) before P5. The platform
|
||||
handles the dual-tagging; you only need to update your own tag-key
|
||||
references.
|
||||
|
||||
### 5. AWS resource names — Phase P4
|
||||
|
||||
- **Old:** `acdl-*` (DynamoDB tables `acdl-contracts`,
|
||||
`acdl-change-requests`; Lambda `acdl-contract-ingestor`; SNS
|
||||
`acdl-sod-halt`; security group `acdl-ecs-sg`; KMS alias
|
||||
`alias/acdl-platform`; ECS services, ECR repos, IAM user
|
||||
`acdl-spike-runner`, state bucket `acdl-tfstate-*`, ALB `acdl-alb`,
|
||||
`acdl-deploy-*`)
|
||||
- **New:** `nova-*` (the same resources, prefixed `nova-`)
|
||||
- **Phase:** P4 (resource names) — **maintenance window**
|
||||
- **Grace period:** P4 is a **planned maintenance window**. AWS resources
|
||||
cannot be renamed in place, so P4 provisions the `nova-*` resources,
|
||||
migrates data (DynamoDB tables, S3 state), repoints the platform, and
|
||||
tears down the `acdl-*` resources. The platform team schedules and
|
||||
announces the window; consumers do not provision or rename anything
|
||||
themselves.
|
||||
- **Cutoff:** the `acdl-*` resources are decommissioned at the end of the
|
||||
P4 maintenance window. After P4, only `nova-*` resources exist.
|
||||
- **What you must do:** nothing for the resource names themselves — the
|
||||
platform owns the rename. If your application code or runbooks reference
|
||||
a specific `acdl-*` resource by name (e.g. a hardcoded DynamoDB table
|
||||
name or ECR URI), update it to the `nova-*` name during P4. The platform
|
||||
publishes the exact old → new name mapping with the P4 announcement.
|
||||
|
||||
## Timeline at a glance
|
||||
|
||||
| Phase | What ships | Grace period | Cutoff |
|
||||
|-------|------------|--------------|--------|
|
||||
| **P1** (this phase) | Brand prose, docs, decks, schema `$id`, release titles | n/a (prose only) | n/a |
|
||||
| **P2** | `.nova/` contract path + `NOVA_*` env vars | dual-read: `.nova/`→`.acdl/`, `NOVA_*`→`ACDL_*` | **P5** removes fallback |
|
||||
| **P3** | `/nova/` SSM path + `nova:*` tag keys | parallel-write (SSM) + parallel-tag (ABAC matches either) | **P5** removes old path/tags |
|
||||
| **P4** | `nova-*` AWS resource names | maintenance window (platform-owned migration) | end of P4 window |
|
||||
| **P5** | Fallback removal | — | `ACDL_*` env vars, `.acdl/` path, `/acdl/` SSM, `acdl:*` tags stop working |
|
||||
|
||||
## What consumers must do (checklist)
|
||||
|
||||
1. **Before P5 — contract path:** move `.acdl/contract.yml` →
|
||||
`.nova/contract.yml` in your consumer repo; update the `contract:`
|
||||
workflow input. *(Can be done any time in P2–P4.)*
|
||||
2. **Before P5 — env vars:** rename `ACDL_*` CI secrets / workflow `env:`
|
||||
blocks / local `.env.secrets` to `NOVA_*`. *(Incremental during P2–P4;
|
||||
dual-read keeps you green.)*
|
||||
3. **Before P5 — SSM reads:** if you read deploy outputs from SSM by
|
||||
hardcoded `/acdl/…` path, update to `/nova/…`. *(Skip if you consume
|
||||
outputs via PR comments only.)*
|
||||
4. **Before P5 — tag-key references:** if you have IAM policies, Cost
|
||||
Explorer filters, or billing groupings keyed off `acdl:*`, add or
|
||||
migrate to `nova:*`. *(Platform handles dual-tagging.)*
|
||||
5. **During P4 — resource-name references:** if your code or runbooks
|
||||
reference a specific `acdl-*` AWS resource by name, update to the
|
||||
`nova-*` name per the P4 mapping announcement. *(Platform owns the
|
||||
rename itself.)*
|
||||
|
||||
## Questions
|
||||
|
||||
If anything in this guide is unclear, or you are unsure whether your
|
||||
consumer repo references a renamed value, open an issue on the platform
|
||||
repo. The platform team will confirm what you need to change and when.
|
||||
|
||||
> **Note:** the real Gitea repository name (`continuous-intelligence/acdl`)
|
||||
> is **not** changing — only the product brand. The `uses:` workflow
|
||||
> reference and repo path are migrated in a separately-announced later step;
|
||||
> until then, keep your `uses: acdl/.github/workflows/deploy.yml@vX.Y`
|
||||
> reference as-is.
|
||||
@@ -1,67 +0,0 @@
|
||||
# Nova — The No-Humans Infrastructure Platform: Thesis Defensibility Brief
|
||||
|
||||
> v1.17 — Strategic Direction, Leadership Metrics & Unified Story (REQ-213)
|
||||
> Generated: 2026-08-04
|
||||
|
||||
## The thesis
|
||||
|
||||
Nova is the autonomous infrastructure layer that lets product teams
|
||||
ship without engaging an operator, and lets executives trust the AI
|
||||
not because it never fails but because every decision is captured,
|
||||
scored, and accountable.
|
||||
|
||||
**Autonomy in operations; human at stage gates.** The operator is
|
||||
removed from the loop of normal operations. Human attestation remains
|
||||
required at stage gates — QA signs off for production, SRE greenlights
|
||||
based on operational readiness. The absence of an operator is never
|
||||
the absence of a record.
|
||||
|
||||
## Grounded proof (measurable today)
|
||||
|
||||
| Proof | Source | Status |
|
||||
|-------|--------|--------|
|
||||
| 18 capabilities verified, 4 honestly skipped (0 broken) | `REGRESSION_REPORT.json` | grounded |
|
||||
| Decision Ledger captures 100% of AI decisions with outcome backfill | `metrics/decision_ledger.db` | grounded (this milestone) |
|
||||
| Attestation Coverage: 100% of prod/dr promotions attested by a human | `hitl_gates.py` + outbox `approver_*` | grounded |
|
||||
| Confidence-gated policy engine (not an LLM) — 6 weighted inputs, band outcome | `confidence_signal.py` | grounded |
|
||||
| 8-concern attestation matrix with separation-of-duties on prod | `attestation_matrix.py` + `separation_of_duties.py` | grounded |
|
||||
| Pre-apply cost estimates (Infracost, offline) | `infracost_adapter.py` | grounded |
|
||||
| Test suite passes (~656 tests) | `metrics/test-results.xml` | grounded |
|
||||
|
||||
## Deferred proof (measurable when blocking decisions lift)
|
||||
|
||||
| Proof | Blocking Decision | Unblock Requirement |
|
||||
|-------|-------------------|---------------------|
|
||||
| Touchless Resolution Rate ≥99% across production estates | 0 consumers today | Pilot estate activation |
|
||||
| Live infrastructure health (ECS, ALB, RPS) | D-096 | Live AWS re-provisioning |
|
||||
| Onboarding funnel: requested → granted | D-113/D-114/D-119 | Auto-grant implementation |
|
||||
| Drift auto-reversal rate ≥95% | D-096 + no scheduler | Drift detection scheduler |
|
||||
| Predictive vs reactive ratio ≥3:1 | future emitter | ML anomaly-forecasting service |
|
||||
| Tamper-evident ledger checkpoints (S3 Object Lock + JWS) | D-083 | Audit ledger build-out |
|
||||
|
||||
## Anti-claims (what Nova is NOT)
|
||||
|
||||
1. **Nova's "AI" is NOT an LLM planner.** It is a confidence-gated
|
||||
policy engine (confidence_signal + HITL gate). The Decision Ledger
|
||||
captures this real decision path — not a fabricated "AI agent" that
|
||||
doesn't exist yet (D-122). When an LLM planner is added, it will emit
|
||||
richer `alternatives_considered` without schema breakage.
|
||||
2. **Nova does NOT remove humans from accountability.** Only from
|
||||
operations. Every stage-gate promotion (qa/prod/dr) requires a human
|
||||
attestation recorded with approver identity, separation-of-duties
|
||||
check, and the 8-concern evidence matrix (NORTH_STAR Anti-Goal #3).
|
||||
3. **Nova is NOT for legacy, untagged, or freeform infrastructure.** It
|
||||
requires Terraform-managed, policy-aligned, fully-tagged inputs
|
||||
(NORTH_STAR Anti-Goal #4).
|
||||
4. **Nova does NOT fabricate metrics.** Every metric is grounded (cites
|
||||
a source file), derived (documented formula), or deferred (cites a
|
||||
blocking decision ID). No fabricated numbers in any deck slide or
|
||||
METRICS.md entry (the "no fabrication" hard constraint).
|
||||
|
||||
## What "won" looks like
|
||||
|
||||
By month 18, Nova is the layer enterprise leadership points to when
|
||||
they say *"we don't have an infrastructure ops team anymore, and the
|
||||
audit trail is stronger than it ever was"* — and it is the default
|
||||
substrate their AI engineering teams reach for first when an agent needs
|
||||
to deploy.
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# Nova Onboarding — No-Humans Request Path (v1.16, REQ-182..184)
|
||||
# Nova Onboarding — Autonomous Request Path (v1.16, REQ-182..184)
|
||||
|
||||
The v1.16 milestone implements the **request path** of the no-humans
|
||||
The v1.16 milestone implements the **request path** of the autonomous
|
||||
onboarding flow (D-113). A consumer can submit an onboarding request
|
||||
without contacting the platform team; the platform generates an
|
||||
environment binding + (in a future milestone) provisions the AWS resources.
|
||||
@@ -77,7 +77,7 @@ milestone (D-113).
|
||||
only (D-114); live apply is deferred.
|
||||
- **OIDC trust policy** — the onboarding Terraform uses a placeholder
|
||||
OIDC provider; real OIDC federation is blocked on
|
||||
go-gitea/gitea#36988 (carries forward from v1.1).
|
||||
upstream forge OIDC support (carries forward from v1.1).
|
||||
|
||||
## See also
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ change to the modules/stack/confidence/audit.
|
||||
- A MAJOR bump requires a new registry entry (immutable publication); the
|
||||
old entry enters a 12-month deprecation window.
|
||||
- The central deploy pipeline is referenced by a floating MAJOR + MINOR tag
|
||||
(e.g. `@v1.13`); patch fixes flow within the tag, breaking changes land
|
||||
(e.g. `@v1.19`); patch fixes flow within the tag, breaking changes land
|
||||
under the next MINOR tag.
|
||||
|
||||
See [Versioning](pipeline/versioning) for the consumer-facing details.
|
||||
|
||||
+13
-13
@@ -19,7 +19,7 @@ definitions.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["your repo<br/>(app code + contracts + CI definitions)"] -->|uses: acdl/.github/workflows/deploy.yml@v1.13| B
|
||||
A["your repo<br/>(app code + contracts + CI definitions)"] -->|uses: nova/.github/workflows/deploy.yml@v1.19| B
|
||||
B["platform runners<br/>(modules + pipelines + adapters + schemas)"] -->|contract -> resolver -> stack -> adapter<br/>-> security checks -> infrastructure plan -> policy checks<br/>-> confidence -> apply -> evidence event| C
|
||||
C["your resources in AWS"]
|
||||
```
|
||||
@@ -27,13 +27,13 @@ flowchart LR
|
||||
## Versioning the `uses:` reference
|
||||
|
||||
The central deployment pipeline is **always versioned with floating MAJOR
|
||||
and MINOR tags** (e.g. `acdl/pipelines/contract.yml@v1.13`). Version
|
||||
and MINOR tags** (e.g. `nova/pipelines/contract.yml@v1.19`). Version
|
||||
constraints cannot be expressed inside the contract, so the tag in
|
||||
`uses:` is the only immutability lever a consumer has. See
|
||||
[Versioning](pipeline/versioning) for the full rationale.
|
||||
|
||||
**Unversioned references are discouraged.** Do not use `@main` or a bare
|
||||
`acdl/pipelines/contract.yml`.
|
||||
`nova/pipelines/contract.yml`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -47,7 +47,7 @@ platform-managed. See [Environments](environments/).
|
||||
environment is bound, your first pipeline run emits a friendly onboarding
|
||||
prompt. See [Environments](environments/).
|
||||
- **Authorization to reference the central pipeline.** Onboarding grants
|
||||
your repo the right to `uses: acdl/.github/workflows/deploy.yml@v1.13`.
|
||||
your repo the right to `uses: nova/.github/workflows/deploy.yml@v1.19`.
|
||||
Contact the platform team if you have not been onboarded.
|
||||
|
||||
## Step 1 — Create a consumer repo
|
||||
@@ -94,7 +94,7 @@ Nova deployment workflow with a **versioned tag** (floating MAJOR + MINOR):
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.13
|
||||
uses: nova/.github/workflows/deploy.yml@v1.19
|
||||
with:
|
||||
contract: .nova/contract.yml
|
||||
environment: dev
|
||||
@@ -140,7 +140,7 @@ name: microservice
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `uses` | string | yes | Reference to the central deployment pipeline, **versioned** with a floating MAJOR+MINOR tag (e.g. `acdl/pipelines/contract.yml@v1.13`). Bare or `@main` references are discouraged. See [Versioning](pipeline/versioning). |
|
||||
| `uses` | string | yes | Reference to the central deployment pipeline, **versioned** with a floating MAJOR+MINOR tag (e.g. `nova/pipelines/contract.yml@v1.19`). Bare or `@main` references are discouraged. See [Versioning](pipeline/versioning). |
|
||||
| `module` | string | yes | Module name from the registry — any primitive or module (e.g. `static-assets`, `microservice`, `s3`). See the [module catalog](modules/). |
|
||||
| `environment` | string | yes | The platform-managed environment to deploy to (e.g. `dev`). See [Environments](environments/). |
|
||||
| `inputs` | object | yes | Module-specific inputs (see the module's README). |
|
||||
@@ -177,14 +177,14 @@ on:
|
||||
branches: [main]
|
||||
jobs:
|
||||
deploy:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.13
|
||||
uses: nova/.github/workflows/deploy.yml@v1.19
|
||||
with:
|
||||
contract: .nova/contract.yml
|
||||
```
|
||||
|
||||
That is the entire consumer-side workflow. When you push to `main`:
|
||||
|
||||
1. The platform runner resolves `uses: acdl/.github/workflows/deploy.yml@v1.13`
|
||||
1. The platform runner resolves `uses: nova/.github/workflows/deploy.yml@v1.19`
|
||||
to the reusable workflow **at the pinned tag**.
|
||||
2. A **platform-provided runner** checks out **your** repo.
|
||||
3. The runner checks out the **Nova platform repo** into the workspace —
|
||||
@@ -326,8 +326,8 @@ per-module extension points. Common examples:
|
||||
| Contract schema | `schemas/contract.schema.json` | JSON Schema for consumer contracts. |
|
||||
| Stack schema | `schemas/stack.schema.json` | JSON Schema for the resolved stack instance. |
|
||||
| Module catalog | [modules/](modules/) | All primitives and modules. |
|
||||
| Sample contract | `contracts/static-assets.yaml` | The reference example contract (uses `@v1.13`). |
|
||||
| Sample contract | `contracts/microservice.yaml` | The microservice example contract (uses `@v1.13`). |
|
||||
| Sample contract | `contracts/static-assets.yaml` | The reference example contract (uses `@v1.19`). |
|
||||
| Sample contract | `contracts/microservice.yaml` | The microservice example contract (uses `@v1.19`). |
|
||||
| Module examples | `modules/<name>/examples/` | Validated per-module example contracts (`simple.yaml` + `complex.yaml`). |
|
||||
| Contract resolver | `core/contract_resolver.py` | Resolves contracts to stack instances. |
|
||||
| Angine adapter | `adapters/terraform/adapter.py` | Compiles stack instances to infrastructure. |
|
||||
@@ -353,7 +353,7 @@ destruction:
|
||||
use `mode: decommission` with the `changeRequestId` input:
|
||||
|
||||
```yaml
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.13
|
||||
uses: nova/.github/workflows/deploy.yml@v1.19
|
||||
with:
|
||||
contract: .nova/contract.yml
|
||||
mode: decommission
|
||||
@@ -421,7 +421,7 @@ name: static-assets
|
||||
```
|
||||
|
||||
**Shape 2 — single contract + `environment` workflow input:** the
|
||||
reusable deploy workflow (`acdl/.github/workflows/deploy.yml@v1.13`)
|
||||
reusable deploy workflow (`nova/.github/workflows/deploy.yml@v1.19`)
|
||||
declares an `environment` input. When non-empty, it overrides the
|
||||
contract's `environment` field at load time (before interpolation), so
|
||||
the same contract can be promoted by passing a different environment:
|
||||
@@ -436,7 +436,7 @@ on: workflow_dispatch:
|
||||
required: true
|
||||
jobs:
|
||||
deploy-qa:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.13
|
||||
uses: nova/.github/workflows/deploy.yml@v1.19
|
||||
with:
|
||||
environment: qa
|
||||
contract: .nova/contract.yml
|
||||
|
||||
@@ -78,10 +78,3 @@ Planned future features (no dates; tracked in the internal roadmap):
|
||||
- [Consumer Guide](consumer-guide) — start here if you are a consumer.
|
||||
- [Architecture](architecture) — start here if you are a platform engineer.
|
||||
- The [README](https://github.com/nova/nova) describes the platform repo.
|
||||
|
||||
> **Note:** The product brand is **Nova** (formerly ACDL — Agentic Cloud
|
||||
> Delivery Platform). The Gitea repository name (`continuous-intelligence/acdl`)
|
||||
> and the GitHub `uses:` reference (`acdl/.github/workflows/deploy.yml@…`)
|
||||
> are unchanged during the rebrand transition; only the product name is
|
||||
> changing. See the [Nova migration guide](NOVA_MIGRATION) for the
|
||||
> scheduled breaking changes.
|
||||
@@ -39,7 +39,7 @@ It is exposed to consumer repos as a **reusable workflow**:
|
||||
- `.github/workflows/deploy.yml` — GitHub Actions (production)
|
||||
|
||||
A consumer repo invokes the reusable workflow via a **versioned tag**
|
||||
(floating MAJOR + MINOR, e.g. `acdl/.github/workflows/deploy.yml@v1.13`).
|
||||
(floating MAJOR + MINOR, e.g. `nova/.github/workflows/deploy.yml@v1.19`).
|
||||
The workflow checks out the consumer repo, then checks out the Nova platform
|
||||
repo into the runner workspace, and runs `scripts/run_platform.sh` against
|
||||
the consumer's contract. The consumer never clones the platform repo or
|
||||
|
||||
@@ -26,7 +26,7 @@ tag** in a consumer's CI workflow definition:
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.13
|
||||
uses: nova/.github/workflows/deploy.yml@v1.19
|
||||
with:
|
||||
contract: .nova/contract.yml
|
||||
```
|
||||
@@ -36,7 +36,7 @@ itself — the contract no longer carries a `uses:` field). The CI workflow
|
||||
`uses:` tag is the only immutability lever a consumer has.
|
||||
|
||||
**Unversioned references are discouraged.** Do not use `@main` or a bare
|
||||
`acdl/.github/workflows/deploy.yml` — `main` is constantly updated and can
|
||||
`nova/.github/workflows/deploy.yml` — `main` is constantly updated and can
|
||||
cause unexpected failures. Pinning to a MAJOR+MINOR tag means:
|
||||
|
||||
- **Immutability** — the pipeline behavior you tested is the behavior you
|
||||
|
||||
@@ -23,7 +23,7 @@ Step 1: full markdown Step 2: Marp deck Step 3: HTML + PPTX
|
||||
|
||||
### Step 1 — Full markdown (source of truth)
|
||||
|
||||
**File convention:** `<deck-name>.md` (e.g. `how-the-platform-works.md`).
|
||||
**File convention:** `<deck-name>.md` (e.g. `nova-no-humans-platform.md`).
|
||||
|
||||
Write the complete deck as a standard markdown file. This is the **source of
|
||||
truth** — it contains:
|
||||
@@ -45,7 +45,7 @@ fact is wrong, fix it here and re-run Steps 2 and 3.
|
||||
|
||||
### Step 2 — Marp deck synthesis
|
||||
|
||||
**File convention:** `<deck-name>-marp.md` (e.g. `how-the-platform-works-marp.md`).
|
||||
**File convention:** `<deck-name>-marp.md` (e.g. `nova-no-humans-platform-marp.md`).
|
||||
|
||||
Synthesize the full markdown into a lean Marp deck:
|
||||
|
||||
@@ -69,7 +69,7 @@ Synthesize the full markdown into a lean Marp deck:
|
||||
|
||||
Both formats are derived from the Marp deck. **HTML is committed to the repo**
|
||||
(viewable in any browser, self-contained with base64-embedded images). **PPTX
|
||||
is uploaded to the Gitea release** as a downloadable attachment (binary, not
|
||||
is uploaded to the release** as a downloadable attachment (binary, not
|
||||
committed to git).
|
||||
|
||||
#### HTML export (committed to repo)
|
||||
@@ -90,7 +90,7 @@ file that renders the full deck with the S&P Global Energy theme.
|
||||
committed artifacts, not generated on-the-fly — they must be re-rendered and
|
||||
re-committed when the Marp deck is updated.
|
||||
|
||||
#### PPTX export (uploaded to Gitea release)
|
||||
#### PPTX export (uploaded to release)
|
||||
|
||||
```bash
|
||||
CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
@@ -102,14 +102,14 @@ CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
The `--allow-local-files` flag is **required** for PPTX export so the local
|
||||
PNG diagrams are embedded in the file. As of v1.18 (REQ-228, D-141), PPTX
|
||||
files **are committed to the repo** as first-class binary artifacts (no LFS)
|
||||
and are also attached to the phase's Gitea release via
|
||||
and are also attached to the phase's release via
|
||||
`scripts/attach_release_asset.py`. The render + commit + attach pipeline is
|
||||
automated by `scripts/render_deck.sh`.
|
||||
|
||||
### Step 4 — Talking points (presenter cues)
|
||||
|
||||
**File convention:** `<deck-name>-talking-points.md` (e.g.
|
||||
`how-the-platform-works-talking-points.md`).
|
||||
`nova-no-humans-platform-talking-points.md`).
|
||||
|
||||
Distill the source of truth (Step 1) into presenter-ready cues, indexed by
|
||||
the Marp deck (Step 2) slide structure:
|
||||
@@ -144,35 +144,20 @@ and re-distill.
|
||||
```
|
||||
docs/presentations/
|
||||
├── README.md ← this file
|
||||
├── how-the-platform-works.md ← Step 1: full source of truth
|
||||
├── how-the-platform-works-marp.md ← Step 2: Marp deck (11 main + TOC + 8 appendix = 20)
|
||||
├── how-the-platform-works.html ← Step 3: rendered HTML (committed)
|
||||
├── how-the-platform-works-talking-points.md ← Step 4: presenter cues (20 sections)
|
||||
├── the-developer-experience.md ← Step 1: full source of truth
|
||||
├── the-developer-experience-marp.md ← Step 2: Marp deck (11 main + TOC + 7 appendix = 19)
|
||||
├── the-developer-experience.html ← Step 3: rendered HTML (committed)
|
||||
├── the-developer-experience-talking-points.md ← Step 4: presenter cues (19 sections)
|
||||
├── nova-no-humans-platform.md ← Step 1: full source of truth (19 main slides + speaker notes)
|
||||
├── nova-no-humans-platform-marp.md ← Step 2: Marp deck (19 main + 2 appendix = 21 slides)
|
||||
├── nova-no-humans-platform.html ← Step 3: rendered HTML (committed, S&P-themed)
|
||||
├── nova-no-humans-platform.pptx ← Step 3: rendered PPTX (committed, S&P-themed)
|
||||
├── nova-no-humans-platform-talking-points.md ← Step 4: presenter cues (21 sections)
|
||||
└── assets/
|
||||
├── nova-sp-theme.css ← S&P Global Energy Marp theme (all slide chrome)
|
||||
├── puppeteer-config.json ← no-sandbox config for mmdc
|
||||
├── mmd/ ← mermaid source files (Step 2 input)
|
||||
│ ├── sp-theme.json ← S&P Red/Black/White theme (mermaid-cli --configFile)
|
||||
│ ├── platform-works-01-contract-driven.mmd
|
||||
│ ├── platform-works-02-frictions.mmd
|
||||
│ ├── platform-works-02-end-to-end-flow.mmd
|
||||
│ ├── platform-works-03-north-star.mmd
|
||||
│ ├── platform-works-03-scope-boundary.mmd
|
||||
│ ├── platform-works-04-confidence-signal.mmd
|
||||
│ ├── platform-works-05-attestation-flow.mmd
|
||||
│ ├── platform-works-07-zero-trust.mmd
|
||||
│ ├── developer-experience-01b-scope-boundary.mmd
|
||||
│ ├── developer-experience-02-what-dev-does.mmd
|
||||
│ ├── developer-experience-03-no-cloning.mmd
|
||||
│ ├── developer-experience-04-promotion-journey.mmd
|
||||
│ ├── developer-experience-05-catalog.mmd
|
||||
│ ├── developer-experience-07-decommission.mmd
|
||||
│ ├── developer-experience-08-semver.mmd
|
||||
│ ├── platform-architecture.mmd ← shared high-level logical architecture (both decks)
|
||||
│ └── road-to-north-star.mmd
|
||||
│ ├── platform-architecture.mmd
|
||||
│ ├── road-to-north-star.mmd
|
||||
│ └── ... (per-slide .mmd files)
|
||||
└── png/ ← rendered mermaid PNGs (committed, S&P-themed)
|
||||
└── png/ ← rendered PNGs (embedded in Marp)
|
||||
├── platform-works-01-contract-driven.png
|
||||
├── platform-works-02-frictions.png
|
||||
@@ -300,7 +285,7 @@ diagram images in `assets/png/`). The resulting HTML is self-contained.
|
||||
**The HTML files are committed artifacts** — re-render and re-commit whenever
|
||||
the Marp source changes.
|
||||
|
||||
### Export a Marp deck to PPTX (uploaded to Gitea release)
|
||||
### Export a Marp deck to PPTX (uploaded to release)
|
||||
|
||||
```bash
|
||||
CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
@@ -311,7 +296,7 @@ CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
|
||||
`--allow-local-files` is **required** for PPTX so local PNG diagrams are
|
||||
embedded in the file. PPTX files are not committed to git — upload them as
|
||||
attachments to the Gitea release.
|
||||
attachments to the release.
|
||||
|
||||
## Adding a new presentation
|
||||
|
||||
@@ -324,7 +309,7 @@ attachments to the Gitea release.
|
||||
no speaker notes, embedded PNGs, and maturity badges.
|
||||
4. **Render to HTML** with `--allow-local-files` and commit the HTML to
|
||||
`docs/presentations/<deck-name>.html`.
|
||||
5. **Render to PPTX** with `--allow-local-files` and upload to the Gitea
|
||||
5. **Render to PPTX** with `--allow-local-files` and upload to the release
|
||||
release (do not commit PPTX to git).
|
||||
6. **Distill the talking points** as `<deck-name>-talking-points.md` — one
|
||||
section per Marp slide, 3-6 talking point bullets + key takeaway, content
|
||||
@@ -352,4 +337,4 @@ attachments to the Gitea release.
|
||||
> deck with a 5-act arc (Problem → Vision → How → Proof → Roadmap). v1.18
|
||||
> (REQ-226) adds 3 slides (17 Scope, 18 RACI, 19 Atelier) → 21 total. The
|
||||
> S&P Global Energy theme is restored (REQ-214, P1). PPTX is committed to
|
||||
> git + attached to the Gitea release (REQ-228, D-141).
|
||||
> git + attached to the release (REQ-228, D-141).
|
||||
@@ -0,0 +1,77 @@
|
||||
/* @theme nova-sp */
|
||||
/* Nova — S&P Global Energy theme for Marp decks.
|
||||
*
|
||||
* Palette: S&P Red (#D6002A), Black (#1B1B1B), White (#FFFFFF), Grey (#F0F0F0).
|
||||
* Font: Akkurat Pro (fallback Helvetica Neue / Arial).
|
||||
*
|
||||
* This theme extends Marp's default and applies the S&P palette to ALL slide
|
||||
* chrome — backgrounds, headers/footers, pagination, tables, blockquotes,
|
||||
* code blocks — not just headings.
|
||||
*/
|
||||
|
||||
:root {
|
||||
--sp-red: #D6002A;
|
||||
--sp-black: #1B1B1B;
|
||||
--sp-white: #FFFFFF;
|
||||
--sp-grey: #F0F0F0;
|
||||
--sp-dark-grey: #2E2E2E;
|
||||
}
|
||||
|
||||
/* Base section */
|
||||
section {
|
||||
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||
font-size: 22px;
|
||||
color: var(--sp-black);
|
||||
background: var(--sp-white);
|
||||
}
|
||||
|
||||
/* Headings — S&P Red */
|
||||
h1 { color: var(--sp-red); font-size: 34px; margin-bottom: 0.3em; }
|
||||
h2 { color: var(--sp-red); font-size: 26px; margin-bottom: 0.2em; }
|
||||
h3 { color: var(--sp-red); font-size: 22px; margin-bottom: 0.2em; }
|
||||
h4 { color: var(--sp-dark-grey); font-size: 20px; margin-bottom: 0.15em; }
|
||||
|
||||
/* Title slides — black background, red top border */
|
||||
section.title {
|
||||
background: var(--sp-black);
|
||||
color: var(--sp-white);
|
||||
border-top: 8px solid var(--sp-red);
|
||||
}
|
||||
section.title h1 { color: var(--sp-white); }
|
||||
section.title h2 { color: var(--sp-white); }
|
||||
|
||||
/* Tables — grey header with red underline */
|
||||
table { font-size: 18px; width: 100%; border-collapse: collapse; }
|
||||
th { background: var(--sp-grey); border-bottom: 2px solid var(--sp-red); padding: 6px 10px; text-align: left; }
|
||||
td { border-bottom: 1px solid var(--sp-grey); padding: 6px 10px; }
|
||||
|
||||
/* Blockquotes — red left border */
|
||||
blockquote { border-left: 4px solid var(--sp-red); color: var(--sp-dark-grey); font-size: 20px; padding-left: 12px; }
|
||||
|
||||
/* Code — dark background */
|
||||
pre { background: var(--sp-black); color: var(--sp-white); border-radius: 4px; padding: 12px; font-size: 16px; }
|
||||
code { background: var(--sp-grey); color: var(--sp-black); border-radius: 2px; padding: 1px 4px; font-size: 18px; }
|
||||
pre code { background: transparent; color: inherit; }
|
||||
|
||||
/* Images — centered, max height */
|
||||
img { display: block; margin: 0 auto; max-height: 320px; }
|
||||
|
||||
/* Header/footer — subtle grey */
|
||||
header { color: var(--sp-dark-grey); border-bottom: 1px solid var(--sp-grey); }
|
||||
footer { color: var(--sp-dark-grey); border-top: 1px solid var(--sp-grey); }
|
||||
|
||||
/* Maturity badges */
|
||||
.badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; }
|
||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||
|
||||
/* Pagination — S&P Red progress bar */
|
||||
.bespoke-progress-parent { background: var(--sp-grey); }
|
||||
.bespoke-progress-bar { background: var(--sp-red) !important; }
|
||||
|
||||
/* Lists — tighter */
|
||||
ul { margin-top: 0.3em; }
|
||||
li { margin-bottom: 0.2em; }
|
||||
|
||||
/* Strong — S&P Red for emphasis in lead lines */
|
||||
strong { color: var(--sp-red); }
|
||||
@@ -1,30 +1,10 @@
|
||||
---
|
||||
marp: true
|
||||
theme: default
|
||||
theme: nova-sp
|
||||
paginate: true
|
||||
size: 16x9
|
||||
header: 'Nova — The No-Humans Infrastructure Platform'
|
||||
footer: 'Act %{page}/5 — v1.17'
|
||||
style: |
|
||||
section {
|
||||
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||
font-size: 22px;
|
||||
color: #1B1B1B;
|
||||
}
|
||||
h1 { color: #D6002A; font-size: 34px; margin-bottom: 0.3em; }
|
||||
h2 { color: #D6002A; font-size: 26px; margin-bottom: 0.2em; }
|
||||
section.title { background: #1B1B1B; color: #fff; border-top: 8px solid #D6002A; }
|
||||
section.title h1 { color: #fff; }
|
||||
table { font-size: 18px; width: 100%; }
|
||||
th { background: #F0F0F0; }
|
||||
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 20px; }
|
||||
img { display: block; margin: 0 auto; max-height: 320px; }
|
||||
.badge {
|
||||
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||
font-size: 14px; font-weight: 600;
|
||||
}
|
||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||
footer: 'Act %{page}/5 — v1.20'
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
@@ -383,4 +363,41 @@ From `docs/METRICS_DEFERRED_ROADMAP.md`.
|
||||
- **Zero-cost steady state:** all resources torn down post-v1.11 (D-096); the platform runs offline
|
||||
- References the pre-mortem (`PRE_MORTEM.md`: v1.10 decay root cause + structural mitigations)
|
||||
|
||||
**Benefit:** you now know the operating cost is negligible — and the structural mitigation that prevents decay.
|
||||
**Benefit:** you now know the operating cost is negligible — and the structural mitigation that prevents decay.
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
## Slide 20 — 12-Month Product Roadmap
|
||||
|
||||
**The product arc from pilot activation to agentic substrate — four quarters, four outcomes.**
|
||||
|
||||
| Quarter | Theme | Board-level outcome |
|
||||
|---------|-------|---------------------|
|
||||
| **Q1** | <span class="badge planned">Pilot Activation</span> | Nova runs a real customer estate end-to-end, autonomously, with a measurable zero-touch rate |
|
||||
| **Q2** | <span class="badge planned">Provable Trust</span> | Every AI decision lands in a tamper-evident ledger; CFO sees real cloud-spend reconciliation |
|
||||
| **Q3** | <span class="badge planned">Compounding ROI</span> | Quarter-over-quarter cloud spend drops; drift is detected and reversed without a human |
|
||||
| **Q4** | <span class="badge planned">Agentic Substrate</span> | AI agents deploy through Nova by default; Nova is the substrate, not a vendor arriving late |
|
||||
|
||||
**Grounded in:** the 4 strategic objectives (autonomy, provable trust, ROI, agentic substrate) + the deferred-metric unblock paths.
|
||||
|
||||
**Benefit:** you now know the 12-month product arc — each quarter activates a strategic objective and its corresponding board-level metric, from pilot activation through agentic substrate leadership.
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
## Slide 21 — Quarter-by-Quarter Outcomes
|
||||
|
||||
| Quarter | Product theme | Key deliverable | Target metric | Grounding |
|
||||
|---------|--------------|-----------------|---------------|-----------|
|
||||
| **Q1** | Pilot Activation | Re-provision live AWS; activate first pilot estate; onboarding auto-grant | Touchless Resolution ≥ 99% · Escalation < 0.1% · AI Accuracy ≥ 99.5% | Strategic Objective #1 — autonomy as the default |
|
||||
| **Q2** | Provable Trust | Tamper-evident ledger (Object Lock + JWS); daily checkpoints; live cost reconciliation (CUR) | Decision Ledger Coverage 100% · Cost Savings ≥ 25% | Strategic Objective #2 — trust is the moat |
|
||||
| **Q3** | Compounding ROI + Drift | Drift detection scheduler; auto-reversal; Infracost→CUR reconciliation on pilot estate | Drift Auto-Reversal ≥ 95% · Spend Reduction ≥ 25% | Strategic Objective #3 — CFO-pointable numbers |
|
||||
| **Q4** | Agentic Substrate + Predictive | ML anomaly-forecasting; AI-agent intent surface; multi-cloud (Azure/GCP) preview | Predictive:Reactive ≥ 3:1 · AI-Agent Intent Share ≥ 40% (first measurement) | Strategic Objective #4 — default substrate for agents |
|
||||
|
||||
**Month-18 destination:** *"Nova is the layer enterprise leadership points to when they say 'we don't have an infrastructure ops team anymore, and the audit trail is stronger than it ever was.'"*
|
||||
|
||||
**Benefit:** you now know the quarter-by-quarter detail — each quarter has a concrete deliverable, a target metric grounded in a strategic objective, and a path from "honestly deferred" to "shipped and measured."
|
||||
|
||||
@@ -131,4 +131,34 @@
|
||||
### Appendix A2 — Operating Model & Cost
|
||||
- The operating cost is negligible (~$0.007/month)
|
||||
- The zero-cost steady state (D-096 teardown) is the structural mitigation
|
||||
- References the pre-mortem for the decay-prevention story
|
||||
- References the pre-mortem for the decay-prevention story
|
||||
---
|
||||
|
||||
## Slide 20 — 12-Month Product Roadmap
|
||||
|
||||
**Key takeaway:** The next 12 months have a clear product arc — pilot activation → provable trust → compounding ROI → agentic substrate. Each quarter activates one strategic objective.
|
||||
|
||||
- This is the *product* roadmap, not the technical roadmap. The technical milestones (v1.0–v1.19) are behind us; this is forward-looking.
|
||||
- Q1 (Pilot Activation): re-provision live AWS, activate the first pilot estate, light up the three post-pilot metrics. Onboarding auto-grant ships.
|
||||
- Q2 (Provable Trust): tamper-evident ledger (Object Lock + JWS), daily checkpoints, live cost reconciliation. Trust is the moat — features can be copied; an immutable decision history cannot.
|
||||
- Q3 (Compounding ROI + Drift): drift detection + auto-reversal, Infracost→CUR reconciliation on the pilot estate. This is the quarter the CFO points to a number that improves quarter-over-quarter.
|
||||
- Q4 (Agentic Substrate + Predictive): ML anomaly-forecasting, AI-agent intent surface, multi-cloud preview. The Future Horizon target moves from aspiration to first measurement.
|
||||
- The roadmap is grounded in the four strategic objectives from the North Star — autonomy, provable trust, ROI, agentic substrate — and the deferred-metric unblock paths from Slide 15.
|
||||
|
||||
**If asked "what about multi-cloud?"**: Q4 preview. AWS-only through Q3; Azure/GCP enters preview in Q4. We optimize for depth first, breadth second.
|
||||
|
||||
**If asked "what about the ML service?"**: Q4. The predictive-vs-reactive ≥3:1 target requires an ML anomaly-forecasting emitter — the most technically ambitious deliverable on the roadmap.
|
||||
|
||||
---
|
||||
|
||||
## Slide 21 — Quarter-by-Quarter Outcomes
|
||||
|
||||
**Key takeaway:** Each quarter has a concrete deliverable, a target metric, and a strategic-objective grounding. Nothing is hand-waved.
|
||||
|
||||
- Q1: three post-pilot metrics go live (Touchless ≥99%, Escalation <0.1%, Accuracy ≥99.5%). The measurement pipeline is already grounded; the denominator activates when the pilot estate runs.
|
||||
- Q2: Decision Ledger Coverage was already grounded — the *tamper-evidence* is the Q2 upgrade (SQLite hash-chain → S3 Object Lock + JWS). Cost Savings ≥25% becomes CFO-grade with live CUR reconciliation.
|
||||
- Q3: Drift Auto-Reversal ≥95% unblocks when the drift scheduler ships. Spend Reduction ≥25% is the same target, now measured against the pilot baseline.
|
||||
- Q4: Predictive:Reactive ≥3:1 requires the ML forecasting service. AI-Agent Intent Share ≥40% moves from aspiration to first measurement.
|
||||
- The month-18 destination: "Nova is the layer enterprise leadership points to when they say 'we don't have an infrastructure ops team anymore, and the audit trail is stronger than it ever was.'"
|
||||
|
||||
**If asked "are these committed or aspirational?"**: Q1–Q3 are committed (grounded pipeline + known unblock paths). Q4 targets are committed-deliverable, aspirational-metric — the ML service ships, the ≥40% intent share is first measurement (we don't control adoption rate).
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -414,4 +414,40 @@ This appendix shows the real cost figures + the zero-cost steady state.
|
||||
---
|
||||
|
||||
> **End of deck.** 16 main slides + 2 appendix slides = 18 total.
|
||||
> Both old decks (`how-the-platform-works` + `the-developer-experience`) are retired (D-130).
|
||||
> Both old decks (`how-the-platform-works` + `the-developer-experience`) are retired (D-130).
|
||||
---
|
||||
|
||||
## Slide 20 — 12-Month Product Roadmap
|
||||
|
||||
**The product arc from pilot activation to agentic substrate — four quarters, four outcomes.**
|
||||
|
||||
This slide shows the 12-month product roadmap — the forward-looking product-outcome arc. It is distinct from Slide 15 (the deferred-metric unblock paths), which explains *why* metrics are deferred and *how* they unblock. This slide shows *what's coming, when* — organized by quarter and board-level outcome.
|
||||
|
||||
**Speaker notes:**
|
||||
|
||||
- The roadmap is organized by product outcome, not by technical milestone. Each quarter activates one strategic objective from the North Star.
|
||||
- Q1 is pilot activation — re-provision live AWS, light up the first pilot estate, and activate the three post-pilot denominator metrics (Touchless Resolution Rate, Human Escalation Frequency, AI Decision Accuracy). The onboarding auto-grant ships, so consumers can self-provision without platform-team intervention.
|
||||
- Q2 is provable trust — the audit substrate goes from a SQLite hash-chain to a tamper-evident ledger (S3 Object Lock + JWS daily checkpoints). Live cost reconciliation (CUR) goes live so the CFO sees real cloud-spend data, not just pre-apply Infracost estimates.
|
||||
- Q3 is compounding ROI + drift — drift detection ships (the scheduler that was deferred), drift auto-reversal activates (≥95% within one detection cycle), and the ≥25% spend-reduction target is measured against the pilot estate's 12-month pre-Nova baseline. This is the quarter the CFO points to a number that improves quarter-over-quarter.
|
||||
- Q4 is agentic substrate + predictive — the ML anomaly-forecasting service ships (predictive-vs-reactive ≥3:1), the AI-agent intent consumption surface goes live, and multi-cloud (Azure/GCP) enters preview. The Future Horizon target (AI-Agent Intent Share ≥40%) moves from aspiration to first measurement.
|
||||
|
||||
**The month-18 destination:** *"Nova is the layer enterprise leadership points to when they say 'we don't have an infrastructure ops team anymore, and the audit trail is stronger than it ever was' — and it is the default substrate their AI engineering teams reach for first when an agent needs to deploy."*
|
||||
|
||||
> **Benefit:** you now know the 12-month product arc — each quarter activates a strategic objective and its corresponding board-level metric, from pilot activation through agentic substrate leadership.
|
||||
|
||||
---
|
||||
|
||||
## Slide 21 — Quarter-by-Quarter Outcomes
|
||||
|
||||
This slide is the detail table behind Slide 20 — the concrete deliverable, target metric, and strategic-objective grounding for each quarter.
|
||||
|
||||
**Speaker notes:**
|
||||
|
||||
- Each row has a product theme (the narrative), a key deliverable (what ships), a target metric (the board-level number), and a grounding (which strategic objective it activates).
|
||||
- Q1's three target metrics (Touchless ≥99%, Escalation <0.1%, Accuracy ≥99.5%) are the post-pilot metrics from the North Star — their measurement pipeline is grounded this milestone, but the denominator is zero until a pilot estate activates. Q1 is when the denominator goes live.
|
||||
- Q2's Decision Ledger Coverage (100%) is already grounded; the *tamper-evidence* is the Q2 upgrade. Cost Savings ≥25% is the Infracost-grounded target — Q2 is when actual-spend reconciliation (CUR) makes it CFO-grade.
|
||||
- Q3's Drift Auto-Reversal ≥95% is the deferred metric that unblocks when the drift detection scheduler ships. Spend Reduction ≥25% is the same target, now measured against the pilot baseline (not just estimated).
|
||||
- Q4's Predictive:Reactive ≥3:1 requires the ML forecasting service — the most technically ambitious deliverable. AI-Agent Intent Share ≥40% is the Future Horizon target — it moves from aspiration to first measurement when the agentic consumption surface goes live.
|
||||
- The roadmap does NOT duplicate the 19 completed technical milestones (v1.0–v1.19) — it is forward-looking only. It does NOT duplicate Slide 15's deferred-metric unblock paths — it uses them as the mechanism, but the audience sees the product arc, not the decision IDs.
|
||||
|
||||
> **Benefit:** you now know the quarter-by-quarter detail — each quarter has a concrete deliverable, a target metric grounded in a strategic objective, and a path from "honestly deferred" to "shipped and measured."
|
||||
|
||||
Binary file not shown.
+45
-33
@@ -1,13 +1,12 @@
|
||||
# RACI — Who Owns What
|
||||
|
||||
> **Source of truth:** `.ciagent/PROJECT.md` § RACI Matrix (v1.18, REQ-215,
|
||||
> D-139). This page is the citizen-developer-facing copy.
|
||||
> This page is the citizen-developer-facing copy.
|
||||
|
||||
Nova's delivery lifecycle has three roles. This page clarifies who owns
|
||||
Nova's delivery lifecycle has four roles. This page clarifies who owns
|
||||
what — so the citizen developer knows what they bring, what the platform
|
||||
provides, and what is co-owned.
|
||||
provides, what quality engineering guards, and what is co-owned with SRE.
|
||||
|
||||
## The Three Roles
|
||||
## The Four Roles
|
||||
|
||||
### Citizen Developer (CD)
|
||||
|
||||
@@ -15,40 +14,49 @@ That's you — the consumer (technical developer L3A or non-technical L3B).
|
||||
You are **Responsible** for all **Functional Requirements (FRs)** and
|
||||
**User Acceptance Testing (UAT)**. You produce the FRs + UAT via your AI
|
||||
coding agent, an upstream agentic SDLC platform, or any upstream
|
||||
development platform. **The source does not matter** — all are subject
|
||||
to the same compliance standards (the submission-readiness gate, the
|
||||
development platform. **The source does not matter** — all are subject to
|
||||
the same compliance standards (the submission-readiness gate, the
|
||||
contract schema, the policy envelope, the immutable audit stream). Nova
|
||||
validates the submission, not the author.
|
||||
|
||||
### Platform (Nova)
|
||||
|
||||
Nova is **Responsible** for all **Non-Functional Requirements (NFRs)**,
|
||||
**Infrastructure** (cloud resource lifecycle, state, IAM), **QA** (the
|
||||
platform-side quality checks: policy enforcement, confidence scoring,
|
||||
schema validation), and **Production deployments to cloud** (the apply
|
||||
path, the pipeline, the release mechanics).
|
||||
**Infrastructure** (cloud resource lifecycle, state, IAM), and
|
||||
**Production deployments to cloud** (the apply path, the pipeline, the
|
||||
release mechanics).
|
||||
|
||||
### Release Management (RM) — co-owned
|
||||
### Quality Engineering (QE)
|
||||
|
||||
The release is **co-owned**. The platform performs the QA + SRE
|
||||
attestations agentically (it runs the confidence signal, the policy
|
||||
checks, the separation-of-duties). The citizen developer **oversees and
|
||||
triggers** the actual release — the human attestation at the stage gate
|
||||
is your authorization. The platform runs the checks; you authorize the
|
||||
promotion. This is the "autonomy in operations, human at stage gates"
|
||||
model.
|
||||
Quality Engineering is **Responsible** for the platform-side quality
|
||||
checks: policy enforcement, confidence scoring, schema validation, and
|
||||
the functional/contract/non-functional evidence that feeds attestation.
|
||||
QE owns the **quality** of what the platform produces — the gate
|
||||
evidence, not the gate decision.
|
||||
|
||||
### SRE — co-owned with you
|
||||
|
||||
Production readiness is **co-owned**. SRE owns operational readiness:
|
||||
the operational attestation (incident response, capacity, resilience,
|
||||
DR). The platform performs the QA + SRE attestations agentically (it
|
||||
runs the confidence signal, the policy checks, the
|
||||
separation-of-duties). The citizen developer **oversees and triggers**
|
||||
the actual release — the human attestation at the stage gate is your
|
||||
authorization. The platform runs the checks; you authorize the promotion.
|
||||
This is the "autonomy in operations, human at stage gates" model.
|
||||
|
||||
## The Matrix
|
||||
|
||||
| Work Category | Citizen Developer | Platform | Release Management |
|
||||
|---|---|---|---|
|
||||
| **Functional Requirements (FRs)** | **R/A** | C | I |
|
||||
| **User Acceptance Testing (UAT)** | **R/A** | C | I |
|
||||
| **Non-Functional Requirements (NFRs)** | I | **R/A** | C |
|
||||
| **Infrastructure (cloud, state, IAM)** | I | **R/A** | C |
|
||||
| **QA (policy, confidence, schema checks)** | C | **R/A** | I |
|
||||
| **Production deployment to cloud** | I | **R/A** | C |
|
||||
| **Release attestation (QA + SRE sign-off)** | **A** | R | **R** |
|
||||
| Work Category | Citizen Developer | Platform | Quality Engineering | SRE |
|
||||
|---|---|---|---|---|
|
||||
| **Functional Requirements (FRs)** | **R/A** | C | I | I |
|
||||
| **User Acceptance Testing (UAT)** | **R/A** | C | I | I |
|
||||
| **Non-Functional Requirements (NFRs)** | I | **R/A** | C | C |
|
||||
| **Infrastructure (cloud, state, IAM)** | I | **R/A** | I | C |
|
||||
| **QA (policy, confidence, schema checks)** | C | R | **R/A** | I |
|
||||
| **Production deployment to cloud** | I | **R/A** | C | C |
|
||||
| **Quality attestation (QA sign-off)** | **A** | R | **R** | I |
|
||||
| **Production readiness (SRE sign-off)** | **A** | R | C | **R** |
|
||||
|
||||
**Key:** **R** = Responsible (does the work) · **A** = Accountable (owns
|
||||
the outcome, sign-off) · **C** = Consulted · **I** = Informed.
|
||||
@@ -64,11 +72,15 @@ the outcome, sign-off) · **C** = Consulted · **I** = Informed.
|
||||
- The NFRs (security, observability, compliance — baked into the
|
||||
pipeline, not your concern).
|
||||
- The infrastructure (cloud resources, state management, IAM scoping).
|
||||
- The QA (policy enforcement, confidence scoring, schema validation).
|
||||
- The production deployment (the apply path, the pipeline, the release).
|
||||
|
||||
**You co-own the release:**
|
||||
- Nova runs the attestations (QA confidence, SRE operational readiness).
|
||||
**Quality Engineering guards:**
|
||||
- The policy enforcement, confidence scoring, schema validation.
|
||||
- The quality attestation evidence that feeds the stage gates.
|
||||
|
||||
**You co-own production readiness with SRE:**
|
||||
- Nova + SRE run the attestations (QA quality sign-off, SRE operational
|
||||
readiness).
|
||||
- You authorize the promotion at the stage gate. No promotion happens
|
||||
without your recorded attestation.
|
||||
|
||||
@@ -79,7 +91,7 @@ agentic SDLC platform, or a traditional IDE. Nova does not
|
||||
differentiate. All submissions pass through the same gate
|
||||
(`schemas/submission-readiness.schema.json`): tags, environment
|
||||
metadata, policy preconditions, profile markers. The compliance
|
||||
standards are the same regardless of how the code was authored. This
|
||||
is by design: the audit trail is the same, the policy envelope is the
|
||||
standards are the same regardless of how the code was authored. This is
|
||||
by design: the audit trail is the same, the policy envelope is the
|
||||
same, the evidence stream is the same. The source does not matter; the
|
||||
submission does.
|
||||
+6
-2
@@ -1,6 +1,5 @@
|
||||
# Scope — Nova is Downstream of PDLC
|
||||
|
||||
> **Source of truth:** `.ciagent/PROJECT.md` § Scope (v1.18, REQ-216).
|
||||
> This page is the citizen-developer-facing copy.
|
||||
|
||||
## The Boundary
|
||||
@@ -15,7 +14,12 @@ PDLC includes:
|
||||
- IDE workflows / developer experience
|
||||
|
||||
Nova never penetrates the PDLC. Nova's domain is **infrastructure +
|
||||
delivery only**.
|
||||
delivery only**. Nova integrates with externally owned PDLC, SDLC,
|
||||
Agentic, and Citizen Developer platforms with no regard for the source
|
||||
of the intent: Nova provides a set of skills and MCP endpoints that help
|
||||
the developer or AI agent make their application production-grade, and
|
||||
all intents to deploy to production go through the same rigorous
|
||||
controls, quality gates, attestation, and evidence stream.
|
||||
|
||||
## What Nova Does
|
||||
|
||||
|
||||
+2
-2
@@ -34,14 +34,14 @@
|
||||
|
||||
## Atelier Provenance
|
||||
|
||||
The skills are derived from [Atelier](https://git.cloudinit.dev/coreci/atelier)
|
||||
The skills are derived from [Atelier](https://example.com/atelier)
|
||||
— a first-principles docs-as-code engineering framework with 8 core
|
||||
principles (C1–C8) and 19 domains, each with 10 derived P-rules. The
|
||||
skills distill the citizen-developer-relevant subset of each domain's
|
||||
first-principles, link to the agent-checklist triggers, and map to the
|
||||
existing BA.A catalog.
|
||||
|
||||
Atelier is vendored under `mcp/atelier/vendor/` (pinned tag, D-136) for
|
||||
Atelier is vendored under `mcp/atelier/vendor/` (pinned tag) for
|
||||
audit reproducibility — an agentic validation result is replayable
|
||||
against the exact principles that produced it.
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
# Nova Atelier MCP Server
|
||||
|
||||
> **v1.18, REQ-223, REQ-224.** An MCP (Model Context Protocol) server that
|
||||
> exposes Atelier engineering principles to the citizen developer's AI
|
||||
> agent. Plugin-registry architecture (D-140); stdio transport (D-135);
|
||||
> vendored Atelier (D-136) for audit reproducibility.
|
||||
> agent. Plugin-registry architecture; stdio transport;
|
||||
> vendored Atelier for audit reproducibility.
|
||||
|
||||
## What This Is
|
||||
|
||||
@@ -22,7 +21,7 @@ observability gaps.
|
||||
| `atelier.matrix_lookup(domain)` | Look up the domain→core principle mapping for a given domain. |
|
||||
| `atelier.validate_against_principles(snippet, domains?)` | Validate a code/diff snippet against the Atelier agent-checklist. Returns pass/fail per check item with the principle citation. |
|
||||
|
||||
## Architecture — Plugin Registry (D-140)
|
||||
## Architecture — Plugin Registry
|
||||
|
||||
```
|
||||
mcp/atelier/
|
||||
@@ -31,7 +30,7 @@ mcp/atelier/
|
||||
│ ├── __init__.py
|
||||
│ ├── principles.py # lookup_principle, list_domains, matrix_lookup
|
||||
│ └── validation.py # validate_against_principles
|
||||
├── vendor/ # pinned Atelier snapshot (D-136)
|
||||
├── vendor/ # pinned Atelier snapshot
|
||||
│ ├── VERSION.md # pinned tag + upgrade instructions
|
||||
│ ├── core/first-principles.md
|
||||
│ ├── domains/security/first-principles.md
|
||||
@@ -68,7 +67,7 @@ s.load_plugins()
|
||||
result = s.call_tool("atelier_lookup_principle", {"domain": "security", "principle_id": "P4"})
|
||||
```
|
||||
|
||||
## Vendoring (D-136)
|
||||
## Vendoring
|
||||
|
||||
Atelier is vendored under `vendor/` at a pinned tag (`v0.3.6`, see
|
||||
`vendor/VERSION.md`). An agentic validation result is only reproducible if
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Nova Metrics Directory
|
||||
|
||||
> v1.17 — Strategic Direction, Leadership Metrics & Unified Story (D-128)
|
||||
|
||||
This directory holds Nova's telemetry/observability artifacts. The
|
||||
metrics layer is **Nova-native** (D-120): JSONL event log + SQLite cold
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Nova PowerBI Dashboard — Import Guide
|
||||
|
||||
> v1.17 — Strategic Direction, Leadership Metrics & Unified Story (REQ-208)
|
||||
> Generated: 2026-08-04
|
||||
|
||||
This guide documents how to import Nova's metrics views into PowerBI
|
||||
via the folder connector, and suggests a starter visual model.
|
||||
|
||||
@@ -48,6 +48,11 @@
|
||||
"description": "Target group target type (ip or instance).",
|
||||
"required": false,
|
||||
"default": "ip"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -85,20 +90,42 @@
|
||||
{
|
||||
"type": "aws:elbv2:loadbalancer",
|
||||
"description": "Application load balancer in the VPC subnets.",
|
||||
"inputs": ["name", "subnets", "security_group", "load_balancer_type"],
|
||||
"outputs": ["lb_arn"]
|
||||
"inputs": [
|
||||
"name",
|
||||
"subnets",
|
||||
"security_group",
|
||||
"load_balancer_type"
|
||||
],
|
||||
"outputs": [
|
||||
"lb_arn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "aws:elbv2:targetgroup",
|
||||
"description": "Target group for the ECS service tasks.",
|
||||
"inputs": ["name", "port", "protocol", "vpc_id", "target_type"],
|
||||
"outputs": ["target_group_arn"]
|
||||
"inputs": [
|
||||
"name",
|
||||
"port",
|
||||
"protocol",
|
||||
"vpc_id",
|
||||
"target_type"
|
||||
],
|
||||
"outputs": [
|
||||
"target_group_arn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "aws:elbv2:listener",
|
||||
"description": "Listener forwarding the LB port to the target group.",
|
||||
"inputs": ["lb_arn", "port", "protocol", "target_group_arn"],
|
||||
"outputs": ["listener_arn"]
|
||||
"inputs": [
|
||||
"lb_arn",
|
||||
"port",
|
||||
"protocol",
|
||||
"target_group_arn"
|
||||
],
|
||||
"outputs": [
|
||||
"listener_arn"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
resource "aws_lb" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name = var.name
|
||||
load_balancer_type = var.load_balancer_type
|
||||
subnets = local.subnet_list
|
||||
@@ -6,6 +7,7 @@ resource "aws_lb" "this" {
|
||||
}
|
||||
|
||||
resource "aws_lb_target_group" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name_prefix = "${var.name}-"
|
||||
port = var.port
|
||||
protocol = var.protocol
|
||||
@@ -18,13 +20,14 @@ resource "aws_lb_target_group" "this" {
|
||||
}
|
||||
|
||||
resource "aws_lb_listener" "this" {
|
||||
load_balancer_arn = aws_lb.this.id
|
||||
count = var.enabled ? 1 : 0
|
||||
load_balancer_arn = aws_lb.this[0].id
|
||||
port = var.port
|
||||
protocol = var.protocol
|
||||
|
||||
default_action {
|
||||
type = "forward"
|
||||
target_group_arn = aws_lb_target_group.this.arn
|
||||
target_group_arn = aws_lb_target_group.this[0].arn
|
||||
}
|
||||
|
||||
depends_on = [aws_lb_target_group.this]
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
output "lb_arn" {
|
||||
value = aws_lb.this.id
|
||||
value = aws_lb.this[0].id
|
||||
description = "The load balancer ARN."
|
||||
}
|
||||
|
||||
output "listener_arn" {
|
||||
value = aws_lb_listener.this.arn
|
||||
value = aws_lb_listener.this[0].arn
|
||||
description = "The listener ARN."
|
||||
}
|
||||
|
||||
output "target_group_arn" {
|
||||
value = aws_lb_target_group.this.arn
|
||||
value = aws_lb_target_group.this[0].arn
|
||||
description = "The target group ARN."
|
||||
}
|
||||
|
||||
@@ -50,3 +50,9 @@ variable "vpc_id" {
|
||||
description = "VPC ID for the target group (ref to vpc or platform VPC)."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@
|
||||
"type": "string",
|
||||
"description": "AWS region (CloudFront is global but the provider region is used for the OAC).",
|
||||
"required": true
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -75,17 +80,37 @@
|
||||
{
|
||||
"type": "aws:cloudfront:distribution",
|
||||
"description": "CloudFront distribution with S3 origin via OAC.",
|
||||
"inputs": ["bucket_regional_domain_name", "price_class", "viewer_protocol_policy", "default_ttl", "max_ttl", "waf_web_acl_arn", "oac_id"],
|
||||
"outputs": ["distribution_arn", "distribution_domain_name"]
|
||||
"inputs": [
|
||||
"bucket_regional_domain_name",
|
||||
"price_class",
|
||||
"viewer_protocol_policy",
|
||||
"default_ttl",
|
||||
"max_ttl",
|
||||
"waf_web_acl_arn",
|
||||
"oac_id"
|
||||
],
|
||||
"outputs": [
|
||||
"distribution_arn",
|
||||
"distribution_domain_name"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "aws:cloudfront:originaccesscontrol",
|
||||
"description": "Origin Access Control for the S3 origin.",
|
||||
"inputs": ["name", "origin_type", "signing_behavior"],
|
||||
"outputs": ["oac_id"]
|
||||
"inputs": [
|
||||
"name",
|
||||
"origin_type",
|
||||
"signing_behavior"
|
||||
],
|
||||
"outputs": [
|
||||
"oac_id"
|
||||
]
|
||||
}
|
||||
],
|
||||
"intra_refs": [
|
||||
{"from": "aws:cloudfront:distribution.oac_id", "to": "aws:cloudfront:originaccesscontrol.oac_id"}
|
||||
{
|
||||
"from": "aws:cloudfront:distribution.oac_id",
|
||||
"to": "aws:cloudfront:originaccesscontrol.oac_id"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
resource "aws_cloudfront_origin_access_control" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name = local.oac_name
|
||||
origin_access_control_origin_type = local.oac_origin_type
|
||||
signing_behavior = local.oac_signing_behavior
|
||||
@@ -6,10 +7,11 @@ resource "aws_cloudfront_origin_access_control" "this" {
|
||||
}
|
||||
|
||||
resource "aws_cloudfront_distribution" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
origin {
|
||||
origin_id = "s3-origin"
|
||||
domain_name = var.bucket_regional_domain_name
|
||||
origin_access_control_id = aws_cloudfront_origin_access_control.this.id
|
||||
origin_access_control_id = aws_cloudfront_origin_access_control.this[0].id
|
||||
s3_origin_config {
|
||||
origin_access_identity = ""
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
output "distribution_arn" {
|
||||
value = aws_cloudfront_distribution.this.arn
|
||||
value = aws_cloudfront_distribution.this[0].arn
|
||||
description = "The CloudFront distribution ARN."
|
||||
}
|
||||
|
||||
output "distribution_domain_name" {
|
||||
value = aws_cloudfront_distribution.this.domain_name
|
||||
value = aws_cloudfront_distribution.this[0].domain_name
|
||||
description = "The CloudFront distribution domain name."
|
||||
}
|
||||
|
||||
output "oac_id" {
|
||||
value = aws_cloudfront_origin_access_control.this.id
|
||||
value = aws_cloudfront_origin_access_control.this[0].id
|
||||
description = "The Origin Access Control ID."
|
||||
}
|
||||
|
||||
@@ -38,3 +38,9 @@ variable "region" {
|
||||
description = "AWS region (CloudFront is global but the provider region is used for the OAC)."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
"type": "string",
|
||||
"description": "ARN of the CMK for repository encryption; if absent, uses AWS-managed key.",
|
||||
"required": false
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -48,4 +53,4 @@
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ locals {
|
||||
}
|
||||
|
||||
resource "aws_ecr_repository" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name = var.name
|
||||
image_tag_mutability = "MUTABLE"
|
||||
image_scanning_configuration {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
output "repository_url" {
|
||||
value = aws_ecr_repository.this.repository_url
|
||||
value = aws_ecr_repository.this[0].repository_url
|
||||
description = "The ECR repository URL."
|
||||
}
|
||||
|
||||
output "repository_arn" {
|
||||
value = aws_ecr_repository.this.arn
|
||||
value = aws_ecr_repository.this[0].arn
|
||||
description = "The ECR repository ARN."
|
||||
}
|
||||
@@ -13,4 +13,10 @@ variable "kms_key_arn" {
|
||||
type = string
|
||||
description = "ARN of the CMK for ECR encryption; if absent, uses managed key."
|
||||
default = null
|
||||
}
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
"type": "string",
|
||||
"description": "ARN of the CMK for CloudWatch log group encryption; if absent, uses managed key.",
|
||||
"required": false
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -43,4 +48,4 @@
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
resource "aws_ecs_cluster" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name = var.name
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
output "cluster_arn" {
|
||||
value = aws_ecs_cluster.this.arn
|
||||
value = aws_ecs_cluster.this[0].arn
|
||||
description = "The ECS cluster ARN."
|
||||
}
|
||||
|
||||
output "cluster_id" {
|
||||
value = aws_ecs_cluster.this.id
|
||||
value = aws_ecs_cluster.this[0].id
|
||||
description = "The ECS cluster ID."
|
||||
}
|
||||
|
||||
@@ -15,3 +15,9 @@ variable "kms_key_arn" {
|
||||
description = "ARN of the CMK for CloudWatch log group encryption; if absent, uses managed key."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -79,6 +79,11 @@
|
||||
"description": "ECS task definition family name.",
|
||||
"required": false,
|
||||
"default": "app"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -107,14 +112,32 @@
|
||||
{
|
||||
"type": "aws:ecs:task_definition",
|
||||
"description": "Fargate task definition; the adapter jsonencodes image/port/env into container_definitions.",
|
||||
"inputs": ["image", "port", "cpu", "memory", "env", "family"],
|
||||
"outputs": ["task_def_arn"]
|
||||
"inputs": [
|
||||
"image",
|
||||
"port",
|
||||
"cpu",
|
||||
"memory",
|
||||
"env",
|
||||
"family"
|
||||
],
|
||||
"outputs": [
|
||||
"task_def_arn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "aws:ecs:service",
|
||||
"description": "Fargate service running the task definition in the cluster + subnets.",
|
||||
"inputs": ["cluster_arn", "subnets", "security_group", "lb_target_group_arn", "desired_count", "launch_type"],
|
||||
"outputs": ["service_arn"]
|
||||
"inputs": [
|
||||
"cluster_arn",
|
||||
"subnets",
|
||||
"security_group",
|
||||
"lb_target_group_arn",
|
||||
"desired_count",
|
||||
"launch_type"
|
||||
],
|
||||
"outputs": [
|
||||
"service_arn"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
resource "aws_ecs_task_definition" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
family = var.family
|
||||
cpu = tostring(var.cpu)
|
||||
memory = tostring(var.memory)
|
||||
@@ -8,9 +9,10 @@ resource "aws_ecs_task_definition" "this" {
|
||||
}
|
||||
|
||||
resource "aws_ecs_service" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name = "nova-microservice"
|
||||
cluster = var.cluster_arn
|
||||
task_definition = aws_ecs_task_definition.this.arn
|
||||
task_definition = aws_ecs_task_definition.this[0].arn
|
||||
desired_count = var.desired_count
|
||||
launch_type = var.launch_type
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
output "service_arn" {
|
||||
value = aws_ecs_service.this.id
|
||||
value = aws_ecs_service.this[0].id
|
||||
description = "The ECS service ARN."
|
||||
}
|
||||
|
||||
output "task_def_arn" {
|
||||
value = aws_ecs_task_definition.this.arn
|
||||
value = aws_ecs_task_definition.this[0].arn
|
||||
description = "The ECS task definition ARN."
|
||||
}
|
||||
|
||||
@@ -78,3 +78,9 @@ variable "family" {
|
||||
description = "ECS task definition family name."
|
||||
default = "app"
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
"type": "string",
|
||||
"description": "AWS region the role is created in.",
|
||||
"required": true
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -48,4 +53,4 @@
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
resource "aws_iam_role" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name = var.role_name
|
||||
assume_role_policy = local.assume_role_policy
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "ecr_logs" {
|
||||
count = local.inline_policy != null ? 1 : 0
|
||||
count = (local.inline_policy != null && var.enabled) ? 1 : 0
|
||||
name = local.inline_policy.name
|
||||
role = aws_iam_role.this.id
|
||||
role = aws_iam_role.this[0].id
|
||||
policy = local.inline_policy.policy
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
output "role_arn" {
|
||||
value = aws_iam_role.this.arn
|
||||
value = aws_iam_role.this[0].arn
|
||||
description = "The IAM role ARN."
|
||||
}
|
||||
|
||||
output "role_id" {
|
||||
value = aws_iam_role.this.id
|
||||
value = aws_iam_role.this[0].id
|
||||
description = "The IAM role ID."
|
||||
}
|
||||
|
||||
@@ -21,3 +21,9 @@ variable "region" {
|
||||
description = "AWS region (provider-level; not a resource arg)."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
"description": "Number of days before the key is deleted after deletion is requested (default 30).",
|
||||
"required": false,
|
||||
"default": 30
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -49,4 +54,4 @@
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
resource "aws_kms_key" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
description = var.description
|
||||
enable_key_rotation = true
|
||||
deletion_window_in_days = var.deletion_window_days
|
||||
}
|
||||
|
||||
resource "aws_kms_alias" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name = local.alias_name
|
||||
target_key_id = aws_kms_key.this.key_id
|
||||
target_key_id = aws_kms_key.this[0].key_id
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
output "kms_key_arn" {
|
||||
value = aws_kms_key.this.arn
|
||||
value = aws_kms_key.this[0].arn
|
||||
description = "The KMS key ARN."
|
||||
}
|
||||
|
||||
output "kms_key_id" {
|
||||
value = aws_kms_key.this.key_id
|
||||
value = aws_kms_key.this[0].key_id
|
||||
description = "The KMS key ID."
|
||||
}
|
||||
@@ -14,4 +14,10 @@ variable "deletion_window_days" {
|
||||
type = number
|
||||
description = "Deletion window in days (7-30)."
|
||||
default = 30
|
||||
}
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -79,6 +79,11 @@
|
||||
"description": "Database admin password",
|
||||
"required": false,
|
||||
"default": "ACdlcI2026!"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
|
||||
@@ -5,6 +5,7 @@ resource "aws_db_subnet_group" "this" {
|
||||
}
|
||||
|
||||
resource "aws_db_instance" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
engine = var.engine
|
||||
engine_version = var.engine_version
|
||||
instance_class = var.instance_class
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
output "db_endpoint" {
|
||||
value = aws_db_instance.this.endpoint
|
||||
value = aws_db_instance.this[0].endpoint
|
||||
description = "The RDS instance endpoint."
|
||||
}
|
||||
|
||||
output "db_arn" {
|
||||
value = aws_db_instance.this.arn
|
||||
value = aws_db_instance.this[0].arn
|
||||
description = "The RDS instance ARN."
|
||||
}
|
||||
|
||||
@@ -64,3 +64,9 @@ variable "subnet_ids" {
|
||||
description = "Comma-separated subnet IDs for the DB subnet group (VPC-dependent)."
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
"type": "string",
|
||||
"description": "ARN of the CMK for SSE-KMS; if absent, uses managed key.",
|
||||
"required": false
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -57,4 +62,4 @@
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
resource "aws_s3_bucket" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
bucket = var.bucket_name
|
||||
tags = local.tags
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_versioning" "this" {
|
||||
bucket = aws_s3_bucket.this.id
|
||||
count = var.enabled ? 1 : 0
|
||||
bucket = aws_s3_bucket.this[0].id
|
||||
|
||||
versioning_configuration {
|
||||
status = "Enabled"
|
||||
@@ -12,7 +14,8 @@ resource "aws_s3_bucket_versioning" "this" {
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
|
||||
bucket = aws_s3_bucket.this.id
|
||||
count = var.enabled ? 1 : 0
|
||||
bucket = aws_s3_bucket.this[0].id
|
||||
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
output "bucket_arn" {
|
||||
value = aws_s3_bucket.this.arn
|
||||
value = aws_s3_bucket.this[0].arn
|
||||
description = "The S3 bucket ARN."
|
||||
}
|
||||
|
||||
output "bucket_name" {
|
||||
value = aws_s3_bucket.this.id
|
||||
value = aws_s3_bucket.this[0].id
|
||||
description = "The bucket name (echoes the input)."
|
||||
}
|
||||
|
||||
output "bucket_regional_domain_name" {
|
||||
value = aws_s3_bucket.this.bucket_regional_domain_name
|
||||
value = aws_s3_bucket.this[0].bucket_regional_domain_name
|
||||
description = "The bucket regional domain name (e.g. nova-spike-bucket.s3.us-east-1.amazonaws.com)."
|
||||
}
|
||||
@@ -19,4 +19,10 @@ variable "tags" {
|
||||
type = map(string)
|
||||
description = "Additional tags to merge with the module defaults."
|
||||
default = {}
|
||||
}
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -71,6 +71,11 @@
|
||||
"type": "string",
|
||||
"description": "ECS cluster ARN to deploy the service into",
|
||||
"required": false
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -99,4 +104,4 @@
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ resource "aws_ecs_service" "uptime" {
|
||||
name = "nova-uptime"
|
||||
cluster = local.cluster_ref
|
||||
task_definition = aws_ecs_task_definition.uptime.arn
|
||||
desired_count = var.feature_flag_enabled ? 1 : 0
|
||||
desired_count = var.enabled ? (var.feature_flag_enabled ? 1 : 0) : 0
|
||||
launch_type = "FARGATE"
|
||||
|
||||
dynamic "network_configuration" {
|
||||
|
||||
@@ -69,3 +69,9 @@ variable "cluster_arn" {
|
||||
description = "ECS cluster ARN to deploy the service into."
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
"type": "string",
|
||||
"description": "AWS region the VPC is created in.",
|
||||
"required": true
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -57,24 +62,44 @@
|
||||
{
|
||||
"type": "aws:ec2:vpc",
|
||||
"description": "The VPC itself.",
|
||||
"inputs": ["cidr", "name"],
|
||||
"outputs": ["vpc_id"]
|
||||
"inputs": [
|
||||
"cidr",
|
||||
"name"
|
||||
],
|
||||
"outputs": [
|
||||
"vpc_id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "aws:ec2:subnet",
|
||||
"description": "One subnet per availability zone (azs split on comma).",
|
||||
"inputs": ["cidr", "az", "vpc_id", "name"],
|
||||
"outputs": ["subnet_ids"]
|
||||
"inputs": [
|
||||
"cidr",
|
||||
"az",
|
||||
"vpc_id",
|
||||
"name"
|
||||
],
|
||||
"outputs": [
|
||||
"subnet_ids"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "aws:ec2:routetable",
|
||||
"description": "Route table bound to the VPC with an internet gateway + default route.",
|
||||
"inputs": ["vpc_id"],
|
||||
"inputs": [
|
||||
"vpc_id"
|
||||
],
|
||||
"outputs": []
|
||||
}
|
||||
],
|
||||
"intra_refs": [
|
||||
{"from": "aws:ec2:subnet.vpc_id", "to": "aws:ec2:vpc.vpc_id"},
|
||||
{"from": "aws:ec2:routetable.vpc_id", "to": "aws:ec2:vpc.vpc_id"}
|
||||
{
|
||||
"from": "aws:ec2:subnet.vpc_id",
|
||||
"to": "aws:ec2:vpc.vpc_id"
|
||||
},
|
||||
{
|
||||
"from": "aws:ec2:routetable.vpc_id",
|
||||
"to": "aws:ec2:vpc.vpc_id"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
resource "aws_vpc" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
cidr_block = local.cidr_block
|
||||
tags = {
|
||||
Name = local.name_tag
|
||||
@@ -11,7 +12,7 @@ resource "aws_vpc" "this" {
|
||||
|
||||
resource "aws_subnet" "this" {
|
||||
count = length(local.az_list)
|
||||
vpc_id = aws_vpc.this.id
|
||||
vpc_id = aws_vpc.this[0].id
|
||||
cidr_block = local.subnet_cidrs[count.index]
|
||||
availability_zone = local.az_list[count.index]
|
||||
tags = {
|
||||
@@ -20,17 +21,19 @@ resource "aws_subnet" "this" {
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "this" {
|
||||
vpc_id = aws_vpc.this.id
|
||||
count = var.enabled ? 1 : 0
|
||||
vpc_id = aws_vpc.this[0].id
|
||||
tags = {
|
||||
Name = "${local.name_tag}-igw"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table" "this" {
|
||||
vpc_id = aws_vpc.this.id
|
||||
count = var.enabled ? 1 : 0
|
||||
vpc_id = aws_vpc.this[0].id
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.this.id
|
||||
gateway_id = aws_internet_gateway.this[0].id
|
||||
}
|
||||
tags = {
|
||||
Name = "${local.name_tag}-rt"
|
||||
@@ -40,5 +43,5 @@ resource "aws_route_table" "this" {
|
||||
resource "aws_route_table_association" "this" {
|
||||
count = length(local.az_list)
|
||||
subnet_id = aws_subnet.this[count.index].id
|
||||
route_table_id = aws_route_table.this.id
|
||||
route_table_id = aws_route_table.this[0].id
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
output "vpc_id" {
|
||||
value = aws_vpc.this.id
|
||||
value = aws_vpc.this[0].id
|
||||
description = "The VPC id."
|
||||
}
|
||||
|
||||
|
||||
@@ -21,3 +21,9 @@ variable "region" {
|
||||
description = "AWS region (provider-level; not a resource arg)."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
"type": "string",
|
||||
"description": "AWS region (CloudFront-scoped WAF is always us-east-1; the adapter ignores this for cloudfront scope).",
|
||||
"required": true
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
@@ -60,8 +65,15 @@
|
||||
{
|
||||
"type": "aws:wafv2:webacl",
|
||||
"description": "WAFv2 Web ACL with managed rules.",
|
||||
"inputs": ["name", "scope", "default_action", "rules"],
|
||||
"outputs": ["web_acl_arn"]
|
||||
"inputs": [
|
||||
"name",
|
||||
"scope",
|
||||
"default_action",
|
||||
"rules"
|
||||
],
|
||||
"outputs": [
|
||||
"web_acl_arn"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
resource "aws_wafv2_web_acl" "this" {
|
||||
count = var.enabled ? 1 : 0
|
||||
name = var.name
|
||||
scope = local.scope
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
output "web_acl_arn" {
|
||||
value = aws_wafv2_web_acl.this.arn
|
||||
value = aws_wafv2_web_acl.this[0].arn
|
||||
description = "The WAF Web ACL ARN."
|
||||
}
|
||||
|
||||
@@ -27,3 +27,9 @@ variable "region" {
|
||||
description = "AWS region (provider-level; not a resource arg)."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enabled" {
|
||||
type = bool
|
||||
description = "Feature flag: enable/disable this module. Set to false to skip resource creation."
|
||||
default = true
|
||||
}
|
||||
|
||||
+5
-5
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
Nova uses declarative pipeline contracts (YAML) as the single source of truth. Both Gitea and GitHub workflows implement the same contract (byte-identical). The shell runner (`scripts/run_ci.sh`) mirrors the CI pipeline locally so that every stage that runs in CI can be reproduced on a developer machine without a forge.
|
||||
Nova uses declarative pipeline contracts (YAML) as the single source of truth. GitHub workflows implement the same contract (byte-identical across forges). The shell runner (`scripts/run_ci.sh`) mirrors the CI pipeline locally so that every stage that runs in CI can be reproduced on a developer machine without a forge.
|
||||
|
||||
## Existing Pipelines
|
||||
|
||||
@@ -20,7 +20,7 @@ Nova uses declarative pipeline contracts (YAML) as the single source of truth. B
|
||||
|
||||
## How to Wire a Pipeline
|
||||
|
||||
1. Create byte-identical workflow YAMLs in `.gitea/workflows/<name>.yml` and `.github/workflows/<name>.yml`.
|
||||
1. Create the workflow YAML in `.github/workflows/<name>.yml`.
|
||||
2. Both workflows must implement the same stages, commands, triggers, and runner declared in the contract.
|
||||
3. `scripts/run_ci.sh` mirrors `ci.yml` locally so the same stages run without a forge.
|
||||
4. Consumer repos reference the deploy pipeline via `uses: acdl/.github/workflows/deploy.yml@vX.Y`.
|
||||
@@ -29,17 +29,17 @@ Nova uses declarative pipeline contracts (YAML) as the single source of truth. B
|
||||
|
||||
- `scripts/run_ci.sh` — local CI mirror that runs the `ci.yml` stages.
|
||||
- `scripts/run_platform.sh` — platform pipeline runner that implements the `contract.yml` stages.
|
||||
- Workflow YAMLs in `.gitea/workflows/` and `.github/workflows/`.
|
||||
- Workflow YAMLs in `.github/workflows/`.
|
||||
- Schemas in `schemas/` (`pipeline.schema.json`, `deploy-pipeline.schema.json`).
|
||||
|
||||
## How to Test Pipelines
|
||||
|
||||
- `tests/test_pipeline_contract.py` — validates each pipeline YAML against its schema, asserts workflow conformance (byte-identical Gitea/GitHub workflows with the same stages/commands/triggers), and tests `scripts/run_ci.sh` execution against the contract.
|
||||
- `tests/test_pipeline_contract.py` — validates each pipeline YAML against its schema, asserts workflow conformance (byte-identical workflows with the same stages/commands/triggers), and tests `scripts/run_ci.sh` execution against the contract.
|
||||
|
||||
## Adding a New Pipeline
|
||||
|
||||
1. Create `pipelines/<name>.yml` using the structure above.
|
||||
2. Create or extend the schema in `schemas/` for the new pipeline shape.
|
||||
3. Create byte-identical workflow YAMLs in `.gitea/workflows/<name>.yml` and `.github/workflows/<name>.yml`.
|
||||
3. Create the workflow YAML in `.github/workflows/<name>.yml`.
|
||||
4. Extend `scripts/run_ci.sh` if a local mirror of the new pipeline is needed.
|
||||
5. Write or extend tests in `tests/test_pipeline_contract.py` to assert schema validity and workflow conformance.
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
# Nova Central CI Pipeline Contract (v1.5)
|
||||
#
|
||||
# This is the single source of truth for the CI/CD pipeline. Both
|
||||
# .gitea/workflows/ci.yml (Gitea Actions, dev) and
|
||||
# .github/workflows/ci.yml (dev) and
|
||||
# .github/workflows/ci.yml (GitHub Actions, production) implement the
|
||||
# stages, commands, triggers, and runner declared here.
|
||||
# scripts/run_ci.sh mirrors the same stages for shell reproducibility.
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# The contract does NOT replace workflow YAML syntax — it declares the
|
||||
# *intent* that the forge-specific workflows implement. The workflow files
|
||||
# use Gitea/GitHub Actions syntax (checkout, setup-python, run blocks);
|
||||
# use GitHub Actions syntax (checkout, setup-python, run blocks);
|
||||
# this contract declares what those blocks must contain.
|
||||
#
|
||||
# Validated against schemas/pipeline.schema.json.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#
|
||||
# This file is the declarative pipeline spec (a contract, not an executable
|
||||
# workflow). The executable workflow is .github/workflows/deploy.yml
|
||||
# (GitHub Actions) / .gitea/workflows/deploy.yml (Gitea Actions), which
|
||||
# (GitHub Actions), which
|
||||
# implements these stages by invoking scripts/run_platform.sh.
|
||||
#
|
||||
# Validated against schemas/deploy-pipeline.schema.json.
|
||||
|
||||
@@ -18,8 +18,8 @@ name: acdl-modules-lifecycle
|
||||
# real apply→modify→destroy against live AWS. The CI VPC apply/destroy
|
||||
# jobs are skipped in plan mode (nothing is applied).
|
||||
#
|
||||
# Both Gitea (.gitea/workflows/modules-lifecycle.yml) and GitHub
|
||||
# (.github/workflows/modules-lifecycle.yml) implement this contract
|
||||
# GitHub
|
||||
# (.github/workflows/modules-lifecycle.yml) implements this contract
|
||||
# byte-identically.
|
||||
|
||||
triggers:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user