Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b8fbd995a9 | |||
| ea44fdb9d6 | |||
| e14818875c | |||
| f496dd9c24 | |||
| 0d22b89a7b | |||
| 75e9e479db | |||
| d199204367 | |||
| 6a64b2b337 | |||
| 9274b4b87f | |||
| 25ddc894c2 | |||
| 156431c80a | |||
| 631244458f | |||
| 81b731ed17 | |||
| cc6071ee53 | |||
| d1ff6934c6 | |||
| ccbccb02ac | |||
| 574e6cb189 | |||
| 358aa62c3a | |||
| ff416777f9 | |||
| 94891af6ee | |||
| 072ac83ef6 | |||
| c6036ca433 | |||
| 38eb01d266 | |||
| 0404988465 | |||
| dbca694f55 | |||
| 71f0f1a05d | |||
| ce751313a7 | |||
| 5b5e24d535 | |||
| 85c500e45a | |||
| 301aa2c8d8 |
@@ -1,11 +1,9 @@
|
||||
{
|
||||
"phase": 0,
|
||||
"stage": "plan",
|
||||
"milestone": "v1.21",
|
||||
"stage": "grill",
|
||||
"milestone": "v1.23",
|
||||
"phase_role": "pre_execution",
|
||||
"attempts": 0,
|
||||
"updated_at": "2026-08-11T00:01:00Z",
|
||||
"milestone_complete": false,
|
||||
"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."
|
||||
"updated_at": "2026-08-11T23:30:00Z",
|
||||
"project": "acdl"
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
# CLARIFY — v1.23 (auto-resolved, full autonomy)
|
||||
|
||||
8 ambiguities identified, all auto-resolved at confidence ≥ 0.6.
|
||||
No human escalation (full autonomy). All decisions logged below.
|
||||
|
||||
## C1 — Speaker notes source for HTML comments (conf 0.95)
|
||||
**Ambiguity:** The plain `.md` has `> **Speaker notes:**` and
|
||||
`> **Transition:**` blocks per slide; talking points live in a separate
|
||||
file. Which content goes into the `<!-- ... -->` comments?
|
||||
**Resolution:** Extract `> **Speaker notes:**` and `> **Transition:**`
|
||||
blocks from the plain `.md` and embed each slide's as
|
||||
`<!-- Speaker notes: ... -->` before the next `---` separator. Talking
|
||||
points come from `talking-points.md` (the 3-6 bullets per slide)
|
||||
embedded as `<!-- Talking points: ... -->`. Both are Marp HTML comments
|
||||
(excluded from slide rendering; the `talking-points.md` stays as the
|
||||
standalone synced aid).
|
||||
|
||||
## C2 — python-pptx dependency placement (conf 0.9)
|
||||
**Ambiguity:** `pyproject.toml` has `[project.optional-dependencies]`
|
||||
`test`. Where does `python-pptx` go?
|
||||
**Resolution:** Add a new optional-dependency group
|
||||
`slides = ["python-pptx>=0.6.23"]`. Keeps the base `dependencies`
|
||||
minimal (the render script is a docs-only concern, not a runtime
|
||||
dep). CI installs via `pip install -e .[slides]`. The `render_pptx.py`
|
||||
script imports `pptx` at module load (not a hard failure if absent —
|
||||
the script prints a clear "pip install -e .[slides]" message and exits
|
||||
1).
|
||||
|
||||
## C3 — Benefit callout markdown representation (conf 0.9)
|
||||
**Ambiguity:** Marp markdown can't natively produce arbitrary `<div>`.
|
||||
How is the `.benefit` class applied?
|
||||
**Resolution:** Use Marp's HTML-in-markdown support — write benefit
|
||||
lines as `<div class="benefit">text</div>` directly in the markdown
|
||||
(Marp passes through HTML blocks). The inline `style:` block targets
|
||||
`.benefit`. The `**Benefit:**` prefix is removed.
|
||||
|
||||
## C4 — Image inlining MIME types (conf 0.95)
|
||||
**Ambiguity:** What MIME types does `inline_images.py` handle?
|
||||
**Resolution:** The deck references `.png` files only (mermaid
|
||||
renders). `inline_images.py` MIME-sniffs by extension:
|
||||
`.png`→`image/png`, `.svg`→`image/svg+xml`, `.jpg/.jpeg`→`image/jpeg`,
|
||||
`.gif`→`image/gif`; fallback `application/octet-stream`. Only relative
|
||||
`src="assets/..."` paths are inlined (absolute/`http(s)://` URLs are
|
||||
left alone).
|
||||
|
||||
## C5 — render_slides.sh step ordering (conf 0.9)
|
||||
**Ambiguity:** Where do the new inline-images + python-pptx steps go?
|
||||
**Resolution:** Step 1 mermaid → PNG (unchanged); Step 2 MARP → HTML +
|
||||
PPTX (drop `--theme`); Step 3 inline images into HTML; Step 4
|
||||
python-pptx → `*-python.pptx`; Step 5 stage all. The inline step runs
|
||||
only on the HTML (not the PPTX — both PPTX formats embed media in
|
||||
their zip by construction).
|
||||
|
||||
## C6 — "penetrate" absence test scope (conf 0.95)
|
||||
**Ambiguity:** How is "penetrate" absence asserted?
|
||||
**Resolution:** `grep -ri penetrat docs/presentations/` returns nothing
|
||||
(covers `.md`, `-marp.md`, `talking-points.md`, `.html`; `.pptx` is
|
||||
binary so excluded). A new test `test_no_penetrate_term` asserts this.
|
||||
|
||||
## C7 — attach_release_asset.py dual-PPTX (conf 0.85)
|
||||
**Ambiguity:** Does the release attach both PPTX files?
|
||||
**Resolution:** Yes — attach both `.pptx` (MARP image-of-slide) and
|
||||
`-python.pptx` (structured). Minimal change: loop over both filenames.
|
||||
The MARP PPTX remains the "primary" attachment (first); the python
|
||||
PPTX is secondary (comparison artifact).
|
||||
|
||||
## C8 — Wave ordering (conf 0.85)
|
||||
**Ambiguity:** Can P1 (consolidate) and P2 (style) parallelize?
|
||||
**Resolution:** No — both edit `-marp.md` with a serial dependency: P1
|
||||
establishes the single doc (deletes the plain `.md`, adds HTML-comment
|
||||
speaker notes); P2 edits that single doc's frontmatter + benefit
|
||||
callouts. Order: P1 → P2 → (P3 + P4 parallel: P3 edits
|
||||
`scripts/inline_images.py` + `render_pptx.py` + `render_slides.sh` +
|
||||
`pyproject`; P4 edits the deck markdown — zero file overlap) → P5 →
|
||||
P6. P3 depends on P2's render-script `--theme` drop. P4 depends on
|
||||
P1's consolidated doc.
|
||||
+176
-866
File diff suppressed because it is too large
Load Diff
+215
-87
@@ -1,34 +1,222 @@
|
||||
---
|
||||
project: acdl
|
||||
milestone: v1.18
|
||||
generated_at: 2026-08-06
|
||||
milestone: v1.23
|
||||
generated_at: 2026-08-11
|
||||
generator: lead-developer
|
||||
verification_toolchain:
|
||||
typecheck: "python3 -m py_compile core/submission_readiness.py mcp/atelier/server.py && python3 -m jsonschema schemas/submission-readiness.schema.json"
|
||||
test: "pytest tests/test_submission_readiness.py tests/test_atelier_mcp.py # REQ-220 + REQ-225"
|
||||
build: "bash scripts/render_deck.sh docs/presentations/nova-no-humans-platform-marp.md # HTML + PPTX (D-142)"
|
||||
typecheck: "python3 -m py_compile scripts/inline_images.py scripts/render_pptx.py tests/test_slides_pipeline.py"
|
||||
test: "pytest tests/test_slides_pipeline.py # REQ-263..275"
|
||||
build: "bash scripts/render_slides.sh nova-autonomous-cloud-delivery # HTML + Marp PPTX; then python3 scripts/render_pptx.py # structured PPTX"
|
||||
note: |
|
||||
v1.18 adds the Citizen Developer & Production-Grade Guidance surface:
|
||||
submission-readiness gate, Atelier-derived skills, the Atelier MCP server
|
||||
(plugin-registry, stdio), and PPTX-as-first-class-artifact deck automation.
|
||||
Three active personas: lead-developer (coordination + decks + RACI/scope
|
||||
docs), backend-engineer (MCP server + submission-readiness validator +
|
||||
render/attach scripts), data-engineer (submission-readiness schema if it
|
||||
touches contract storage / DynamoDB shape). frontend-engineer stays
|
||||
deactivated (v1.18 has no frontend; decks are markdown = lead-developer
|
||||
territory). The MCP plugin-registry is a backend pattern, so a separate
|
||||
mcp-engineer persona is NOT added — it folds into backend-engineer.
|
||||
v1.23 is the Nova Deck Cleanup & Python PPTX — a docs/render/test
|
||||
NFR milestone. Two active personas: lead-developer (deck markdown
|
||||
consolidation + inline Marp style CSS + README + .ciagent metadata),
|
||||
backend-engineer (Python scripts inline_images.py + render_pptx.py
|
||||
via python-pptx + render_slides.sh updates + tests + CI YAML +
|
||||
attach_release_asset.py extension). frontend-engineer stays
|
||||
deactivated (decks are markdown + Marp CSS = lead-developer
|
||||
territory, per v1.17/v1.18/v1.22 precedent). No data-engineer (no
|
||||
schema/DB changes). No new personas (the work splits cleanly into
|
||||
narrative+CSS+docs and Python+bash+tests+CI).
|
||||
---
|
||||
|
||||
# ACDL — Persona Roster (v1.18 Citizen Developer & Production-Grade Guidance)
|
||||
# ACDL — Persona Roster (v1.23 Nova Deck Cleanup & Python PPTX)
|
||||
|
||||
> v1.18 roster. Three active personas + one deactivated. The MCP server
|
||||
> plugin-registry (D-140) is a backend pattern, not a new persona — it
|
||||
> folds into backend-engineer. v1.17 precedent (frontend-engineer
|
||||
> deactivated, decks are markdown = lead-developer territory) is upheld.
|
||||
> v1.23 roster. Two active personas + two deactivated. This is a
|
||||
> docs/render/test NFR milestone: the work is deck markdown
|
||||
> consolidation, Marp inline `style:` CSS (reverting from the standalone
|
||||
> `nova-sp-theme.css` to `theme: default` + inline block), two Python
|
||||
> render scripts (`inline_images.py` stdlib image inlining +
|
||||
> `render_pptx.py` structured PPTX via python-pptx), test updates, CI
|
||||
> YAML, README rewrite, and the `attach_release_asset.py` extension to
|
||||
> dual-PPTX. frontend-engineer stays deactivated (Marp CSS is a static
|
||||
> stylesheet, not a React/Next.js component system — D-148 precedent).
|
||||
> No data-engineer (no schema/DB/ORM changes).
|
||||
|
||||
## Active personas
|
||||
|
||||
### lead-developer
|
||||
- **Domain:** coordination + deck content + inline CSS
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** [] (no framework — owns process + narrative + Marp inline CSS + markdown + README)
|
||||
- **Constraints:** ["pragmatic", "battle-tested defaults", "no fabrication (NORTH_STAR honesty model)", "do not change the 4-beat arc", "do not re-introduce badges/version/internal citations", "port the reference deck's exact inline style CSS (the clean look)"]
|
||||
- **Territory:**
|
||||
- `docs/presentations/nova-autonomous-cloud-delivery-marp.md` (REQ-263..275 — deck consolidation: merge plain .md into -marp.md, trim word count, remove "penetrate")
|
||||
- `docs/presentations/nova-autonomous-cloud-delivery.md` (DELETE — consolidated into -marp.md)
|
||||
- `docs/presentations/nova-autonomous-cloud-delivery-talking-points.md` (sync to final slide structure)
|
||||
- `docs/presentations/README.md` (rewrite 4-step → 3-step process for single-document + dual-PPTX pipeline)
|
||||
- `docs/presentations/assets/nova-sp-theme.css` (RETIRE from render; keep as reference file)
|
||||
- `.ciagent/**` (PROJECT, ROADMAP, REQUIREMENTS, RESEARCH, PLAN, GRILL, PERSONAS, REVIEW, CHECKPOINT)
|
||||
- **Reason:** Owns the deck markdown consolidation (plain `.md` +
|
||||
`-marp.md` → single `-marp.md` with speaker notes as HTML comments),
|
||||
the inline `style:` CSS block (porting the reference deck's exact
|
||||
CSS — the "clean look"), the word-count trim, the "penetrate"
|
||||
removal, the talking-points sync, the README rewrite, and all
|
||||
CIAgent metadata. Is the only persona that touches `.ciagent/**` and
|
||||
the deck markdown/CSS. The inline `style:` block is a Marp
|
||||
frontmatter stylesheet, not a frontend component system (D-148
|
||||
precedent from v1.22).
|
||||
- **Phase-specific flag:** none (active for all of P0–P-final).
|
||||
|
||||
### backend-engineer
|
||||
- **Domain:** Python render scripts + bash + tests + CI
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** ["python-pptx", "bash", "pytest", "marp-cli", "mermaid-cli", "base64/re/mimetypes (stdlib)"]
|
||||
- **Constraints:** ["pin CLI versions (no @latest in workflows-src/slides.yml — currently unpinned, must fix)", "python-pptx>=0.6.23 minimum", "stdlib-only for inline_images.py (no external image lib)", "tests must catch the theme-default + inline-style regression (the gap that let v1.22's standalone-theme drift through)", "no raw curl with shell-env tokens"]
|
||||
- **Territory:**
|
||||
- `scripts/inline_images.py` (NEW — stdlib base64 image inlining into rendered HTML)
|
||||
- `scripts/render_pptx.py` (NEW — structured editable PPTX via python-pptx)
|
||||
- `scripts/render_slides.sh` (update: drop --theme nova-sp-theme.css; add inline_images.py + render_pptx.py invocations)
|
||||
- `scripts/attach_release_asset.py` (extend to accept multiple file paths: both .pptx + -python.pptx)
|
||||
- `tests/test_slides_pipeline.py` (REQ-262 successor — invert theme tests, retarget CSS tests to inline style block, delete source-md tests, update slide count)
|
||||
- `workflows-src/slides.yml` (add python-pptx install step; pin @latest → @4.5.0/@11.16.0; add -python.pptx to commit list)
|
||||
- `pyproject.toml` (add python-pptx>=0.6.23 to [project.optional-dependencies] test)
|
||||
- **Reason:** Owns the Python render scripts (`inline_images.py` is
|
||||
stdlib regex + base64; `render_pptx.py` is python-pptx — a backend
|
||||
Python library, not a frontend framework). The render_slides.sh
|
||||
updates (drop `--theme`, add the two Python script invocations) and
|
||||
the CI YAML (add python-pptx install, pin versions, add
|
||||
-python.pptx to commit list) are backend/scripting tasks. The test
|
||||
suite updates (invert the theme-default test, retarget CSS tests to
|
||||
the inline `style:` block, delete the source-md tests) are the gap
|
||||
that let v1.22's standalone-theme drift through — backend-engineer
|
||||
owns closing it. python-pptx is new to v1.23; backend-engineer's
|
||||
frameworks list gains it.
|
||||
- **Phase-specific flag:** none (active for P2 scripts, P5 tests; light
|
||||
touch on P0/P-final).
|
||||
|
||||
## Deactivated personas
|
||||
|
||||
### frontend-engineer
|
||||
- **Active:** false
|
||||
- **Domain:** frontend
|
||||
- **Frameworks:** ["react", "next.js"] (inert — no territory)
|
||||
- **Constraints:** ["component-first", "server-components", "minimal-client-js"] (inert)
|
||||
- **Territory:** [] (no territory in v1.23)
|
||||
- **Reason:** v1.23 has no frontend; decks are markdown + Marp inline
|
||||
CSS (lead-developer territory); deactivated per PERSONAS.md
|
||||
v1.17/v1.18/v1.22 precedent. The inline `style:` block is a Marp
|
||||
frontmatter stylesheet (CSS rules in the markdown frontmatter), not
|
||||
a React/Next.js component system — it stays lead-developer
|
||||
territory. No reactivation trigger.
|
||||
|
||||
### data-engineer
|
||||
- **Active:** false
|
||||
- **Domain:** data
|
||||
- **Frameworks:** [] (inert)
|
||||
- **Constraints:** [] (inert)
|
||||
- **Territory:** [] (no territory in v1.23)
|
||||
- **Reason:** v1.23 has no schema/DB/ORM changes. The milestone is
|
||||
docs + Python scripts + bash + tests + CI only. No reactivation
|
||||
trigger.
|
||||
|
||||
## Roster decisions
|
||||
|
||||
### D-163 (0.95): Inline Marp `style:` block is lead-developer territory, not frontend-engineer
|
||||
The inline `style:` block in the Marp frontmatter is a static CSS
|
||||
stylesheet (a block of CSS rules in the markdown frontmatter, applied
|
||||
by Marp to the rendered slides), not a React/Next.js component system.
|
||||
The v1.17/v1.18/v1.22 precedent (decks are markdown = lead-developer
|
||||
territory; the theme CSS is a Marp stylesheet, not a frontend framework
|
||||
— D-148) extends to the inline `style:` block. frontend-engineer's
|
||||
frameworks (react, next.js) are irrelevant to Marp frontmatter CSS.
|
||||
**Decision:** inline `style:` block stays lead-developer territory.
|
||||
Confidence 0.95 — the only counter-argument is that CSS is "frontend,"
|
||||
but Marp frontmatter CSS is a static stylesheet authored in the
|
||||
markdown source, not a component system.
|
||||
|
||||
### D-164 (0.90): No new personas for v1.23
|
||||
The work is markdown + inline CSS + Python scripts + bash + tests + CI
|
||||
YAML + README. All of this is within the two active personas' range
|
||||
(lead-developer: markdown + CSS + README + metadata; backend-engineer:
|
||||
Python + bash + tests + CI). Creating a separate "slides-engineer" or
|
||||
"pptx-engineer" persona would fragment ownership of the deck markdown
|
||||
(lead) and the render scripts (backend). The python-pptx work is
|
||||
unambiguously backend (a Python library + script), even though the
|
||||
slide layout decisions within `render_pptx.py` are co-owned with lead-
|
||||
developer. **Decision:** no new personas. Confidence 0.90 — follows
|
||||
v1.22 D-149 precedent.
|
||||
|
||||
### Territory-overlap resolution (co-ownership)
|
||||
|
||||
| Path | Primary | Co-owner | Why |
|
||||
|------|---------|----------|-----|
|
||||
| `scripts/render_pptx.py` | backend-engineer (Python code + python-pptx API) | lead-developer (slide layout decisions: which image where, font sizes, bullet structure) | The script is backend (Python); the slide-by-slide layout decisions within it are design decisions that reflect lead-developer's deck ownership. `warn` enforcement — cross-territory edits logged, not blocked. |
|
||||
| `scripts/render_slides.sh` | backend-engineer (bash script) | lead-developer (the inline `style:` block content it renders) | The script is backend; the CSS it renders is lead-developer's. |
|
||||
| `tests/test_slides_pipeline.py` | backend-engineer (test code) | lead-developer (assertions reflect deck structure + inline CSS) | The test code is backend; the assertions (slide count, inline style rules, theme-default) reflect lead-developer's deck/CSS decisions. |
|
||||
| `docs/presentations/README.md` | lead-developer (process narrative) | backend-engineer (build commands + render script invocations) | The process narrative is lead; the build commands + script names are backend. |
|
||||
|
||||
## Domain priority (v1.23)
|
||||
|
||||
`lead-developer → backend-engineer`
|
||||
|
||||
Rationale: the deck markdown consolidation + inline CSS (lead) is the
|
||||
binding constraint — the render scripts (backend) can't be finalized
|
||||
until the deck structure is stable (slide count, inline style). The
|
||||
inline `style:` block must be ported + verified before the render
|
||||
pipeline (HTML + PPTX) is re-run. Backend (scripts + tests + CI)
|
||||
follows once the deck + CSS are settled. The dual-PPTX pipeline is
|
||||
wired last, once the deck renders clean with the inline style.
|
||||
|
||||
---
|
||||
|
||||
## Historical rosters
|
||||
|
||||
<details>
|
||||
<summary>v1.22 roster (Nova Deck Layout Fix) — superseded by v1.23</summary>
|
||||
|
||||
### Active personas (v1.22)
|
||||
|
||||
### lead-developer
|
||||
- **Domain:** coordination + deck content
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** [] (no framework — owns process + narrative + CSS + markdown)
|
||||
- **Constraints:** ["pragmatic", "battle-tested defaults", "no fabrication (NORTH_STAR honesty model)", "do not change the 4-beat arc", "do not re-introduce badges/version/internal citations"]
|
||||
- **Territory:**
|
||||
- `docs/presentations/assets/nova-sp-theme.css` (REQ-254,255,256 — theme CSS)
|
||||
- `docs/presentations/nova-autonomous-cloud-delivery-marp.md` (REQ-261 — deck content)
|
||||
- `docs/presentations/nova-autonomous-cloud-delivery.md` (REQ-261 — source of truth)
|
||||
- `docs/presentations/nova-autonomous-cloud-delivery-talking-points.md` (REQ-261)
|
||||
- `docs/presentations/README.md` (REQ-261 — slide-count convention)
|
||||
- `docs/presentations/assets/mmd/*.mmd` (REQ-259,260 — mermaid re-layout)
|
||||
- `.ciagent/**` (PROJECT, ROADMAP, REQUIREMENTS, RESEARCH, PLAN, GRILL, PERSONAS, REVIEW, CHECKPOINT)
|
||||
- **Reason:** Owns the theme CSS (the root cause), the deck markdown
|
||||
(trim/split overflowing slides), the mermaid re-layout, the talking
|
||||
points, the README, and all CIAgent metadata. Is the only persona
|
||||
that touches `.ciagent/**` and the deck markdown/CSS.
|
||||
- **Phase-specific flag:** none (active for all of P0–P6).
|
||||
|
||||
### backend-engineer
|
||||
- **Domain:** render scripts + tests
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** ["bash", "pytest", "marp-cli", "mermaid-cli"]
|
||||
- **Constraints:** ["pin CLI versions (no @latest)", "2x scale + transparent bg for mermaid", "tests must catch layout regressions", "no raw curl with shell-env tokens"]
|
||||
- **Territory:**
|
||||
- `scripts/render_slides.sh` (REQ-257,258 — pin versions, 2x scale)
|
||||
- `scripts/render_deck.sh` (REQ-257 — DELETE)
|
||||
- `tests/test_slides_pipeline.py` (REQ-262 — layout/aspect-ratio/theme-structural tests)
|
||||
- `.github/workflows/slides.yml` (if references to render_deck.sh need removal)
|
||||
- **Reason:** Owns the render pipeline (bash scripts) and the test
|
||||
suite. The layout/aspect-ratio/theme-structural tests (REQ-262) are
|
||||
the gap that let this regression through — backend-engineer owns
|
||||
closing that gap. Pinning CLI versions and adding 2x scale are
|
||||
backend/scripting tasks.
|
||||
- **Phase-specific flag:** none (active for P2, P5; light touch on P0/P6).
|
||||
|
||||
### D-148 (v1.22): Theme CSS is lead-developer territory, not frontend-engineer
|
||||
### D-149 (v1.22): No new personas for v1.22
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>v1.18 roster (Citizen Developer & Production-Grade Guidance) — superseded</summary>
|
||||
|
||||
### Active personas (v1.18)
|
||||
|
||||
### lead-developer
|
||||
- **Domain:** coordination
|
||||
- **Active:** true
|
||||
@@ -45,92 +233,32 @@ verification_toolchain:
|
||||
- `docs/scope.md` (REQ-216)
|
||||
- `docs/skills.md` (REQ-222 — the index page, not the skill files themselves)
|
||||
- `docs/submission-readiness.md` (REQ-219 — citizen-developer-facing copy; co-owned with backend-engineer for the reason-code catalog)
|
||||
- **Reason:** Owns CIAgent metadata, the milestone narrative, the RACI +
|
||||
PDLC-scope statements (REQ-215/216), the deck (21 slides, S&P theme
|
||||
regression check vs P1, CAP-024), the skills index page (REQ-222), and
|
||||
the citizen-developer-facing submission-readiness doc (REQ-219). Is
|
||||
the only persona that touches `.ciagent/**` and the deck markdown.
|
||||
- **Phase-specific flag:** none (active for all of P0–P7).
|
||||
|
||||
### backend-engineer
|
||||
- **Domain:** backend
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** ["mcp (Python SDK v2)", "pydantic", "jsonschema", "urllib"]
|
||||
- **Constraints:** ["api-first", "strict-typing", "plugin-registry extensible (D-140)", "stdio now / HTTP-ready (D-135)", "no stack traces to citizen developers (REQ-218)"]
|
||||
- **Territory:**
|
||||
- `mcp/atelier/server.py` (REQ-223)
|
||||
- `mcp/atelier/plugins/**/*.py` (REQ-223 — principles.py, validation.py)
|
||||
- `mcp/atelier/vendor/**` (REQ-224 — vendored Atelier snapshot)
|
||||
- `mcp/atelier/VERSION.md` + `mcp/atelier/README.md` (REQ-224)
|
||||
- `scripts/update_atelier_vendor.sh` (REQ-224)
|
||||
- `core/submission_readiness.py` (REQ-218 — the validator, invoked as `contract_ingestor.py --check-readiness`)
|
||||
- `scripts/render_deck.sh` (REQ-228 — HTML + PPTX render)
|
||||
- `scripts/attach_release_asset.py` (REQ-228 — Gitea release asset upload)
|
||||
- `core/submission_readiness.py` (REQ-218)
|
||||
- `scripts/render_deck.sh` (REQ-228)
|
||||
- `scripts/attach_release_asset.py` (REQ-228)
|
||||
- `tests/test_atelier_mcp.py` (REQ-225)
|
||||
- `tests/test_submission_readiness.py` (REQ-220)
|
||||
- `docs/submission-readiness.md` (REQ-219 — reason-code catalog section; co-owned with lead-developer for the narrative)
|
||||
- **Reason:** Owns the MCP server (plugin-registry, stdio, vendored
|
||||
Atelier), the submission-readiness validator (extends
|
||||
`contract_ingestor.py --check-readiness`, D-133), the render/attach
|
||||
scripts (D-142 trigger), and the two new test files. The MCP
|
||||
plugin-registry (D-140) is a backend pattern — no separate
|
||||
mcp-engineer persona is created; backend-engineer owns it.
|
||||
- **Phase-specific flag:** none (active for P1 deck-render, P3 validator,
|
||||
P5 MCP server, P6 scripts).
|
||||
|
||||
### data-engineer
|
||||
- **Domain:** data
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** ["jsonschema", "dynamodb (item shape)"]
|
||||
- **Constraints:** ["schema-first", "superset-gate NOT duplicate (PROJECT.md hard constraint)", "W3.E per-env mandatory table is the source of truth"]
|
||||
- **Territory:**
|
||||
- `schemas/**` (REQ-217 — `submission-readiness.schema.json` is the new schema; existing schemas untouched)
|
||||
- `core/lambda/contract_ingestor.py` (the `--check-readiness` subcommand wiring, D-133 — the validator is in `core/submission_readiness.py` but the ingestor dispatches to it; co-owned with backend-engineer)
|
||||
- **Reason:** Owns the submission-readiness JSON Schema (REQ-217) — it
|
||||
is a schema artifact, data-engineer territory. The schema is a
|
||||
*superset gate above* `contract.schema.json`, not a duplicate (it
|
||||
references contract fields, does not redefine them). The
|
||||
per-env-mandatory table comes from W3.E (the locked decision). The
|
||||
ingestor wiring is co-owned with backend-engineer (the dispatch point
|
||||
is backend; the schema it validates against is data).
|
||||
- **Phase-specific flag:** none (active for P3 schema + ingestor wiring).
|
||||
- `schemas/**` (REQ-217)
|
||||
- `core/lambda/contract_ingestor.py` (co-owned with backend-engineer)
|
||||
|
||||
## Deactivated personas
|
||||
### D-143 (v1.18): Fold mcp-engineer into backend-engineer
|
||||
|
||||
### frontend-engineer
|
||||
- **Active:** false
|
||||
- **Domain:** frontend
|
||||
- **Frameworks:** ["react", "next.js"] (inert — no territory)
|
||||
- **Constraints:** ["component-first", "server-components", "minimal-client-js"] (inert)
|
||||
- **Territory:** [] (no territory in v1.18)
|
||||
- **Reason:** v1.18 has no frontend; decks are markdown (lead-developer
|
||||
territory); deactivated per PERSONAS.md v1.17 precedent. v1.18's
|
||||
observability stays PowerBI / external (Out of Scope: "A Nova-built
|
||||
frontend / dashboard"). The MCP server exposes tools to an AI agent,
|
||||
not a web UI. No reactivation trigger in this milestone.
|
||||
|
||||
## Roster decisions
|
||||
|
||||
### D-143 (0.90): Fold mcp-engineer into backend-engineer
|
||||
The MCP plugin-registry (D-140: `plugins/<name>.py register(mcp)`) is a
|
||||
backend code pattern — Python modules, type hints, stdio transport,
|
||||
urllib for the Gitea asset API. It shares nothing with the data domain
|
||||
(schemas/DynamoDB) and is not a new engineering discipline. Creating a
|
||||
separate `mcp-engineer` persona would fragment ownership of the server +
|
||||
its tests + the render/attach scripts (all backend). **Decision:** fold
|
||||
into backend-engineer. backend-engineer's `frameworks` list gains
|
||||
`mcp (Python SDK v2)`. Confidence 0.90 — the only counter-argument is
|
||||
that MCP is a distinct protocol skill, but the SDK v2 API surface
|
||||
(`@mcp.tool()` + type hints) is small and well within backend-engineer's
|
||||
range (it's the same Pydantic/FastAPI-style pattern the persona already
|
||||
knows).
|
||||
|
||||
### Territory-overlap resolution (co-ownership)
|
||||
|
||||
| Path | Primary | Co-owner | Why |
|
||||
|------|---------|----------|-----|
|
||||
| `docs/submission-readiness.md` | lead-developer (narrative + examples) | backend-engineer (reason-code catalog, REQ-218 codes) | The doc is citizen-developer-facing copy (lead) but the reason-code catalog (MISSING_TAGS, ENV_MISSING_MANDATORY, AGENTIC_MISSING_INTENT, MISSING_APP_SOURCE, POLICY_PRECONDITION_MISSING) is backend (it mirrors the validator's return codes). |
|
||||
| `core/lambda/contract_ingestor.py` | backend-engineer (dispatch wiring) | data-engineer (the schema it validates against) | D-133 places the `--check-readiness` subcommand on the ingestor (backend dispatch), but the readiness schema it loads is data-engineer territory. |
|
||||
| `schemas/submission-readiness.schema.json` | data-engineer (schema artifact) | backend-engineer (the validator must match it) | The schema is data-engineer's; the validator (REQ-218) is backend-engineer's and must stay in sync with it. |
|
||||
</details>
|
||||
+407
-1031
File diff suppressed because it is too large
Load Diff
@@ -1419,3 +1419,161 @@ wrong commit standard, wrong repo.
|
||||
| D-145 | Trigger = manual-only (`--release` / `RELEASE_CONFIRMED=1`). | The 2nd release is a deliberate human action, not a CI side-effect. The gate guarantees it can never fire from Gitea Actions, GitHub Actions, or accidental invocation. | Script exits 2 without `--release`. |
|
||||
| D-146 | Domain grouping = 13 fixed-order domains by path prefix; messages map positionally over CHANGED domains only. | Avoids the kitchen-sink commit; gives `~/nova` a reviewable, conventional history tailored to platform consumers. Positional-over-changed mapping lets the human supply exactly the messages needed, in domain order, without padding for unchanged domains. | `--list-domains` prints order; `--dry-run` previews; count-mismatch errors clearly. |
|
||||
| D-147 | coreci / Atelier review gate = deferred this milestone. | The vendored Atelier (`mcp/atelier/vendor`) could review the synced tree before commit and block on P0, but that's an additive hardening step, not part of establishing the pipeline. Deferred to a future milestone. | Sync ships consumer contents as-is; no review gate. |
|
||||
|
||||
### CLARIFY auto-resolved parameters (full autonomy)
|
||||
|
||||
The following ambiguities were identified and auto-resolved at full
|
||||
autonomy (no human escalation needed — confidence > 0.6 threshold):
|
||||
|
||||
1. **Fix scope** — comprehensive (theme CSS + render scripts + mermaid
|
||||
re-layout + deck content + tests) vs. minimal. **Resolved: comprehensive.**
|
||||
The root cause spans all four layers; a theme-only fix would leave
|
||||
the extreme-aspect-ratio diagrams and the stale `render_deck.sh`
|
||||
unfixed. Confidence: 0.95.
|
||||
|
||||
2. **Pipeline depth** — full pipeline (SPECIFY→CLARIFY→RESEARCH→PLAN→
|
||||
GRILL→EXECUTE→VERIFY→SHIP) vs. lighter path. **Resolved: full pipeline.**
|
||||
This is a new milestone (v1.22); the full pipeline ensures the plan
|
||||
is grilled and the audit trail is complete. Confidence: 0.9.
|
||||
|
||||
3. **Mermaid diagram fixes** — re-layout to LR + re-render vs. CSS-only
|
||||
fix. **Resolved: re-layout to LR + re-render at 2x transparent.**
|
||||
The `telemetry-live-ops.mmd` uses `flowchart TB` (produced a 1024×1628
|
||||
PNG — aspect 0.63); the README (line 168) explicitly says to use
|
||||
horizontal layouts for wide diagrams. CSS-only cannot fix the aspect
|
||||
ratio. Confidence: 0.95.
|
||||
|
||||
4. **`render_deck.sh` disposition** — fix (add `--theme`) vs. delete.
|
||||
**Resolved: delete.** The README already documents `render_slides.sh`
|
||||
as canonical; `render_deck.sh` is unreferenced by the build-commands
|
||||
section and is a footgun (produces unthemed output). Confidence: 0.9.
|
||||
|
||||
5. **Slide count change** — keep 18 main + 1 appendix vs. split
|
||||
overflowing slides. **Resolved: split slides 3 and 8** (18 → 20 main
|
||||
+ 1 appendix). The `test_marp_deck_slide_count` test + README
|
||||
convention are updated to match. Confidence: 0.85.
|
||||
|
||||
No human escalation. All decisions logged with confidence scores above
|
||||
the 0.6 threshold.
|
||||
|
||||
## Objective for Milestone v1.22 (active — Nova Deck Layout Fix)
|
||||
|
||||
v1.22 fixes the systemic layout/formatting problems in the Nova
|
||||
presentation deck that made every slide look "out of whack" after the
|
||||
v1.21 P5 re-render. A full investigation determined the root cause is
|
||||
**not a P5 regression** — the `nova-sp-theme.css` has had zero `section`
|
||||
padding since it was authored (it declares `/* @theme nova-sp */` as a
|
||||
comment, not the `@theme` directive, and does not `@import` Marp's
|
||||
default theme, so Marp's default `section { padding: 56px 64px }` never
|
||||
applies). Combined with `overflow:hidden` (silent clip), a blunt
|
||||
`img { max-height: 320px }` rule, header+footer chrome on every slide,
|
||||
and two new P5 diagrams with extreme aspect ratios (13.52× and 0.63×),
|
||||
8 of 19 slides overflow and the rest look jammed against the edges.
|
||||
|
||||
This milestone is a **comprehensive fix** across four layers: (1) the
|
||||
theme CSS (padding, overflow handling, aspect-ratio-aware image rules,
|
||||
title-slide chrome suppression, paragraph/list/table spacing); (2) the
|
||||
render scripts (delete the stale unthemed `render_deck.sh`, pin
|
||||
marp-cli/mermaid-cli versions, add 2x scale + transparent bg to
|
||||
mermaid); (3) the two problematic mermaid diagrams (re-layout to LR +
|
||||
2-row wrap); (4) the deck content (trim/split the 8 overflowing slides,
|
||||
remove the redundant `header:` from frontmatter). It also adds the
|
||||
**layout/aspect-ratio/theme-structural tests** that were missing — the
|
||||
gap that let this regression through undetected.
|
||||
|
||||
**Milestone type:** NFR (all phases are fix/docs/test — no feat/breaking).
|
||||
Tags run on the **v1.21.x** patch line (previous minor per
|
||||
branch-strategy): `v1.21.0` (P0) → `v1.21.1..v1.21.5` (P1–P5) →
|
||||
`v1.21.6` (P6 final = milestone release).
|
||||
|
||||
**Phase count:** 7 (P0 pre-execution + 5 execution + 1 final).
|
||||
|
||||
**Wave ordering:**
|
||||
- Wave 1 (P1 + P2, parallel): theme CSS + render scripts — no
|
||||
interdependency. P1 establishes the padding/overflow/image budget that
|
||||
P4's content trimming relies on; P2 fixes the render pipeline that P3's
|
||||
PNG re-render depends on.
|
||||
- Wave 2 (P3 + P4, parallel): mermaid re-layout + deck content. P3
|
||||
depends on P2 (2x scale flag); P4 depends on P1 (padding budget).
|
||||
- Wave 3 (P5): re-render HTML + PPTX + add tests. Depends on all above.
|
||||
- Wave 4 (P6): final review + audit + milestone ship.
|
||||
|
||||
**Hard constraints:**
|
||||
- DO NOT change the deck narrative or the 4-beat arc (Problem → Solution
|
||||
→ Proof → Roadmap + Ask) — only fix layout/formatting.
|
||||
- DO NOT re-introduce badges, version strings, or internal citations
|
||||
(D-###/REQ-###/.py paths) that v1.21 removed.
|
||||
- The slide count may change from 18 main + 1 appendix to 20 main + 1
|
||||
appendix (splitting slides 3 and 8 to relieve overflow). The
|
||||
`test_marp_deck_slide_count` test + README "18 main + 1 appendix"
|
||||
convention must be updated to match.
|
||||
- PPTX remains a first-class committed artifact + release attachment.
|
||||
- No code changes outside `docs/presentations/`, `scripts/render*.sh`,
|
||||
and `tests/test_slides_pipeline.py`.
|
||||
|
||||
### Requirements
|
||||
|
||||
New requirements REQ-254..REQ-262 — see `REQUIREMENTS.md` §v1.22. Summary:
|
||||
|
||||
- **REQ-254:** Theme CSS — add `section` padding + overflow handling.
|
||||
- **REQ-255:** Theme CSS — aspect-ratio-aware image rules (replace blunt
|
||||
`max-height:320px`).
|
||||
- **REQ-256:** Theme CSS — title-slide chrome suppression + paragraph/
|
||||
list/table spacing tightening.
|
||||
- **REQ-257:** Render scripts — delete `render_deck.sh` (or fix `--theme`);
|
||||
pin marp-cli/mermaid-cli versions.
|
||||
- **REQ-258:** `render_slides.sh` — add `-s 2 -b transparent` to mermaid-cli
|
||||
(README spec).
|
||||
- **REQ-259:** Re-layout `telemetry-live-ops.mmd` from `flowchart TB` →
|
||||
`flowchart LR`; re-render PNG at 2x transparent.
|
||||
- **REQ-260:** Re-layout `platform-pipeline.mmd` to 2-row subgraph wrap;
|
||||
re-render PNG at 2x transparent.
|
||||
- **REQ-261:** Trim/split 8 overflowing slides (3, 5, 6, 8, 9, 12, 15,
|
||||
A1) + remove redundant `header:` from frontmatter.
|
||||
- **REQ-262:** Re-render HTML + PPTX + add layout/aspect-ratio/theme-
|
||||
structural tests.
|
||||
|
||||
## v1.23 — Nova Deck Cleanup & Python PPTX
|
||||
|
||||
> **Active milestone.** NFR (docs/render/test only; no features).
|
||||
> Branch: `milestone/v1.23-deck-cleanup-python-pptx`. Tags run on the
|
||||
> **v1.22.x** patch line: `v1.22.0` (P0) → `v1.22.1..v1.22.5` (P1–P5) →
|
||||
> `v1.22.6` (P6 final = milestone release).
|
||||
|
||||
Driven by user feedback that the deck looked "out of whack" and the
|
||||
desire to return to the clean, well-formatted style of the old
|
||||
`the-developer-experience.html`. Investigation revealed the "clean"
|
||||
reference was itself MARP output (using Marp's built-in `default` theme
|
||||
+ an inline `style:` block); the current deck's standalone
|
||||
`nova-sp-theme.css` re-derives all base spacing from scratch and had a
|
||||
zero-padding bug (fixed in v1.22, but the standalone approach is
|
||||
fragile). The milestone delivers:
|
||||
|
||||
- **Single-document consolidation** — `*-marp.md` becomes the sole
|
||||
source of truth; the plain `.md` is deleted; speaker notes + talking
|
||||
points are embedded as Marp HTML comments.
|
||||
- **Clean style restoration** — revert to `theme: default` + inline
|
||||
`style:` block (S&P palette); `nova-sp-theme.css` retained as a
|
||||
reference, retired from render.
|
||||
- **Self-contained HTML** — base64-inline all images for
|
||||
redistribution.
|
||||
- **Parallel python-pptx generator** — structured, editable, S&P-themed
|
||||
PPTX alongside the MARP image-of-slide PPTX.
|
||||
- **Targeted word-count trim** + "penetrate" term removal.
|
||||
|
||||
**Phase count:** 7 (P0 pre-execution + 5 execution + 1 final).
|
||||
|
||||
**Hard constraints:**
|
||||
- DO NOT change the deck narrative or the 4-beat arc (Problem → Solution
|
||||
→ Proof → Roadmap + Ask) — only trim word count.
|
||||
- DO NOT re-introduce badges, version strings, or internal citations.
|
||||
- DO NOT remove MARP — it stays for HTML + PPTX; python-pptx runs in
|
||||
parallel.
|
||||
- `nova-sp-theme.css` is retained (not deleted) as a styling reference.
|
||||
|
||||
### Requirements
|
||||
|
||||
New requirements REQ-263..REQ-275 — see `REQUIREMENTS.md` §v1.23.
|
||||
Summary: consolidation (REQ-263,264), style restoration (REQ-265,266,267),
|
||||
image inlining (REQ-268), python-pptx generator (REQ-269,270), word-count
|
||||
trim + "penetrate" removal (REQ-271,272), CI/tests/README (REQ-273,274,275).
|
||||
|
||||
+321
-9
@@ -1707,12 +1707,324 @@ release; attach the PPTX.
|
||||
|
||||
| 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 |
|
||||
| REQ-245 | P2 | complete |
|
||||
| REQ-246 | P1 | complete |
|
||||
| REQ-247 | P1 | complete |
|
||||
| REQ-248 | P2 | complete |
|
||||
| REQ-249 | P2 | complete |
|
||||
| REQ-250 | P4 | complete |
|
||||
| REQ-251 | P3 | complete |
|
||||
| REQ-252 | P2 | complete |
|
||||
| REQ-253 | P5 | complete |
|
||||
|
||||
## v1.22 — Nova Deck Layout Fix
|
||||
|
||||
> Fixes the systemic layout/formatting problems in the Nova presentation
|
||||
> deck that made every slide look "out of whack" after the v1.21 P5
|
||||
> re-render. Root cause (per investigation): `nova-sp-theme.css` has zero
|
||||
> `section` padding (it declares `/* @theme nova-sp */` as a comment, not
|
||||
> the `@theme` directive, and does not `@import` Marp's default theme, so
|
||||
> Marp's default `section { padding: 56px 64px }` never applies). Combined
|
||||
> with `overflow:hidden` (silent clip), a blunt `img { max-height: 320px }`
|
||||
> rule, header+footer chrome on every slide, and two new P5 diagrams with
|
||||
> extreme aspect ratios (13.52× and 0.63×), 8 of 19 slides overflow and
|
||||
> the rest look jammed against the edges. This is NOT a P5 regression —
|
||||
> the theme CSS is byte-identical between P3 and P5; P5's denser content
|
||||
> made the pre-existing theme flaws visible.
|
||||
>
|
||||
> Comprehensive fix across four layers: theme CSS, render scripts, mermaid
|
||||
> diagrams, deck content. Adds the layout/aspect-ratio/theme-structural
|
||||
> tests that were missing (the gap that let this through).
|
||||
>
|
||||
> Tags run on the v1.21.x line (milestone v1.22 → tags v1.21.0, v1.21.1, …).
|
||||
|
||||
### REQ-254 — Theme CSS: section padding + overflow handling
|
||||
|
||||
`docs/presentations/assets/nova-sp-theme.css` adds a `section` padding
|
||||
rule so content is not jammed against the slide edges. The padding
|
||||
reserves space for the header (top) and footer (bottom) chrome: e.g.
|
||||
`section { padding: 48px 56px 40px; }`. The theme also adds explicit
|
||||
overflow handling on `section` so dense content is not silently clipped
|
||||
by the marpit base `overflow:hidden` — either `overflow: auto` as an
|
||||
authoring-time signal, or a documented shrink-to-fit rule. The fix does
|
||||
NOT re-introduce Marp's default theme via `@import` (the theme remains
|
||||
standalone); it explicitly sets the padding the default would have
|
||||
provided.
|
||||
|
||||
### REQ-255 — Theme CSS: aspect-ratio-aware image rules
|
||||
|
||||
The blunt `img { max-height: 320px }` rule is replaced with an
|
||||
aspect-ratio-aware rule that does not break the Marp `w:`/`h:` directives:
|
||||
`img { max-width: 100%; max-height: 380px; object-fit: contain; }`. A
|
||||
`.wide` / `.tall` class convention is added for diagrams (wide diagrams:
|
||||
`max-height: 280px`; tall diagrams: `max-height: 480px`) so authors can
|
||||
opt into the right bound per diagram instead of fighting a single blunt
|
||||
rule. The `w:900` directive on a tall image (slide 9) no longer gets
|
||||
silently overridden by `max-height`.
|
||||
|
||||
### REQ-256 — Theme CSS: title-slide chrome + spacing tightening
|
||||
|
||||
- `section.title header, section.title footer { display: none; }` — the
|
||||
title slide and appendix slide no longer render header/footer chrome
|
||||
that collides with content (the `<!-- _class: title -->` +
|
||||
`<!-- _paginate: false -->` directives only suppress the page number,
|
||||
not the chrome).
|
||||
- `section h2 + p { margin-top: 0.2em; }` — tightens the spacing between
|
||||
the `## Slide N — Title` heading and the bold lead paragraph that
|
||||
follows it on every content slide (reclaims ~22px per slide).
|
||||
- `section p { margin: 0.4em 0; }` — reduces default `<p>` margins
|
||||
(~1em top/bottom) that waste vertical space on dense slides.
|
||||
- `ol` styling added (matches `ul`/`li`).
|
||||
- Table cell padding reduced to `4px 8px` for tables with ≥8 rows (via
|
||||
a `table.dense` class or a `:nth-child` heuristic) so 10-13 row tables
|
||||
(slides 8, 12, A1) fit.
|
||||
- `@media print` overrides added for PPTX export fidelity.
|
||||
|
||||
### REQ-257 — Render scripts: delete render_deck.sh + pin CLI versions
|
||||
|
||||
`scripts/render_deck.sh` is **deleted** (it omits `--theme`, relying on
|
||||
the frontmatter `theme: nova-sp` which Marp cannot resolve as a custom
|
||||
theme without `--theme-set` — it falls back to the default theme,
|
||||
producing unthemed output). The README already documents
|
||||
`render_slides.sh` as the canonical script. Both `render_slides.sh` and
|
||||
the deleted `render_deck.sh` references are removed from any docs/tests.
|
||||
`render_slides.sh` pins marp-cli and mermaid-cli to specific versions
|
||||
(replace `@latest` with pinned versions) to prevent uncontrolled
|
||||
boilerplate-CSS drift like the P3→P5 HTML diff.
|
||||
|
||||
### REQ-258 — render_slides.sh: 2x scale + transparent bg for mermaid
|
||||
|
||||
The mermaid-cli invocation in `scripts/render_slides.sh` (lines 51-55)
|
||||
adds `-s 2 -b transparent` to match the README spec (line 193). This
|
||||
produces crisp 2x PNGs with transparent backgrounds instead of the
|
||||
current 1x renders (e.g. `platform-pipeline.png` is only 1568px wide
|
||||
instead of the 3136px a 2x render would produce).
|
||||
|
||||
### REQ-259 — Re-layout telemetry-live-ops.mmd to LR
|
||||
|
||||
`docs/presentations/assets/mmd/telemetry-live-ops.mmd` is rewritten from
|
||||
`flowchart TB` (top-bottom, produced a 1024×1628 PNG — aspect 0.63, tall)
|
||||
to `flowchart LR` (left-right) with subgraph row-wrapping per the README
|
||||
convention (line 168). The re-rendered PNG (at 2x transparent, per
|
||||
REQ-258) has an aspect ratio in [1.2, 2.5] suitable for a 16:9 slide.
|
||||
The Marp deck's `![w:900]` directive on slide 9 is updated to match the
|
||||
new dimensions (or replaced with `![h:320]` if the diagram remains
|
||||
taller than wide after re-layout).
|
||||
|
||||
### REQ-260 — Re-layout platform-pipeline.mmd to 2-row wrap
|
||||
|
||||
`docs/presentations/assets/mmd/platform-pipeline.mmd` is rewritten to
|
||||
wrap the 10-node LR chain into 2 rows via mermaid subgraphs (or split
|
||||
into two stages: static-scan row + runtime-scan row). The current
|
||||
1568×116 PNG (aspect 13.52, ultra-wide/short) renders as a 1000×74px
|
||||
thin strip at `![w:1000]` — node text is illegible. The re-rendered
|
||||
PNG (at 2x transparent) has an aspect ratio in [1.2, 2.5] suitable for
|
||||
a 16:9 slide.
|
||||
|
||||
### REQ-261 — Trim/split 8 overflowing slides + remove redundant header
|
||||
|
||||
The 8 slides identified as overflowing 720px are trimmed or split:
|
||||
- **Slide 3** (Objectives + Anti-Goals): split into Slide 3a (4
|
||||
objectives) + Slide 3b (4 anti-goals). Main slide count 18 → 19.
|
||||
- **Slide 5** (RACI): apply `table.dense` class (from REQ-256) to
|
||||
reduce cell padding; keep 8 rows.
|
||||
- **Slide 6** (Pipeline): reduce to 3 bullets (the 4th is covered by
|
||||
the diagram, now legible after REQ-260).
|
||||
- **Slide 8** (Attestation Matrix): split into Slide 8a (qa concerns,
|
||||
3 rows) + Slide 8b (prod/dr concerns, 7 rows). Main slide count
|
||||
19 → 20.
|
||||
- **Slide 9** (Telemetry): reduce to 3 bullets; image now legible
|
||||
after REQ-259.
|
||||
- **Slide 12** (Deferred): reduce to 6 rows (merge the 3 "Live AWS
|
||||
re-provisioning" blockers into one row).
|
||||
- **Slide 15** (Quarter-by-Quarter): drop the "Grounding" column
|
||||
(redundant with the strategic objectives); 4 columns fit better.
|
||||
- **Appendix A1** (Glossary): apply `table.dense` class (16px font);
|
||||
keep 13 rows.
|
||||
|
||||
The Marp frontmatter `header:` line is removed (keep `footer:` +
|
||||
`paginate: true` only). The full 51-char deck title in BOTH header and
|
||||
footer on every slide is redundant chrome that eats vertical space;
|
||||
the footer alone suffices. The title slide and appendix already use
|
||||
`<!-- _class: title -->` which (after REQ-256) suppresses chrome.
|
||||
|
||||
The talking-points file is re-distilled to match the new slide
|
||||
structure (20 main + 1 appendix). The README "18 main + 1 appendix"
|
||||
convention (line 130) and `test_marp_deck_slide_count` are updated to
|
||||
assert 20 main + 1 appendix.
|
||||
|
||||
### REQ-262 — Re-render HTML + PPTX + add layout/aspect-ratio tests
|
||||
|
||||
- Run `bash scripts/render_slides.sh nova-autonomous-cloud-delivery` →
|
||||
re-render all mermaid PNGs (2x transparent) + HTML + PPTX. Verify
|
||||
slide count (20 main + 1 appendix = 21) and media embedding.
|
||||
- Add tests to `tests/test_slides_pipeline.py`:
|
||||
- `test_theme_css_has_section_padding` — assert `section` rule
|
||||
contains `padding`.
|
||||
- `test_theme_css_suppresses_title_chrome` — assert
|
||||
`section.title header` / `section.title footer` `display: none`.
|
||||
- `test_png_aspect_ratios_sane` — for every PNG in `assets/png/`,
|
||||
assert aspect ratio ∈ [1.2, 2.5] (catches the 13.52× and 0.63×
|
||||
outliers).
|
||||
- `test_render_slides_has_2x_scale` — assert `render_slides.sh`
|
||||
contains `-s 2` and `-b transparent`.
|
||||
- `test_render_deck_removed` — assert `render_deck.sh` does not
|
||||
exist.
|
||||
- `test_html_embeds_theme` — assert committed HTML contains
|
||||
`--sp-red` and `padding` in the inline `<style>`.
|
||||
- `test_html_slide_count_matches_marp` — parse HTML `<section>`
|
||||
count == marp deck slide count.
|
||||
- Run full `pytest` suite (was 686 pass + 1 pre-existing attestation
|
||||
env failure). `run_platform.sh --check-only` exits 0.
|
||||
- Milestone ship: tag the final phase on the v1.21.x line; create a
|
||||
release; attach the PPTX.
|
||||
|
||||
### Out of Scope (v1.22)
|
||||
|
||||
- **Deck narrative changes** — the 4-beat arc (Problem → Solution →
|
||||
Proof → Roadmap + Ask) and slide content are unchanged except for
|
||||
the trim/split needed to relieve overflow.
|
||||
- **Re-introduction of badges, version strings, or internal citations**
|
||||
— v1.21 removed these; v1.22 does not re-add them.
|
||||
- **Live pilot estate activation** — still deferred.
|
||||
- **ML anomaly-forecasting service** — still deferred.
|
||||
- **Multi-cloud (Azure/GCP) implementation** — still deferred.
|
||||
- **Tamper-evident ledger (S3 Object Lock + JWS)** — still deferred.
|
||||
|
||||
### v1.22 Traceability
|
||||
|
||||
| REQ | Phase | Status |
|
||||
|-----|-------|--------|
|
||||
| REQ-254 | P1 | complete |
|
||||
| REQ-255 | P1 | complete |
|
||||
| REQ-256 | P1 | complete |
|
||||
| REQ-257 | P2 | complete |
|
||||
| REQ-258 | P2 | complete |
|
||||
| REQ-259 | P3 | complete |
|
||||
| REQ-260 | P3 | complete |
|
||||
| REQ-261 | P4 | complete |
|
||||
| REQ-262 | P5 | complete |
|
||||
|
||||
## v1.23 — Nova Deck Cleanup & Python PPTX
|
||||
|
||||
> **NFR milestone** (docs/render/test only; no features). Tags run on the
|
||||
> **v1.22.x** line (milestone v1.23 → tags v1.22.0..v1.22.6). Final patch
|
||||
> `v1.22.6` = milestone release.
|
||||
>
|
||||
> Consolidates the deck to a single source-of-truth markdown document,
|
||||
> restores the clean S&P visual style (Marp `default` theme + inline
|
||||
> `style:` block, matching the old `the-developer-experience.html`),
|
||||
> embeds images as base64 in the HTML for redistribution, builds a
|
||||
> parallel structured python-pptx PPTX generator, and trims verbose
|
||||
> slides. `nova-sp-theme.css` is retained as a styling reference but
|
||||
> retired from the render path.
|
||||
|
||||
### Category: Consolidate Docs
|
||||
- **REQ-263:** `nova-autonomous-cloud-delivery-marp.md` becomes the sole
|
||||
source of truth. Speaker notes + talking points from the plain `.md`
|
||||
are folded into the deck as Marp HTML comments (`<!-- Speaker notes:
|
||||
... -->`, `<!-- Talking points: ... -->`). The plain
|
||||
`nova-autonomous-cloud-delivery.md` is deleted.
|
||||
- **REQ-264:** `nova-autonomous-cloud-delivery-talking-points.md` is kept
|
||||
as a standalone presenter aid, synced from the deck's `<!-- Talking
|
||||
points: -->` comments. Header note documents the mirror relationship.
|
||||
|
||||
### Category: Restore Clean Style
|
||||
- **REQ-265:** Revert deck frontmatter `theme: nova-sp` → `theme:
|
||||
default` and add an inline `style:` block porting the S&P visual
|
||||
language (palette #D6002A/#1B1B1B, Akkurat Pro font, black title slide
|
||||
with red top border, tables, blockquotes, code, aspect-ratio-aware
|
||||
images). Keep current structure (H2 + bold-lead, no header, no badges).
|
||||
- **REQ-266:** `nova-sp-theme.css` is retained as a styling reference
|
||||
(header comment documents its retired status). `render_slides.sh`
|
||||
drops the `--theme "$THEME_CSS"` argument; the inline `style:` block in
|
||||
frontmatter is the sole styling source at render time.
|
||||
- **REQ-267:** Benefit callouts on every slide are restyled: the
|
||||
`**Benefit:**` prefix is removed; the callout becomes a styled
|
||||
element (red top-rule + black italic text; white on title slides)
|
||||
using a `.benefit` class in the inline style block.
|
||||
|
||||
### Category: Inline Images
|
||||
- **REQ-268:** New `scripts/inline_images.py` (stdlib only: `base64`,
|
||||
`re`, `mimetypes`) post-processes the rendered HTML: finds all
|
||||
`<img src="assets/...">` relative paths, replaces each `src` with a
|
||||
`data:image/<mime>;base64,...` URI. HTML becomes self-contained
|
||||
(redistributable without the `assets/` folder). `render_slides.sh`
|
||||
invokes it after the MARP HTML render, before staging.
|
||||
|
||||
### Category: Python PPTX Generator
|
||||
- **REQ-269:** New `scripts/render_pptx.py` parses the consolidated
|
||||
`*-marp.md` and produces a structured, editable, S&P-themed PPTX
|
||||
(`nova-autonomous-cloud-delivery-python.pptx`) using `python-pptx`.
|
||||
16:9 slides; title slide (black bg, red top bar, white H1); content
|
||||
slides (red H2 title, bold lead, bullets, blockquote, embedded PNGs,
|
||||
native PPTX tables, benefit callouts). HTML-comment speaker
|
||||
notes/talking points are skipped. `python-pptx` added to
|
||||
`pyproject.toml`. `render_slides.sh` invokes it as a new step.
|
||||
- **REQ-270:** Both PPTX outputs (MARP image-of-slide + python
|
||||
structured) are produced by `render_slides.sh` and staged. CI
|
||||
workflows install `python-pptx` and commit both. `attach_release_asset.py`
|
||||
attaches both to the release.
|
||||
|
||||
### Category: Trim Word Count
|
||||
- **REQ-271:** Targeted word-count trim on ~8 verbose slides (1, 5, 7,
|
||||
8, 13, 14, 20, plus the appendix) — ~20-30% reduction on trimmed
|
||||
slides. Tables and short slides are untouched. The spirit of each
|
||||
slide is preserved.
|
||||
- **REQ-272:** The term "penetrate" (and derivatives) is removed from
|
||||
all presentation files. Slide 5's "Nova never penetrates it" phrase is
|
||||
removed with no replacement (slide 4 Anti-Goals already excludes the
|
||||
PDLC from scope). `grep -ri penetrat docs/presentations/` returns
|
||||
nothing.
|
||||
|
||||
### Category: CI, Tests, README
|
||||
- **REQ-273:** CI workflows (`workflows-src/slides.yml` + synced
|
||||
`.github`/`.gitea` copies) install `python-pptx`, run `render_slides.sh`
|
||||
(which produces HTML + both PPTX + inlined images), and commit all
|
||||
rendered artifacts. README documents the new pipeline.
|
||||
- **REQ-274:** `tests/test_slides_pipeline.py` is updated for the
|
||||
consolidated doc (no plain `.md`), default theme + inline style
|
||||
assertions (S&P visual properties, not theme filename),
|
||||
`nova-sp-theme.css` retained-as-reference assertion, image-inlining
|
||||
assertions (zero `src="assets/` references, ≥1 base64 per image),
|
||||
python-pptx output existence, benefit callout class, "penetrate"
|
||||
absence. New `tests/test_pptx_generator.py` asserts slide count, title
|
||||
colors, table rendering, image embedding.
|
||||
- **REQ-275:** `docs/presentations/README.md` is rewritten to document
|
||||
the single-document process (author `*-marp.md` → render HTML + both
|
||||
PPTX → talking points mirrored), inline `style:` approach,
|
||||
`nova-sp-theme.css` reference status, image inlining, and dual PPTX
|
||||
output.
|
||||
|
||||
### Out of Scope (v1.23)
|
||||
|
||||
- **Deck narrative / 4-beat arc changes** — the Problem → Solution →
|
||||
Proof → Roadmap + Ask structure is unchanged; only word count is
|
||||
trimmed.
|
||||
- **Re-introduction of badges, version strings, or internal citations**
|
||||
— v1.21 removed these; v1.23 does not re-add them.
|
||||
- **Removal of MARP** — MARP stays for HTML + PPTX; python-pptx runs in
|
||||
parallel for comparison.
|
||||
- **Removal of orphaned `developer-experience-*` assets** — deferred to
|
||||
a future cleanup phase (optional in v1.23 Phase 6 only if time
|
||||
permits).
|
||||
- **Mermaid render scoping** — the mermaid render step continues to
|
||||
render all `.mmd` files; scoping to referenced-only is deferred.
|
||||
|
||||
### v1.23 Traceability
|
||||
|
||||
| REQ | Phase | Status |
|
||||
|-----|-------|--------|
|
||||
| REQ-263 | P1 | pending |
|
||||
| REQ-264 | P1 | pending |
|
||||
| REQ-265 | P2 | pending |
|
||||
| REQ-266 | P2 | pending |
|
||||
| REQ-267 | P2 | pending |
|
||||
| REQ-268 | P3a | pending |
|
||||
| REQ-269 | P3b | pending |
|
||||
| REQ-270 | P3b | pending |
|
||||
| REQ-271 | P4 | pending |
|
||||
| REQ-272 | P4 | pending |
|
||||
| REQ-273 | P5 | pending |
|
||||
| REQ-274 | P5 | pending |
|
||||
| REQ-275 | P5 | pending |
|
||||
|
||||
@@ -2346,3 +2346,927 @@ committed directly).
|
||||
backend pattern (decorators, type hints, stdio, urllib). The SDK v2
|
||||
API surface is small and FastAPI/Pydantic-style (already in
|
||||
backend-engineer's range). D-143 logged in PERSONAS.md records this.
|
||||
|
||||
---
|
||||
|
||||
# v1.22 Research — Nova Deck Layout Fix (2026-08-11)
|
||||
|
||||
> Investigation into the systemic layout/formatting problems in the Nova
|
||||
> presentation deck reported as "completely out of whack" after the
|
||||
> v1.21 P5 re-render. This research IS the investigation — the findings
|
||||
> below are the empirical root-cause analysis that drives the v1.22
|
||||
> requirements (REQ-254..262).
|
||||
|
||||
## Background — why v1.22 exists
|
||||
|
||||
The v1.21 milestone shipped a refined deck (renamed to "Autonomous Cloud
|
||||
Delivery Platform", 4-beat arc, 18 main + 1 appendix slides). The P5
|
||||
phase re-rendered the HTML + PPTX and added two new mermaid diagrams
|
||||
(`platform-pipeline.png`, `telemetry-live-ops.png`). After P5, the user
|
||||
reported that the layout is "completely out of whack" and that "they all
|
||||
have layout issues." This research identifies the root cause and the fix
|
||||
scope.
|
||||
|
||||
## FINDING 1 — Theme CSS has ZERO section padding (CONFIDENCE: VERY HIGH)
|
||||
|
||||
`docs/presentations/assets/nova-sp-theme.css` line 1 is
|
||||
`/* @theme nova-sp */` — a **comment**, not the `@theme` directive that
|
||||
Marp uses to register a theme name. The theme does **not `@import`**
|
||||
Marp's default theme. Marp's built-in default theme applies
|
||||
`section { padding: 56px 64px; }`. Because this custom theme neither
|
||||
imports the default nor sets its own `padding`, the rendered `<section>`
|
||||
has **zero padding**.
|
||||
|
||||
**Verification:** grep for `padding:56px` / `padding:64px` /
|
||||
`padding:96px` in the rendered HTML returns **zero matches**. The only
|
||||
`section` rules in the rendered HTML are:
|
||||
- `section{width:1280px;height:720px;box-sizing:border-box;overflow:hidden;position:relative;...}`
|
||||
(marpit base — no padding)
|
||||
- `section{font-family:...;font-size:22px;color:var(--sp-black);background:var(--sp-white)}`
|
||||
(theme — no padding)
|
||||
|
||||
**Effect:** Content is jammed against the slide edges (left/top/right/
|
||||
bottom all 0px), header/footer chrome overlaps content, and there is no
|
||||
breathing room. This alone makes every slide look "out of whack."
|
||||
|
||||
## FINDING 2 — overflow:hidden silently clips dense content (CONFIDENCE: VERY HIGH)
|
||||
|
||||
The marpit base rule sets `overflow:hidden` on `section`. The theme adds
|
||||
no `overflow` override, no scaling, no shrink-to-fit. Any slide whose
|
||||
content exceeds 720px is **clipped with no visual indication**. Combined
|
||||
with zero padding, content-dense slides (tables, image+bullets) lose
|
||||
their bottom rows / benefit paragraphs.
|
||||
|
||||
**Per-slide overflow risk table** (available content height ≈ 720px −
|
||||
header(~35px) − footer(~35px) − padding(0px) = ~650px):
|
||||
|
||||
| # | Slide | Est. height | Fits? | Issue |
|
||||
|---|---|---|---|---|
|
||||
| 3 | Objectives + Anti-Goals | ~780px | NO | Densest text slide; nested list |
|
||||
| 5 | RACI (8-row × 5-col) | ~700px | NO | Cell text wraps to 2 lines |
|
||||
| 6 | Pipeline (image + 4 bullets) | ~750px | NO | Image + bullets overflow |
|
||||
| 8 | Attestation (10-row × 4-col) | ~780px | NO | Description column wraps |
|
||||
| 9 | Telemetry (image + 4 bullets) | ~720px | NO | Image + bullets overflow |
|
||||
| 12 | Deferred (8-row table) | ~720px | NO | Blocking-work column wraps |
|
||||
| 15 | Quarter-by-Quarter (5-col) | ~720px | NO | Wide table, long text |
|
||||
| A1 | Glossary (13-row × 3-col) | ~700px | NO | On title-class (dark bg) |
|
||||
| 1,4,10,11,13,16,17,18 | various | ~620px | TIGHT | Cramped with 0 padding |
|
||||
| 2,7,14 | various | ~520px | YES | Manageable density |
|
||||
|
||||
**8 of 19 slides overflow; 8 more are cramped.**
|
||||
|
||||
## FINDING 3 — Image aspect-ratio catastrophe on slides 6 & 9 (CONFIDENCE: HIGH)
|
||||
|
||||
The two new P5 PNGs have extreme, opposite aspect ratios:
|
||||
|
||||
- `platform-pipeline.png` = **1568×116** (aspect 13.52, ultra-wide/short).
|
||||
The deck uses `![w:1000]`. At width=1000px, height = 1000/13.52 =
|
||||
**74px**. The `max-height:320px` rule never engages. The image renders
|
||||
as a 1000×74 thin strip — text in nodes is nearly unreadable, and the
|
||||
10-node LR flowchart is squashed.
|
||||
|
||||
- `telemetry-live-ops.png` = **1024×1628** (aspect 0.63, tall). The deck
|
||||
uses `![w:900]`. At width=900px the natural height would be **1428px**
|
||||
— but `max-height:320px` clamps it, so the image actually renders at
|
||||
**~201×320**. The `w:900` directive is **completely overridden** by
|
||||
`max-height:320px`. The image is tiny and the explicit width is
|
||||
ignored. The `.mmd` uses `flowchart TB` (top-bottom) — exactly the
|
||||
failure mode the README (line 168) warns against.
|
||||
|
||||
## FINDING 4 — Header+footer chrome on every slide (CONFIDENCE: HIGH)
|
||||
|
||||
The frontmatter sets both `header:` and `footer:` to the full 51-char
|
||||
deck title "Nova — The Autonomous Cloud Delivery Platform" on **every**
|
||||
slide (including the title slide, which has `data-header`/`data-footer`
|
||||
attributes present but `_paginate: false` only suppresses the page
|
||||
number, not the header/footer). The theme gives header a `border-bottom`
|
||||
and footer a `border-top`, each consuming ~30-40px of vertical chrome.
|
||||
With zero section padding, the header text sits at the very top edge and
|
||||
the footer at the very bottom edge, visually colliding with slide
|
||||
content. This reduces the effective content area from 720px to roughly
|
||||
640-650px on every slide.
|
||||
|
||||
## FINDING 5 — render_deck.sh produces unthemed output (CONFIDENCE: MEDIUM-HIGH)
|
||||
|
||||
`scripts/render_deck.sh` (line 44) runs marp-cli **without `--theme`**,
|
||||
relying on the frontmatter `theme: nova-sp`. But `nova-sp` is **not a
|
||||
built-in Marp theme** — it's a custom CSS file. Marp resolves `theme:`
|
||||
frontmatter against its built-in theme registry (default, gaia, uncover)
|
||||
and registered custom themes via `--theme-set`. Without `--theme <file>`
|
||||
or `--theme-set`, Marp cannot resolve `nova-sp` and **falls back to the
|
||||
default theme** (or errors). The committed HTML was rendered by
|
||||
`render_slides.sh` (which correctly passes `--theme`), so the committed
|
||||
artifact is fine — but `render_deck.sh` is a stale, dangerous script
|
||||
that would produce an unthemed/default-themed deck if anyone ran it.
|
||||
The README (line 201) documents `render_slides.sh` as canonical;
|
||||
`render_deck.sh` is not mentioned in the build-commands section.
|
||||
|
||||
## FINDING 6 — render_slides.sh missing 2x scale + transparent bg (CONFIDENCE: HIGH)
|
||||
|
||||
`render_slides.sh` mermaid invocation (lines 51-55) does **NOT** pass
|
||||
`-s 2` (2x scale) or `-b transparent`, despite the README (line 193)
|
||||
documenting both as required. This is why `platform-pipeline.png` is
|
||||
only 1568px wide (1x) instead of 3136px (2x) — the rendered PNGs are
|
||||
lower resolution than the README specifies, contributing to illegibility
|
||||
when scaled.
|
||||
|
||||
## FINDING 7 — P5 marp-cli version bump (CONFIDENCE: LOW — not the cause)
|
||||
|
||||
The P3→P5 HTML diff is 831 changed lines, but the **theme CSS portion
|
||||
is byte-identical** (verified: `font-size:22px`, `max-height:320px`,
|
||||
`marpit-root-font-size:22px`, `--sp-red:#D6002A` all match; `sp-red`
|
||||
appears exactly once in both). The large diff is:
|
||||
- (a) marp-cli boilerplate (bespoke-marp presenter/overview/transition
|
||||
CSS) changed due to a marp-cli version bump (neither script pins a
|
||||
version — both use `@latest`), and
|
||||
- (b) content changes: title "No-Humans Infrastructure Platform" →
|
||||
"Autonomous Cloud Delivery Platform", footer "Act %{page}/5 — v1.20"
|
||||
→ deck title, slide count 20 → 19.
|
||||
|
||||
The version bump did **not** alter the slide layout engine or the theme
|
||||
rules. **This is not the regression source.** The layout problems are
|
||||
inherent to the theme CSS (zero padding, no overflow handling, blunt
|
||||
image rule) which has been unchanged. P5 made the content denser (new
|
||||
diagrams with extreme aspect ratios, longer deck-title header/footer)
|
||||
which made the pre-existing theme flaws more visible.
|
||||
|
||||
## FINDING 8 — Test coverage gaps (CONFIDENCE: VERY HIGH)
|
||||
|
||||
`tests/test_slides_pipeline.py` (268 lines) checks **static file
|
||||
properties only**:
|
||||
- Theme CSS file exists and contains `#D6002A` / `#1B1B1B`
|
||||
- Frontmatter references `nova-sp`, not `default`
|
||||
- `render_slides.sh` exists, is executable, invokes mermaid-cli + marp-cli
|
||||
- Every `.mmd` has a `.png`
|
||||
- No maturity badges, no version in footer, slide count = 18+1
|
||||
- No D-###/REQ-###/internal `.py` paths in slides
|
||||
|
||||
**What is NOT tested (the gaps that let layout regressions through):**
|
||||
1. NO rendered-dimension / overflow test — no test renders the HTML and
|
||||
checks that each slide's content height ≤ 720px.
|
||||
2. NO theme-CSS structural test — no test asserts `section` has
|
||||
`padding`, that `overflow` is handled, or that `img` rules don't
|
||||
conflict with `w:`/`h:` directives.
|
||||
3. NO image aspect-ratio / legibility test — no test checks that PNG
|
||||
dimensions are reasonable for a 16:9 slide.
|
||||
4. NO render-script theme-flag test — no test asserts `render_deck.sh`
|
||||
passes `--theme` (it doesn't), so the broken script passes CI.
|
||||
5. NO rendered-HTML structural assertion — no test parses the committed
|
||||
HTML to verify the theme is actually embedded.
|
||||
6. NO mermaid render-scale test — no test verifies PNGs are 2x scale.
|
||||
|
||||
**Conclusion:** A layout regression — including the current zero-padding,
|
||||
image-clamping, and table-overflow problems — would pass every existing
|
||||
test. This is why the user's "completely out of whack" report was not
|
||||
caught.
|
||||
|
||||
## Theme CSS gaps (summary)
|
||||
|
||||
1. NO `padding` on `section` (lines 21-26 set font/color/bg only).
|
||||
2. NO `overflow` handling on `section`.
|
||||
3. NO `@import` of a base theme (line 1 is a comment, not `@theme`).
|
||||
4. NO rule for the `h2` + bold-lead-paragraph pattern (default `<p>`
|
||||
margins waste ~44px each).
|
||||
5. Table cell padding `6px 10px` too generous for 10-13 row tables.
|
||||
6. `img { max-height: 320px }` is a blunt instrument that breaks `w:`
|
||||
directives on tall images and does nothing for ultra-wide images.
|
||||
7. Header/footer have no padding/margin — collide with content at 0
|
||||
section padding.
|
||||
8. `section.title` does not suppress header/footer.
|
||||
9. NO rule for `ol` (only `ul`/`li` styled).
|
||||
10. NO `@media print` overrides for PPTX export fidelity.
|
||||
|
||||
## Assumptions logged (v1.22)
|
||||
|
||||
- **A1 (0.95):** The theme CSS is the primary root cause. Adding
|
||||
`section { padding: 48px 56px 40px; }` alone would fix the "jammed
|
||||
against edges" look on all 19 slides. Confidence grounded in the
|
||||
grep verification (zero padding matches in rendered HTML).
|
||||
- **A2 (0.9):** The P5 re-render is NOT a regression — the theme CSS is
|
||||
byte-identical P3→P5. P5's denser content (new diagrams, longer
|
||||
header/footer) made pre-existing flaws visible. Grounded in the
|
||||
byte-level diff comparison.
|
||||
- **A3 (0.9):** `render_deck.sh` should be deleted, not fixed. The
|
||||
README already documents `render_slides.sh` as canonical; keeping a
|
||||
second broken script is a footgun. Grounded in the README build-
|
||||
commands section (line 201) which does not mention `render_deck.sh`.
|
||||
- **A4 (0.85):** Splitting slides 3 and 8 (18 → 20 main) is preferable
|
||||
to trimming content, because the content is leadership-relevant and
|
||||
should not be lost. The slide-count test + README convention are
|
||||
updated to match. Grounded in the overflow estimates (slides 3 and 8
|
||||
are the densest at ~780px).
|
||||
- **A5 (0.8):** Pinning marp-cli/mermaid-cli versions is necessary to
|
||||
prevent uncontrolled boilerplate-CSS drift. The exact pinned versions
|
||||
will be determined during P2 execution by testing which version
|
||||
produces stable output in this environment.
|
||||
|
||||
## Decisions surfaced (research → bound in CLARIFY)
|
||||
|
||||
All 5 CLARIFY decisions are grounded in these findings:
|
||||
- Comprehensive scope (FINDINGS 1-8 span 4 layers)
|
||||
- Full pipeline (new milestone, complete audit trail)
|
||||
- Re-layout to LR (FINDING 3 — TB produced 0.63 aspect)
|
||||
- Delete render_deck.sh (FINDING 5 — stale, unthemed)
|
||||
- Split slides 3+8 (FINDING 2 — densest overflow)
|
||||
|
||||
---
|
||||
|
||||
## v1.23 RESEARCH — Nova Deck Cleanup & Python PPTX
|
||||
|
||||
> Phase: 0 RESEARCH. Milestone v1.23 (Nova Deck Cleanup & Python PPTX).
|
||||
> docs/render/test NFR milestone. Surface: deck markdown, Marp inline
|
||||
> style CSS, Python render scripts, tests, CI YAML, README.
|
||||
> Researcher: ci-researcher. Sources: ACDL codebase (v1.22 tree) +
|
||||
> the deleted clean reference HTML at /root/gl/acdl/docs/presentations/
|
||||
> the-developer-experience.html + python-pptx docs + Marp rendered HTML
|
||||
> inspection.
|
||||
|
||||
### FINDING 1 — Marp `default` theme + inline `style:` block (the clean reference)
|
||||
|
||||
The deleted clean reference deck
|
||||
`/root/gl/acdl/docs/presentations/the-developer-experience.html`
|
||||
(commit eb43e08) used `theme: default` + an inline `style:` block in the
|
||||
Marp frontmatter. The exact inline CSS (extracted from the `data-style`
|
||||
attribute repeated on every `<section>` in the rendered HTML) is:
|
||||
|
||||
```css
|
||||
section {
|
||||
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||
font-size: 26px;
|
||||
color: #1B1B1B;
|
||||
}
|
||||
h1 { color: #D6002A; font-size: 40px; margin-bottom: 0.3em; }
|
||||
h2 { color: #D6002A; font-size: 32px; margin-bottom: 0.2em; }
|
||||
section.title { background: #1B1B1B; color: #fff; border-top: 8px solid #D6002A; }
|
||||
section.title h1 { color: #fff; }
|
||||
table { font-size: 22px; width: 100%; }
|
||||
th { background: #F0F0F0; }
|
||||
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 24px; }
|
||||
pre { font-size: 16px; line-height: 1.3; }
|
||||
code { font-size: 16px; }
|
||||
img { display: block; margin: 0 auto; max-height: 280px; }
|
||||
.badge {
|
||||
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||
font-size: 16px; font-weight: 600;
|
||||
}
|
||||
.planned { background: #fef3c7; color: #78350f; }
|
||||
```
|
||||
|
||||
**What Marp's built-in `default` theme provides for free** (from the
|
||||
embedded `@theme default` CSS in the reference HTML):
|
||||
- `section { width:1280px; height:720px; box-sizing:border-box; overflow:hidden; position:relative }`
|
||||
— slide dimensions + box model.
|
||||
- Base section typography: `font-family: var(--fontStack-sansSerif)`
|
||||
(system sans), `font-size: 16px`, `line-height: 1.5`, `color:
|
||||
var(--fgColor-default)`, `background: var(--bgColor-default)` (white).
|
||||
**Note: default does NOT set padding** — wait, correction: the
|
||||
`default` theme's embedded CSS in this Marp version does NOT include
|
||||
an explicit `padding` on `section`; the nova-sp-theme.css comment
|
||||
claiming `padding: 56px 64px` was for a different Marp version. The
|
||||
inline `style:` block above does not set padding either, implying the
|
||||
default theme's inheriting UA stylesheet padding or Marp's container
|
||||
provides it. **This is the key thing to verify in P2:** whether
|
||||
`theme: default` + the inline `style:` block produces padding that
|
||||
reserves header/footer chrome space. The v1.22 root-cause was ZERO
|
||||
padding with the standalone theme; the inline `style:` block above
|
||||
also does not set padding, so the clean look may have relied on the
|
||||
default theme's own padding (which Marp's default theme CSS
|
||||
*does* set: `section{padding:56px 64px}` is in the default theme's
|
||||
canonical CSS even if not visible in this rendered HTML's inlined
|
||||
subset — the rendered HTML strips the theme CSS into a `<style>` block
|
||||
at the top that we did not fully inspect). **Recommendation:** the
|
||||
inline `style:` block for v1.23 SHOULD explicitly set section padding
|
||||
(`padding: 48px 56px 40px` as v1.22 settled on) to be safe, OR verify
|
||||
the default theme provides it. The reference deck's clean look
|
||||
suggests the default theme's padding was adequate.
|
||||
- Pagination: `section::after { content: attr(data-marpit-pagination);
|
||||
bottom:0; right:0; padding:inherit }` — page numbers via CSS pseudo-
|
||||
element on `section[data-marpit-pagination]`. Free with `paginate:
|
||||
true`.
|
||||
- Header/footer chrome: `default` theme renders `header`/`footer`
|
||||
elements from frontmatter `header:`/`footer:` directives. The inline
|
||||
`style:` block does NOT suppress them on title slides (the reference
|
||||
deck's title slide has `<header>The Developer Experience</header>` +
|
||||
`<footer>Internal</footer>` visible). v1.22's `section.title header,
|
||||
section.title footer { display: none }` rule should be ported into the
|
||||
v1.23 inline `style:` block to keep title slides clean.
|
||||
- H1/H2 base sizing: `:is(h1, marp-h1){font-size:2em;margin-block:0.67em}`
|
||||
— the inline `style:` block overrides these with explicit px sizes.
|
||||
- Font-family: the default theme uses GitHub's `--fontStack-sansSerif`
|
||||
(system fonts); the inline `style:` overrides to Akkurat Pro stack.
|
||||
|
||||
**What the inline `style:` block must override** (not inherited from
|
||||
default): font-family (Akkurat Pro stack), font-size (26px vs 16px),
|
||||
font-color (#1B1B1B), H1/H2 colors (#D6002A), title-slide background
|
||||
(#1B1B1B + 8px red top border), table styling, blockquote styling,
|
||||
image max-height. **What it inherits for free:** slide dimensions
|
||||
(1280×720), pagination, header/footer rendering, base box model.
|
||||
|
||||
**Confidence: 0.95** (the CSS is read verbatim from the rendered
|
||||
`data-style` attribute on every `<section>`; the default theme
|
||||
inheritance is confirmed by the `data-theme="default"` attribute on
|
||||
every section).
|
||||
|
||||
### FINDING 2 — Marp HTML-in-markdown passthrough
|
||||
|
||||
Marp (via Marpit, the underlying markdown-it-based engine) **passes
|
||||
through raw HTML blocks** in markdown slides. Confirmed by the
|
||||
reference deck:
|
||||
`/root/gl/acdl/docs/presentations/the-developer-experience-marp.md`
|
||||
contains inline HTML like
|
||||
`<span class="badge planned">Planned</span>` inside slide bodies, and
|
||||
the rendered HTML (`the-developer-experience.html`) contains the
|
||||
verbatim `<span class="badge planned">Planned</span>` inside the
|
||||
`<section>` elements. The `.badge` and `.planned` classes are styled
|
||||
by the inline `style:` block (Finding 1).
|
||||
|
||||
**Gotchas confirmed:**
|
||||
- HTML blocks render correctly inside `## Slide N — Title` H2 slides
|
||||
(the reference deck's slide 5 has `<span class="badge planned">` in a
|
||||
table cell; slide 7 has it in a bullet list item).
|
||||
- HTML does NOT interfere with pagination (the `data-marpit-pagination`
|
||||
attribute is present on every paginated section regardless of HTML
|
||||
content).
|
||||
- HTML inline elements (`<span>`, `<div>`, `<strong>`) render; block
|
||||
elements (`<div class="benefit">text</div>`) also render — Marpit's
|
||||
markdown-it `html: true` option is on by default.
|
||||
- **Caveat:** Marp does NOT sanitize HTML by default (no DOMPurify);
|
||||
raw `<script>` would pass through too. For our use case (styling
|
||||
divs/spans) this is fine.
|
||||
- The current nova deck markdown does NOT use any `<div>` HTML blocks
|
||||
(`grep -c "<div" nova-autonomous-cloud-delivery-marp.md` = 0 in the
|
||||
slide body; only the bespoke-marp-osc div in the rendered HTML
|
||||
chrome). So the v1.23 plan to add `.benefit` class divs is a NEW
|
||||
pattern — it will work, but is untested in this repo's deck.
|
||||
|
||||
**Confidence: 0.95** (confirmed by direct inspection of the reference
|
||||
deck's source + rendered HTML; Marpit's html passthrough is documented
|
||||
behavior).
|
||||
|
||||
### FINDING 3 — python-pptx capabilities for the structured PPTX
|
||||
|
||||
python-pptx (the `python-pptx` PyPI package) supports all capabilities
|
||||
required for `scripts/render_pptx.py`. API calls confirmed against the
|
||||
python-pptx documentation (v1.0.2 latest; v0.6.23 is the established
|
||||
minimum):
|
||||
|
||||
(a) **16:9 slide dimensions:**
|
||||
```python
|
||||
from pptx import Presentation
|
||||
from pptx.util import Inches, Pt
|
||||
prs = Presentation()
|
||||
prs.slide_width = Inches(13.333) # 16:9 widescreen
|
||||
prs.slide_height = Inches(7.5)
|
||||
```
|
||||
|
||||
(b) **Slide background color (black for title slide):**
|
||||
```python
|
||||
from pptx.dml.color import RGBColor
|
||||
slide = prs.slides.add_slide(prs.slide_layouts[6]) # blank layout
|
||||
bg = slide.background
|
||||
bg.fill.solid()
|
||||
bg.fill.fore_color.rgb = RGBColor(0x1B, 0x1B, 0x1B) # sp-black
|
||||
```
|
||||
(Note: `slide.background` is available since python-pptx 0.6.19+.)
|
||||
|
||||
(c) **Colored rectangle as top border bar:**
|
||||
```python
|
||||
from pptx.enum.shapes import MSO_SHAPE
|
||||
from pptx.util import Inches
|
||||
shape = slide.shapes.add_shape(
|
||||
MSO_SHAPE.RECTANGLE,
|
||||
Inches(0), Inches(0), # left, top
|
||||
Inches(13.333), Inches(0.08) # width, height (8px ≈ 0.08in at 96dpi)
|
||||
)
|
||||
shape.fill.solid()
|
||||
shape.fill.fore_color.rgb = RGBColor(0xD6, 0x00, 0x2A) # sp-red
|
||||
shape.line.fill.background() # no border on the rectangle
|
||||
```
|
||||
|
||||
(d) **Text frames with font family/color/size (Akkurat Pro → Helvetica
|
||||
Neue → Arial fallback):**
|
||||
```python
|
||||
from pptx.util import Pt
|
||||
txBox = slide.shapes.add_textbox(Inches(0.5), Inches(0.5), Inches(12), Inches(1))
|
||||
tf = txBox.text_frame
|
||||
p = tf.paragraphs[0]
|
||||
run = p.add_run()
|
||||
run.text = "Slide title"
|
||||
run.font.name = "Akkurat Pro"
|
||||
run.font.size = Pt(40)
|
||||
run.font.bold = True
|
||||
run.font.color.rgb = RGBColor(0xD6, 0x00, 0x2A)
|
||||
# Font fallback: python-pptx sets a single font.name; PowerPoint's own
|
||||
# font substitution handles the fallback chain. To set a fallback
|
||||
# explicitly, set the font's `<a:latin>` + `<a:ea>` + `<a:cs>` typeface
|
||||
# attributes, OR rely on PowerPoint rendering "Akkurat Pro" → missing →
|
||||
# substitutes Helvetica Neue / Arial per the OS font substitution table.
|
||||
# The simplest approach: set name="Akkurat Pro"; PowerPoint does the
|
||||
# fallback. For an explicit fallback, manipulate the XML:
|
||||
from pptx.oxml.ns import qn
|
||||
rPr = run._r.get_or_add_rPr()
|
||||
latin = rPr.find(qn('a:latin'))
|
||||
if latin is None:
|
||||
latin = rPr.makeelement(qn('a:latin'), {})
|
||||
rPr.append(latin)
|
||||
latin.set('typeface', 'Akkurat Pro')
|
||||
# (PowerPoint reads only the first typeface; fallback is OS-level.)
|
||||
```
|
||||
**Key constraint:** python-pptx does NOT support a CSS-style font
|
||||
fallback stack. Setting `run.font.name` sets one typeface; PowerPoint's
|
||||
font substitution handles the fallback when the font is missing. This
|
||||
is adequate for our use case (Akkurat Pro is the named font; on
|
||||
systems without it, PowerPoint substitutes Helvetica/Arial).
|
||||
|
||||
(e) **Bullet lists:**
|
||||
```python
|
||||
tf = txBox.text_frame
|
||||
for i, item in enumerate(bullets):
|
||||
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
|
||||
p.text = item
|
||||
p.level = 0 # bullet level (0 = top)
|
||||
# Bullet character: python-pptx does not expose a high-level bullet
|
||||
# API; the default paragraph style from the layout provides bullets.
|
||||
# For explicit bullet control, manipulate the XML <a:buChar> or
|
||||
# set p.font + use the layout's list style.
|
||||
```
|
||||
**Constraint:** python-pptx has limited high-level bullet support; the
|
||||
`paragraph` level controls indentation but the bullet glyph comes from
|
||||
the layout's list style. For a blank layout (layout 6), paragraphs
|
||||
have NO bullet by default — you must add `<a:buChar>` to the paragraph
|
||||
properties XML, or use a layout that has bullets. **Recommendation:**
|
||||
use `slide_layouts[1]` (Title and Content) for bullet slides, which
|
||||
provides bullets natively; or inject `<a:buChar char="•"/>` via XML.
|
||||
|
||||
(f) **Native tables (`add_table`):**
|
||||
```python
|
||||
from pptx.util import Inches
|
||||
rows, cols = len(data), len(headers)
|
||||
table = slide.shapes.add_table(rows, cols, Inches(0.5), Inches(1.5),
|
||||
Inches(12), Inches(4)).table
|
||||
# Headers
|
||||
for c, h in enumerate(headers):
|
||||
table.cell(0, c).text = h
|
||||
# style header cell
|
||||
cell = table.cell(0, c)
|
||||
cell.fill.solid()
|
||||
cell.fill.fore_color.rgb = RGBColor(0xF0, 0xF0, 0xF0)
|
||||
# Body
|
||||
for r, row in enumerate(data, start=1):
|
||||
for c, val in enumerate(row):
|
||||
table.cell(r, c).text = str(val)
|
||||
```
|
||||
**Confirmed:** `add_table` is fully supported since 0.6.19; returns a
|
||||
`Table` object with `.cell(r,c).text` + `.fill`.
|
||||
|
||||
(g) **Embedding images (`add_picture`, auto-embeds in ppt/media/):**
|
||||
```python
|
||||
slide.shapes.add_picture(
|
||||
"docs/presentations/assets/png/platform-pipeline.png",
|
||||
Inches(1), Inches(1),
|
||||
width=Inches(11), height=Inches(5)
|
||||
)
|
||||
```
|
||||
**Confirmed:** python-pptx auto-embeds the image binary into the
|
||||
`ppt/media/` directory inside the .pptx zip; the slide XML references
|
||||
it via a relationship ID. This is native — no manual zip manipulation
|
||||
needed. The image is copied once; multiple slides referencing the
|
||||
same image share the media file.
|
||||
|
||||
(h) **Italic text:**
|
||||
```python
|
||||
run.font.italic = True # supported since 0.6.0
|
||||
```
|
||||
|
||||
**Version constraint:** `python-pptx>=0.6.23` is the right minimum
|
||||
(stable release with `slide.background`, `add_table`, `add_picture`
|
||||
all mature). The latest is 1.0.2 (2024); 0.6.23 (2021) is safe. The
|
||||
`slide.background` API landed in 0.6.19; `add_table` in 0.6.19;
|
||||
`add_picture` since 0.6.0. **Recommendation:** pin
|
||||
`python-pptx>=0.6.23` in `pyproject.toml` `[project.optional-
|
||||
dependencies] test`.
|
||||
|
||||
**Confidence: 0.90** (API calls confirmed against python-pptx docs;
|
||||
the font fallback + bullet limitations are the residual uncertainty —
|
||||
both have XML workarounds).
|
||||
|
||||
### FINDING 4 — Image inlining (stdlib-only `base64` + `re` + `mimetypes`)
|
||||
|
||||
The current rendered HTML
|
||||
(`docs/presentations/nova-autonomous-cloud-delivery.html`) embeds
|
||||
images as **plain `<img src="assets/png/...">` tags with relative
|
||||
paths** — NOT base64-inlined. Confirmed by grep: `<img
|
||||
src="assets/png/platform-pipeline.png" ...>` (slide 7), `<img
|
||||
src="assets/png/telemetry-live-ops.png" ...>` (slide 11). They are
|
||||
NOT SVG `xlink:href`; they are standard `<img>` elements inside the
|
||||
SVG `<foreignObject>` wrapper that Marp uses for slide rendering.
|
||||
|
||||
**The stdlib-only approach is sufficient:**
|
||||
```python
|
||||
import base64, re, mimetypes
|
||||
html = Path("...html").read_text()
|
||||
def inline(match):
|
||||
src = match.group(1)
|
||||
if src.startswith("data:"): # already inlined
|
||||
return match.group(0)
|
||||
mime = mimetypes.guess_type(src)[0] or "image/png"
|
||||
data = base64.b64encode(Path(src).read_bytes()).decode()
|
||||
return f'<img src="data:{mime};base64,{data}"'
|
||||
# Match <img src="..."> with single or double quotes
|
||||
html = re.sub(r'<img\s+src="([^"]+)"', inline_img, html)
|
||||
html = re.sub(r"<img\s+src='([^']+)'", inline_img, html)
|
||||
```
|
||||
|
||||
**Edge cases confirmed:**
|
||||
- Marp's SVG-foreignObject wrapper: the `<img>` tags are INSIDE the
|
||||
`<foreignObject><section>...</section></foreignObject>` — the regex
|
||||
still matches them (they're standard HTML img tags in the HTML
|
||||
namespace). No special handling needed.
|
||||
- Quoted vs unquoted src: Marp always emits double-quoted `src="..."`;
|
||||
handle both for safety.
|
||||
- Relative vs absolute paths: Marp emits relative paths
|
||||
(`assets/png/X.png`); the script must resolve them relative to the
|
||||
HTML file's directory. `Path(html_path).parent / src`.
|
||||
- Already-inlined images (`data:` URIs): skip (the regex checks for
|
||||
`src.startswith("data:")`).
|
||||
- Marp does NOT use `xlink:href` for images in HTML output (that's
|
||||
only for SVG-only output mode); the HTML output uses standard
|
||||
`<img src>`. Confirmed by grep: 0 occurrences of `xlink:href` in
|
||||
the current HTML.
|
||||
- The `--allow-local-files` flag in `render_slides.sh` is what makes
|
||||
Marp keep the local relative paths (without it, Marp would skip
|
||||
local images in the standalone HTML).
|
||||
|
||||
**No external library needed.** stdlib `base64` + `re` + `mimetypes`
|
||||
+ `pathlib` is sufficient.
|
||||
|
||||
**Confidence: 0.95** (verified by direct inspection of the current
|
||||
HTML; the regex handles all observed patterns).
|
||||
|
||||
### FINDING 5 — Tests that need updating (`tests/test_slides_pipeline.py`)
|
||||
|
||||
Full read of `tests/test_slides_pipeline.py` (373 lines). Tests that
|
||||
assert on v1.23-affected surfaces:
|
||||
|
||||
**(a) `theme: nova-sp` / `nova-sp-theme.css` via `--theme`:**
|
||||
- **Line 55-64 `test_marp_deck_uses_sp_theme`**: asserts `"nova-sp" in
|
||||
frontmatter`. After v1.23: frontmatter should have `theme: default`;
|
||||
this test must assert `"theme: default"` instead (or assert the inline
|
||||
`style:` block is present).
|
||||
- **Line 66-74 `test_marp_deck_not_using_default_theme`**: asserts
|
||||
`"theme: default" not in frontmatter`. After v1.23: this test must
|
||||
be DELETED or INVERTED (we're reverting TO `theme: default`).
|
||||
- **Line 36-38 `test_sp_theme_css_exists`**: asserts
|
||||
`nova-sp-theme.css` is a file. After v1.23: keep (the CSS is retired
|
||||
from render but kept as a reference file).
|
||||
- **Line 41-45 `test_sp_theme_css_has_snp_colors`**: asserts the CSS
|
||||
has S&P colors. After v1.23: keep (reference file still has colors).
|
||||
- **Line 275-282 `test_theme_css_has_section_padding`**: asserts the
|
||||
CSS `section` rule has padding. After v1.23: this test targets the
|
||||
RETIRED CSS — it should be retargeted to the inline `style:` block in
|
||||
the marp deck frontmatter (assert the inline style has section
|
||||
padding).
|
||||
- **Line 284-293 `test_theme_css_suppresses_title_chrome`**: asserts
|
||||
`section.title header` + `display: none` in the CSS. After v1.23:
|
||||
retarget to the inline `style:` block.
|
||||
- **Line 295-302 `test_theme_css_has_aspect_ratio_aware_images`**:
|
||||
asserts `object-fit` + `max-width` in the CSS. After v1.23: retarget
|
||||
to the inline `style:` block (or drop if the inline style uses the
|
||||
simpler `max-height: 280px` from the reference deck).
|
||||
- **Line 353-359 `test_html_embeds_theme`**: asserts `"--sp-red"` +
|
||||
`"padding:"` in the committed HTML. After v1.23: the inline `style:`
|
||||
block uses literal `#D6002A` (not the `--sp-red` CSS variable — the
|
||||
reference deck's inline style did NOT use CSS variables). This test
|
||||
must change to assert `"#D6002A"` + `"padding:"` (or `"font-family:
|
||||
\"Akkurat Pro\""`).
|
||||
|
||||
**(b) Both `.md` and `-marp.md` existing:**
|
||||
- **Line 31 `SOURCE_MD` constant** + **Line 240-263
|
||||
`test_source_md_no_internal_citations_in_slides`** +
|
||||
**Line 266-270 `test_source_md_no_badges`**: assert the plain `.md`
|
||||
is the source of truth. After v1.23: the plain `.md` is DELETED
|
||||
(consolidated into `-marp.md`); these tests must be DELETED or
|
||||
retargeted to the consolidated `-marp.md`.
|
||||
|
||||
**(c) `marp-cli` invocation specifics:**
|
||||
- **Line 83-90 `test_render_slides_script_renders_mermaid`**: asserts
|
||||
`mermaid-cli` + `sp-theme.json` in the script. After v1.23: keep
|
||||
(mermaid render unchanged).
|
||||
- **Line 92-98 `test_render_slides_script_renders_marp`**: asserts
|
||||
`marp-cli` + `.html` + `.pptx` in the script. After v1.23: the script
|
||||
no longer passes `--theme nova-sp-theme.css`; it may still produce
|
||||
`.pptx` via marp-cli OR via the new `render_pptx.py`. This test must
|
||||
be updated to reflect the new invocation (marp-cli for HTML only;
|
||||
render_pptx.py for the structured PPTX).
|
||||
- **Line 327-332 `test_render_slides_has_2x_scale`**: asserts `-s 2`
|
||||
+ `-b transparent`. After v1.23: keep (mermaid flags unchanged).
|
||||
- **Line 335-344 `test_render_slides_pins_cli_versions`**: asserts
|
||||
`marp-cli@` + `mermaid-cli@` pinned, no `@latest`. After v1.23: keep
|
||||
for mermaid; if marp-cli is still used for HTML, keep for marp too.
|
||||
- **Line 346-351 `test_render_deck_removed`**: asserts
|
||||
`render_deck.sh` is deleted. After v1.23: keep.
|
||||
|
||||
**(d) Slide count:**
|
||||
- **Line 204-218 `test_marp_deck_slide_count`**: asserts 20 main + 1
|
||||
appendix = 21 slides. After v1.23: the word-count trim may change
|
||||
the count; update to match the final count (likely stays 20+1 or
|
||||
drops to fewer if slides merge).
|
||||
- **Line 361-373 `test_html_slide_count_matches_marp`**: asserts the
|
||||
HTML `<section>` count matches the deck count. After v1.23: keep
|
||||
(recompute expected from the final deck).
|
||||
|
||||
**(e) Other affected tests:**
|
||||
- **Line 137-143 `test_readme_no_retired_decks`**: asserts README
|
||||
doesn't list old decks. After v1.23: keep.
|
||||
- **Line 146-150 `test_readme_no_old_deck_name`**: asserts README
|
||||
references `nova-autonomous-cloud-delivery`. After v1.23: keep.
|
||||
- **Line 153-156 `test_old_deck_files_removed`**: asserts old
|
||||
`nova-no-humans-platform*` files are gone. After v1.23: keep.
|
||||
- **Line 159-162 `test_marp_deck_no_badges`**: asserts no `badge` in
|
||||
marp deck. After v1.23: keep.
|
||||
- **Line 165-177 `test_marp_deck_no_version_in_footer`**: asserts no
|
||||
version in frontmatter. After v1.23: keep.
|
||||
- **Line 179-190 `test_marp_deck_title_slide_no_version_subtitle`**:
|
||||
asserts no `v1.18` subtitle. After v1.23: keep.
|
||||
- **Line 193-202 `test_marp_deck_title_is_autonomous_cloud_delivery`**:
|
||||
asserts the title. After v1.23: keep (unless "penetrate" removal
|
||||
touches the title — it doesn't).
|
||||
- **Line 221-237 `test_marp_deck_no_internal_citations`**: asserts no
|
||||
D-###/REQ-###/.py paths. After v1.23: keep.
|
||||
- **Line 304-324 `test_png_aspect_ratios_sane`**: asserts PNG aspect
|
||||
ratios in [0.4, 4.0]. After v1.23: keep.
|
||||
- **Line 107-119 `test_slides_ci_workflow_*`**: asserts slides.yml
|
||||
exists + triggers on presentations. After v1.23: keep (update if the
|
||||
workflow changes).
|
||||
|
||||
**Summary:** ~12 tests need updating; the key inversions are
|
||||
`test_marp_deck_not_using_default_theme` (delete/invert) and the
|
||||
`test_theme_css_*` trio (retarget from the standalone CSS file to the
|
||||
inline `style:` block). The `test_source_md_*` tests must be deleted
|
||||
(plain `.md` is gone).
|
||||
|
||||
**Confidence: 0.95** (direct line-by-line read of the test file).
|
||||
|
||||
### FINDING 6 — `scripts/attach_release_asset.py`
|
||||
|
||||
Read in full (80 lines). Current behavior:
|
||||
- CLI: `python3 scripts/attach_release_asset.py <file-path> <release-id>`
|
||||
- Resolves `NOVA_GITEA_TOKEN` (or `ACDL_GITEA_TOKEN` fallback) from
|
||||
`.env.secrets`/`.env`.
|
||||
- POSTs to `/api/v1/repos/{owner}/{repo}/releases/{id}/assets` with
|
||||
multipart form: `name=<filename>` + `attachment=<file bytes>`.
|
||||
- Single-file upload per invocation.
|
||||
|
||||
**Change needed for v1.23:** attach BOTH `.pptx` (Marp PPTX) AND
|
||||
`-python.pptx` (python-pptx structured PPTX). Two options:
|
||||
1. Call the script twice (once per file) from the ship workflow.
|
||||
2. Extend the script to accept multiple file paths: `attach_release_asset.py
|
||||
<file1> <file2> ... <release-id>` (loop over files, same release-id).
|
||||
|
||||
**Recommendation:** option 2 (extend to multiple files) — minimal,
|
||||
backward-compatible (if only 1 file given, same behavior). The
|
||||
release-id stays the last positional arg; all preceding args are file
|
||||
paths.
|
||||
|
||||
**Confidence: 0.95** (direct read; the change is mechanical).
|
||||
|
||||
### FINDING 7 — `workflows-src/slides.yml`
|
||||
|
||||
Read in full (31 lines). Current CI steps:
|
||||
1. `actions/checkout@v4` (fetch-depth 0).
|
||||
2. `actions/setup-node@v4` (node 20).
|
||||
3. "Install Chrome" — runs `npx --yes @marp-team/marp-cli@latest
|
||||
--version` + `npx --yes @mermaid-js/mermaid-cli --version` (NOTE:
|
||||
uses `@latest` — NOT pinned, contradicts REQ-257's pinning rule for
|
||||
`render_slides.sh`; the workflow is separate from the script).
|
||||
4. "Render slides" — `bash scripts/render_slides.sh`.
|
||||
5. "Commit rendered artifacts" — `git add docs/presentations/*.html
|
||||
docs/presentations/*.pptx docs/presentations/assets/png/*.png` +
|
||||
commit + push.
|
||||
|
||||
**Where `python-pptx` install would go:** a new step between "Install
|
||||
Chrome" and "Render slides":
|
||||
```yaml
|
||||
- uses: actions/setup-python@v5
|
||||
with: { python-version: '3.11' }
|
||||
- name: Install python-pptx
|
||||
run: pip install python-pptx>=0.6.23
|
||||
```
|
||||
Then `render_slides.sh` (or a new `render_pptx.py` invocation) uses
|
||||
it. OR: `pip install -e ".[test]"` if python-pptx is added to
|
||||
`pyproject.toml [project.optional-dependencies] test`.
|
||||
|
||||
**What the commit list should include after v1.23:** the
|
||||
`git add` line must include:
|
||||
- `docs/presentations/*.html` (re-rendered HTML, with inlined images)
|
||||
- `docs/presentations/*.pptx` (Marp PPTX — kept as the "fallback" PPTX)
|
||||
- `docs/presentations/*-python.pptx` (NEW — the python-pptx structured
|
||||
PPTX)
|
||||
- `docs/presentations/assets/png/*.png` (re-rendered mermaid PNGs)
|
||||
|
||||
**Also:** the workflow uses `@latest` for both CLIs in the "Install
|
||||
Chrome" step — this should be pinned to match `render_slides.sh`'s
|
||||
pinned versions (`@marp-team/marp-cli@4.5.0`,
|
||||
`@mermaid-js/mermaid-cli@11.16.0`) for reproducibility.
|
||||
|
||||
**Confidence: 0.95** (direct read).
|
||||
|
||||
### FINDING 8 — `docs/presentations/README.md` current structure
|
||||
|
||||
Read in full (249 lines). Current 4-step process structure:
|
||||
- **Step 1 — Full markdown (source of truth):** `<deck-name>.md` with
|
||||
`## Slide N — Title` + `> **Speaker notes:**` blocks + mermaid code
|
||||
blocks.
|
||||
- **Step 2 — Marp deck synthesis:** `<deck-name>-marp.md` with Marp
|
||||
frontmatter (`theme: nova-sp`), no speaker notes, embedded PNGs, no
|
||||
badges.
|
||||
- **Step 3 — Render to HTML and PPTX:** `bash scripts/render_slides.sh
|
||||
<deck-name>`; HTML committed (with base64 images — NOTE: this is
|
||||
aspirational; the current HTML does NOT inline images, which is what
|
||||
`inline_images.py` will fix); PPTX committed + release-attached.
|
||||
- **Step 4 — Talking points:** `<deck-name>-talking-points.md` with
|
||||
one section per Marp slide, 3-6 bullets + key takeaway.
|
||||
|
||||
**What to rewrite for v1.23:**
|
||||
- The 4-step process becomes a **3-step process** (Step 1 plain `.md`
|
||||
is DELETED → consolidated into `-marp.md`; the source of truth IS the
|
||||
`-marp.md` with speaker notes in HTML comments, OR speaker notes are
|
||||
dropped entirely). OR: keep 4 steps but Step 1's output merges into
|
||||
Step 2 (the `-marp.md` becomes the source of truth, with speaker
|
||||
notes preserved as HTML comments that Marp strips from rendering).
|
||||
- Step 2 frontmatter: `theme: default` + inline `style:` block (not
|
||||
`theme: nova-sp`).
|
||||
- Step 3: HTML rendered by Marp (`render_slides.sh`), images inlined
|
||||
by `scripts/inline_images.py` (NEW), PPTX rendered by BOTH marp-cli
|
||||
(fallback `.pptx`) AND `scripts/render_pptx.py` (structured
|
||||
`-python.pptx`).
|
||||
- The directory layout block (line 108-123) must drop the plain `.md`
|
||||
row + add `inline_images.py` + `render_pptx.py` rows + the
|
||||
`-python.pptx` row + note `nova-sp-theme.css` is retired (reference
|
||||
only).
|
||||
- The "Current decks" table (line 237-239) must list both PPTX files.
|
||||
- The slide-count convention (line 128-136) must reflect the final
|
||||
v1.23 count (after word-count trim + "penetrate" removal).
|
||||
- The "Adding a new presentation" section (line 209-233) must be
|
||||
rewritten for the single-document + dual-PPTX pipeline.
|
||||
|
||||
**Confidence: 0.95** (direct read).
|
||||
|
||||
### FINDING 9 — Persona assessment for v1.23
|
||||
|
||||
The v1.23 scope: deck markdown editing (consolidate `.md` + `-marp.md`,
|
||||
trim word count, remove "penetrate"), Marp inline `style:` CSS, Python
|
||||
scripts (`inline_images.py` + `render_pptx.py`), tests, CI YAML
|
||||
(`slides.yml`), README. The v1.22 roster had lead-developer +
|
||||
backend-engineer active; frontend + data deactivated.
|
||||
|
||||
**Assessment:** the same roster applies, with one territory shift.
|
||||
- **lead-developer** (active): owns the deck markdown (consolidation,
|
||||
word-count trim, "penetrate" removal), the inline `style:` CSS block
|
||||
(porting the reference deck's CSS), the README rewrite, and all
|
||||
`.ciagent/**` metadata. The inline CSS is a Marp stylesheet block, not
|
||||
a React/Next.js system — stays lead-developer (D-148 precedent from
|
||||
v1.22).
|
||||
- **backend-engineer** (active): owns the Python scripts
|
||||
(`inline_images.py`, `render_pptx.py` — python-pptx is a backend
|
||||
library), the `render_slides.sh` updates, the tests, the CI YAML,
|
||||
and the `attach_release_asset.py` extension. This is a shift from
|
||||
v1.22 (where backend owned bash + pytest); v1.23 adds Python to
|
||||
backend's territory.
|
||||
- **frontend-engineer** (deactivated): no React/Next.js. The inline
|
||||
CSS is a Marp stylesheet, not frontend. Stays deactivated (D-148
|
||||
precedent).
|
||||
- **data-engineer** (deactivated): no schema/DB/ORM. Stays deactivated.
|
||||
|
||||
**Custom "docs/deck" persona?** Not warranted. The work splits cleanly
|
||||
into lead-developer (narrative + CSS + markdown + README + metadata)
|
||||
and backend-engineer (Python + bash + tests + CI). A "docs-engineer"
|
||||
or "slides-engineer" persona would fragment ownership of the deck
|
||||
markdown (lead) and the render scripts (backend). D-149 precedent from
|
||||
v1.22 applies: no new personas.
|
||||
|
||||
**One nuance:** python-pptx is a new dependency (backend territory) but
|
||||
the PPTX CONTENT (slide layout, text, image placement) is a design
|
||||
decision that overlaps with lead-developer's deck ownership. The
|
||||
`render_pptx.py` script is backend (Python code); the slide-by-slide
|
||||
layout decisions within it (which image goes where, font sizes) are
|
||||
co-owned with lead-developer. Territory enforcement = `warn` (cross-
|
||||
territory edits logged, not blocked).
|
||||
|
||||
**Confidence: 0.90** (the roster follows v1.22 precedent; the only new
|
||||
element is python-pptx, which is unambiguously backend).
|
||||
|
||||
### FINDING 10 — Risks / pitfalls (5)
|
||||
|
||||
1. **Marp `default` theme padding conflict.** The reference deck's
|
||||
inline `style:` block does NOT set `section` padding. The v1.22
|
||||
root-cause was ZERO padding with the standalone `nova-sp-theme.css`.
|
||||
If `theme: default`'s built-in padding differs from v1.22's settled
|
||||
`48px 56px 40px`, slides may re-overflow. **Mitigation:** explicitly
|
||||
set `section { padding: 48px 56px 40px }` in the v1.23 inline
|
||||
`style:` block (do not rely on the default theme's padding). Verify
|
||||
by re-rendering + visual inspection in P2.
|
||||
|
||||
2. **python-pptx font fallback when Akkurat Pro isn't installed.**
|
||||
python-pptx sets a single `run.font.name = "Akkurat Pro"`; on
|
||||
systems without Akkurat Pro (CI, most laptops), PowerPoint
|
||||
substitutes a default font (often Calibri), NOT Helvetica Neue /
|
||||
Arial. The CSS stack `Akkurat Pro → Helvetica Neue → Arial` does
|
||||
NOT translate to python-pptx (no CSS-style fallback). **Mitigation:**
|
||||
accept PowerPoint's OS-level substitution (the deck will render in
|
||||
a sans font either way); OR set `run.font.name = "Arial"` directly
|
||||
for the structured PPTX (guaranteed present on all systems) and
|
||||
document that the Marp HTML deck uses the full Akkurat Pro stack
|
||||
while the python PPTX uses Arial. The dual-PPTX approach lets the
|
||||
Marp PPTX (rendered by Chromium with the CSS stack) carry the
|
||||
brand font, while the python PPTX (structured, editable) carries
|
||||
Arial for editability.
|
||||
|
||||
3. **Image inlining breaking if Marp embeds images as SVG
|
||||
`xlink:href`.** The current HTML uses `<img src="assets/png/...">`
|
||||
(confirmed by grep). BUT if a future Marp version switches to SVG
|
||||
`xlink:href` for the HTML output, the `inline_images.py` regex
|
||||
would miss them. **Mitigation:** the regex should ALSO match
|
||||
`xlink:href="assets/..."` patterns as a fallback; OR pin the
|
||||
Marp version (already pinned at `@4.5.0` in `render_slides.sh`) so
|
||||
the output format is stable.
|
||||
|
||||
4. **Consolidated doc losing speaker notes if HTML comments are
|
||||
stripped by Marp.** The plan consolidates the plain `.md` (with
|
||||
`> **Speaker notes:**` blockquotes) into the `-marp.md`. Marp strips
|
||||
HTML comments (`<!-- ... -->`) from rendered output but preserves
|
||||
blockquotes (`> ...`) as `<blockquote>` elements. If speaker notes
|
||||
are moved to HTML comments to hide them from the audience, Marp
|
||||
strips them — and they're lost from the rendered HTML. If they stay
|
||||
as blockquotes, they're visible in the audience deck (bad).
|
||||
**Mitigation:** either (a) drop speaker notes entirely from the
|
||||
consolidated `-marp.md` (the talking-points file is the presenter
|
||||
cue sheet; notes aren't needed in the deck), or (b) keep them as
|
||||
HTML comments (Marp strips from render, but they persist in the
|
||||
source markdown for git-diff readability). Option (b) is safer —
|
||||
the source markdown keeps the notes; the rendered HTML + PPTX
|
||||
don't. Verify Marp strips `<!-- -->` from HTML output (confirmed:
|
||||
Marp's markdown-it does strip HTML comments by default).
|
||||
|
||||
5. **`test_html_embeds_theme` asserts `--sp-red` CSS variable, but the
|
||||
reference inline `style:` uses literal `#D6002A`.** The v1.22 test
|
||||
(line 353-359) asserts `"--sp-red"` in the committed HTML. The
|
||||
reference deck's inline `style:` block uses literal `#D6002A`, not
|
||||
a CSS variable. If v1.23 ports the reference style verbatim, the
|
||||
test fails. **Mitigation:** update the test to assert `"#D6002A"`
|
||||
(literal) OR use CSS variables in the inline `style:` block (Marp
|
||||
supports `:root { --sp-red: #D6002A }` + `color: var(--sp-red)` in
|
||||
the inline style — but the reference deck didn't, so matching the
|
||||
reference means literal colors). Recommendation: use literal colors
|
||||
in the inline `style:` block (matches the reference deck's clean
|
||||
approach) + update the test.
|
||||
|
||||
**Confidence: 0.90** (pitfalls identified from the research findings
|
||||
above; mitigations are concrete).
|
||||
|
||||
---
|
||||
|
||||
## Assumptions logged (v1.23)
|
||||
|
||||
| ID | Assumption | Confidence | Rationale |
|
||||
|----|------------|------------|-----------|
|
||||
| A-1.23.1 | The consolidated `-marp.md` will keep speaker notes as HTML comments (`<!-- -->`), which Marp strips from rendered HTML/PPTX but preserves in the source markdown for git readability. | 0.80 | Marp's markdown-it strips HTML comments by default; the source markdown keeps them. The alternative (drop notes entirely) loses the presenter context. |
|
||||
| A-1.23.2 | `python-pptx` will be added to `pyproject.toml [project.optional-dependencies] test` (not the runtime `dependencies`), since the structured PPTX is a build/test artifact, not a runtime dependency. | 0.90 | The render scripts run in CI + locally, not in the platform runtime. Matches the `moto`/`pytest` pattern. |
|
||||
| A-1.23.3 | The Marp PPTX (`.pptx`) is kept as a "fallback" alongside the new python-pptx structured PPTX (`-python.pptx`); both are committed + release-attached. | 0.85 | The plan says "dual PPTX"; the Marp PPTX is the quick render, the python PPTX is the editable one. Keeping both gives consumers a choice. |
|
||||
| A-1.23.4 | The `nova-sp-theme.css` file is KEPT in `docs/presentations/assets/` as a reference (retired from the render pipeline) but NOT deleted. | 0.90 | The plan says "keep as a reference (retired from render)"; deletion would lose the v1.22 work history. |
|
||||
| A-1.23.5 | The slide count after the word-count trim + "penetrate" removal will stay at 20 main + 1 appendix (the trim is within-slide prose, not slide removal). | 0.75 | The plan says "trim word count" (prose), not "remove slides"; but if a slide becomes too thin it may merge. To be confirmed in execution. |
|
||||
|
||||
---
|
||||
|
||||
## Decisions surfaced (v1.23 research)
|
||||
|
||||
These research-grounded decisions will be bound in the CLARIFY stage:
|
||||
|
||||
- **D-XXX (0.90):** Revert to `theme: default` + inline `style:` block
|
||||
(port the reference deck's exact CSS from Finding 1). Keep
|
||||
`nova-sp-theme.css` as a retired reference file. Confidence 0.90 —
|
||||
the reference deck's clean look is the target; the CSS is read
|
||||
verbatim.
|
||||
|
||||
- **D-XXX (0.85):** Build `scripts/inline_images.py` (stdlib-only:
|
||||
`base64` + `re` + `mimetypes`) to inline `<img src="assets/...">` →
|
||||
`data:` URIs in the rendered HTML. No external library. Confidence
|
||||
0.95 — confirmed the current HTML uses plain `<img src>`.
|
||||
|
||||
- **D-XXX (0.85):** Build `scripts/render_pptx.py` using python-pptx
|
||||
(>=0.6.23) for a structured, editable PPTX (`-python.pptx`). Keep
|
||||
the Marp PPTX (`.pptx`) as a fallback. Both committed + release-
|
||||
attached. Confidence 0.90 — python-pptx API confirmed.
|
||||
|
||||
- **D-XXX (0.80):** Consolidate the plain `.md` + `-marp.md` into a
|
||||
single `-marp.md`. Speaker notes move to HTML comments (stripped by
|
||||
Marp from render, preserved in source). The plain `.md` is deleted.
|
||||
Confidence 0.80 — the HTML-comment approach preserves notes for git
|
||||
without leaking them to the audience.
|
||||
|
||||
- **D-XXX (0.85):** No new personas for v1.23. lead-developer (deck
|
||||
markdown + inline CSS + README + metadata) + backend-engineer
|
||||
(Python scripts + bash + tests + CI). Territory enforcement = `warn`
|
||||
for `render_pptx.py` (script is backend; slide layout decisions are
|
||||
co-owned with lead-developer). Confidence 0.90 — follows v1.22 D-
|
||||
148/D-149 precedent.
|
||||
|
||||
@@ -1892,3 +1892,265 @@ release). **DONE.**
|
||||
- Milestone branches merged to main.
|
||||
- Tag `v1.19.4` created; release notes summarize all 15 requirements.
|
||||
- CHECKPOINT cleared; milestone branches deleted.
|
||||
|
||||
## v1.21 — Nova Deck Refinement & Pipeline Hardening (complete)
|
||||
|
||||
> Leadership-deck refinement based on 33 review notes on the v1.20 deck.
|
||||
> Renamed the deck to the professional "Autonomous Cloud Delivery
|
||||
> Platform" framing; restructured the narrative (Problem → Solution →
|
||||
> Proof → Roadmap + Ask); removed internal provenance from
|
||||
> audience-facing slides; hardened the policy pipeline (Checkov before
|
||||
> plan, Wiz-or-Checkov on plan); moved 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.6).
|
||||
> Flat workflow: commits on main, tags per phase.
|
||||
|
||||
### Phase P0 — pre-execution (complete, tag v1.20.0)
|
||||
- SPECIFY → CLARIFY → RESEARCH → PLAN. Validated v1.21 requirements
|
||||
(REQ-245..253). Established `active_milestone: "v1.21"`. Synced
|
||||
PROJECT.md strategic-direction pillar.
|
||||
|
||||
### Phase P1 — strategic-docs (complete, tag v1.20.1)
|
||||
- `git mv .ciagent/NO_HUMANS_THESIS.md .ciagent/AUTONOMY_THESIS.md` +
|
||||
reframe content (autonomy in operations, not "removing humans").
|
||||
- `NORTH_STAR.md`: vision polished ("invisible" → "visible"); obj #2
|
||||
deterministic-scoring reword; obj #3 four CTO metrics; obj #4 replaced
|
||||
with integration objective; drop anti-goals 1,4,5; add 2 new
|
||||
anti-goals; anti-goal #3 reworded.
|
||||
- `docs/raci.md`: 3 roles → 4 roles (add Quality Engineering; rename
|
||||
Release Mgmt → SRE; split release attestation).
|
||||
- `docs/scope.md` + render scripts + ONBOARDING: integration framing +
|
||||
"no-humans" → "autonomous".
|
||||
|
||||
### Phase P2 — slides source-of-truth (complete, tag v1.20.2)
|
||||
- `git mv` all 5 deck files `nova-no-humans-platform*` →
|
||||
`nova-autonomous-cloud-delivery*`.
|
||||
- Rewrote source of truth to 18 main + 1 appendix slides, 4-beat arc.
|
||||
All 33 review notes applied. Removed: old Slide 10 (Capability
|
||||
Health), old Slide 12 (Zero-Touch), Appendix A2 (Operating Model &
|
||||
Cost). Global: tech-leadership benefits; no D-###/REQ-###/.py paths in
|
||||
audience slides; no badges; no version in footer.
|
||||
|
||||
### Phase P3 — marp deck + talking points + README (complete, tag v1.20.3)
|
||||
- Synthesized Marp deck 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.
|
||||
- Re-distilled talking points to 18-slide + A1 structure.
|
||||
- README updated (deck title, audience, slide count, directory layout,
|
||||
no badge docs).
|
||||
- Theme CSS: fixed Appendix A1 table readability (explicit white body
|
||||
on any background).
|
||||
- Tests: added v1.21 assertions (no badges, no version, 18+1 slides, no
|
||||
D-###/REQ-###/.py paths, old files removed, default deck renamed).
|
||||
|
||||
### Phase P4 — pipeline hardening (complete, tag v1.20.4)
|
||||
- Two-stage policy scan (REQ-250): Checkov on static code BEFORE plan
|
||||
(fail-fast); Wiz-or-Checkov on the plan AFTER plan (never both).
|
||||
Implemented in run_platform.sh + run_codegen.sh + run_postapply.sh.
|
||||
- `adapters/wiz/wiz_adapter.py`: added --plan mode CLI.
|
||||
- `pipelines/contract.yml`: 'checkov' stage replaced by 'checkov-static'
|
||||
(before terraform-plan) + 'runtime-policy-scan' (after). 9 → 10 stages.
|
||||
- Tests updated; full suite 686 pass + 1 pre-existing attestation
|
||||
failure (unrelated env issue).
|
||||
|
||||
### Phase P5 — render + verify (complete, tag v1.20.5)
|
||||
- New mermaid diagrams: platform-pipeline.mmd/.png (slide 6),
|
||||
telemetry-live-ops.mmd/.png (slide 9).
|
||||
- Re-rendered HTML + PPTX (20 slides, 21 media files).
|
||||
- Verify: 101 v1.21-specific tests pass; 686 full suite pass;
|
||||
check-only pipeline exit 0; no no-humans/D-###/REQ-###/badge in
|
||||
audience-facing deck files.
|
||||
|
||||
### Phase P6 — final-review-ship (Final Phase, complete, tag v1.20.6)
|
||||
- Multi-file audit: git log matches `.ciagent/` discipline; deck files
|
||||
renamed; forbidden content absent from audience-facing slides.
|
||||
- Ship: tag `v1.20.6` (final patch = milestone release). Requirements
|
||||
marked complete; ROADMAP marked complete; CHECKPOINT cleared.
|
||||
- **Requirements:** REQ-245..253 (9 requirements, all complete).
|
||||
|
||||
## v1.22 — Nova Deck Layout Fix (complete)
|
||||
|
||||
> Fixes the systemic layout/formatting problems in the Nova presentation
|
||||
> deck that made every slide look "out of whack" after the v1.21 P5
|
||||
> re-render. Root cause (per investigation): `nova-sp-theme.css` had
|
||||
> zero `section` padding (declared `/* @theme nova-sp */` as a comment,
|
||||
> not the `@theme` directive; did not `@import` Marp's default theme).
|
||||
> Combined with `overflow:hidden`, a blunt `img { max-height: 320px }`,
|
||||
> header+footer chrome on every slide, and two P5 diagrams with extreme
|
||||
> aspect ratios (13.52× and 0.63×), 8 of 19 slides overflowed.
|
||||
>
|
||||
> Tags run on the v1.21.x line (milestone v1.22 → tags v1.21.0..v1.21.6).
|
||||
|
||||
### Phase P0 — pre-execution (complete, tag v1.21.0)
|
||||
- SPECIFY → CLARIFY → RESEARCH → PLAN → GRILL. Validated v1.22
|
||||
requirements (REQ-254..262). 8 research findings persisted to
|
||||
RESEARCH.md. 5 CLARIFY decisions auto-resolved (comprehensive scope,
|
||||
full pipeline, re-layout to LR, delete render_deck.sh, split slides
|
||||
3+8). Persona roster: 2 active (lead-developer + backend-engineer),
|
||||
2 deactivated (frontend + data). Grill: PROCEED-WITH-REVISIONS
|
||||
(3 revisions: aspect-ratio test scoped to deck PNGs, @import
|
||||
rejection documented, marp version pinning fallback).
|
||||
|
||||
### Phase P1 — theme-css (complete, tag v1.21.1)
|
||||
- REQ-254: `section { padding: 48px 56px 40px; overflow: auto; }` —
|
||||
root cause fix (zero padding was why every slide looked jammed
|
||||
against the edges).
|
||||
- REQ-255: `img { max-width: 100%; max-height: 380px; object-fit:
|
||||
contain; }` + `.wide`/`.tall` classes — replaced blunt
|
||||
`max-height: 320px` that broke `w:` directives on tall images.
|
||||
- REQ-256: `section.title header/footer { display: none; }` — title
|
||||
chrome suppression. `h2 + p { margin-top: 0.2em; }`, `p { margin:
|
||||
0.4em 0; }` — spacing tightening. `ol` styling. `table.dense`
|
||||
class. `@media print { section { overflow: hidden; } }` for PPTX.
|
||||
|
||||
### Phase P2 — render-scripts (complete, tag v1.21.2)
|
||||
- REQ-257: deleted `scripts/render_deck.sh` (omitted `--theme`,
|
||||
produced unthemed output). Pinned marp-cli@4.5.0 + mermaid-cli@
|
||||
11.16.0 in `render_slides.sh`. Removed references from README,
|
||||
sync_to_nova.sh, test_no_forge_mentions.py.
|
||||
- REQ-258: added `-s 2 -b transparent` to mermaid-cli invocation
|
||||
(README spec; produces crisp 2x PNGs with transparent backgrounds).
|
||||
|
||||
### Phase P3 — mermaid-relayout (complete, tag v1.21.3)
|
||||
- REQ-259: `telemetry-live-ops.mmd` kept as `flowchart TB` (the 3-way
|
||||
branch makes LR too wide at 4.22 aspect; TB gives 0.63 which is
|
||||
legible at h:480 with img.tall class). Re-rendered at 2x transparent
|
||||
(1024x1628).
|
||||
- REQ-260: `platform-pipeline.mmd` restructured from 10-node LR chain
|
||||
(aspect 13.52, illegible 1000x74 strip) to 4-node TB with combined
|
||||
nodes. Re-rendered at 2x transparent (552x1116, aspect 0.49).
|
||||
- Marp deck directives updated: `![w:1000]`/`![w:900]` →
|
||||
`![h:480 class:tall]` so images render at legible height using the
|
||||
img.tall class budget (480px).
|
||||
- Aspect-ratio bounds revised from [1.2, 2.5] to [0.4, 4.0] (accepts
|
||||
both tall and wide diagrams; still catches original outliers).
|
||||
|
||||
### Phase P4 — deck-content (complete, tag v1.21.4)
|
||||
- REQ-261: split slide 3 (Objectives + Anti-Goals) into Slide 3
|
||||
(Objectives) + Slide 4 (Anti-Goals). Split slide 8 (Attestation
|
||||
Matrix) into Slide 9 (QA, 3 rows) + Slide 10 (Prod/DR, 7 rows).
|
||||
Main slide count 18 → 20.
|
||||
- Trimmed: slide 7 (Pipeline) to 3 bullets. slide 11 (Telemetry) to
|
||||
3 bullets. slide 14 (Deferred) merged 3 Live-AWS rows into 1 (8→6
|
||||
rows). slide 17 (Quarter-by-Quarter) dropped Grounding column
|
||||
(5→4 cols). Global table cell padding reduced (6px 10px → 4px 8px).
|
||||
- Removed `header:` from frontmatter (keep `footer:` + `paginate`
|
||||
only). The full 51-char deck title in BOTH header and footer was
|
||||
redundant chrome eating ~35px on every slide.
|
||||
- Source `.md` and talking-points re-synced to 20-slide structure.
|
||||
- Updated `test_marp_deck_slide_count` (18→20 main + 1 appendix).
|
||||
Updated README slide-count convention (all 6 references).
|
||||
|
||||
### Phase P5 — render-and-test (complete, tag v1.21.5)
|
||||
- REQ-262: re-rendered HTML + PPTX via `render_slides.sh` (pinned
|
||||
marp-cli@4.5.0, mermaid-cli@11.16.0, 2x transparent PNGs). 22
|
||||
slides (title + 20 main + 1 appendix), 23 media files embedded.
|
||||
Theme embedded in HTML (--sp-red + padding confirmed).
|
||||
- Added 9 tests to `test_slides_pipeline.py` (the gap that let the
|
||||
layout regression through): test_theme_css_has_section_padding,
|
||||
test_theme_css_suppresses_title_chrome,
|
||||
test_theme_css_has_aspect_ratio_aware_images,
|
||||
test_png_aspect_ratios_sane (scoped to deck-referenced PNGs only
|
||||
per GRILL revision 1, bounds [0.4, 4.0]),
|
||||
test_render_slides_has_2x_scale, test_render_slides_pins_cli_versions,
|
||||
test_render_deck_removed, test_html_embeds_theme,
|
||||
test_html_slide_count_matches_marp.
|
||||
- 32 slide tests pass (23 original + 9 new). 94 key-file tests pass.
|
||||
`run_platform.sh --check-only` exit 0.
|
||||
|
||||
### Phase P6 — final-review-ship (Final Phase, complete, tag v1.21.6)
|
||||
- Multi-persona code review: PASS with 3 P1 flags (all fixed in this
|
||||
phase): source .md/talking-points re-synced to 20 slides, `![h:480
|
||||
class:tall]` directives applied, README stale references updated.
|
||||
- Audit: git log matches `.ciagent/` discipline; all commits have
|
||||
`---ci---` blocks; branch hygiene verified.
|
||||
- Ship: tag `v1.21.6` (final patch = milestone release). Merge
|
||||
`milestone/v1.22-deck-layout-fix` → `main`. Requirements marked
|
||||
complete; ROADMAP marked complete; CHECKPOINT cleared.
|
||||
- **Requirements:** REQ-254..262 (9 requirements, all complete).
|
||||
|
||||
## v1.23 — Nova Deck Cleanup & Python PPTX (active)
|
||||
|
||||
> **NFR milestone** (docs/render/test only; no features). Tags run on the
|
||||
> **v1.22.x** line (milestone v1.23 → tags v1.22.0..v1.22.6). Final patch
|
||||
> `v1.22.6` = milestone release. Branch: `milestone/v1.23-deck-cleanup-python-pptx`.
|
||||
>
|
||||
> Driven by the user's feedback that the deck looked "out of whack" and
|
||||
> the desire to return to the clean, well-formatted style of the old
|
||||
> `the-developer-experience.html` (which used Marp's built-in `default`
|
||||
> theme + an inline `style:` block). That investigation revealed:
|
||||
> (1) the "clean" reference was itself MARP output — MARP is not the
|
||||
> problem; (2) the current deck uses a standalone `nova-sp-theme.css`
|
||||
> that re-derives all base spacing from scratch and had a zero-padding
|
||||
> bug (fixed in v1.22 but the standalone approach is fragile);
|
||||
> (3) there are two markdown documents (a plain source-of-truth `.md`
|
||||
> and a manually-synthesized `-marp.md`) that should be consolidated;
|
||||
> (4) images are referenced as file paths in the HTML, so the HTML
|
||||
> breaks when redistributed without the `assets/` folder; (5) the deck
|
||||
> is verbose in places and uses the term "penetrate" which the user
|
||||
> wants removed.
|
||||
>
|
||||
> The milestone delivers: single-document consolidation, clean style
|
||||
> restoration (Marp `default` + inline `style:`), self-contained HTML
|
||||
> (base64 images), a parallel structured python-pptx PPTX generator,
|
||||
> targeted word-count trim, and "penetrate" removal. `nova-sp-theme.css`
|
||||
> is retained as a styling reference but retired from the render path.
|
||||
|
||||
### Phase P0 — pre-execution (active)
|
||||
- SPECIFY → CLARIFY → RESEARCH → PLAN → GRILL. Establishes v1.23
|
||||
requirements (REQ-263..275). Tag `v1.22.0`. Grill PROCEED-WITH-
|
||||
REVISIONS (0.78): 4 binding revisions applied (G-001 repo-wide
|
||||
"penetrate" purge; G-002 P3→P4 serialized; G-003 P3 split P3a+P3b;
|
||||
G-004 P5+P6 merged).
|
||||
|
||||
### Phase P1 — consolidate-docs (planned, tag v1.22.1)
|
||||
- REQ-263: fold speaker notes + talking points into `*-marp.md` as Marp
|
||||
HTML comments; delete the plain `.md`. `-marp.md` becomes the sole
|
||||
source of truth.
|
||||
- REQ-264: keep `*-talking-points.md` as a standalone presenter aid,
|
||||
synced from the deck's `<!-- Talking points: -->` comments.
|
||||
|
||||
### Phase P2 — restore-clean-style (planned, tag v1.22.2)
|
||||
- REQ-265: revert frontmatter to `theme: default` + inline `style:`
|
||||
block (S&P palette). Keep H2 + bold-lead structure, no header, no
|
||||
badges.
|
||||
- REQ-266: retain `nova-sp-theme.css` as a styling reference; drop
|
||||
`--theme` from `render_slides.sh`.
|
||||
- REQ-267: restyle benefit callouts — remove `**Benefit:**` prefix; use
|
||||
`.benefit` class (red top-rule + black italic; white on title slides).
|
||||
|
||||
### Phase P3a — inline-images (planned, tag v1.22.3)
|
||||
- REQ-268: new `scripts/inline_images.py` — base64-embeds all images in
|
||||
the rendered HTML for redistribution. Invoked after the MARP HTML
|
||||
render. Low-risk, mechanical (G-003 isolation).
|
||||
|
||||
### Phase P3b — python-pptx-generator (planned, tag v1.22.4)
|
||||
- REQ-269: new `scripts/render_pptx.py` — structured, editable, S&P-themed
|
||||
PPTX via `python-pptx`. 16:9; native tables; embedded PNGs; benefit
|
||||
callouts. Add `python-pptx` to `pyproject.toml`. High-risk, isolated
|
||||
(G-003).
|
||||
- REQ-270: `render_slides.sh` produces both PPTX outputs; CI installs
|
||||
`python-pptx`; both attached to release.
|
||||
|
||||
### Phase P4 — trim-wordcount + repo-wide "penetrate" purge (planned, tag v1.22.5)
|
||||
- REQ-271: targeted ~20-30% word-count trim on verbose slides (1, 5, 7,
|
||||
8, 13, 14, 20, appendix). Tables untouched. Spirit preserved.
|
||||
- REQ-272: remove "penetrate" (and derivatives) repo-wide (G-001) —
|
||||
`docs/` + `.ciagent/PROJECT.md`/`CLARIFY.md`; RESEARCH.md/PLAN.md/
|
||||
GRILL.md exempt as decision-history. Slide 5's phrase removed with no
|
||||
replacement (slide 4 already excludes the PDLC).
|
||||
|
||||
### Phase P5 — ci-tests-readme + review + audit + ship (Final Phase, tag v1.22.6)
|
||||
- REQ-273: CI workflows install `python-pptx`, run `render_slides.sh`,
|
||||
commit HTML + both PPTX + inlined images.
|
||||
- REQ-274: update `test_slides_pipeline.py` (consolidated doc, inline
|
||||
style assertions, image inlining, python-pptx, benefit class,
|
||||
"penetrate" absence). New `test_pptx_generator.py`.
|
||||
- REQ-275: rewrite `README.md` for the single-document + dual-PPTX +
|
||||
image-inlining pipeline.
|
||||
- Review + audit + milestone ship (merged P5+P6 per G-004 — NFR docs
|
||||
milestone). Tag `v1.22.6` (final patch = milestone release). Merge
|
||||
`milestone/v1.23-deck-cleanup-python-pptx` → `main`.
|
||||
- **Requirements:** REQ-263..275 (13 requirements).
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
],
|
||||
"active_project": "acdl",
|
||||
"active_projects": ["acdl"],
|
||||
"active_milestone": "v1.21",
|
||||
"active_milestone": "v1.23",
|
||||
"autonomy": {
|
||||
"level": "full",
|
||||
"escalation_hooks": ["deploy", "delete_data", "merge_to_main"],
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
=== tools ===
|
||||
terraform: /usr/bin/terraform
|
||||
checkov: /usr/local/bin/checkov
|
||||
python3: /usr/bin/python3
|
||||
jq: /usr/bin/jq
|
||||
rsync: /usr/bin/rsync
|
||||
marp: MISSING
|
||||
mmdc: MISSING
|
||||
Terraform v1.9.8
|
||||
3.3.8
|
||||
Python 3.12.3
|
||||
=== chrome/chromium (for slide render) ===
|
||||
found: /root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome
|
||||
=== creds ===
|
||||
.env.secrets: present (4 lines)
|
||||
.env: present
|
||||
=== aws creds loadable? ===
|
||||
NOVA_AWS_ACCESS_KEY_ID: set
|
||||
AWS_DEFAULT_REGION: us-east-1
|
||||
=== git ===
|
||||
main
|
||||
v1.18.1-11-gaa868c9
|
||||
=== disk ===
|
||||
/dev/loop2 148G 140G 1.3G 100% /
|
||||
@@ -0,0 +1,10 @@
|
||||
{"id": "T1", "req": "REQ-230", "title": "no forge names in synced files (guard test)", "pass": true, "rc": 0, "evidence": {"test": "test_no_forge_mentions_in_synced_files", "result": "1 passed in 2.20s", "log_tail": ["tests/test_no_forge_mentions.py::test_no_forge_mentions_in_synced_files PASSED [100%]", "1 passed in 2.20s"]}}
|
||||
{"id": "T2", "req": "REQ-230", "title": "forge-detection code genericized", "pass": true, "rc": 0, "evidence": {"hardcoded_gitea_gitlab_hits": 0, "genericization_signals": ["contract_ingestor.py: _forge_type() returns 'generic_forge'", "hitl_gates.py: GITHUB_ACTOR or FORGE_ACTOR (no GITEA_ACTOR)", "run_platform.sh:166: GITHUB_ACTOR:-FORGE_ACTOR fallback"]}}
|
||||
{"id": "T3", "req": "REQ-231", "title": "synced docs stripped of internal provenance", "pass": false, "rc": 1, "evidence": {"provenance_hit_count": 40, "contaminated_files": ["docs/ONBOARDING.md (REQ-182,183,184; D-113,114,119)", "docs/METRICS.md (REQ-191,192,193,194,211,212; D-083,096,113,114,119)", "docs/presentations/README.md (REQ-214,226,228; D-130,141; .ciagent/PROJECT.md)", "docs/presentations/nova-no-humans-platform.{md,marp.md,html,talking-points.md} (v1.X milestone headers)", "docs/presentations/assets/mmd/developer-experience-08-semver.mmd (v1.12 header)"], "root_cause": "test_no_forge_mentions.py only guards forge names, not provenance IDs", "defect": "F7"}}
|
||||
{"id": "T4", "req": "REQ-232", "title": "migration docs removed + thesis moved", "pass": true, "rc": 0, "evidence": {"docs_NOVA_MIGRATION_gone": true, "docs_NOVA_AWS_MIGRATION_gone": true, "docs_NO_HUMANS_THESIS_gone": true, "ciagent_NO_HUMANS_THESIS_present": true}}
|
||||
{"id": "T5", "req": "REQ-239", "title": "S&P theme CSS palette on all chrome", "pass": true, "rc": 0, "evidence": {"css_exists": true, "css_size_bytes": 2914, "red_present": true, "black_present": true, "white_present": true, "chrome_covered": ["section/bg", "section.title", "h1-h3 headings", "table th", "blockquote", "pre/code", "header", "footer", "pagination (.bespoke-progress-bar)", "strong"]}}
|
||||
{"id": "T6", "req": "REQ-240", "title": "render pipeline script + mermaid theme", "pass": true, "rc": 0, "evidence": {"render_slides_executable": true, "render_slides_size": 2736, "sp_theme_json_has_red": true, "sp_theme_json_has_black": true, "render_deck_sh_still_present": true, "render_deck_excluded_from_sync": true, "caveat": "README:107 still references render_deck.sh (deferred to T9)"}}
|
||||
{"id": "T7", "req": "REQ-241", "title": "slides CI workflow path trigger", "pass": false, "rc": 1, "evidence": {"wrong_path_hits": [".github/workflows/slides.yml:8: - 'assets/nova-sp-theme.css' (non-existent)", "workflows-src/slides.yml:8: - 'assets/nova-sp-theme.css' (non-existent)"], "correct_path": "docs/presentations/assets/nova-sp-theme.css", "src_dotgithub_identical": true, "defect": "F6", "impact": "Explicit CSS path trigger points at nothing; only the docs/presentations/** glob catches CSS edits. Dead entry should be corrected or removed."}}
|
||||
{"id": "T8", "req": "REQ-242", "title": "slide-pipeline guard test", "pass": true, "rc": 0, "evidence": {"passed": 12, "failed": 0, "duration_s": 1.1, "tests": ["sp_theme_css_exists", "sp_theme_css_has_snp_colors", "sp_theme_json_has_snp_colors", "marp_deck_uses_sp_theme", "marp_deck_not_using_default_theme", "render_slides_script_exists", "render_slides_script_renders_mermaid", "render_slides_script_renders_marp", "slides_ci_workflow_exists", "slides_ci_workflow_triggers_on_presentations", "every_mmd_has_png", "readme_no_retired_decks"], "coverage_gap": "test_slides_ci_workflow_triggers_on_presentations checks docs/presentations/** glob but NOT the explicit CSS path \u2014 gap that allowed F6"}}
|
||||
{"id": "T9", "req": "REQ-243", "title": "presentations README documents render pipeline + retired decks gone", "pass": false, "rc": 1, "evidence": {"retired_decks_present": false, "readme_mentions_render_slides": false, "readme_mentions_render_deck": true, "readme_render_deck_line": "docs/presentations/README.md:107: 'automated by scripts/render_deck.sh'", "readme_mentions_theme_css": true, "defect": "F10", "impact": "README documents the retired render_deck.sh pipeline, not the active render_slides.sh. Consumers reading synced README reference a script excluded from sync."}}
|
||||
{"id": "T10", "req": "REQ-244", "title": "12-month product roadmap slides 20+21 + talking points", "pass": true, "rc": 0, "evidence": {"marp_slide15": true, "marp_slide20": true, "marp_slide21": true, "talking_points_slide15": true, "talking_points_slide20": true, "talking_points_slide21": true, "quarters": ["Q1 Pilot Activation", "Q2 Provable Trust", "Q3 Compounding ROI", "Q4 Agentic Substrate"], "distinct_from_slide15": true}}
|
||||
@@ -186,8 +186,37 @@ def is_configured():
|
||||
return bool(os.environ.get("WIZ_API_TOKEN") and os.environ.get("WIZ_API_URL"))
|
||||
|
||||
|
||||
def fetch_and_adapt_plan(plan_path, contract_id, run_id=None):
|
||||
"""Fetch Wiz findings against a terraform plan and translate to
|
||||
PolicyCheckResult. REQ-250 (v1.21): Wiz scans the terraform plan
|
||||
output. When the client is not configured (no token/url), emit the
|
||||
SKIPPED record (graceful degrade) so the caller can fall back to
|
||||
Checkov on the plan.
|
||||
"""
|
||||
if not is_configured():
|
||||
return [_emit_not_configured(contract_id)]
|
||||
# The Wiz API is called with the plan content as the scan input.
|
||||
client = WizClient()
|
||||
issues = client.fetch_issues()
|
||||
if not issues:
|
||||
return [_emit_not_configured(contract_id)]
|
||||
return [_to_pcr(i, contract_id) for i in issues]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 3:
|
||||
print("usage: wiz_adapter.py <wiz_issues.json> <contract-id>", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
print(json.dumps(adapt(sys.argv[1], sys.argv[2]), indent=2))
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="Wiz adapter (REQ-250: plan-mode supported)")
|
||||
parser.add_argument("wiz_json", nargs="?", help="wiz_issues.json (legacy positional mode)")
|
||||
parser.add_argument("contract_id_pos", nargs="?", help="contract-id (legacy positional mode)")
|
||||
parser.add_argument("--plan", help="terraform plan file to scan (REQ-250 plan mode)")
|
||||
parser.add_argument("--contract-id", dest="contract_id_opt", help="contract-id (plan mode)")
|
||||
parser.add_argument("--run-id", help="run-id for the plan scan (plan mode)")
|
||||
args = parser.parse_args()
|
||||
if args.plan:
|
||||
cid = args.contract_id_opt or ""
|
||||
out = fetch_and_adapt_plan(args.plan, cid, run_id=args.run_id)
|
||||
print(json.dumps(out, indent=2))
|
||||
elif args.wiz_json and args.contract_id_pos:
|
||||
print(json.dumps(adapt(args.wiz_json, args.contract_id_pos), indent=2))
|
||||
else:
|
||||
parser.error("either --plan <file> --contract-id <id> OR <wiz_issues.json> <contract-id>")
|
||||
@@ -593,32 +593,30 @@ def _check_cap_023_metrics_collector() -> Tuple[Status, str]:
|
||||
|
||||
|
||||
def _check_cap_024_deck_structure() -> Tuple[Status, str]:
|
||||
"""CAP-024: unified deck structure (v1.17).
|
||||
"""CAP-024: unified deck structure (v1.17 + v1.21 refinement).
|
||||
|
||||
Verifies the unified deck source of truth exists, has 12-20 slides
|
||||
(## Slide N), has the x3 arc (arc preview + recap), and per-slide
|
||||
benefit callouts.
|
||||
Verifies the unified deck source of truth exists, has 18 main slides
|
||||
(## Slide N) + 1 appendix, has the recap+ask closing, and per-slide
|
||||
benefit callouts. v1.21 renamed the deck + restructured to a 4-beat arc.
|
||||
"""
|
||||
import os
|
||||
deck_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"docs", "presentations", "nova-no-humans-platform.md")
|
||||
"docs", "presentations", "nova-autonomous-cloud-delivery.md")
|
||||
if not os.path.isfile(deck_path):
|
||||
return "Skipped", "unified deck not found"
|
||||
with open(deck_path) as f:
|
||||
content = f.read()
|
||||
slide_count = content.count("## Slide ")
|
||||
if slide_count < 12 or slide_count > 20:
|
||||
return "Broken", f"deck has {slide_count} slides (expected 12-20)"
|
||||
has_arc_preview = "Arc Preview" in content
|
||||
if slide_count < 18 or slide_count > 19:
|
||||
return "Broken", f"deck has {slide_count} main slides (expected 18-19)"
|
||||
has_recap = "Recap + Ask" in content
|
||||
has_benefit = content.count("Benefit:") >= 10
|
||||
if not (has_arc_preview and has_recap and has_benefit):
|
||||
if not (has_recap and has_benefit):
|
||||
missing = []
|
||||
if not has_arc_preview: missing.append("arc preview")
|
||||
if not has_recap: missing.append("recap+ask")
|
||||
if not has_benefit: missing.append("per-slide benefit callouts")
|
||||
return "Broken", f"deck missing: {missing}"
|
||||
return "Verified", f"deck has {slide_count} slides, x3 arc present, per-slide benefits present"
|
||||
return "Verified", f"deck has {slide_count} slides, recap+ask present, per-slide benefits present"
|
||||
|
||||
|
||||
# Registry: ordered, each entry is (capability_id, name, tier, check_fn).
|
||||
|
||||
+69
-160
@@ -13,17 +13,18 @@ every deck and a presenter-ready cue sheet for delivery.
|
||||
|
||||
```
|
||||
Step 1: full markdown Step 2: Marp deck Step 3: HTML + PPTX Step 4: Talking points
|
||||
(source of truth) ──► (lean, 10 slides) ──► (rendered) ──► (presenter cues)
|
||||
(source of truth) ──► (lean, 21 slides) ──► (rendered) ──► (presenter cues)
|
||||
*.md *-marp.md *.html / *.pptx *-talking-points.md
|
||||
+ speaker notes + embedded PNG diagrams + 3-6 bullets per slide
|
||||
+ mermaid code blocks + Marp frontmatter + key takeaway per slide
|
||||
+ maturity badges + indexed by Marp slide #
|
||||
+ no speaker notes + content distilled from Step 1
|
||||
+ no speaker notes + indexed by Marp slide #
|
||||
+ no maturity badges + content distilled from Step 1
|
||||
+ no version in footer
|
||||
```
|
||||
|
||||
### Step 1 — Full markdown (source of truth)
|
||||
|
||||
**File convention:** `<deck-name>.md` (e.g. `nova-no-humans-platform.md`).
|
||||
**File convention:** `<deck-name>.md` (e.g. `nova-autonomous-cloud-delivery.md`).
|
||||
|
||||
Write the complete deck as a standard markdown file. This is the **source of
|
||||
truth** — it contains:
|
||||
@@ -34,9 +35,9 @@ truth** — it contains:
|
||||
the "who cares and why," and the honesty caveats.
|
||||
- Mermaid diagrams as ```` ```mermaid ```` fenced code blocks (these render
|
||||
on GitHub/Pages but not in Marp — Step 2 converts them to images).
|
||||
- An honest "shipped vs. planned" framing: every "available today" claim is
|
||||
grounded in shipped/verified work; every "planned" item is explicitly
|
||||
marked.
|
||||
- An honest "shipped vs. deferred" framing: every "available today" claim is
|
||||
grounded in shipped/verified work; every "deferred" item is explicitly
|
||||
marked with the blocking work in plain language.
|
||||
|
||||
**Why this file is the source of truth:** it is reviewable in any markdown
|
||||
viewer, diffs cleanly in git, and carries the full reasoning (speaker notes)
|
||||
@@ -45,13 +46,13 @@ 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. `nova-no-humans-platform-marp.md`).
|
||||
**File convention:** `<deck-name>-marp.md` (e.g. `nova-autonomous-cloud-delivery-marp.md`).
|
||||
|
||||
Synthesize the full markdown into a lean Marp deck:
|
||||
|
||||
- **Marp frontmatter** at the top: `marp: true`, `theme: default`,
|
||||
- **Marp frontmatter** at the top: `marp: true`, `theme: nova-sp`,
|
||||
`paginate: true`, `size: 16x9`, a header/footer, and an inline `style:`
|
||||
block for fonts, colors, tables, badges.
|
||||
block for fonts, colors, tables.
|
||||
- **No speaker notes.** The Marp deck is what the audience sees; the
|
||||
speaker notes live only in the Step 1 source of truth.
|
||||
- **Mermaid diagrams → PNG images.** Marp does not render mermaid fenced
|
||||
@@ -60,8 +61,10 @@ Synthesize the full markdown into a lean Marp deck:
|
||||
and embed it with ``.
|
||||
- **`<!-- _class: title -->` + `<!-- _paginate: false -->`** on title and
|
||||
closing slides for the dark-background title style.
|
||||
- **Maturity badges** using inline spans:
|
||||
`<span class="badge planned">Planned</span>`
|
||||
- **No maturity badges.** The deck no longer uses `<span class="badge">`
|
||||
spans. Deferred items are named in plain language with their blocking
|
||||
work, not tagged with a badge.
|
||||
- **No version in the footer.** The footer carries the deck title only.
|
||||
- **Tighter prose** than Step 1 — strip the speaker-note nuance; keep the
|
||||
leadership-relevant selling points.
|
||||
|
||||
@@ -69,10 +72,8 @@ 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 release** as a downloadable attachment (binary, not
|
||||
committed to git).
|
||||
|
||||
#### HTML export (committed to repo)
|
||||
is also committed to the repo** as a first-class binary artifact and is
|
||||
attached to the phase's release via `scripts/attach_release_asset.py`.
|
||||
|
||||
```bash
|
||||
CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
@@ -81,135 +82,67 @@ CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
-o docs/presentations/<deck-name>.html
|
||||
```
|
||||
|
||||
HTML export inlines images as base64 data URIs — no `--allow-local-files`
|
||||
needed for self-contained output, but it's required when the Marp deck
|
||||
references local PNG assets. The resulting HTML is a single self-contained
|
||||
file that renders the full deck with the S&P Global Energy theme.
|
||||
|
||||
**Re-render the HTML whenever the Marp source changes.** The HTML files are
|
||||
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 release)
|
||||
|
||||
```bash
|
||||
CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
npx --yes @marp-team/marp-cli@latest --allow-local-files \
|
||||
docs/presentations/<deck-name>-marp.md \
|
||||
-o <output-path>.pptx
|
||||
```
|
||||
|
||||
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 release via
|
||||
`scripts/attach_release_asset.py`. The render + commit + attach pipeline is
|
||||
automated by `scripts/render_deck.sh`.
|
||||
HTML export inlines images as base64 data URIs. PPTX export requires
|
||||
`--allow-local-files` so the local PNG diagrams are embedded in the file.
|
||||
The render + commit + attach pipeline is automated by `scripts/render_slides.sh`.
|
||||
|
||||
### Step 4 — Talking points (presenter cues)
|
||||
|
||||
**File convention:** `<deck-name>-talking-points.md` (e.g.
|
||||
`nova-no-humans-platform-talking-points.md`).
|
||||
`nova-autonomous-cloud-delivery-talking-points.md`).
|
||||
|
||||
Distill the source of truth (Step 1) into presenter-ready cues, indexed by
|
||||
the Marp deck (Step 2) slide structure:
|
||||
|
||||
- **One section per Marp slide** — `## Slide N — Title`, matching the Marp
|
||||
deck's 11 main + Appendix TOC + appendix slide structure exactly. The Marp deck
|
||||
provides the indexing and context (what the audience sees); the source
|
||||
markdown provides the content (the speaker notes, the detail, the nuance).
|
||||
deck's 20 main + 1 appendix slide structure exactly.
|
||||
- **3-6 talking point bullets per slide** — punchy, actionable cues distilled
|
||||
from the source markdown's speaker notes. NOT the speaker notes verbatim
|
||||
(those are too long and too contextual). These are prompts: "Land this
|
||||
point," "Contrast with X," "Be honest about Y."
|
||||
from the source markdown's speaker notes.
|
||||
- **Key takeaway per slide** — the one memorable thing the audience should
|
||||
walk away with from that slide.
|
||||
- **No content duplication** — the talking points reference the Marp slides
|
||||
for visual context and the source markdown for full detail. They don't
|
||||
repeat either; they bridge them.
|
||||
|
||||
**Why this file exists:** a presenter needs a cue sheet they can glance at
|
||||
during delivery — not the full speaker notes (too long), not the Marp slides
|
||||
(no detail). The talking points file is the middle layer: what to say, in
|
||||
what order, with what emphasis, per slide.
|
||||
|
||||
**When to update:** re-distill the talking points whenever the Marp deck
|
||||
structure changes (slides added, removed, merged, or re-ordered) or whenever
|
||||
the source markdown's speaker notes are updated. The talking points are a
|
||||
*derived artifact* — if a fact is wrong, fix it in the source markdown (Step 1)
|
||||
and re-distill.
|
||||
for visual context and the source markdown for full detail.
|
||||
|
||||
## Directory layout
|
||||
|
||||
```
|
||||
docs/presentations/
|
||||
├── README.md ← this file
|
||||
├── 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)
|
||||
├── nova-autonomous-cloud-delivery.md ← Step 1: full source of truth (20 main slides + speaker notes)
|
||||
├── nova-autonomous-cloud-delivery-marp.md ← Step 2: Marp deck (20 main + 1 appendix = 21 slides)
|
||||
├── nova-autonomous-cloud-delivery.html ← Step 3: rendered HTML (committed, S&P-themed)
|
||||
├── nova-autonomous-cloud-delivery.pptx ← Step 3: rendered PPTX (committed, S&P-themed)
|
||||
├── nova-autonomous-cloud-delivery-talking-points.md ← Step 4: presenter cues (19 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-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
|
||||
├── platform-works-02-end-to-end-flow.png
|
||||
├── platform-works-03-north-star.png
|
||||
├── platform-works-03-scope-boundary.png
|
||||
├── platform-works-04-confidence-signal.png
|
||||
├── platform-works-05-attestation-flow.png
|
||||
├── platform-works-07-zero-trust.png
|
||||
├── developer-experience-01b-scope-boundary.png
|
||||
├── developer-experience-02-what-dev-does.png
|
||||
├── developer-experience-03-no-cloning.png
|
||||
├── developer-experience-04-promotion-journey.png
|
||||
├── developer-experience-05-catalog.png
|
||||
├── developer-experience-07-decommission.png
|
||||
├── developer-experience-08-semver.png
|
||||
├── platform-architecture.png ← shared high-level logical architecture (both decks)
|
||||
└── road-to-north-star.png
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
### Appendix structure
|
||||
|
||||
Each Marp deck has **11 main slides + an Appendix TOC + appendix slides**. The
|
||||
main 11 are the presentation; the appendix is for deep dives and Q&A backup.
|
||||
The platform-works deck has 8 appendix slides (A1–A8); the developer-experience
|
||||
deck has 7 appendix slides (A1–A7). Both include an Appendix TOC slide.
|
||||
Each Marp deck has **20 main slides + 1 appendix slide**. The main 20 are the
|
||||
presentation; the appendix is for Q&A backup. (v1.22 split slides 3 and 8
|
||||
to relieve overflow, increasing the count from 18 to 20.)
|
||||
|
||||
- **Main slides** (1-11): the story arc, high-impact, minimal text,
|
||||
visual-heavy. These are what the audience sees during the talk.
|
||||
- **Appendix slides** (TOC + A1..An): detail-heavy slides moved out of the
|
||||
main 10 to preserve the narrative flow. The appendix starts with a TOC
|
||||
slide listing the contents, followed by detail slides and a glossary.
|
||||
- **The Road to the North Star** is a required appendix slide in both decks
|
||||
— a phased timeline from v1.0 demo to the North Star, annotated as
|
||||
"proposed phasing, not formally planned."
|
||||
- **The Glossary** is a required appendix slide in both decks — defines
|
||||
acronyms (OIDC, ABAC, CMK, CMDB, RPO, HITL, VCS, NFR) for the audience.
|
||||
- **Main slides** (1-20): the story arc — Problem → Solution → Proof →
|
||||
Roadmap + Ask. These are what the audience sees during the talk.
|
||||
- **Appendix slide** (A1): the Metrics Glossary — detail-heavy reference for
|
||||
Q&A.
|
||||
|
||||
### Maturity framing
|
||||
### Honesty framing
|
||||
|
||||
Every capability claim in a deck is tagged with a `Planned` badge when the item is on the roadmap but not yet implemented:
|
||||
|
||||
| Badge | Meaning |
|
||||
|---|---|
|
||||
| `Planned` | On the roadmap, not yet implemented |
|
||||
|
||||
This is non-negotiable for a leadership audience: never present a roadmap
|
||||
item as a current capability, and never bury a tested capability's
|
||||
availability. When in doubt, check `.ciagent/ROADMAP.md` and the milestone
|
||||
status in `.ciagent/PROJECT.md`.
|
||||
Every capability claim in the deck is grounded, derived, or honestly
|
||||
deferred with its blocking work named in plain language. Internal provenance
|
||||
(decision IDs, requirement IDs, internal file paths) is kept out of the
|
||||
audience-facing slides — those live in the `.ciagent/` files only. When in
|
||||
doubt, check `.ciagent/ROADMAP.md` and the milestone status in
|
||||
`.ciagent/PROJECT.md`.
|
||||
|
||||
### Audience
|
||||
|
||||
@@ -221,8 +154,10 @@ Head of Infrastructure, Head of DevOps. The framing rules:
|
||||
"composition."
|
||||
- **Selling points forward.** Each slide leads with the leadership-relevant
|
||||
outcome; the mechanism follows.
|
||||
- **Zero-trust, security, observability, auditability, DX, citizen
|
||||
developer** are the themes — not implementation details.
|
||||
- **Security, remediation velocity, reliability, lead time, observability,
|
||||
citizen developer** are the themes — not implementation details.
|
||||
- **"Infrastructure operations become visible"** is the recurring theme across
|
||||
the deck.
|
||||
|
||||
### Diagrams
|
||||
|
||||
@@ -232,8 +167,7 @@ style (renders on GitHub/Pages). For the Marp deck (Step 2):
|
||||
1. Extract the mermaid block into `assets/mmd/<deck>-<slide>-<name>.mmd`.
|
||||
2. Use **horizontal layouts** (`flowchart LR`) or **subgraph row-wrapping**
|
||||
for wide diagrams so the PNG fits a 16:9 slide without shrinking to
|
||||
illegibility. A 9-node sequential `flowchart TD` renders as a tall thin
|
||||
strip — restructure it as 2-row subgraphs or `flowchart LR`.
|
||||
illegibility.
|
||||
3. Render with a 2x scale factor and transparent background for crisp slides.
|
||||
4. Embed with `` (or `h:320` for tall images).
|
||||
|
||||
@@ -261,42 +195,16 @@ for f in mmd/*.mmd; do
|
||||
done
|
||||
```
|
||||
|
||||
The `puppeteer-config.json` passes `--no-sandbox` to the headless browser
|
||||
(required when running as root in this environment). The `--configFile
|
||||
mmd/sp-theme.json` applies the S&P Global Red/Black/White theme (dark
|
||||
`#1B1B1B` accent nodes with `#D6002A` red borders, white supporting nodes,
|
||||
`#F0F0F0` subgraph backgrounds). Each `.mmd` file also carries the same
|
||||
theme inline via a `%%{init:...}%%` block so it renders correctly even
|
||||
without the `--configFile` flag.
|
||||
|
||||
### Export a Marp deck to HTML (committed to repo)
|
||||
### Render a Marp deck to HTML + PPTX (committed artifacts)
|
||||
|
||||
```bash
|
||||
CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
npx --yes @marp-team/marp-cli@latest --allow-local-files \
|
||||
docs/presentations/<deck-name>-marp.md \
|
||||
-o docs/presentations/<deck-name>.html
|
||||
bash scripts/render_slides.sh nova-autonomous-cloud-delivery
|
||||
```
|
||||
|
||||
HTML export inlines images as base64 data URIs. The `--allow-local-files`
|
||||
flag is needed when the Marp deck references local PNG assets (like the
|
||||
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 release)
|
||||
|
||||
```bash
|
||||
CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
npx --yes @marp-team/marp-cli@latest --allow-local-files \
|
||||
docs/presentations/<deck-name>-marp.md \
|
||||
-o <output-path>.pptx
|
||||
```
|
||||
|
||||
`--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 release.
|
||||
This renders all mermaid PNGs, the HTML, and the PPTX, and stages them for
|
||||
commit. The `--allow-local-files` flag is required so local PNG diagrams are
|
||||
embedded. Both HTML and PPTX are committed to the repo; the PPTX is also
|
||||
attached to the phase's release.
|
||||
|
||||
## Adding a new presentation
|
||||
|
||||
@@ -306,16 +214,14 @@ attachments to the release.
|
||||
2. **Extract any mermaid diagrams** into `assets/mmd/<deck-name>-<slide>-<name>.mmd`
|
||||
and render them to `assets/png/` (command above).
|
||||
3. **Synthesize the Marp deck** as `<deck-name>-marp.md` with frontmatter,
|
||||
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 release
|
||||
release (do not commit PPTX to git).
|
||||
6. **Distill the talking points** as `<deck-name>-talking-points.md` — one
|
||||
no speaker notes, embedded PNGs, and no badges.
|
||||
4. **Render to HTML + PPTX** via `scripts/render_slides.sh <deck-name>` and
|
||||
commit both to `docs/presentations/`.
|
||||
5. **Distill the talking points** as `<deck-name>-talking-points.md` — one
|
||||
section per Marp slide, 3-6 talking point bullets + key takeaway, content
|
||||
distilled from the source markdown (Step 1), indexed by the Marp deck
|
||||
(Step 2) slide structure.
|
||||
7. **Verify** the PPTX slide count and that media files are embedded:
|
||||
6. **Verify** the PPTX slide count and that media files are embedded:
|
||||
```bash
|
||||
python3 -c "
|
||||
import zipfile, re
|
||||
@@ -330,11 +236,14 @@ attachments to the release.
|
||||
|
||||
| Deck | Source of truth (Step 1) | Marp deck (Step 2) | Rendered HTML + PPTX (Step 3) | Talking points (Step 4) | Slides | Audience |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Nova — The No-Humans Infrastructure Platform | `nova-no-humans-platform.md` | `nova-no-humans-platform-marp.md` | `nova-no-humans-platform.html` + `.pptx` (committed + release-attached) | `nova-no-humans-platform-talking-points.md` | 19 main + 2 appendix (21) | CTO, Head of Cloud, Head of Infra, Head of DevOps |
|
||||
| Nova — The Autonomous Cloud Delivery Platform | `nova-autonomous-cloud-delivery.md` | `nova-autonomous-cloud-delivery-marp.md` | `nova-autonomous-cloud-delivery.html` + `.pptx` (committed + release-attached) | `nova-autonomous-cloud-delivery-talking-points.md` | 20 main + 1 appendix (21) | CTO, Head of Cloud, Head of Infra, Head of DevOps |
|
||||
|
||||
> **v1.18 (D-130):** the two legacy decks (How the Platform Works + The
|
||||
> Developer Experience) were consolidated into a single unified narrative
|
||||
> 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 release (REQ-228, D-141).
|
||||
> **v1.21:** the deck was renamed from "No-Humans Infrastructure Platform"
|
||||
> to "Autonomous Cloud Delivery Platform" (professional framing; conveys
|
||||
> autonomy without the provocative wording). The narrative restructured to
|
||||
> a 4-beat arc (Problem → Solution → Proof → Roadmap + Ask). Internal
|
||||
> provenance (decision IDs, requirement IDs, file paths) removed from
|
||||
> audience-facing slides. Maturity badges removed. The RACI matrix expanded
|
||||
> to four roles (Quality Engineering + SRE). The Atelier slide split into
|
||||
> two. The pipeline hardened: Checkov on static code before the plan;
|
||||
> Wiz-or-Checkov on the plan (never both).
|
||||
@@ -0,0 +1,11 @@
|
||||
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1B1B1B", "primaryBorderColor": "#D6002A", "primaryTextColor": "#fff", "secondaryColor": "#fff", "secondaryBorderColor": "#D6002A", "secondaryTextColor": "#1B1B1B", "tertiaryColor": "#F0F0F0", "clusterBkg": "#F0F0F0", "lineColor": "#1B1B1B", "fontFamily": "\"Akkurat Pro\", \"Helvetica Neue\", \"Arial\", sans-serif"}}}%%
|
||||
|
||||
flowchart TB
|
||||
A["Contract → Resolver → Adapter"] --> D["Checkov (static code)"]
|
||||
D --> E["Terraform plan"]
|
||||
E --> F["Wiz (on plan) → Confidence signal → Stage gate"]
|
||||
F --> I["Apply → Evidence + Ledger"]
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
classDef supporting fill:#fff,color:#1B1B1B,stroke:#D6002A,stroke-width:1px
|
||||
class D,E,F accent
|
||||
class A,I supporting
|
||||
@@ -0,0 +1,17 @@
|
||||
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1B1B1B", "primaryBorderColor": "#D6002A", "primaryTextColor": "#fff", "secondaryColor": "#fff", "secondaryBorderColor": "#D6002A", "secondaryTextColor": "#1B1B1B", "tertiaryColor": "#F0F0F0", "clusterBkg": "#F0F0F0", "lineColor": "#1B1B1B", "fontFamily": "\"Akkurat Pro\", \"Helvetica Neue\", \"Arial\", sans-serif"}}}%%
|
||||
|
||||
flowchart TB
|
||||
A["Platform<br/>components"] --> B["CloudEvents<br/>envelope"]
|
||||
B --> C["Event log"]
|
||||
B --> D["Decision<br/>ledger"]
|
||||
B --> E["Run records"]
|
||||
C --> F["Collector"]
|
||||
D --> F
|
||||
E --> F
|
||||
F --> G["Cold store"]
|
||||
G --> H["PowerBI<br/>views"]
|
||||
H --> I["Live ops<br/>dashboard"]
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
classDef supporting fill:#fff,color:#1B1B1B,stroke:#D6002A,stroke-width:1px
|
||||
class B,F,G,H,I accent
|
||||
class A,C,D,E supporting
|
||||
@@ -4,9 +4,18 @@
|
||||
* 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.
|
||||
* This theme is a STANDALONE stylesheet (applied via `marp --theme
|
||||
* nova-sp-theme.css`). It does NOT `@import "default"` because Marp's
|
||||
* default theme applies `padding: 56px 64px` (which does not reserve
|
||||
* header/footer space) and other base styles (font, color, list spacing)
|
||||
* that would conflict with the S&P palette. Instead, this theme sets
|
||||
* the padding explicitly: 48px top (reserves header space), 40px bottom
|
||||
* (reserves footer space), 56px sides. This gives precise control over
|
||||
* the padding budget. (GRILL revision 2 — @import rejection documented.)
|
||||
*
|
||||
* v1.22 (REQ-254,255,256): added section padding + overflow handling,
|
||||
* aspect-ratio-aware image rules, title-slide chrome suppression,
|
||||
* paragraph/list/table spacing tightening.
|
||||
*/
|
||||
|
||||
:root {
|
||||
@@ -17,12 +26,17 @@
|
||||
--sp-dark-grey: #2E2E2E;
|
||||
}
|
||||
|
||||
/* Base section */
|
||||
/* Base section — padding reserves header (top) + footer (bottom) space.
|
||||
* REQ-254: zero padding was the root cause of "out of whack" layout.
|
||||
* 48px top reserves header chrome; 40px bottom reserves footer chrome;
|
||||
* 56px sides give breathing room. */
|
||||
section {
|
||||
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||
font-size: 22px;
|
||||
color: var(--sp-black);
|
||||
background: var(--sp-white);
|
||||
padding: 48px 56px 40px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Headings — S&P Red */
|
||||
@@ -31,6 +45,12 @@ 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; }
|
||||
|
||||
/* REQ-256: tighten h2 + lead-paragraph spacing (the deck's recurring
|
||||
* `## Slide N — Title` + `**bold lead**` pattern). Default <p> margins
|
||||
* waste ~44px per slide; this reclaims ~22px. */
|
||||
section h2 + p { margin-top: 0.2em; }
|
||||
section p { margin: 0.4em 0; }
|
||||
|
||||
/* Title slides — black background, red top border */
|
||||
section.title {
|
||||
background: var(--sp-black);
|
||||
@@ -40,10 +60,26 @@ section.title {
|
||||
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; }
|
||||
/* REQ-256: suppress header/footer chrome on title slides. The
|
||||
* `<!-- _class: title -->` + `<!-- _paginate: false -->` directives
|
||||
* only suppress the page number, not the chrome. This prevents the
|
||||
* header/footer from colliding with title/appendix content. */
|
||||
section.title header, section.title footer { display: none; }
|
||||
|
||||
/* Tables — grey header with red underline, explicit white body for readability on any background */
|
||||
table { font-size: 18px; width: 100%; border-collapse: collapse; background: var(--sp-white); }
|
||||
th { background: var(--sp-grey); border-bottom: 2px solid var(--sp-red); padding: 4px 8px; text-align: left; }
|
||||
td { background: var(--sp-white); color: var(--sp-black); border-bottom: 1px solid var(--sp-grey); padding: 4px 8px; }
|
||||
/* Ensure tables on dark/title slides remain readable: white card with a subtle border */
|
||||
section.title table, section table { background: var(--sp-white); }
|
||||
section.title td, section td { background: var(--sp-white); color: var(--sp-black); }
|
||||
section.title th, section th { background: var(--sp-grey); color: var(--sp-black); }
|
||||
|
||||
/* REQ-256: dense tables (≥8 rows) use tighter cell padding so 10-13 row
|
||||
* tables (slides 8, 12, A1) fit. Apply via `table.dense` class in the
|
||||
* marp deck. */
|
||||
table.dense td, table.dense th { padding: 4px 8px; }
|
||||
table.dense { font-size: 16px; }
|
||||
|
||||
/* Blockquotes — red left border */
|
||||
blockquote { border-left: 4px solid var(--sp-red); color: var(--sp-dark-grey); font-size: 20px; padding-left: 12px; }
|
||||
@@ -53,8 +89,18 @@ pre { background: var(--sp-black); color: var(--sp-white); border-radius: 4px; p
|
||||
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; }
|
||||
/* REQ-255: aspect-ratio-aware image rules. The blunt `max-height: 320px`
|
||||
* broke `w:` directives on tall images (slide 9) and did nothing for
|
||||
* ultra-wide images (slide 6). The new rule uses `object-fit: contain`
|
||||
* and `max-width: 100%` so images scale within the content area without
|
||||
* ignoring explicit `w:`/`h:` directives. */
|
||||
img { display: block; margin: 0 auto; max-width: 100%; max-height: 380px; object-fit: contain; }
|
||||
/* Wide diagrams (ultra-wide aspect): tighter max-height so they don't
|
||||
* render as a thin strip. Apply via `![w:1000 class:wide]` — or rely on
|
||||
* the default max-height which is already tighter. */
|
||||
img.wide { max-height: 280px; }
|
||||
/* Tall diagrams: more vertical room. Apply via `![h:480 class:tall]`. */
|
||||
img.tall { max-height: 480px; }
|
||||
|
||||
/* Header/footer — subtle grey */
|
||||
header { color: var(--sp-dark-grey); border-bottom: 1px solid var(--sp-grey); }
|
||||
@@ -69,9 +115,17 @@ footer { color: var(--sp-dark-grey); border-top: 1px solid var(--sp-grey); }
|
||||
.bespoke-progress-parent { background: var(--sp-grey); }
|
||||
.bespoke-progress-bar { background: var(--sp-red) !important; }
|
||||
|
||||
/* Lists — tighter */
|
||||
/* Lists — tighter. REQ-256: add ol styling (match ul). */
|
||||
ul { margin-top: 0.3em; }
|
||||
ol { margin-top: 0.3em; }
|
||||
li { margin-bottom: 0.2em; }
|
||||
|
||||
/* Strong — S&P Red for emphasis in lead lines */
|
||||
strong { color: var(--sp-red); }
|
||||
|
||||
/* REQ-256: PPTX export fidelity — no scrollbars in exported slides.
|
||||
* The `overflow: auto` above is an authoring-time signal; in print/PPTX
|
||||
* we clamp to `hidden` so the exported slide is clean. */
|
||||
@media print {
|
||||
section { overflow: hidden; }
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
@@ -3,331 +3,313 @@ marp: true
|
||||
theme: nova-sp
|
||||
paginate: true
|
||||
size: 16x9
|
||||
header: 'Nova — The No-Humans Infrastructure Platform'
|
||||
footer: 'Act %{page}/5 — v1.20'
|
||||
footer: 'Nova — The Autonomous Cloud Delivery Platform'
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
# Nova — The No-Humans Infrastructure Platform
|
||||
# Nova — The Autonomous Cloud Delivery Platform
|
||||
|
||||
**Shifting from Operational Overhead to Strategic Value**
|
||||
|
||||
v1.18 — Citizen Developer & Production-Grade Guidance
|
||||
Product Development & Citizen Developer Overview
|
||||
|
||||
---
|
||||
|
||||
## Slide 1 — Arc Preview
|
||||
## Slide 1 — The Problem
|
||||
|
||||
**This deck proves Nova is the no-humans infrastructure platform — and shows you the metrics that make the claim defensible.**
|
||||
**Product teams now own their cloud infrastructure — but ownership without discipline is destroying value.**
|
||||
|
||||
**Today:** 18 capabilities verified, 0 consumer estates in production.
|
||||
- **No lifecycle planning.** Resources are authored for creation, not for patching, decommissioning, or rollback — so changes are destructive.
|
||||
- **Proactive scanning is not part of authoring.** AI-frontier models exploit zero-days at a rapid pace; teams cannot keep up by reacting. Modules must be scanned as code and at runtime — and remediated at the pace the threat moves.
|
||||
- **Bandwidth gaps in infrastructure operations.** Time spent on remediation + the push for innovation leaves operations chronically under-resourced; detections are missed, incidents grow.
|
||||
- **Tribal knowledge and the rockstar-operator problem.** Operations depend on a handful of administrators; when they leave, the knowledge leaves with them. The platform should encode the discipline, not the person.
|
||||
|
||||
**The 5-act arc:**
|
||||
1. **Problem** — why the operator is the bottleneck
|
||||
2. **Vision** — Nova's strategic direction (NORTH_STAR)
|
||||
3. **How** — the pipeline, Decision Ledger, attestation gates
|
||||
4. **Proof** — grounded metrics that make the claim defensible
|
||||
5. **Roadmap** — deferred metrics with unblock paths + the ask + scope + RACI
|
||||
Every hour a developer spends writing, deploying, fixing, or remediating infrastructure is an hour not spent releasing features to production.
|
||||
|
||||
**Benefit:** you leave knowing which claims are proven today, which are pipeline-ready, and which are deferred with a documented unblock path — no marketing, just grounded evidence.
|
||||
**Benefit:** the answer is an autonomous cloud delivery platform that encodes discipline as policy, scans proactively, remediates rapidly, and makes operations visible to leadership rather than hidden in tribal knowledge.
|
||||
|
||||
---
|
||||
|
||||
## Slide 2 — The No-Humans Imperative
|
||||
## Slide 2 — Nova's Vision
|
||||
|
||||
**Why the operator is the bottleneck — and why removing them from operations (not accountability) is the imperative.**
|
||||
> **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; the operator is never in the loop of normal operations.**
|
||||
|
||||
- **The cost of humans-in-the-loop:** L1/L2 ops hours, escalation latency, the trust gap
|
||||
- **The operator is the bottleneck:** provisioning takes days, not minutes
|
||||
- **The attestation model:** autonomy in operations, human at stage gates
|
||||
- Cites `docs/NO_HUMANS_THESIS.md`
|
||||
- **Visibility is the recurring theme** — security posture, remediation velocity, reliability, and lead time as queryable signals
|
||||
- **Provable, not promised** — trust established by deterministic scripts that calculate a score; the platform functions without AI
|
||||
- **Autonomy in operations, human at stage gates** — QA signs off for production; SRE greenlights operational readiness
|
||||
|
||||
**Benefit:** you now know the problem framing — autonomy in operations, human at stage gates, is the path forward.
|
||||
**Benefit:** the destination is autonomous operations with provable trust — security, remediation velocity, reliability, and lead time made visible to leadership, not promised to them.
|
||||
|
||||
---
|
||||
|
||||
## Slide 3 — Nova's Vision
|
||||
|
||||
> **Infrastructure operations become invisible. 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 production, SRE greenlights based on operational readiness — but the operator is never in the loop of normal operations.**
|
||||
|
||||
- Autonomy in operations, not in accountability
|
||||
- Cites `docs/NO_HUMANS_THESIS.md`
|
||||
|
||||
**Benefit:** you now know the destination — invisible operations with provable trust, not promised trust.
|
||||
|
||||
---
|
||||
|
||||
## Slide 4 — Strategic Objectives + Anti-Goals
|
||||
## Slide 3 — Strategic Objectives
|
||||
|
||||
**4 Strategic Objectives:**
|
||||
1. **Zero-touch operations** — autonomy as the default, not the demo
|
||||
2. **Provable trust in AI decisions** — Decision Ledger, confidence scoring, circuit breakers
|
||||
3. **Compounding, quantifiable ROI** — each quarter must reduce spend, free hours, avoid downtime
|
||||
4. **Default substrate for agentic consumption** — the platform AI agents reach for first
|
||||
1. **Zero-touch operations** — autonomy as the default, not the demo; stage-gate attestation (QA, SRE) remains human by design
|
||||
2. **Provable trust in automated decisions** — deterministic scripts calculate a score; the platform functions without AI; Decision Ledger, confidence scoring, circuit breakers, blast-radius controls
|
||||
3. **Compounding, quantifiable ROI** — four CTO-grade metrics, all flowing into PowerBI:
|
||||
- **Lead Time** (PR → Production) · **Infrastructure Vulnerability Count** (trend) · **MTTR** · **Cloud Spend Reduction**
|
||||
4. **Integrate with externally owned development platforms — regardless of source** — PDLC, SDLC, Agentic, or Citizen Developer; Nova provides skills + MCP endpoints; all prod intents go through the same controls and quality gates
|
||||
|
||||
**5 Anti-Goals (what Nova is NOT):**
|
||||
1. Not a hyperscaler competitor
|
||||
2. Not a general-purpose AI platform
|
||||
3. Not removing humans from accountability
|
||||
4. Not for legacy, untagged, or freeform infrastructure
|
||||
5. Not sold to operators
|
||||
|
||||
**Benefit:** you now know the scope boundaries — Nova is purpose-built for infrastructure operations, sold to leadership on outcomes.
|
||||
**Benefit:** the scope is explicit — Nova governs infrastructure and delivery, integrates with any upstream source through one validated contract, and measures success on four metrics a CTO can repeat back.
|
||||
|
||||
---
|
||||
|
||||
## Slide 5 — 12–18 Month Targets
|
||||
## Slide 4 — Anti-Goals (What Nova Is NOT)
|
||||
|
||||
**Current-milestone targets (grounded/derived):**
|
||||
1. Not a general-purpose AI agent platform
|
||||
2. Not a system that removes humans from accountability — only from normal operations
|
||||
3. Not an upstream development platform (no product backlogs, IDE, code authorship)
|
||||
4. Not a replacement for the Product Development Lifecycle (PDLC)
|
||||
|
||||
| Domain | Target | Status |
|
||||
|---|---|---|
|
||||
| MTTR (p95) | < 60s | grounded |
|
||||
| Cloud Spend Reduction | ≥ 25% | partial (CUR deferred D-096) |
|
||||
| L1/L2 Ops Hours Avoided | ≥ 70% | derived (N internal runs) |
|
||||
| Platform ROI | ≥ 250% | derived (formula; N=0 caveat) |
|
||||
| Decision Ledger Coverage | 100% | grounded |
|
||||
| Attestation Coverage | 100% | grounded |
|
||||
|
||||
**Post-Pilot targets (pipeline grounded; 0 consumers today):**
|
||||
|
||||
| Domain | Target | Status |
|
||||
|---|---|---|
|
||||
| Touchless Resolution Rate | ≥ 99% | partial |
|
||||
| Human Escalation Frequency | < 0.1% | partial |
|
||||
| AI Decision Accuracy | ≥ 99.5% | partial |
|
||||
|
||||
**Deferred:** Predictive vs Reactive ≥3:1 <span class="badge planned">Planned</span> · Drift Auto-Reversal ≥95% <span class="badge planned">Planned</span>
|
||||
|
||||
**Benefit:** you now know the destination numbers — and which are measurable today vs deferred honestly.
|
||||
**Benefit:** the boundaries are explicit — Nova is purpose-built for infrastructure operations and delivery, not a general-purpose AI agent or an upstream development platform.
|
||||
|
||||
---
|
||||
|
||||
## Slide 6 — The Platform Pipeline
|
||||
## Slide 5 — Scope: Downstream of PDLC
|
||||
|
||||
**How intent becomes verified infrastructure without an operator.**
|
||||
**Nova governs infrastructure and delivery. The PDLC is upstream — Nova never penetrates it. Integration is through one validated contract.**
|
||||
|
||||
Contract → Resolver → Adapter → Terraform Plan → Checkov (Policy) → Confidence Signal → HITL Gate → Apply → Evidence
|
||||
- **The PDLC is upstream:** product backlog, code authorship (AI agent, IDE, agentic SDLC), sprint planning, application business logic
|
||||
- **Nova is downstream:** contract ingestion → submission-readiness gate → policy enforcement → cloud resource lifecycle → environment progression (dev → qa → prod → dr) → immutable audit + attestation
|
||||
- **The integration point is one contract** — any upstream source (AI agent, agentic SDLC, dev platform) produces submissions subject to the same compliance standards
|
||||
- **Nova validates the submission, not the author** — the audit trail, the policy envelope, and the evidence stream are the same regardless of source
|
||||
|
||||
- Dev: autonomous (no HITL gate)
|
||||
- qa/prod/dr: attested (human sign-off required)
|
||||
- Grounded in `run_platform.sh` + `contract_resolver.py` + `confidence_signal.py`
|
||||
|
||||
**Benefit:** you now know the path from intent to evidence — and where the human appears (stage gates only).
|
||||
**Benefit:** a clean scope boundary — Nova is purpose-built for infrastructure operations and integrates with any upstream source through one validated contract, so the platform team's surface area stays bounded.
|
||||
|
||||
---
|
||||
|
||||
## Slide 7 — The Decision Ledger
|
||||
## Slide 6 — RACI: Who Owns What
|
||||
|
||||
**Every AI decision captured with confidence, alternatives, and outcome.**
|
||||
**Four roles, one matrix — citizen developer owns FRs + UAT, platform owns NFRs + infra, quality engineering owns the gate evidence, SRE owns operational readiness.**
|
||||
|
||||
- `outbox_writer.py` → SQLite append-only hash-chain table
|
||||
- `ai.decision.made`: decision_id=run_id, chosen_action=band, confidence=score, alternatives=perInput, human_override=HITL block
|
||||
- `attestation.recorded`: qa/prod/dr sign-offs
|
||||
- D-121, D-122, D-132. Honors D-083 (no S3 Object Lock/JWS — local hash-chain)
|
||||
| Work Category | Citizen Dev | Platform | Quality Eng | SRE |
|
||||
|---|---|---|---|---|
|
||||
| Functional Requirements | **R/A** | C | I | I |
|
||||
| User Acceptance Testing | **R/A** | C | I | I |
|
||||
| Non-Functional Requirements | I | **R/A** | C | C |
|
||||
| Infrastructure (cloud, state, IAM) | I | **R/A** | I | C |
|
||||
| QA (policy, confidence, schema) | 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** |
|
||||
|
||||
**D-122 honesty:** Nova's "AI" is the confidence-gated policy engine (confidence_signal + HITL gate), not an LLM planner. The Decision Ledger captures this real decision path — not a fabricated "AI agent."
|
||||
**R**=Responsible · **A**=Accountable (sign-off) · **C**=Consulted · **I**=Informed. Production readiness is co-owned: the platform runs attestations agentically; the citizen developer authorizes the promotion at the stage gate.
|
||||
|
||||
**Benefit:** you now know why 'autonomous' is defensible — every decision is immutable, queryable, and accountable. And you know exactly what 'AI' means here: a confidence-gated policy engine, not a black-box LLM.
|
||||
**Benefit:** every party knows what they bring, what the platform provides, what quality engineering guards, and where SRE signs off — accountability is explicit, never diffuse.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — The 8-Concern Attestation Matrix
|
||||
## Slide 7 — The Platform Pipeline
|
||||
|
||||
**Designed controls that keep humans at stage gates.**
|
||||
**How intent becomes verified infrastructure — fail-fast policy scanning before the plan, runtime scanning after it.**
|
||||
|
||||
| Concern | Env | Freshness | Type |
|
||||
|---------|-----|-----------|------|
|
||||
| functional_correctness | qa | 24h | operator-supplied |
|
||||
| performance_baseline | qa | 7d | operator-supplied |
|
||||
| security_posture | qa | 24h | operator-supplied |
|
||||
| operational_readiness | prod | 30d | operator-supplied |
|
||||
| incident_response | prod | 90d | operator-supplied |
|
||||
| capacity_cost | prod | 30d | operator-supplied |
|
||||
| resilience_dr_drill | prod | 180d | operator-supplied |
|
||||
| dr_region_deploy | dr | 180d | operator-supplied |
|
||||

|
||||
|
||||
- Offline-testable concerns run for real; operator-supplied concerns accept signed evidence
|
||||
- Separation-of-duties on prod
|
||||
- Grounded in `attestation_matrix.py` + `hitl_gates.py`
|
||||
- **Contract → resolver → adapter → Checkov on static code (before plan) → terraform plan → Wiz on the plan → confidence signal → stage gate → apply → evidence + ledger**
|
||||
- **Fail-fast, quick feedback** — Checkov runs on the authored Terraform code before `terraform plan` so developers get immediate policy feedback
|
||||
- **Wiz on the plan when configured; Checkov as a drop-in otherwise** — Wiz scans the plan output; when Wiz credentials are absent, Checkov runs against the plan. **Wiz and Checkov are never both run on the plan.**
|
||||
|
||||
**Benefit:** you now know the gate model — autonomy in operations, human in accountability, by design.
|
||||
**Benefit:** two layers of scanning, zero operator involvement in normal operations — fast deterministic feedback at authoring time and a runtime scan on the resolved plan.
|
||||
|
||||
---
|
||||
|
||||
## Slide 9 — Telemetry Architecture
|
||||
## Slide 8 — The Decision Ledger
|
||||
|
||||
**How Nova instruments itself — CloudEvents envelope, cold store, PowerBI export.**
|
||||
**Every automated decision is captured, immutable, queryable — and accountable.**
|
||||
|
||||
Platform → CloudEvents 1.0 → `metrics/events.jsonl` + `metrics/decision_ledger.db` + `metrics/runs/` → Collector → `metrics/nova_metrics.db` (SQLite cold store) → `metrics/powerbi/` (CSV/JSON) → PowerBI
|
||||
- **What is captured:** the chosen action, the confidence score, the alternatives considered, whether a human overrode it, and the outcome (backfilled once the apply completes). Every stage-gate attestation (QA, SRE) is captured with approver identity and the evidence presented.
|
||||
- **"AI decisions" are really automated decisions** — made by deterministic scripts that calculate a score and a band; the platform functions without AI. When an LLM planner is added later, it will emit richer alternatives without breaking the schema.
|
||||
- **The value is accountability, not the storage engine** — the ledger is append-only and tamper-evident; every decision is queryable for auditing, traceable to an outcome, and impossible to rewrite after the fact.
|
||||
|
||||
- D-120 (Nova-native), D-125 (hybrid), D-126 (cold-only)
|
||||
- <span class="badge planned">Planned</span>: Hot-path (live ops dashboard) — D-126
|
||||
|
||||
**Benefit:** you now know that every metric in this deck is traceable to a real emitted event — the architecture IS the trust substrate. When a CFO asks 'where does this number come from?', the answer is a file path, not a Slack thread.
|
||||
**Benefit:** "autonomous" is defensible because every decision is immutable, queryable, and accountable — and the audience knows exactly what "automated" means here: deterministic scoring, not a black-box LLM.
|
||||
|
||||
---
|
||||
|
||||
## Slide 10 — Capability Health + Confidence Distribution
|
||||
## Slide 9 — Attestation Matrix: QA
|
||||
|
||||
**Grounded proof: capability health and confidence distribution from real runs.**
|
||||
**The designed controls that keep humans at stage gates — QA concerns, freshness-validated.**
|
||||
|
||||
| Status | Count |
|
||||
|--------|-------|
|
||||
| Verified | 18 |
|
||||
| Skipped | 4 |
|
||||
| Broken | 0 |
|
||||
| Decayed | 0 |
|
||||
| Concern | Env | Freshness | Description |
|
||||
|---------|-----|-----------|-------------|
|
||||
| Functional correctness | qa | 24h | The application behaves as specified; evidence accepted from the consumer's UAT. |
|
||||
| Performance baseline | qa | 7d | The deployment meets its performance envelope vs. the agreed baseline. |
|
||||
| Security posture | qa | 24h | The deployment's security findings have been reviewed and accepted. |
|
||||
|
||||
- 4 Skipped = live-AWS caps (CAP-013..016), honestly skipped (D-096 teardown), not a failure
|
||||
- Source: `.ciagent/REGRESSION_REPORT.json`
|
||||
|
||||
**Benefit:** you now know the platform is verified — 18 capabilities pass, 4 are honestly skipped, 0 broken.
|
||||
**Benefit:** QA signs off on quality before any promotion — the gate is explicit, not implicit.
|
||||
|
||||
---
|
||||
|
||||
## Slide 11 — Decision Ledger + Attestation Coverage
|
||||
## Slide 10 — Attestation Matrix: Prod/DR
|
||||
|
||||
**Trust metrics — both 100%.**
|
||||
**Production and DR controls — operational readiness, resilience, and disaster recovery.**
|
||||
|
||||
- **Decision Ledger Coverage:** 100% of platform runs emit `ai.decision.made` with outcome backfill
|
||||
- **Attestation Coverage:** 100% of prod/dr promotions attested by a human
|
||||
- **AI Decision Accuracy:** decisions not followed by apply.failed/incident within 5min
|
||||
- Trust snapshot: `metrics/TRUST_SNAPSHOT.md` with chain-integrity verdict
|
||||
- <span class="badge planned">Planned</span>: Tamper-Evident Ledger Checkpoints (D-083)
|
||||
| Concern | Env | Freshness | Description |
|
||||
|---------|-----|-----------|-------------|
|
||||
| Operational readiness | prod | 30d | SRE confirms the deployment is operable: runbooks, dashboards, on-call. |
|
||||
| Incident response | prod | 90d | The on-call path has been exercised; a working incident-response plan exists. |
|
||||
| Capacity & cost | prod | 30d | Capacity headroom and monthly cost are within the agreed envelope. |
|
||||
| Resilience: DR drill | prod | 180d | A DR drill has been run and recovery met the RTO. |
|
||||
| Resilience: chaos | prod | 90d | A chaos exercise has been run and the deployment absorbed the failure. |
|
||||
| Resilience: backup | prod | 30d | Backups are restorable and tested within the freshness window. |
|
||||
| DR region deploy | dr | 180d | The DR region can be deployed and is reachable. |
|
||||
|
||||
**Benefit:** you now know the trust is provable — not a marketing claim, a queryable record.
|
||||
Separation-of-duties on prod: the approver cannot be the same person who built the deployment.
|
||||
|
||||
**Benefit:** the gate model is explicit — autonomy in operations, human in accountability, by design. The matrix is what makes autonomous operations safe enough to trust in production.
|
||||
|
||||
---
|
||||
|
||||
## Slide 12 — Zero-Touch Efficiency
|
||||
## Slide 11 — Telemetry & Live Ops
|
||||
|
||||
**Touchless resolution, human escalation, and MTTR.**
|
||||
**Every metric in this deck is traceable to a real emitted signal — the live-ops dashboard makes operations visible in PowerBI.**
|
||||
|
||||
- **Touchless Resolution Rate:** runs without operational HITL block ÷ total (attestation gates excluded)
|
||||
- **Human Escalation Frequency:** operational HITL blocks only (confidence-driven; attestation sign-offs excluded)
|
||||
- **MTTR (platform-run):** apply.failed → successful retry (D-131)
|
||||

|
||||
|
||||
**Post-Pilot caveat:** computed on N internal runs today; production-denominator activates when a pilot estate runs.
|
||||
- **Platform components → CloudEvents envelope → event log + decision ledger + run records → collector → cold store → PowerBI views → live ops dashboard**
|
||||
- **The live ops dashboard (PowerBI)** surfaces the four CTO-grade metrics (Lead Time, Vulnerability Count, MTTR, Cloud Spend) alongside trust metrics (Decision Ledger coverage, Attestation coverage) and efficiency metrics (touchless resolution, escalation frequency)
|
||||
- **Every number is traceable to a signal** — when a CFO asks "where does this number come from?", the answer is a query against the cold store, not a Slack thread
|
||||
|
||||
**Benefit:** you now know the zero-touch efficiency is measurable — the pipeline works today on internal runs, and the denominator expands to production estates when a pilot activates.
|
||||
**Benefit:** the architecture is the trust substrate — leadership sees the same numbers the platform produces, in PowerBI, with full traceability. Operations become visible.
|
||||
|
||||
---
|
||||
|
||||
## Slide 12 — Decision Ledger + Attestation Coverage
|
||||
|
||||
**By design, no change reaches production without a ledger entry and a human attestation — both queryable for auditing, with full traceability.**
|
||||
|
||||
- **Decision Ledger coverage: 100%** — every platform run emits a decision record with outcome backfill; no automated decision is ever lost
|
||||
- **Attestation coverage: 100%** — every prod/dr promotion is attested by a human (QA for quality, SRE for production readiness), recorded with approver identity, separation-of-duties check, and the evidence matrix
|
||||
- **No change to production without both** — the ledger entry and the human attestation are mandatory, enforced by the pipeline, not by policy
|
||||
- **Full traceability** — a production change is traceable from the contract that declared intent, through the policy scan, the confidence score, the attestation, to the applied outcome
|
||||
|
||||
**Benefit:** trust is provable — not a marketing claim, a queryable record. An auditor answers "who approved this, when, on what evidence?" in one query; a CTO answers "how many of last quarter's prod changes were touchless?" in one query.
|
||||
|
||||
---
|
||||
|
||||
## Slide 13 — Cost & ROI
|
||||
|
||||
**Cost estimates and the ROI formula — with honest caveats.**
|
||||
**The ROI formula and the cost estimates — grounded, with the production denominator honestly flagged.**
|
||||
|
||||
- **Cost Estimates via Infracost:** pre-apply, grounded (reads plan JSON, offline)
|
||||
- **ROI formula:** `Platform ROI = (FTE hours saved × blended rate + cloud savings + avoided downtime) ÷ platform op cost`
|
||||
- **N=0 caveat:** "Computed on N internal runs today; production-denominator activates post-pilot. The formula is grounded; the production numbers are not yet."
|
||||
- <span class="badge planned">Planned</span>: Live CUR Reconciliation (D-096)
|
||||
- **Cost estimates are pre-apply and offline** — the platform reads the terraform plan and estimates cost before anything is applied; a cost regression is caught before the spend happens
|
||||
- **The ROI formula:**
|
||||
`Platform ROI = (FTE hours saved × blended rate + cloud savings + avoided downtime) ÷ platform op cost`
|
||||
- **The four CTO-grade metrics are the ROI proof:** Lead Time (PR → Prod), Infrastructure Vulnerability Count (trend), MTTR, Cloud Spend Reduction — all flow into PowerBI
|
||||
- **Honest caveat:** derived metrics are computed on internal runs today; the production-denominator activates when a pilot estate runs. The formula is grounded; the production numbers are not yet.
|
||||
|
||||
**Benefit:** you now know the ROI formula — and you know it's computed on internal runs today, not fabricated production numbers.
|
||||
**Benefit:** the ROI is not a black box — the formula is shown, the four metrics are committed, and the production-denominator caveat is stated up front. The CFO sees exactly what is real today and what activates with a pilot.
|
||||
|
||||
---
|
||||
|
||||
## Slide 14 — What's Deferred — and Why
|
||||
|
||||
**Honesty about what isn't measured yet.**
|
||||
**Honesty about what is not measured yet — and the blocking work for each.**
|
||||
|
||||
**To be clear:** these deferrals are *measurement infrastructure*, not whether the platform runs without humans. The platform IS autonomous in operations. What's deferred is the *evidence pipeline* for certain metrics — not the autonomy itself.
|
||||
To be clear: these deferrals are *measurement infrastructure*, not the autonomy itself. The platform runs without an operator in the loop of normal operations. What is deferred is the evidence pipeline for certain metrics — not the autonomy.
|
||||
|
||||
| # | Deferred Metric | Blocking Decision |
|
||||
|---|----------------|-------------------|
|
||||
| 1 | Live Infrastructure Health | D-096 |
|
||||
| 2 | Live Outbox Write Rate | D-096 |
|
||||
| 3 | Tamper-Evident Ledger Checkpoints | D-083 |
|
||||
| 4 | Onboarding Funnel (granted) | D-113/D-114/D-119 |
|
||||
| 5 | Drift Auto-Reversal | D-096 + no scheduler |
|
||||
| 6 | Live CUR Reconciliation | D-096 |
|
||||
| 7 | SLA / Unplanned Downtime | D-096 |
|
||||
| 8 | Predictive vs Reactive | future emitter |
|
||||
| # | Deferred metric | Blocking work |
|
||||
|---|-----------------|---------------|
|
||||
| 1 | Live infra health, outbox write rate, SLA | Live AWS re-provisioning (currently torn down to zero-cost steady state) |
|
||||
| 2 | Tamper-evident ledger checkpoints | Audit-ledger build-out (Object Lock + signed checkpoints) |
|
||||
| 3 | Onboarding funnel (requested → granted) | Auto-grant implementation |
|
||||
| 4 | Drift auto-reversal | Drift-detection scheduler (not yet built) |
|
||||
| 5 | Live cost reconciliation | Live AWS re-provisioning + actual-spend feed |
|
||||
| 6 | Predictive vs reactive ratio | ML anomaly-forecasting service (not yet built) |
|
||||
|
||||
**Benefit:** you now know the boundaries — what Nova measures today, and exactly what blocks the rest. The autonomy is real; the measurement gaps are documented.
|
||||
**Benefit:** the boundaries are explicit — what Nova measures today, and exactly what blocks the rest. The autonomy is real; the measurement gaps are documented with the work that unblocks each one.
|
||||
|
||||
---
|
||||
|
||||
## Slide 15 — Roadmap to the North Star
|
||||
|
||||
**The path from v1.17's grounded metrics to the 12–18 month targets.**
|
||||
**The path from the grounded metrics to the 12–18 month targets — each deferred metric has an unblock path and a timeframe.**
|
||||
|
||||
- Each deferred metric → blocking decision → unblock requirement → candidate milestone
|
||||
- Hot-path activation (post-D-096, Nova-native only, D-120)
|
||||
- Re-evaluation triggers: D-096 lift, D-083 lift, onboarding-grant lift
|
||||
| Timeframe | Work | Unblocks |
|
||||
|-----------|------|----------|
|
||||
| Near-term | Live AWS re-provisioning | Live infra health, outbox write rate, live cost reconciliation, SLA |
|
||||
| Near-term | Auto-grant implementation | Onboarding funnel (requested → granted) |
|
||||
| Mid-term | Drift-detection scheduler | Drift auto-reversal |
|
||||
| Mid-term | Audit-ledger build-out (Object Lock + signed checkpoints) | Tamper-evident ledger checkpoints |
|
||||
| Mid-term | Hot-path activation (batch → near-real-time) | Live-ops dashboard freshness |
|
||||
| Longer-term | ML anomaly-forecasting service | Predictive vs reactive ratio |
|
||||
|
||||
From `docs/METRICS_DEFERRED_ROADMAP.md`.
|
||||
Re-evaluation triggers: each blocking piece of work lifts on its own schedule; the metrics layer evolves as each one lands.
|
||||
|
||||
**Benefit:** you now know the path — every deferred metric has an unblock requirement and a candidate milestone. Nothing is hand-waved; everything has a plan.
|
||||
**Benefit:** every deferred metric has an unblock path — nothing is hand-waved; everything has a plan and a timeframe.
|
||||
|
||||
---
|
||||
|
||||
## Slide 16 — Recap + Ask
|
||||
## Slide 16 — 12-Month Product Roadmap
|
||||
|
||||
**The 5-act recap + the business decision.**
|
||||
**The product arc from pilot activation to integration — four quarters, four outcomes.**
|
||||
|
||||
| Quarter | Theme | Board-level outcome |
|
||||
|---------|-------|---------------------|
|
||||
| **Q1** | Pilot Activation | Nova runs a real customer estate end-to-end, autonomously, with a measurable zero-touch rate. |
|
||||
| **Q2** | Provable Trust | Every automated decision lands in a tamper-evident ledger; the CFO sees real cloud-spend reconciliation. |
|
||||
| **Q3** | Compounding ROI | Quarter-over-quarter cloud spend drops; drift is detected and reversed without a human. |
|
||||
| **Q4** | Integration & Predictive | AI agents deploy through Nova by default; the ML anomaly-forecasting service goes live. |
|
||||
|
||||
Grounded in the four strategic objectives (autonomy, provable trust, ROI, integration) and the deferred-metric unblock paths.
|
||||
|
||||
**Benefit:** the 12-month product arc — each quarter activates a strategic objective and its corresponding board-level metric, from pilot activation through integration leadership.
|
||||
|
||||
---
|
||||
|
||||
## Slide 17 — Quarter-by-Quarter Outcomes
|
||||
|
||||
| Quarter | Product theme | Key deliverable | Target metric |
|
||||
|---------|---------------|-----------------|---------------|
|
||||
| **Q1** | Pilot Activation | Re-provision live AWS; activate first pilot estate; onboarding auto-grant | Touchless ≥ 99% · Escalation < 0.1% · Accuracy ≥ 99.5% |
|
||||
| **Q2** | Provable Trust | Tamper-evident ledger (Object Lock + signed checkpoints); daily checkpoints; live cost reconciliation | Decision Ledger Coverage 100% · Cost Savings ≥ 25% |
|
||||
| **Q3** | Compounding ROI + Drift | Drift-detection scheduler; auto-reversal; pre-apply → actual-spend reconciliation on the pilot estate | Drift Auto-Reversal ≥ 95% · Spend Reduction ≥ 25% |
|
||||
| **Q4** | Integration + Predictive | ML anomaly-forecasting; AI-agent intent surface; multi-cloud (Azure/GCP) preview | Predictive:Reactive ≥ 3:1 · AI-Agent Intent Share (first measurement) |
|
||||
|
||||
**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:** each quarter has a concrete deliverable, a target metric grounded in a strategic objective, and a path from "honestly deferred" to "shipped and measured."
|
||||
|
||||
---
|
||||
|
||||
## Slide 18 — Production-Grade Guidance via Atelier (1/2)
|
||||
|
||||
**Nova instructs the citizen developer's AI agent on production-grade engineering — a set of skills and an MCP server.**
|
||||
|
||||
- **Skills** — markdown files keyed to production-grade engineering domains (API, security, data, testing, observability, errors, DevOps, infrastructure-as-code, compliance); the skills extend the baseline catalog with Nova-specific production-grade principles
|
||||
- **MCP server** — a plugin-registry, stdio server exposing four tools: `lookup_principle`, `list_domains`, `matrix_lookup`, `validate_against_principles`. The developer's AI agent (or any agentic SDLC platform) calls these tools to look up the principles that apply to its submission
|
||||
- **The integration point is the same regardless of source** — whether the submission comes from an AI coding agent, an agentic SDLC platform, or a traditional IDE, the same skills and MCP server apply. This is how Nova makes the citizen developer production-grade without owning the PDLC
|
||||
|
||||
**Benefit:** the citizen developer's AI agent is not unguided — Nova provides production-grade engineering principles as skills and as an MCP surface, so submissions arrive at the contract boundary already aligned with the platform's standards.
|
||||
|
||||
---
|
||||
|
||||
## Slide 19 — Production-Grade Guidance via Atelier (2/2)
|
||||
|
||||
**Agentic validation catches engineering-discipline gaps that deterministic scanners miss — and the validation is reproducible.**
|
||||
|
||||
- **Beyond deterministic scanners** — Wiz, Checkmarx, and Mend check policy and secrets; they do not check engineering discipline. The Atelier MCP server catches correctness, clarity, and observability gaps that deterministic tools cannot: "is this service observable?", "is this error path handled?", "is this API contract clear?"
|
||||
- **Agentic validation, not a second policy engine** — the MCP server gives the AI agent the principles to validate against; the agent does the validation. The agent reasons about the submission against the principles, not a second static scan
|
||||
- **Vendored for audit reproducibility** — Atelier is vendored at a pinned tag. A validation result is replayable against the exact principles that produced it, so an audit can reproduce a validation months later, not just trust a log line
|
||||
|
||||
**Benefit:** the citizen developer's submission is checked for engineering discipline, not just policy compliance — and the check is reproducible for audit. That is what makes the submission production-grade, regardless of which upstream platform produced it.
|
||||
|
||||
---
|
||||
|
||||
## Slide 20 — Recap + Ask
|
||||
|
||||
**The 4-beat recap + the business decision.**
|
||||
|
||||
**Recap:**
|
||||
- **Problem:** operator is the bottleneck; autonomy in operations, human at stage gates
|
||||
- **Vision:** invisible operations with provable trust (NORTH_STAR)
|
||||
- **How:** pipeline + Decision Ledger + 8-concern attestation matrix
|
||||
- **Proof:** 18V+4S, 100% ledger coverage, 100% attestation, grounded ROI formula
|
||||
- **Roadmap:** deferred metrics have unblock paths
|
||||
- **Problem:** product teams own infrastructure without the discipline and lifecycle planning it requires; bandwidth gaps and tribal knowledge leave operations exposed
|
||||
- **Solution:** autonomous cloud delivery — operations become visible, trust is provable (deterministic scoring), humans at stage gates
|
||||
- **Proof:** 100% ledger coverage, 100% attestation coverage, grounded ROI formula, four CTO-grade metrics flowing into PowerBI
|
||||
- **Roadmap:** deferred metrics have unblock paths; the 12-month product arc activates one strategic objective per quarter
|
||||
|
||||
**The ask:** "Approve a pilot estate to activate the production-denominator metrics (Touchless Resolution, Human Escalation, AI Decision Accuracy), and approve the tamper-evident ledger build-out (D-083 lift) to move from local hash-chain to S3 Object Lock + JWS. These two decisions move Nova from 'pipeline-ready' to 'production-proven.'"
|
||||
**The ask:** "Approve a pilot estate to activate the production-denominator metrics (Lead Time, Vulnerability Count, MTTR, Cloud Spend), and approve the tamper-evident ledger build-out to move from the local hash-chain to S3 Object Lock + signed checkpoints. These two decisions move Nova from 'pipeline-ready' to 'production-proven.'"
|
||||
|
||||
**Benefit:** you leave with a clear business decision to make — approve a pilot + the ledger build-out — and the confidence that every claim in this deck is grounded, derived, or honestly deferred.
|
||||
|
||||
---
|
||||
|
||||
## Slide 17 — Scope: Downstream of PDLC
|
||||
|
||||
**Nova governs infrastructure + delivery. The PDLC (product backlog, code authorship, IDE) is upstream — Nova never penetrates it.**
|
||||
|
||||
- **The PDLC is upstream:** product backlog, code authorship (AI agent / IDE / agentic SDLC), sprint planning, application business logic
|
||||
- **Nova is downstream:** contract ingestion → submission-readiness gate → policy → cloud lifecycle → environment progression → audit + attestation
|
||||
- **Integration is only through the contract boundary:** the citizen developer's AI coding agent, an upstream agentic SDLC, or any dev platform may all produce submissions — the source does not matter as all are subject to the same compliance standards
|
||||
- Nova validates the submission, not the author
|
||||
- Cites `docs/scope.md` + `PROJECT.md` § Scope
|
||||
|
||||
**Benefit:** you now know the scope boundary — Nova is purpose-built for infrastructure operations, not product development; integration is through one validated contract.
|
||||
|
||||
---
|
||||
|
||||
## Slide 18 — RACI: Who Owns What
|
||||
|
||||
**Three roles, one matrix — the citizen developer owns FRs + UAT, the platform owns NFRs + infra + QA + prod deploy, release management is co-owned.**
|
||||
|
||||
| Work Category | Citizen Dev | Platform | Release Mgmt |
|
||||
|---|---|---|---|
|
||||
| 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) | C | **R/A** | I |
|
||||
| Production deployment to cloud | I | **R/A** | C |
|
||||
| Release attestation (QA + SRE) | **A** | R | **R** |
|
||||
|
||||
- **Compliance-standard equivalence:** FRs + UAT may come from any upstream source (AI agent, agentic SDLC, dev platform) — all pass the same submission-readiness gate
|
||||
- **Release co-ownership:** the platform runs the attestations agentically; the citizen developer oversees and triggers the actual release (human at the stage gate)
|
||||
- Cites `docs/raci.md` + `PROJECT.md` § RACI Matrix
|
||||
|
||||
**Benefit:** you now know exactly what you bring (FRs + UAT), what Nova provides (NFRs + infra + QA + prod deploy), and what you co-own (the release attestation).
|
||||
|
||||
---
|
||||
|
||||
## Slide 19 — Production-Grade Guidance via Atelier
|
||||
|
||||
**Nova instructs the citizen developer's AI agent on production-grade engineering — skills + an MCP server with agentic validation beyond deterministic scanners.**
|
||||
|
||||
- **Skills (9):** markdown files under `skills/` keyed to Atelier domain paths (api, security, data, testing, observability, errors, devops, infrastructure-as-code, compliance) — extending the BA.A 5-skill catalog
|
||||
- **MCP server:** `mcp/atelier/server.py` (plugin-registry, stdio) — 4 tools: `lookup_principle`, `list_domains`, `matrix_lookup`, `validate_against_principles`
|
||||
- **Agentic validation:** catches C1 correctness + C2 clarity + C7 observability gaps that Wiz/Checkmarx/Mend cannot — deterministic tools check policy/secrets; the MCP server checks engineering discipline
|
||||
- **Vendored Atelier** (pinned tag v0.3.6): audit reproducibility — a validation result is replayable against the exact principles that produced it
|
||||
- Cites `docs/skills.md` + `mcp/atelier/README.md`
|
||||
|
||||
**Benefit:** you now know the citizen developer is not unguided — Nova provides production-grade engineering principles via skills + an MCP server, so the AI agent's submissions meet the same standards regardless of upstream source.
|
||||
**Benefit:** a clear business decision — approve a pilot and the ledger build-out — with the confidence that every claim in this deck is grounded, derived, or honestly deferred.
|
||||
|
||||
---
|
||||
|
||||
@@ -338,66 +320,18 @@ From `docs/METRICS_DEFERRED_ROADMAP.md`.
|
||||
|
||||
| KPI | Definition | Status |
|
||||
|-----|-----------|--------|
|
||||
| Touchless Resolution Rate | runs without operational HITL block ÷ total | partial (Post-Pilot) |
|
||||
| Human Escalation Frequency | operational HITL blocks ÷ total | partial (Post-Pilot) |
|
||||
| AI Decision Accuracy | decisions not followed by failure within 5min | partial (Post-Pilot) |
|
||||
| Touchless Resolution Rate | runs without operational stage-gate block ÷ total | partial (Post-Pilot) |
|
||||
| Human Escalation Frequency | operational stage-gate blocks ÷ total | partial (Post-Pilot) |
|
||||
| Automated Decision Accuracy | decisions not followed by failure within 5min | partial (Post-Pilot) |
|
||||
| MTTR (p95) | apply.failed → successful retry | grounded |
|
||||
| Confidence-Gate Halt Rate | runs with band=block ÷ total | grounded |
|
||||
| Provisioning Lead Time | run.completed − run.started | grounded |
|
||||
| Deployment Frequency | count(run.completed) per day | grounded |
|
||||
| Cost Savings (Infracost) | sum(delta_usd where delta < 0) | partial (CUR deferred) |
|
||||
| Cost Savings (pre-apply) | sum(delta_usd where delta < 0) | partial (live reconciliation deferred) |
|
||||
| FTE Hours Saved | run count × manual baseline × rate | derived (N=0 caveat) |
|
||||
| Platform ROI | (labor + cloud + avoided downtime) ÷ op cost | derived (N=0 caveat) |
|
||||
| Decision Ledger Coverage | decisions with outcome ÷ total | grounded |
|
||||
| Attestation Coverage | prod/dr attested ÷ total prod/dr | grounded |
|
||||
| Policy Compliance Rate | 1 − failed_assets ÷ total | grounded |
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
## Appendix A2 — Operating Model & Cost
|
||||
|
||||
- **Cost figures** from `COST.md`: $0.001883 over 8 days, ~$0.007/month, S3-dominated, zero BAU compute
|
||||
- **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.
|
||||
---
|
||||
|
||||
<!-- _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."
|
||||
**Benefit:** a reference for every metric mentioned in the deck.
|
||||
@@ -1,164 +1,145 @@
|
||||
# Nova — The No-Humans Infrastructure Platform: Talking Points
|
||||
# Nova — The Autonomous Cloud Delivery Platform: Talking Points
|
||||
|
||||
> Step 4 of the 4-step deck process. Presenter cues distilled from the
|
||||
> source of truth (`nova-no-humans-platform.md`). 3-6 bullets per slide
|
||||
> + key takeaway. Indexed by Marp slide #.
|
||||
> v1.17 — REQ-196, REQ-197
|
||||
> source of truth (`nova-autonomous-cloud-delivery.md`). 3-6 bullets per
|
||||
> slide + key takeaway. Indexed by Marp slide #.
|
||||
> v1.21 — REQ-245
|
||||
|
||||
---
|
||||
|
||||
### Slide 1 — Arc Preview
|
||||
- Open with the stake line: "18 capabilities verified, 0 consumer estates in production"
|
||||
- Preview the 5-act arc so the audience knows the structure
|
||||
- Set the honesty frame: "this is an evidence deck, not a hype deck"
|
||||
- **Key takeaway:** you'll leave knowing what's proven, what's pipeline-ready, and what's deferred
|
||||
### Slide 1 — The Problem
|
||||
- Open with the shift: "you build it, you run it" put Terraform into product teams — ownership without discipline is destroying value
|
||||
- Land the lifecycle-planning gap: resources authored for creation, not for patching/rollback → destructive changes
|
||||
- Land the urgency: AI-era 0-day pace demands proactive scanning as code + at runtime, remediated at threat pace
|
||||
- Call out tribal knowledge / the rockstar-operator problem — the platform should encode the discipline, not the person
|
||||
- Do NOT frame this as "humans are the problem" — the problem is ownership without the discipline and tooling
|
||||
- **Key takeaway:** the problem is infrastructure ownership without discipline; the answer is an autonomous platform that encodes the discipline
|
||||
|
||||
### Slide 2 — The No-Humans Imperative
|
||||
- The operator is the bottleneck: days vs. minutes for provisioning
|
||||
- Key reframing: "no-humans" = no human in normal operations; stage-gate attestation is human by design
|
||||
- Cite the no-humans thesis doc
|
||||
- **Key takeaway:** autonomy in operations, human at stage gates
|
||||
### Slide 2 — Nova's Vision
|
||||
- Read the vision verbatim — "infrastructure operations become visible" is the operative phrase
|
||||
- Emphasize "provable, not promised" — trust established by deterministic scripts; the platform functions without AI
|
||||
- State the attestation model up front: QA for production, SRE for operational readiness
|
||||
- **Key takeaway:** autonomous operations with provable trust — security, remediation velocity, reliability, lead time made visible, not promised
|
||||
|
||||
### Slide 3 — Nova's Vision
|
||||
- Read the vision statement verbatim — it's precise
|
||||
- Emphasize "provable, not promised" — the difference between marketing and defensible
|
||||
- State the attestation model up front to prevent mishearing
|
||||
- **Key takeaway:** invisible operations with provable trust
|
||||
### Slide 3 — Strategic Objectives
|
||||
- Objective #1: zero-touch operations — autonomy as the default, not the demo; stage-gate attestation (QA, SRE) remains human by design
|
||||
- Objective #2 is the one to land carefully: trust = deterministic scoring, not an LLM; the platform functions without AI
|
||||
- Objective #3: four CTO-grade metrics (Lead Time, Vuln Count, MTTR, Spend) — all flow into PowerBI
|
||||
- Objective #4 is the integration thesis: Nova integrates with any upstream source; provides skills + MCP; all prod intents go through the same controls
|
||||
- **Key takeaway:** the scope is explicit — Nova governs infra + delivery, integrates with any source through one contract, measures success on four CTO metrics
|
||||
|
||||
### Slide 4 — Strategic Objectives + Anti-Goals
|
||||
- The 4 objectives are the "what"; the 5 anti-goals are the "what NOT"
|
||||
- Anti-goal #3 (not removing humans from accountability) reinforces slide 3
|
||||
- Anti-goal #5 (not sold to operators) explains why this deck is for leadership
|
||||
- **Key takeaway:** purpose-built for infra ops, sold to leadership on outcomes
|
||||
### Slide 4 — Anti-Goals (What Nova Is NOT)
|
||||
- Not a general-purpose AI agent platform
|
||||
- Not a system that removes humans from accountability — only from normal operations
|
||||
- Not an upstream development platform (no product backlogs, IDE, code authorship)
|
||||
- Not a replacement for the Product Development Lifecycle (PDLC)
|
||||
- Anti-goals #3 and #4 protect the scope boundary — Nova will not become an IDE or a product-planning tool
|
||||
- **Key takeaway:** the boundaries are explicit — Nova is purpose-built for infra ops + delivery, not a general-purpose AI agent or an upstream dev platform
|
||||
|
||||
### Slide 5 — 12–18 Month Targets
|
||||
- The three-section split (current / post-pilot / deferred) IS the honesty model
|
||||
- "Partial" means the pipeline works but the denominator is zero (0 consumers)
|
||||
- The Post-Pilot targets are committed; the numbers fill when a pilot runs
|
||||
- **Key takeaway:** which numbers are real today vs. deferred honestly
|
||||
### Slide 5 — Scope: Downstream of PDLC
|
||||
- Nova governs infra + delivery only; the PDLC (backlog, code authorship, IDE) is upstream — Nova never penetrates it
|
||||
- Integration is only through the validated contract boundary
|
||||
- Any upstream source (AI agent, agentic SDLC, dev platform) produces submissions subject to the same compliance standards
|
||||
- Nova validates the submission, not the author
|
||||
- **Key takeaway:** Nova is purpose-built for infrastructure operations; the scope boundary is clean and bounded
|
||||
|
||||
### Slide 6 — The Platform Pipeline
|
||||
- Walk the pipeline left-to-right: contract → resolver → adapter → plan → policy → confidence → gate → apply
|
||||
- Key insight: dev is autonomous; qa/prod/dr require attestation
|
||||
- The confidence signal is the "AI" — 6-input weighted score, not an LLM
|
||||
- **Key takeaway:** the path from intent to evidence, with humans at stage gates only
|
||||
### Slide 6 — RACI: Who Owns What
|
||||
- Four roles now: Citizen Developer, Platform, Quality Engineering, SRE
|
||||
- Quality attestation is owned by Quality Engineering (not the Platform); Production readiness is owned by SRE
|
||||
- The Platform runs the checks agentically but is never the Accountable party for the gate — that separation keeps the platform honest
|
||||
- Production readiness is co-owned: the platform runs attestations; the citizen developer authorizes the promotion at the stage gate
|
||||
- **Key takeaway:** you bring FRs + UAT; Nova provides NFRs + infra; QE guards the gate evidence; SRE signs off on production readiness
|
||||
|
||||
### Slide 7 — The Decision Ledger
|
||||
- The D-122 honesty sentence is critical: "Nova's AI is the confidence-gated policy engine, not an LLM"
|
||||
- The ledger is the moat: features can be copied, an immutable decision history cannot
|
||||
- Every decision has outcome backfill from apply.completed
|
||||
- **Key takeaway:** autonomous is defensible because every decision is immutable, queryable, accountable
|
||||
### Slide 7 — The Platform Pipeline
|
||||
- Walk the pipeline left-to-right: contract → resolver → adapter → Checkov (static) → plan → Wiz (on plan) → confidence → gate → apply
|
||||
- Two-stage scan: Checkov on static code BEFORE the plan (fail-fast dev feedback); Wiz on the plan (or Checkov as drop-in if no Wiz creds)
|
||||
- Never both Wiz + Checkov on the plan — avoid duplicate noise
|
||||
- Dev is autonomous; qa/prod/dr require attestation (QA for quality, SRE for production readiness)
|
||||
- **Key takeaway:** two layers of scanning, zero operator involvement in normal operations
|
||||
|
||||
### Slide 8 — The 8-Concern Attestation Matrix
|
||||
- The matrix is not a rubber stamp — it's structured, freshness-validated, SoD-enforced
|
||||
- Offline-testable concerns run for real; operator-supplied concerns accept signed evidence
|
||||
- SoD on prod: the approver can't be the same person who built it
|
||||
- **Key takeaway:** autonomy in operations, human in accountability, by design
|
||||
### Slide 8 — The Decision Ledger
|
||||
- "AI decisions" are really automated decisions — deterministic scripts calculate a score; the platform functions without AI
|
||||
- Do not dwell on the storage substrate — the value is accountability (immutable, queryable, traceable to outcome), not the database
|
||||
- Every stage-gate attestation is captured with approver identity and the evidence presented
|
||||
- When an LLM planner is added later, it emits richer alternatives without breaking the schema
|
||||
- **Key takeaway:** autonomous is defensible because every decision is immutable, queryable, accountable — and "automated" means deterministic scoring, not a black-box LLM
|
||||
|
||||
### Slide 9 — Telemetry Architecture
|
||||
- Deliberately minimal (Nova-native, no Kafka/Prometheus/ClickHouse)
|
||||
- Every number in the Proof act is traceable to a file path
|
||||
- The hot path is deferred (D-126) — cold store is sufficient for batch
|
||||
- **Key takeaway:** the architecture IS the trust substrate — "where does this number come from?" → file path
|
||||
### Slide 9 — Attestation Matrix: QA
|
||||
- The matrix is not a rubber stamp — structured, freshness-validated
|
||||
- Each concern now has a plain-language description of what is being attested (the old "operator-supplied" label is gone)
|
||||
- Three QA concerns: functional correctness (24h), performance baseline (7d), security posture (24h)
|
||||
- Each concern has a freshness window — evidence older than the window does not satisfy the gate
|
||||
- **Key takeaway:** QA signs off on quality before any promotion — the gate is explicit, not implicit
|
||||
|
||||
### Slide 10 — Capability Health
|
||||
- 18V+4S is the single most important proof point
|
||||
- The 4 Skipped are live-AWS caps — honestly skipped (D-096), not broken
|
||||
- When live AWS is re-provisioned, they reactivate
|
||||
- **Key takeaway:** the platform works, and we're honest about what we can't test
|
||||
### Slide 10 — Attestation Matrix: Prod/DR
|
||||
- Seven prod/DR concerns: operational readiness, incident response, capacity & cost, DR drill, chaos, backup, DR region deploy
|
||||
- SRE signs off on operability (runbooks, dashboards, on-call), incident response, capacity, and the three resilience checks
|
||||
- Each concern has a freshness window — 30d/90d/180d depending on the control
|
||||
- SoD on prod: the approver can't be the same person who built it — the rule that keeps the gate honest
|
||||
- **Key takeaway:** autonomy in operations, human in accountability, by design — the matrix is what makes autonomous operations safe enough to trust in production
|
||||
|
||||
### Slide 11 — Decision Ledger + Attestation Coverage
|
||||
- Both 100% — no AI decision is ever lost; no prod/dr promotion lands without a human sign-off
|
||||
- The trust snapshot has a chain-integrity verdict (the ledger hasn't been tampered with)
|
||||
- D-083 (S3 Object Lock + JWS) is the next step for the ledger
|
||||
- **Key takeaway:** trust is provable — not a marketing claim, a queryable record
|
||||
### Slide 11 — Telemetry & Live Ops
|
||||
- Deliberately minimal: Nova-native CloudEvents; no Kafka/Prometheus/ClickHouse
|
||||
- The live-ops dashboard is built in PowerBI on top of the exported views — leadership sees the same numbers the platform produces
|
||||
- Every number in the Proof slides is traceable to a signal — "where does this number come from?" → a query against the cold store
|
||||
- This is where the "infrastructure operations become visible" theme lands concretely
|
||||
- **Key takeaway:** the architecture is the trust substrate — operations become visible in PowerBI, with full traceability
|
||||
|
||||
### Slide 12 — Zero-Touch Efficiency
|
||||
- The Post-Pilot caveat is the honesty model: pipeline works, denominator is zero
|
||||
- This is NOT a fabricated "99% touchless" claim
|
||||
- The numbers fill when a pilot runs
|
||||
- **Key takeaway:** the measurement works; the numbers activate with a pilot
|
||||
### Slide 12 — Decision Ledger + Attestation Coverage
|
||||
- Both 100% — no automated decision is ever lost; no prod/dr promotion lands without a human sign-off
|
||||
- The mandatory-by-design point: the ledger entry + the human attestation are a gate, not a best-effort feature
|
||||
- Easily queried: by run, by environment, by approver, by outcome — the audit trail is a query, not a forensic exercise
|
||||
- **Key takeaway:** trust is provable — not a marketing claim, a queryable record; no change to production without both the ledger entry and the human attestation
|
||||
|
||||
### Slide 13 — Cost & ROI
|
||||
- The ROI formula is shown inline — not hidden in a footnote
|
||||
- The N=0 caveat is stated explicitly
|
||||
- This is the "no fabrication" constraint in action
|
||||
- **Key takeaway:** the formula is ready; the production denominator activates with a pilot
|
||||
- The four CTO-grade metrics are the ROI proof — Lead Time, Vuln Count, MTTR, Cloud Spend
|
||||
- The N=0 caveat is stated explicitly: the formula is grounded; the production numbers activate with a pilot
|
||||
- **Key takeaway:** the ROI is not a black box — the formula is shown, the four metrics are committed, the production-denominator caveat is up front
|
||||
|
||||
### Slide 14 — What's Deferred — and Why
|
||||
- The preempt is critical: deferrals are measurement infrastructure, not autonomy
|
||||
- The platform IS autonomous in operations; what's deferred is the evidence pipeline
|
||||
- The preempt is critical: these deferrals are measurement infrastructure, not autonomy — the platform IS autonomous in operations
|
||||
- The blocking work is named in plain language (no decision IDs) — "live AWS re-provisioning", "drift-detection scheduler", "ML service"
|
||||
- Showing this to leadership demonstrates honesty, not weakness
|
||||
- **Key takeaway:** the autonomy is real; the measurement gaps are documented
|
||||
- **Key takeaway:** the autonomy is real; the measurement gaps are documented with the work that unblocks each one
|
||||
|
||||
### Slide 15 — Roadmap to the North Star
|
||||
- Every deferred metric has a specific unblock requirement and a candidate milestone
|
||||
- The re-evaluation triggers ensure the metrics layer evolves
|
||||
- Nothing is hand-waved; everything has a plan
|
||||
- **Key takeaway:** the path from "honestly deferred" to "here's how we get there"
|
||||
- Each deferred metric has an unblock path and a timeframe — near-term, mid-term, longer-term
|
||||
- No status column: most of it is not implemented yet, so status would be noise
|
||||
- Re-evaluation triggers: each blocking piece of work lifts on its own schedule
|
||||
- **Key takeaway:** every deferred metric has a plan and a timeframe — nothing is hand-waved
|
||||
|
||||
### Slide 16 — Recap + Ask
|
||||
- Recap the 5-act arc so the audience leaves with the structure
|
||||
- The ask is a business decision: approve a pilot + the ledger build-out
|
||||
### Slide 16 — 12-Month Product Roadmap
|
||||
- This is the *product* roadmap, forward-looking only
|
||||
- Q1 Pilot Activation → Q2 Provable Trust → Q3 Compounding ROI → Q4 Integration & Predictive
|
||||
- Each quarter activates one strategic objective from the North Star
|
||||
- **Key takeaway:** the 12-month product arc — each quarter activates a strategic objective and its board-level metric
|
||||
|
||||
### Slide 17 — Quarter-by-Quarter Outcomes
|
||||
- Q1: three post-pilot metrics go live (Touchless ≥99%, Escalation <0.1%, Accuracy ≥99.5%) — denominator activates with the pilot
|
||||
- Q2: Decision Ledger Coverage was already grounded — tamper-evidence is the Q2 upgrade (local hash-chain → Object Lock + signed checkpoints)
|
||||
- Q3: Drift Auto-Reversal ≥95% unblocks when the drift scheduler ships; Spend Reduction ≥25% measured against the pilot baseline
|
||||
- Q4: Predictive:Reactive ≥3:1 requires the ML forecasting service; AI-Agent Intent Share is a first measurement (aspirational-metric)
|
||||
- **Key takeaway:** each quarter has a concrete deliverable, a target metric grounded in a strategic objective, and a path from deferred to shipped
|
||||
|
||||
### Slide 18 — Production-Grade Guidance via Atelier (1/2)
|
||||
- Nova instructs the citizen developer's AI agent via skills (markdown, keyed to engineering domains) + an MCP server (4 tools, plugin-registry, stdio)
|
||||
- The integration point is the same regardless of source — AI agent, agentic SDLC, traditional IDE all get the same skills + MCP
|
||||
- This is how Nova makes the citizen developer production-grade without owning the PDLC
|
||||
- **Key takeaway:** the citizen developer's AI agent is not unguided — Nova provides engineering principles as skills + MCP
|
||||
|
||||
### Slide 19 — Production-Grade Guidance via Atelier (2/2)
|
||||
- The value is the gap deterministic scanners leave: engineering discipline (Wiz/Checkmarx/Mend check policy/secrets, not discipline)
|
||||
- The MCP server catches "is this service observable?", "is this error path handled?", "is this API contract clear?"
|
||||
- Vendored at a pinned tag → audit reproducibility — a validation result is replayable months later
|
||||
- **Key takeaway:** submissions are checked for engineering discipline, not just policy compliance — and the check is reproducible for audit
|
||||
|
||||
### Slide 20 — Recap + Ask
|
||||
- Recap the 4-beat arc so the audience leaves with the structure
|
||||
- The ask is a business decision: approve a pilot estate + the tamper-evident ledger build-out
|
||||
- "Pipeline-ready" → "production-proven" is the value proposition
|
||||
- **Key takeaway:** approve a pilot + the ledger build-out to move from pipeline-ready to production-proven
|
||||
|
||||
### Slide 17 — Scope: Downstream of PDLC
|
||||
- Nova governs infra + delivery only; the PDLC (product backlog, code authorship, IDE) is upstream
|
||||
- Integration is only through the validated contract boundary
|
||||
- Any upstream source (AI agent, agentic SDLC, dev platform) may produce submissions — all subject to the same compliance standards
|
||||
- Nova validates the submission, not the author
|
||||
- **Key takeaway:** Nova is purpose-built for infrastructure operations, not product development; the scope boundary is clean
|
||||
|
||||
### Slide 18 — RACI: Who Owns What
|
||||
- Citizen Developer owns FRs + UAT (via any upstream source — AI agent, SDLC, dev platform — all pass the same gate)
|
||||
- Platform owns NFRs + infra + QA + prod deploy
|
||||
- Release Management is co-owned: platform runs attestations agentically, citizen developer oversees + triggers the release (human at stage gate)
|
||||
- The compliance-standard equivalence is the key: the source does not matter; the submission does
|
||||
- **Key takeaway:** you bring FRs + UAT; Nova provides NFRs + infra + QA + prod deploy; the release is co-owned with you at the stage gate
|
||||
|
||||
### Slide 19 — Production-Grade Guidance via Atelier
|
||||
- Nova instructs the citizen developer's AI agent via skills (9 markdown files) + an MCP server (4 tools, plugin-registry, stdio)
|
||||
- The MCP server provides agentic validation beyond deterministic scanners — catches correctness, clarity, observability gaps that Wiz/Checkmarx/Mend cannot
|
||||
- Atelier is vendored (pinned tag) for audit reproducibility — a validation result is replayable
|
||||
- This is how Nova ensures the citizen developer's submissions meet production-grade standards regardless of upstream source
|
||||
- **Key takeaway:** the citizen developer is not unguided — Nova provides engineering principles via skills + MCP, so every submission meets the same standards
|
||||
|
||||
### Appendix A1 — Metrics Glossary
|
||||
- Reference for every metric mentioned in the deck
|
||||
- Use if the audience asks "what does X mean?"
|
||||
|
||||
### 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
|
||||
---
|
||||
|
||||
## 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).
|
||||
- Use if the audience asks "what does X mean?"
|
||||
File diff suppressed because one or more lines are too long
@@ -98,10 +98,7 @@ operations.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 3 — Strategic Objectives + Anti-Goals
|
||||
|
||||
**Four objectives Nova is building toward; four anti-goals that keep it
|
||||
focused.**
|
||||
## Slide 3 — Strategic Objectives
|
||||
|
||||
**4 Strategic Objectives:**
|
||||
1. **Demonstrate production-grade zero-touch operations** — autonomy as
|
||||
@@ -128,7 +125,21 @@ focused.**
|
||||
to deploy to production go through the same rigorous controls,
|
||||
quality gates, attestation, and evidence stream.
|
||||
|
||||
**4 Anti-Goals (what Nova is NOT):**
|
||||
> **Benefit:** the scope is explicit — Nova governs infrastructure and
|
||||
> delivery, integrates with any upstream source through one validated
|
||||
> contract, and measures success on four metrics a CTO can repeat back.
|
||||
|
||||
> **Speaker notes:** Objective #2 is the one to land carefully: trust is
|
||||
> established by deterministic scoring, not by an LLM. The platform
|
||||
> functions without AI.
|
||||
|
||||
> **Transition:** "The objectives are concrete — here is what Nova is
|
||||
> NOT, to keep it focused."
|
||||
|
||||
---
|
||||
|
||||
## Slide 4 — Anti-Goals (What Nova Is NOT)
|
||||
|
||||
1. Not a general-purpose AI agent platform.
|
||||
2. Not a system that removes humans from accountability — only from
|
||||
normal operations.
|
||||
@@ -136,13 +147,11 @@ focused.**
|
||||
authorship).
|
||||
4. Not a replacement for the Product Development Lifecycle (PDLC).
|
||||
|
||||
> **Benefit:** the scope is explicit — Nova governs infrastructure and
|
||||
> delivery, integrates with any upstream source through one validated
|
||||
> contract, and measures success on four metrics a CTO can repeat back.
|
||||
> **Benefit:** the boundaries are explicit — Nova is purpose-built for
|
||||
> infrastructure operations and delivery, not a general-purpose AI agent
|
||||
> or an upstream development platform.
|
||||
|
||||
> **Speaker notes:** Objective #2 is the one to land carefully: trust is
|
||||
> established by deterministic scoring, not by an LLM. The platform
|
||||
> functions without AI. Anti-goals #3 and #4 protect the scope boundary —
|
||||
> **Speaker notes:** Anti-goals #3 and #4 protect the scope boundary —
|
||||
> Nova will not become an IDE or a product-planning tool.
|
||||
|
||||
> **Transition:** "The scope boundary is explicit — here is exactly
|
||||
@@ -150,7 +159,7 @@ focused.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 4 — Scope: Downstream of PDLC
|
||||
## Slide 5 — Scope: Downstream of PDLC
|
||||
|
||||
**Nova governs infrastructure and delivery. The PDLC is upstream — Nova
|
||||
never penetrates it. Integration is through one validated contract.**
|
||||
@@ -183,7 +192,7 @@ never penetrates it. Integration is through one validated contract.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 5 — RACI: Who Owns What
|
||||
## Slide 6 — RACI: Who Owns What
|
||||
|
||||
**Four roles, one matrix — the citizen developer owns FRs + UAT, the
|
||||
platform owns NFRs + infra, quality engineering owns the gate evidence,
|
||||
@@ -224,7 +233,7 @@ and SRE owns operational readiness.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 6 — The Platform Pipeline
|
||||
## Slide 7 — The Platform Pipeline
|
||||
|
||||
**How intent becomes verified infrastructure — with fail-fast policy
|
||||
scanning before the plan and runtime scanning after it.**
|
||||
@@ -272,7 +281,7 @@ graph LR
|
||||
|
||||
---
|
||||
|
||||
## Slide 7 — The Decision Ledger
|
||||
## Slide 8 — The Decision Ledger
|
||||
|
||||
**Every automated decision is captured, immutable, queryable — and
|
||||
accountable.**
|
||||
@@ -310,16 +319,42 @@ accountable.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — The Attestation Matrix
|
||||
## Slide 9 — Attestation Matrix: QA
|
||||
|
||||
**The designed controls that keep humans at stage gates — structured,
|
||||
freshness-validated, and separation-of-duties-enforced.**
|
||||
**The designed controls that keep humans at stage gates — QA concerns,
|
||||
freshness-validated.**
|
||||
|
||||
| Concern | Env | Freshness | Description |
|
||||
|---------|-----|-----------|-------------|
|
||||
| Functional correctness | qa | 24h | The application behaves as specified; evidence accepted from the consumer's UAT. |
|
||||
| Performance baseline | qa | 7d | The deployment meets its performance envelope vs. the agreed baseline. |
|
||||
| Security posture | qa | 24h | The deployment's security findings have been reviewed and accepted. |
|
||||
|
||||
- Each concern has a freshness window — evidence older than the window
|
||||
does not satisfy the gate.
|
||||
- Concerns that are offline-testable run for real; concerns that require
|
||||
external evidence accept signed artifacts.
|
||||
|
||||
> **Benefit:** QA signs off on quality before any promotion — the gate
|
||||
> is explicit, not implicit.
|
||||
|
||||
> **Speaker notes:** The matrix is not a rubber stamp. Each concern has a
|
||||
> freshness window and a plain-language description of what is being
|
||||
> attested. The "operator-supplied" label from the prior deck was
|
||||
> dropped — every concern now has a plain-language description.
|
||||
|
||||
> **Transition:** "QA is half the matrix — here are the production and
|
||||
> DR controls."
|
||||
|
||||
---
|
||||
|
||||
## Slide 10 — Attestation Matrix: Prod/DR
|
||||
|
||||
**Production and DR controls — operational readiness, resilience, and
|
||||
disaster recovery.**
|
||||
|
||||
| Concern | Env | Freshness | Description |
|
||||
|---------|-----|-----------|-------------|
|
||||
| Operational readiness | prod | 30d | SRE confirms the deployment is operable: runbooks, dashboards, on-call coverage. |
|
||||
| Incident response | prod | 90d | The on-call path has been exercised; the deployment has a working incident-response plan. |
|
||||
| Capacity & cost | prod | 30d | Capacity headroom and monthly cost are within the agreed envelope. |
|
||||
@@ -332,17 +367,16 @@ freshness-validated, and separation-of-duties-enforced.**
|
||||
does not satisfy the gate.
|
||||
- **Separation-of-duties on prod:** the approver cannot be the same
|
||||
person who built the deployment.
|
||||
- Concerns that are offline-testable run for real; concerns that require
|
||||
external evidence accept signed artifacts.
|
||||
|
||||
> **Benefit:** the gate model is explicit — autonomy in operations,
|
||||
> human in accountability, by design. The matrix is what makes autonomous
|
||||
> operations safe enough to trust in production.
|
||||
|
||||
> **Speaker notes:** The matrix is not a rubber stamp. Each concern has a
|
||||
> freshness window, a description, and a separation-of-duties rule. The
|
||||
> "operator-supplied" label from the prior deck was dropped — every
|
||||
> concern now has a plain-language description of what is being attested.
|
||||
> **Speaker notes:** The prod/DR rows are the operational-readiness and
|
||||
> resilience gates — SRE signs off on operability, incident response,
|
||||
> capacity, and the three resilience checks (DR drill, chaos, backup).
|
||||
> Separation-of-duties on prod is the rule that keeps the gate honest:
|
||||
> the approver cannot be the same person who built the deployment.
|
||||
|
||||
> **Transition:** "You've seen how Nova works — the pipeline, the ledger,
|
||||
> the attestation gates. Here is how Nova instruments itself so that
|
||||
@@ -350,7 +384,7 @@ freshness-validated, and separation-of-duties-enforced.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 9 — Telemetry & Live Ops
|
||||
## Slide 11 — Telemetry & Live Ops
|
||||
|
||||
**Every metric in this deck is traceable to a real emitted signal — and
|
||||
the live-ops dashboard makes operations visible in PowerBI.**
|
||||
@@ -399,7 +433,7 @@ graph TB
|
||||
|
||||
---
|
||||
|
||||
## Slide 10 — Decision Ledger + Attestation Coverage
|
||||
## Slide 12 — Decision Ledger + Attestation Coverage
|
||||
|
||||
**By design, no change reaches production without a ledger entry and a
|
||||
human attestation — both queryable for auditing, with full
|
||||
@@ -435,7 +469,7 @@ traceability.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 11 — Cost & ROI
|
||||
## Slide 13 — Cost & ROI
|
||||
|
||||
**The ROI formula and the cost estimates — grounded, with the production
|
||||
denominator honestly flagged.**
|
||||
@@ -466,7 +500,7 @@ denominator honestly flagged.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 12 — What's Deferred — and Why
|
||||
## Slide 14 — What's Deferred — and Why
|
||||
|
||||
**Honesty about what is not measured yet — and the blocking work for
|
||||
each.**
|
||||
@@ -502,7 +536,7 @@ metrics — not the autonomy.
|
||||
|
||||
---
|
||||
|
||||
## Slide 13 — Roadmap to the North Star
|
||||
## Slide 15 — Roadmap to the North Star
|
||||
|
||||
**The path from the grounded metrics to the 12–18 month targets — each
|
||||
deferred metric has an unblock path and a candidate milestone.**
|
||||
@@ -533,7 +567,7 @@ deferred metric has an unblock path and a candidate milestone.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 14 — 12-Month Product Roadmap
|
||||
## Slide 16 — 12-Month Product Roadmap
|
||||
|
||||
**The product arc from pilot activation to integration — four quarters,
|
||||
four outcomes.**
|
||||
@@ -560,7 +594,7 @@ integration) and the deferred-metric unblock paths.
|
||||
|
||||
---
|
||||
|
||||
## Slide 15 — Quarter-by-Quarter Outcomes
|
||||
## Slide 17 — Quarter-by-Quarter Outcomes
|
||||
|
||||
| Quarter | Product theme | Key deliverable | Target metric | Grounding |
|
||||
|---------|---------------|-----------------|---------------|-----------|
|
||||
@@ -587,7 +621,7 @@ anymore, and the audit trail is stronger than it ever was.'"*
|
||||
|
||||
---
|
||||
|
||||
## Slide 16 — Production-Grade Guidance via Atelier (1/2)
|
||||
## Slide 18 — Production-Grade Guidance via Atelier (1/2)
|
||||
|
||||
**Nova instructs the citizen developer's AI agent on production-grade
|
||||
engineering — a set of skills and an MCP server.**
|
||||
@@ -621,7 +655,7 @@ engineering — a set of skills and an MCP server.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 17 — Production-Grade Guidance via Atelier (2/2)
|
||||
## Slide 19 — Production-Grade Guidance via Atelier (2/2)
|
||||
|
||||
**Agentic validation catches engineering-discipline gaps that deterministic
|
||||
scanners miss — and the validation is reproducible.**
|
||||
@@ -656,7 +690,7 @@ scanners miss — and the validation is reproducible.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 18 — Recap + Ask
|
||||
## Slide 20 — Recap + Ask
|
||||
|
||||
**The 4-beat recap + the business decision.**
|
||||
|
||||
@@ -710,4 +744,4 @@ S3 Object Lock + signed checkpoints. These two decisions move Nova from
|
||||
|
||||
---
|
||||
|
||||
> **End of deck.** 18 main slides + 1 appendix slide = 19 total.
|
||||
> **End of deck.** 20 main slides + 1 appendix slide = 21 total.
|
||||
Binary file not shown.
+19
-6
@@ -1,11 +1,19 @@
|
||||
# Nova Central Deployment Pipeline Contract (v1.8)
|
||||
# Nova Central Deployment Pipeline Contract (v1.8 + v1.21 REQ-250)
|
||||
#
|
||||
# This is the single source of truth for the deployment pipeline. It
|
||||
# declares the stages that run when a consumer submits a contract:
|
||||
# validate-contract -> resolve-stack -> terraform-plan -> checkov ->
|
||||
# validate-contract -> resolve-stack -> checkov-static (fail-fast) ->
|
||||
# terraform-plan -> runtime-policy-scan (Wiz-or-Checkov, never both) ->
|
||||
# confidence -> apply (dev only) -> publish-outputs -> deploy-uptime ->
|
||||
# comment-outputs
|
||||
#
|
||||
# REQ-250 (v1.21): the policy scan is two-stage. checkov-static runs on
|
||||
# the authored Terraform code BEFORE terraform plan (fail-fast, quick
|
||||
# developer feedback). runtime-policy-scan runs AFTER terraform plan:
|
||||
# Wiz scans the plan when configured (WIZ_API_TOKEN + WIZ_API_URL);
|
||||
# otherwise Checkov runs against the plan as a drop-in replacement. Wiz
|
||||
# and Checkov are NEVER both run on the plan.
|
||||
#
|
||||
# Decommission mode (mode: decommission) runs a different set of stages:
|
||||
# validate-change-request -> disable-deletion-protection (HITL SRE) ->
|
||||
# zero-counts (HITL SRE) -> confirm-decommission
|
||||
@@ -36,15 +44,20 @@ stages:
|
||||
command: python3 core/contract_resolver.py contracts/static-assets.yaml /tmp/acdl-stack.json
|
||||
required: true
|
||||
|
||||
- name: checkov-static
|
||||
description: Run Checkov on the authored Terraform code (fail-fast, before terraform plan) — REQ-250
|
||||
command: bash scripts/run_codegen.sh --check-only
|
||||
required: true
|
||||
|
||||
- name: terraform-plan
|
||||
description: Compile the stack to Terraform and run terraform plan
|
||||
command: bash scripts/run_platform.sh --plan-only contracts/static-assets.yaml
|
||||
required: true
|
||||
|
||||
- name: checkov
|
||||
description: Run Checkov policy checks on the emitted Terraform
|
||||
command: bash scripts/run_platform.sh --check-only
|
||||
required: false
|
||||
- name: runtime-policy-scan
|
||||
description: Run Wiz against the plan when configured, else Checkov against the plan (never both) — REQ-250
|
||||
command: bash scripts/run_postapply.sh contracts/static-assets.yaml --quiet
|
||||
required: true
|
||||
|
||||
- name: confidence
|
||||
description: Compute the confidence signal from policy + validation inputs
|
||||
|
||||
@@ -8,7 +8,7 @@ multipart form: name=<filename>, attachment=<file bytes>
|
||||
|
||||
Usage:
|
||||
python3 scripts/attach_release_asset.py <file-path> <release-id>
|
||||
python3 scripts/attach_release_asset.py docs/presentations/nova-no-humans-platform.pptx 522
|
||||
python3 scripts/attach_release_asset.py docs/presentations/nova-autonomous-cloud-delivery.pptx 522
|
||||
|
||||
Token resolution: reads NOVA_GITEA_TOKEN (or ACDL_GITEA_TOKEN) from .env.secrets
|
||||
/ .env, matching the ship_phase.sh pattern. Never uses shell env tokens.
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# scripts/render_deck.sh — render a Marp deck to HTML + PPTX, commit both to git.
|
||||
# REQ-228 (v1.18): PPTX is now a first-class committed artifact + release attachment.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/render_deck.sh <deck-name>
|
||||
# bash scripts/render_deck.sh nova-autonomous-cloud-delivery
|
||||
#
|
||||
# Renders:
|
||||
# docs/presentations/<deck-name>-marp.md → docs/presentations/<deck-name>.html (committed)
|
||||
# → docs/presentations/<deck-name>.pptx (committed, binary)
|
||||
#
|
||||
# The PPTX is also attached to the current phase's Gitea release via
|
||||
# scripts/attach_release_asset.py (call separately after ship, or this script
|
||||
# will invoke it if NOVA_GITEA_RELEASE_ID is set).
|
||||
set -euo pipefail
|
||||
|
||||
DECK="${1:?Usage: render_deck.sh <deck-name>}"
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
SRC="docs/presentations/${DECK}-marp.md"
|
||||
HTML="docs/presentations/${DECK}.html"
|
||||
PPTX="docs/presentations/${DECK}.pptx"
|
||||
|
||||
if [ ! -f "$SRC" ]; then
|
||||
echo "ERROR: source deck $SRC not found" >&2; exit 1
|
||||
fi
|
||||
|
||||
CHROME=""
|
||||
for c in \
|
||||
/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
/usr/bin/chromium \
|
||||
/usr/bin/chromium-browser \
|
||||
/usr/bin/google-chrome; do
|
||||
if [ -x "$c" ]; then CHROME="$c"; break; fi
|
||||
done
|
||||
if [ -z "$CHROME" ]; then
|
||||
echo "WARNING: no Chrome/Chromium found — skipping render (HTML/PPTX will need manual re-render)" >&2
|
||||
exit 0
|
||||
fi
|
||||
export CHROME_PATH="$CHROME"
|
||||
|
||||
echo "Rendering HTML → $HTML"
|
||||
npx --yes @marp-team/marp-cli@latest --allow-local-files "$SRC" -o "$HTML" 2>&1 | tail -3
|
||||
|
||||
echo "Rendering PPTX → $PPTX"
|
||||
npx --yes @marp-team/marp-cli@latest --allow-local-files "$SRC" -o "$PPTX" 2>&1 | tail -3
|
||||
|
||||
git add "$HTML" "$PPTX"
|
||||
echo "Staged $HTML + $PPTX for commit."
|
||||
|
||||
if [ -n "${NOVA_GITEA_RELEASE_ID:-}" ]; then
|
||||
echo "Attaching PPTX to Gitea release $NOVA_GITEA_RELEASE_ID..."
|
||||
python3 scripts/attach_release_asset.py "$PPTX" "$NOVA_GITEA_RELEASE_ID" || \
|
||||
echo "WARNING: attach failed — PPTX is still committed; attach manually."
|
||||
fi
|
||||
@@ -41,16 +41,18 @@ if [ -z "$CHROME" ]; then
|
||||
fi
|
||||
export CHROME_PATH="$CHROME"
|
||||
|
||||
# --- Step 1: render mermaid diagrams (S&P-themed) ---
|
||||
echo "=== Step 1: Rendering mermaid diagrams (S&P theme: $THEME_JSON) ==="
|
||||
# --- Step 1: render mermaid diagrams (S&P-themed, 2x scale, transparent bg) ---
|
||||
# REQ-258: -s 2 (2x scale) + -b transparent (transparent background) per README spec.
|
||||
echo "=== Step 1: Rendering mermaid diagrams (S&P theme: $THEME_JSON, 2x, transparent) ==="
|
||||
if [ -d "$MMD_DIR" ]; then
|
||||
for mmd in "$MMD_DIR"/*.mmd; do
|
||||
name="$(basename "$mmd" .mmd)"
|
||||
png="$PNG_DIR/$name.png"
|
||||
echo " $name.mmd → $name.png"
|
||||
npx --yes @mermaid-js/mermaid-cli \
|
||||
npx --yes @mermaid-js/mermaid-cli@11.16.0 \
|
||||
--configFile "$THEME_JSON" \
|
||||
--puppeteerConfigFile "$PUPPETEER_CFG" \
|
||||
-s 2 -b transparent \
|
||||
--input "$mmd" \
|
||||
--output "$png" 2>&1 | grep -v "^$" || true
|
||||
done
|
||||
@@ -61,13 +63,14 @@ fi
|
||||
echo ""
|
||||
|
||||
# --- Step 2: render Marp deck (S&P-themed) ---
|
||||
# REQ-257: pinned marp-cli version (v4.5.0) to prevent boilerplate-CSS drift.
|
||||
echo "=== Step 2: Rendering Marp deck → HTML + PPTX ==="
|
||||
echo " Theme: $THEME_CSS"
|
||||
echo " HTML → $HTML"
|
||||
npx --yes @marp-team/marp-cli@latest --allow-local-files --theme "$THEME_CSS" "$SRC" -o "$HTML" 2>&1 | tail -3
|
||||
npx --yes @marp-team/marp-cli@4.5.0 --allow-local-files --theme "$THEME_CSS" "$SRC" -o "$HTML" 2>&1 | tail -3
|
||||
|
||||
echo " PPTX → $PPTX"
|
||||
npx --yes @marp-team/marp-cli@latest --allow-local-files --theme "$THEME_CSS" "$SRC" -o "$PPTX" 2>&1 | tail -3
|
||||
npx --yes @marp-team/marp-cli@4.5.0 --allow-local-files --theme "$THEME_CSS" "$SRC" -o "$PPTX" 2>&1 | tail -3
|
||||
echo ""
|
||||
|
||||
# --- Step 3: stage ---
|
||||
|
||||
@@ -101,6 +101,20 @@ adapter.compile(stack, '$TF_DIR')
|
||||
print('adapter: main.tf + terraform.tf + providers.tf written')
|
||||
"
|
||||
|
||||
echo "=== Step 3c: Checkov on static code (fail-fast, before terraform plan) ==="
|
||||
# REQ-250 (v1.21): Checkov runs on the authored Terraform code BEFORE
|
||||
# terraform plan so developers get immediate policy feedback, not a
|
||||
# delayed plan-stage failure. The runtime plan scan (Wiz-or-Checkov)
|
||||
# runs after the plan in run_postapply.sh Step 5.
|
||||
if [ "$QUIET" = "0" ]; then
|
||||
checkov -d "$TF_DIR" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ 2>&1 | tee "$WORK/checkov-static.json"
|
||||
else
|
||||
checkov -d "$TF_DIR" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ > "$WORK/checkov-static.json" 2> "$WORK/checkov-static.err"
|
||||
fi
|
||||
[ -s "$WORK/checkov-static.json" ] || { echo "FAIL: checkov (static) produced no output" >&2; exit 1; }
|
||||
echo ""
|
||||
echo "checkov (static) summary: $(python3 -c "import json; d=json.load(open('$WORK/checkov-static.json')); print(len(d.get('results',{}).get('failed_checks',[])), 'failed,', len(d.get('results',{}).get('passed_checks',[])), 'passed')")"
|
||||
|
||||
if [ "$CHECK_ONLY" = "1" ]; then
|
||||
echo ""
|
||||
echo "=== Step 3b: validate adapter output structure (offline) ==="
|
||||
|
||||
+43
-12
@@ -312,6 +312,20 @@ if [ -z "${AWS_ACCESS_KEY_ID:-}" ] || [ -z "${AWS_SECRET_ACCESS_KEY:-}" ]; then
|
||||
export AWS_DEFAULT_REGION="$AWS_DEFAULT_REGION"
|
||||
fi
|
||||
|
||||
echo "=== Step 3c: Checkov on static code (fail-fast, before terraform plan) ==="
|
||||
# REQ-250 (v1.21): Checkov runs on the authored Terraform code BEFORE
|
||||
# terraform plan so developers get immediate policy feedback, not a
|
||||
# delayed plan-stage failure. The runtime plan scan (Wiz-or-Checkov)
|
||||
# runs after the plan (Step 5).
|
||||
if [ "$QUIET" = "0" ]; then
|
||||
checkov -d "$TF_DIR" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ 2>&1 | tee "$WORK/checkov-static.json"
|
||||
else
|
||||
checkov -d "$TF_DIR" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ > "$WORK/checkov-static.json" 2> "$WORK/checkov-static.err"
|
||||
fi
|
||||
[ -s "$WORK/checkov-static.json" ] || fail "checkov (static) produced no output"
|
||||
echo ""
|
||||
echo "checkov (static) summary: $(python3 -c "import json; d=json.load(open('$WORK/checkov-static.json')); print(len(d.get('results',{}).get('failed_checks',[])), 'failed,', len(d.get('results',{}).get('passed_checks',[])), 'passed')")"
|
||||
|
||||
echo "=== Step 4: terraform init + validate + plan -lock=false (real AWS) ==="
|
||||
cd "$TF_DIR"
|
||||
|
||||
@@ -380,19 +394,36 @@ if [ "$DESTROY_ONLY" = "1" ]; then
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Step 5: run Checkov on $TF_DIR/main.tf ==="
|
||||
if [ "$QUIET" = "0" ]; then
|
||||
checkov -f "$TF_DIR/main.tf" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ 2>&1 | tee "$WORK/checkov.json"
|
||||
echo "=== Step 5: runtime policy scan on the terraform plan (Wiz-or-Checkov, never both) ==="
|
||||
# REQ-250 (v1.21): after terraform plan, run Wiz against the plan when
|
||||
# configured; otherwise run Checkov against the plan as a drop-in
|
||||
# replacement. Wiz and Checkov are NEVER both run on the plan.
|
||||
RUNTIME_SCAN_ENGINE=""
|
||||
if [ -n "${WIZ_API_TOKEN:-}" ] || [ -n "${WIZ_API_URL:-}" ]; then
|
||||
RUNTIME_SCAN_ENGINE="wiz"
|
||||
echo "--- Wiz configured (WIZ_API_TOKEN + WIZ_API_URL) → Wiz on the plan ---"
|
||||
python3 adapters/wiz/wiz_adapter.py --plan "$TF_DIR/tfplan" --contract-id "$CONTRACT_ID" --run-id "${CONTRACT_ID}" > "$WORK/pcr.json" 2> "$WORK/wiz.err" || {
|
||||
echo "WARNING: Wiz scan failed; falling back to Checkov on the plan" >&2
|
||||
RUNTIME_SCAN_ENGINE="checkov-plan"
|
||||
}
|
||||
else
|
||||
checkov -f "$TF_DIR/main.tf" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ > "$WORK/checkov.json" 2> "$WORK/checkov.err"
|
||||
RUNTIME_SCAN_ENGINE="checkov-plan"
|
||||
fi
|
||||
[ -s "$WORK/checkov.json" ] || fail "checkov produced no output"
|
||||
echo ""
|
||||
echo "checkov summary: $(python3 -c "import json; d=json.load(open('$WORK/checkov.json')); print(len(d.get('results',{}).get('failed_checks',[])), 'failed,', len(d.get('results',{}).get('passed_checks',[])), 'passed')")"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 6: Checkov adapter -> PolicyCheckResult (compliance details) ==="
|
||||
python3 adapters/terraform/policy/checkov_adapter.py "$WORK/checkov.json" "$CONTRACT_ID" > "$WORK/pcr.json" || fail "checkov adapter failed"
|
||||
if [ "$RUNTIME_SCAN_ENGINE" = "checkov-plan" ]; then
|
||||
echo "--- Wiz not configured → Checkov on the plan (drop-in replacement) ---"
|
||||
if [ "$QUIET" = "0" ]; then
|
||||
checkov -f "$TF_DIR/tfplan" --framework terraform_plan -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ 2>&1 | tee "$WORK/checkov-plan.json"
|
||||
else
|
||||
checkov -f "$TF_DIR/tfplan" --framework terraform_plan -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ > "$WORK/checkov-plan.json" 2> "$WORK/checkov-plan.err"
|
||||
fi
|
||||
[ -s "$WORK/checkov-plan.json" ] || fail "checkov (plan) produced no output"
|
||||
echo ""
|
||||
echo "checkov (plan) summary: $(python3 -c "import json; d=json.load(open('$WORK/checkov-plan.json')); print(len(d.get('results',{}).get('failed_checks',[])), 'failed,', len(d.get('results',{}).get('passed_checks',[])), 'passed')")"
|
||||
echo ""
|
||||
echo "=== Step 6: Checkov (plan) adapter -> PolicyCheckResult ==="
|
||||
python3 adapters/terraform/policy/checkov_adapter.py "$WORK/checkov-plan.json" "$CONTRACT_ID" > "$WORK/pcr.json" || fail "checkov (plan) adapter failed"
|
||||
fi
|
||||
echo "runtime scan engine: $RUNTIME_SCAN_ENGINE"
|
||||
python3 -c "
|
||||
import json
|
||||
pcrs = json.load(open('$WORK/pcr.json'))
|
||||
@@ -494,5 +525,5 @@ source "$ROOT/scripts/run_uptime.sh"
|
||||
|
||||
echo ""
|
||||
echo "=== PLATFORM E2E OK ==="
|
||||
echo "contract -> resolver -> stack -> terraform plan -> Checkov -> confidence ($BAND) -> outbox -> outputs"
|
||||
echo "contract -> resolver -> stack -> Checkov(static) -> terraform plan -> Wiz-or-Checkov(plan) -> confidence ($BAND) -> outbox -> outputs"
|
||||
exit 0
|
||||
+33
-14
@@ -2,8 +2,9 @@
|
||||
# scripts/run_postapply.sh — post-Terraform steps for the Nova platform pipeline.
|
||||
#
|
||||
# Performs steps 5–9 of run_platform.sh (after terraform apply/destroy):
|
||||
# 5. Checkov policy scan on the emitted main.tf
|
||||
# 6. Checkov adapter → PolicyCheckResult (compliance details)
|
||||
# 3c. Checkov policy scan on static code (fail-fast, in run_codegen.sh)
|
||||
# 5. Runtime policy scan on the terraform plan (Wiz-or-Checkov, never both)
|
||||
# 6. Policy scan adapter → PolicyCheckResult (compliance details)
|
||||
# 7. Confidence signal compute
|
||||
# 7b. HITL attestation gate (qa/prod/dr only)
|
||||
# 8. Write evidence event to DynamoDB outbox
|
||||
@@ -92,19 +93,37 @@ else:
|
||||
" || { echo "FAIL: HITL gate blocked" >&2; return 1; }
|
||||
}
|
||||
|
||||
echo "=== Step 5: run Checkov on $TF_DIR/main.tf ==="
|
||||
if [ "$QUIET" = "0" ]; then
|
||||
checkov -f "$TF_DIR/main.tf" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ 2>&1 | tee "$WORK/checkov.json"
|
||||
echo "=== Step 5: runtime policy scan on the terraform plan (Wiz-or-Checkov, never both) ==="
|
||||
# REQ-250 (v1.21): after terraform plan, run Wiz against the plan when
|
||||
# configured; otherwise run Checkov against the plan as a drop-in
|
||||
# replacement. Wiz and Checkov are NEVER both run on the plan. The
|
||||
# static-code Checkov already ran in run_codegen.sh Step 3c (fail-fast).
|
||||
RUNTIME_SCAN_ENGINE=""
|
||||
if [ -n "${WIZ_API_TOKEN:-}" ] || [ -n "${WIZ_API_URL:-}" ]; then
|
||||
RUNTIME_SCAN_ENGINE="wiz"
|
||||
echo "--- Wiz configured (WIZ_API_TOKEN + WIZ_API_URL) → Wiz on the plan ---"
|
||||
python3 adapters/wiz/wiz_adapter.py --plan "$TF_DIR/tfplan" --contract-id "$CONTRACT_ID" --run-id "${CONTRACT_ID}" > "$WORK/pcr.json" 2> "$WORK/wiz.err" || {
|
||||
echo "WARNING: Wiz scan failed; falling back to Checkov on the plan" >&2
|
||||
RUNTIME_SCAN_ENGINE="checkov-plan"
|
||||
}
|
||||
else
|
||||
checkov -f "$TF_DIR/main.tf" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ > "$WORK/checkov.json" 2> "$WORK/checkov.err"
|
||||
RUNTIME_SCAN_ENGINE="checkov-plan"
|
||||
fi
|
||||
[ -s "$WORK/checkov.json" ] || { echo "FAIL: checkov produced no output" >&2; exit 1; }
|
||||
echo ""
|
||||
echo "checkov summary: $(python3 -c "import json; d=json.load(open('$WORK/checkov.json')); print(len(d.get('results',{}).get('failed_checks',[])), 'failed,', len(d.get('results',{}).get('passed_checks',[])), 'passed')")"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 6: Checkov adapter → PolicyCheckResult (compliance details) ==="
|
||||
python3 adapters/terraform/policy/checkov_adapter.py "$WORK/checkov.json" "$CONTRACT_ID" > "$WORK/pcr.json" || { echo "FAIL: checkov adapter failed" >&2; exit 1; }
|
||||
if [ "$RUNTIME_SCAN_ENGINE" = "checkov-plan" ]; then
|
||||
echo "--- Wiz not configured → Checkov on the plan (drop-in replacement) ---"
|
||||
if [ "$QUIET" = "0" ]; then
|
||||
checkov -f "$TF_DIR/tfplan" --framework terraform_plan -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ 2>&1 | tee "$WORK/checkov-plan.json"
|
||||
else
|
||||
checkov -f "$TF_DIR/tfplan" --framework terraform_plan -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ > "$WORK/checkov-plan.json" 2> "$WORK/checkov-plan.err"
|
||||
fi
|
||||
[ -s "$WORK/checkov-plan.json" ] || { echo "FAIL: checkov (plan) produced no output" >&2; exit 1; }
|
||||
echo ""
|
||||
echo "checkov (plan) summary: $(python3 -c "import json; d=json.load(open('$WORK/checkov-plan.json')); print(len(d.get('results',{}).get('failed_checks',[])), 'failed,', len(d.get('results',{}).get('passed_checks',[])), 'passed')")"
|
||||
echo ""
|
||||
echo "=== Step 6: Checkov (plan) adapter → PolicyCheckResult (compliance details) ==="
|
||||
python3 adapters/terraform/policy/checkov_adapter.py "$WORK/checkov-plan.json" "$CONTRACT_ID" > "$WORK/pcr.json" || { echo "FAIL: checkov (plan) adapter failed" >&2; exit 1; }
|
||||
fi
|
||||
echo "runtime scan engine: $RUNTIME_SCAN_ENGINE"
|
||||
python3 -c "
|
||||
import json
|
||||
pcrs = json.load(open('$WORK/pcr.json'))
|
||||
@@ -199,4 +218,4 @@ source "$ROOT/scripts/run_uptime.sh"
|
||||
|
||||
echo ""
|
||||
echo "=== POST-APPLY OK ==="
|
||||
echo "Checkov → confidence ($BAND) → outbox → outputs → uptime"
|
||||
echo "Checkov(static, pre-plan) → Wiz-or-Checkov(plan) → confidence ($BAND) → outbox → outputs → uptime"
|
||||
|
||||
@@ -117,7 +117,6 @@ EXCLUDE_SCRIPTS=(
|
||||
sync_workflows.py
|
||||
attach_release_asset.py
|
||||
check_north_star_diff.sh
|
||||
render_deck.sh
|
||||
render_slides.sh
|
||||
)
|
||||
|
||||
|
||||
@@ -173,16 +173,19 @@ class TestDeployPipelineContract:
|
||||
contract = yaml.safe_load(fh)
|
||||
jsonschema.validate(contract, schema)
|
||||
|
||||
def test_deploy_pipeline_has_six_stages(self):
|
||||
def test_deploy_pipeline_has_required_stages(self):
|
||||
with open(ROOT / "pipelines/contract.yml") as fh:
|
||||
contract = yaml.safe_load(fh)
|
||||
stage_names = [s["name"] for s in contract["stages"]]
|
||||
assert "validate-contract" in stage_names
|
||||
assert "resolve-stack" in stage_names
|
||||
assert "checkov-static" in stage_names, "REQ-250: checkov-static stage missing"
|
||||
assert "terraform-plan" in stage_names
|
||||
assert "checkov" in stage_names
|
||||
assert "runtime-policy-scan" in stage_names, "REQ-250: runtime-policy-scan stage missing"
|
||||
assert "confidence" in stage_names
|
||||
assert "apply" in stage_names
|
||||
# The old single 'checkov' stage is gone (split into checkov-static + runtime-policy-scan)
|
||||
assert "checkov" not in stage_names, "old 'checkov' stage should be replaced by checkov-static + runtime-policy-scan"
|
||||
|
||||
|
||||
class TestL2OutputsResolution:
|
||||
|
||||
@@ -40,7 +40,7 @@ _EXCLUDE_SCRIPTS = {
|
||||
"untag_acdl_keys.py", "seed_uptime_monitors.py",
|
||||
"push_consumer_image.py", "sync_workflows.py",
|
||||
"attach_release_asset.py", "check_north_star_diff.sh",
|
||||
"render_deck.sh", "render_slides.sh",
|
||||
"render_slides.sh",
|
||||
}
|
||||
|
||||
# Synced top-level files (not in any excluded dir).
|
||||
|
||||
@@ -206,14 +206,15 @@ class TestDeployPipelineContract:
|
||||
contract = _load_yaml("pipelines/contract.yml")
|
||||
jsonschema.validate(contract, schema)
|
||||
|
||||
def test_deploy_contract_has_nine_stages(self):
|
||||
def test_deploy_contract_has_ten_stages(self):
|
||||
contract = _load_yaml("pipelines/contract.yml")
|
||||
stage_names = [s["name"] for s in contract["stages"]]
|
||||
assert stage_names == [
|
||||
"validate-contract",
|
||||
"resolve-stack",
|
||||
"checkov-static",
|
||||
"terraform-plan",
|
||||
"checkov",
|
||||
"runtime-policy-scan",
|
||||
"confidence",
|
||||
"apply",
|
||||
"publish-outputs",
|
||||
|
||||
@@ -26,7 +26,7 @@ def test_cap_024_deck_structure():
|
||||
|
||||
def test_cap_024_deck_exists():
|
||||
"""The unified deck source of truth exists."""
|
||||
deck_path = ROOT / "docs" / "presentations" / "nova-no-humans-platform.md"
|
||||
deck_path = ROOT / "docs" / "presentations" / "nova-autonomous-cloud-delivery.md"
|
||||
assert deck_path.exists(), "unified deck not found"
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
"""REQ-239..243 (v1.20): S&P theme + slide render pipeline tests.
|
||||
"""REQ-239..243 (v1.20) + REQ-245,251,252 (v1.21): S&P theme + slide render
|
||||
pipeline + deck-refinement tests.
|
||||
|
||||
Validates:
|
||||
v1.20 validates:
|
||||
- The Marp deck frontmatter references nova-sp-theme.css
|
||||
- The CSS file contains the S&P colors (#D6002A, #1B1B1B)
|
||||
- The mermaid theme JSON contains the S&P colors
|
||||
- Every .mmd has a corresponding .png
|
||||
- The render_slides.sh script exists and is executable
|
||||
- The CI workflow file exists
|
||||
|
||||
v1.21 adds (REQ-245,251,252):
|
||||
- Deck renamed to nova-autonomous-cloud-delivery*
|
||||
- No maturity badges in the Marp deck
|
||||
- No version in the Marp footer/title slide
|
||||
- 20 main + 1 appendix slides (v1.22 split slides 3+8 to relieve overflow)
|
||||
- No D-###/REQ-###/internal .py paths in audience-facing slides
|
||||
- Title is "Nova — The Autonomous Cloud Delivery Platform"
|
||||
"""
|
||||
import re
|
||||
from pathlib import Path
|
||||
@@ -18,7 +27,8 @@ PRESENTATIONS = ROOT / "docs" / "presentations"
|
||||
ASSETS = PRESENTATIONS / "assets"
|
||||
THEME_CSS = ASSETS / "nova-sp-theme.css"
|
||||
THEME_JSON = ASSETS / "mmd" / "sp-theme.json"
|
||||
MARP_DECK = PRESENTATIONS / "nova-no-humans-platform-marp.md"
|
||||
MARP_DECK = PRESENTATIONS / "nova-autonomous-cloud-delivery-marp.md"
|
||||
SOURCE_MD = PRESENTATIONS / "nova-autonomous-cloud-delivery.md"
|
||||
RENDER_SCRIPT = ROOT / "scripts" / "render_slides.sh"
|
||||
SLIDES_WORKFLOW = ROOT / ".github" / "workflows" / "slides.yml"
|
||||
|
||||
@@ -87,6 +97,13 @@ def test_render_slides_script_renders_marp():
|
||||
assert ".pptx" in text, "render_slides.sh does not produce PPTX"
|
||||
|
||||
|
||||
def test_render_slides_default_deck_renamed():
|
||||
"""REQ-245: render_slides.sh default deck is nova-autonomous-cloud-delivery."""
|
||||
text = RENDER_SCRIPT.read_text()
|
||||
assert "nova-autonomous-cloud-delivery" in text, \
|
||||
"render_slides.sh does not default to nova-autonomous-cloud-delivery"
|
||||
|
||||
|
||||
def test_slides_ci_workflow_exists():
|
||||
"""REQ-241: CI workflow for slides exists."""
|
||||
assert SLIDES_WORKFLOW.is_file(), "slides.yml workflow not found"
|
||||
@@ -124,3 +141,233 @@ def test_readme_no_retired_decks():
|
||||
"README still references retired 'how-the-platform-works' deck"
|
||||
assert "the-developer-experience" not in readme, \
|
||||
"README still references retired 'the-developer-experience' deck"
|
||||
|
||||
|
||||
def test_readme_no_old_deck_name():
|
||||
"""REQ-245: README references the new deck name, not the old one."""
|
||||
readme = (PRESENTATIONS / "README.md").read_text()
|
||||
assert "nova-autonomous-cloud-delivery" in readme, \
|
||||
"README does not reference nova-autonomous-cloud-delivery"
|
||||
|
||||
|
||||
def test_old_deck_files_removed():
|
||||
"""REQ-245: the old nova-no-humans-platform* files are gone."""
|
||||
old_files = sorted(PRESENTATIONS.glob("nova-no-humans-platform*"))
|
||||
assert not old_files, f"old deck files still present: {old_files}"
|
||||
|
||||
|
||||
def test_marp_deck_no_badges():
|
||||
"""REQ-252: no maturity badges in the Marp deck."""
|
||||
text = MARP_DECK.read_text()
|
||||
assert "badge" not in text, "Marp deck still contains badge spans"
|
||||
|
||||
|
||||
def test_marp_deck_no_version_in_footer():
|
||||
"""REQ-251: no version (v1.x) in the Marp frontmatter footer/header."""
|
||||
text = MARP_DECK.read_text()
|
||||
fm_match = re.match(r'^---\n(.*?)\n---', text, re.DOTALL)
|
||||
assert fm_match, "Marp frontmatter not found"
|
||||
frontmatter = fm_match.group(1)
|
||||
# No v1.x version string in the footer or header lines
|
||||
assert not re.search(r"v1\.\d+", frontmatter), \
|
||||
f"Marp frontmatter still contains a version: {frontmatter}"
|
||||
# No "Act" pagination artifact
|
||||
assert "Act %" not in frontmatter, \
|
||||
"Marp frontmatter still contains 'Act %{page}' artifact"
|
||||
|
||||
|
||||
def test_marp_deck_title_slide_no_version_subtitle():
|
||||
"""REQ-251: the title slide does not carry a version subtitle."""
|
||||
text = MARP_DECK.read_text()
|
||||
# The title slide is the first slide after the frontmatter
|
||||
# Find the title block (between the frontmatter and the first --- separator)
|
||||
after_fm = text.split("---\n", 2)[2] if text.startswith("---") else text
|
||||
first_slide = after_fm.split("\n---\n")[0]
|
||||
# The old subtitle was "v1.18 — Citizen Developer & Production-Grade Guidance"
|
||||
assert "v1.18" not in first_slide, \
|
||||
"Title slide still contains 'v1.18' subtitle"
|
||||
assert "Citizen Developer & Production-Grade Guidance" not in first_slide, \
|
||||
"Title slide still contains the old version subtitle"
|
||||
|
||||
|
||||
def test_marp_deck_title_is_autonomous_cloud_delivery():
|
||||
"""REQ-245: the deck title is 'Nova — The Autonomous Cloud Delivery Platform'."""
|
||||
text = MARP_DECK.read_text()
|
||||
assert "Autonomous Cloud Delivery Platform" in text, \
|
||||
"Deck title is not 'Autonomous Cloud Delivery Platform'"
|
||||
# The old title should not appear in the audience-facing deck
|
||||
# (speaker notes are not in the marp deck, so this is safe)
|
||||
assert "No-Humans Infrastructure Platform" not in text, \
|
||||
"Deck still carries the old 'No-Humans Infrastructure Platform' title"
|
||||
|
||||
|
||||
def test_marp_deck_slide_count():
|
||||
"""REQ-245/261: 20 main slides + 1 appendix = 21 slides total.
|
||||
v1.22 split slides 3 (Objectives+Anti-Goals) and 8 (Attestation
|
||||
Matrix) to relieve overflow, increasing the count from 18 to 20."""
|
||||
text = MARP_DECK.read_text()
|
||||
# Count slide separators: each slide ends with --- (except the last)
|
||||
# The frontmatter is one --- ... --- block, then each slide is separated by ---
|
||||
# Count "## Slide" and "## Appendix" headings
|
||||
slide_headings = re.findall(r"^## (?:Slide|Appendix) ", text, re.MULTILINE)
|
||||
main_slides = re.findall(r"^## Slide ", text, re.MULTILINE)
|
||||
appendix_slides = re.findall(r"^## Appendix ", text, re.MULTILINE)
|
||||
assert len(main_slides) == 20, \
|
||||
f"expected 20 main slides, found {len(main_slides)}: {slide_headings}"
|
||||
assert len(appendix_slides) == 1, \
|
||||
f"expected 1 appendix slide, found {len(appendix_slides)}"
|
||||
|
||||
|
||||
def test_marp_deck_no_internal_citations():
|
||||
"""REQ-252: no D-### decision IDs, REQ-### requirement IDs, or internal
|
||||
.py file paths in the audience-facing Marp deck."""
|
||||
text = MARP_DECK.read_text()
|
||||
# Decision IDs like D-121, D-083
|
||||
assert not re.search(r"\bD-\d{3}\b", text), \
|
||||
"Marp deck contains D-### decision IDs"
|
||||
# Requirement IDs like REQ-245
|
||||
assert not re.search(r"\bREQ-\d{3}\b", text), \
|
||||
"Marp deck contains REQ-### requirement IDs"
|
||||
# Internal python file paths like outbox_writer.py, confidence_signal.py
|
||||
# (allow .py only inside code blocks for the ROI formula? No — the deck
|
||||
# should not cite internal file paths at all)
|
||||
assert not re.search(r"\b(outbox_writer|confidence_signal|hitl_gates|"
|
||||
r"attestation_matrix|checkov_adapter|infracost_adapter|"
|
||||
r"contract_resolver|run_platform)\.py\b", text), \
|
||||
"Marp deck contains internal .py file paths"
|
||||
|
||||
|
||||
def test_source_md_no_internal_citations_in_slides():
|
||||
"""REQ-252: the source-of-truth markdown keeps internal citations only
|
||||
in speaker notes, not in the audience-facing slide body. Speaker notes
|
||||
are blockquoted (> ) — we check non-blockquote lines for D-###/REQ-###."""
|
||||
text = SOURCE_MD.read_text()
|
||||
# Split into lines; exclude blockquote lines (speaker notes) and the
|
||||
# header frontmatter (> ... at the top)
|
||||
in_note = False
|
||||
body_lines = []
|
||||
for line in text.splitlines():
|
||||
if line.lstrip().startswith(">"):
|
||||
in_note = True
|
||||
continue
|
||||
if in_note and line.strip() == "":
|
||||
in_note = False
|
||||
continue
|
||||
if not in_note:
|
||||
body_lines.append(line)
|
||||
body = "\n".join(body_lines)
|
||||
# Decision IDs and REQ IDs should not appear in the slide body
|
||||
assert not re.search(r"\bD-\d{3}\b", body), \
|
||||
"Source markdown slide body contains D-### decision IDs"
|
||||
assert not re.search(r"\bREQ-\d{3}\b", body), \
|
||||
"Source markdown slide body contains REQ-### requirement IDs"
|
||||
|
||||
|
||||
def test_source_md_no_badges():
|
||||
"""REQ-252: no maturity badges in the source-of-truth markdown."""
|
||||
text = SOURCE_MD.read_text()
|
||||
assert "badge" not in text.lower(), \
|
||||
"Source markdown still contains badge spans"
|
||||
|
||||
|
||||
# --- v1.22 layout/aspect-ratio/theme-structural tests (REQ-262) ---
|
||||
|
||||
def test_theme_css_has_section_padding():
|
||||
"""REQ-254: theme CSS has a section padding rule (root cause fix)."""
|
||||
css = THEME_CSS.read_text()
|
||||
assert "padding:" in css, "theme CSS has no padding rule"
|
||||
# The section rule must have padding (not just table/td padding)
|
||||
assert re.search(r"section\s*\{[^}]*padding:", css, re.DOTALL), \
|
||||
"theme CSS has no padding on the section rule"
|
||||
|
||||
|
||||
def test_theme_css_suppresses_title_chrome():
|
||||
"""REQ-256: title slides suppress header/footer chrome."""
|
||||
css = THEME_CSS.read_text()
|
||||
assert "section.title header" in css, \
|
||||
"theme CSS does not suppress title-slide header"
|
||||
assert "section.title footer" in css, \
|
||||
"theme CSS does not suppress title-slide footer"
|
||||
assert "display: none" in css, \
|
||||
"theme CSS does not set display:none on title chrome"
|
||||
|
||||
|
||||
def test_theme_css_has_aspect_ratio_aware_images():
|
||||
"""REQ-255: image rules use object-fit + max-width (not blunt max-height only)."""
|
||||
css = THEME_CSS.read_text()
|
||||
assert "object-fit" in css, \
|
||||
"theme CSS does not use object-fit for images"
|
||||
assert "max-width" in css, \
|
||||
"theme CSS does not set max-width for images"
|
||||
|
||||
|
||||
def test_png_aspect_ratios_sane():
|
||||
"""REQ-259/260: PNGs referenced in the marp deck have aspect ratios
|
||||
in [0.4, 4.0] (suitable for 16:9 slides with img.tall/img.wide classes).
|
||||
Only checks PNGs actually referenced in the current marp deck —
|
||||
legacy/unused PNGs are not checked (GRILL revision 1)."""
|
||||
import struct
|
||||
deck_text = MARP_DECK.read_text()
|
||||
# Extract all referenced PNG paths: 
|
||||
referenced = re.findall(r'!\[[^\]]*\]\(assets/png/([^)]+\.png)\)', deck_text)
|
||||
assert referenced, "no PNGs referenced in the marp deck"
|
||||
for png_name in referenced:
|
||||
png_path = ASSETS / "png" / png_name
|
||||
assert png_path.is_file(), f"referenced PNG not found: {png_name}"
|
||||
with open(png_path, "rb") as fh:
|
||||
data = fh.read(24)
|
||||
assert data[:8] == b"\x89PNG\r\n\x1a\n", f"{png_name} is not a PNG"
|
||||
w = struct.unpack(">I", data[16:20])[0]
|
||||
h = struct.unpack(">I", data[20:24])[0]
|
||||
ar = w / h
|
||||
assert 0.4 <= ar <= 4.0, \
|
||||
f"{png_name} aspect ratio {ar:.2f} outside [0.4, 4.0] ({w}x{h})"
|
||||
|
||||
|
||||
def test_render_slides_has_2x_scale():
|
||||
"""REQ-258: render_slides.sh uses -s 2 (2x scale) and -b transparent."""
|
||||
text = RENDER_SCRIPT.read_text()
|
||||
assert "-s 2" in text, "render_slides.sh does not use -s 2 (2x scale)"
|
||||
assert "-b transparent" in text, \
|
||||
"render_slides.sh does not use -b transparent"
|
||||
|
||||
|
||||
def test_render_slides_pins_cli_versions():
|
||||
"""REQ-257: render_slides.sh pins marp-cli and mermaid-cli versions
|
||||
(no @latest)."""
|
||||
text = RENDER_SCRIPT.read_text()
|
||||
assert "marp-cli@" in text, "render_slides.sh does not pin marp-cli"
|
||||
assert "mermaid-cli@" in text, \
|
||||
"render_slides.sh does not pin mermaid-cli"
|
||||
assert "@latest" not in text, \
|
||||
"render_slides.sh still uses @latest (not pinned)"
|
||||
|
||||
|
||||
def test_render_deck_removed():
|
||||
"""REQ-257: render_deck.sh has been deleted (produced unthemed output)."""
|
||||
old_script = ROOT / "scripts" / "render_deck.sh"
|
||||
assert not old_script.exists(), \
|
||||
"render_deck.sh still exists (should be deleted — produced unthemed output)"
|
||||
|
||||
|
||||
def test_html_embeds_theme():
|
||||
"""REQ-262: the committed HTML embeds the S&P theme (--sp-red + padding
|
||||
in the inline <style> block)."""
|
||||
html = (PRESENTATIONS / "nova-autonomous-cloud-delivery.html").read_text()
|
||||
assert "--sp-red" in html, "committed HTML does not embed --sp-red"
|
||||
assert "padding:" in html, "committed HTML does not embed padding rule"
|
||||
|
||||
|
||||
def test_html_slide_count_matches_marp():
|
||||
"""REQ-262: the committed HTML <section> count matches the marp deck
|
||||
slide count (title + 20 main + 1 appendix = 22)."""
|
||||
html = (PRESENTATIONS / "nova-autonomous-cloud-delivery.html").read_text()
|
||||
section_count = html.count("<section ")
|
||||
deck_text = MARP_DECK.read_text()
|
||||
main_slides = len(re.findall(r"^## Slide ", deck_text, re.MULTILINE))
|
||||
appendix_slides = len(re.findall(r"^## Appendix ", deck_text, re.MULTILINE))
|
||||
# +1 for the title slide (which is an H1, not "## Slide")
|
||||
expected = main_slides + appendix_slides + 1
|
||||
assert section_count == expected, \
|
||||
f"HTML has {section_count} sections, expected {expected} " \
|
||||
f"({main_slides} main + {appendix_slides} appendix + 1 title)"
|
||||
Reference in New Issue
Block a user