Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 156431c80a | |||
| 631244458f | |||
| 81b731ed17 | |||
| cc6071ee53 | |||
| d1ff6934c6 | |||
| ccbccb02ac | |||
| 574e6cb189 | |||
| 358aa62c3a |
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"phase": 0,
|
||||
"phase": 4,
|
||||
"stage": "complete",
|
||||
"milestone": "v1.22",
|
||||
"phase_role": "pre_execution",
|
||||
"phase_role": "execution",
|
||||
"attempts": 0,
|
||||
"updated_at": "2026-08-11T14:40:00Z",
|
||||
"updated_at": "2026-08-11T15:00:00Z",
|
||||
"milestone_complete": false,
|
||||
"tag": "v1.21.0",
|
||||
"requirements": ["REQ-254","REQ-255","REQ-256","REQ-257","REQ-258","REQ-259","REQ-260","REQ-261","REQ-262"],
|
||||
"notes": "v1.22 P0 complete. Tag v1.21.0. Merged phase/00 -> milestone/v1.22-deck-layout-fix. Release creation failed (local-only fallback). Phase branch deleted. Proceeding to P1 (theme CSS)."
|
||||
"tag": "v1.21.4",
|
||||
"requirements": ["REQ-261"],
|
||||
"notes": "v1.22 P4 complete. Tag v1.21.4. 8 overflowing slides trimmed/split. Header removed from frontmatter. Slide count 18->20 main + 1 appendix. 23 slide tests pass. Proceeding to P5 (re-render + tests)."
|
||||
}
|
||||
@@ -84,8 +84,7 @@ CHROME_PATH=/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome \
|
||||
|
||||
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_deck.sh`
|
||||
and `scripts/render_slides.sh`.
|
||||
The render + commit + attach pipeline is automated by `scripts/render_slides.sh`.
|
||||
|
||||
### Step 4 — Talking points (presenter cues)
|
||||
|
||||
@@ -127,10 +126,11 @@ docs/presentations/
|
||||
|
||||
### Appendix structure
|
||||
|
||||
Each Marp deck has **18 main slides + 1 appendix slide**. The main 18 are the
|
||||
presentation; the appendix is for Q&A backup.
|
||||
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-18): the story arc — Problem → Solution → Proof →
|
||||
- **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.
|
||||
|
||||
@@ -1,19 +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 LR
|
||||
A["Contract"] --> B["Resolver"]
|
||||
B --> C["Adapter"]
|
||||
C --> D["Checkov<br/>(static code)"]
|
||||
D --> E["Terraform<br/>plan"]
|
||||
E --> F["Wiz<br/>(on plan)"]
|
||||
F --> G["Confidence<br/>signal"]
|
||||
G --> H{"Stage<br/>gate"}
|
||||
H -->|"dev: autonomous"| I["Apply"]
|
||||
H -->|"qa/prod/dr: attested"| I
|
||||
I --> J["Evidence +<br/>Ledger"]
|
||||
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
|
||||
classDef decision fill:#D6002A,color:#fff,stroke:#1B1B1B,stroke-width:2px
|
||||
class D,E,F,G,J accent
|
||||
class H decision
|
||||
class A,B,C,I supporting
|
||||
class D,E,F accent
|
||||
class A,I supporting
|
||||
@@ -68,8 +68,8 @@ 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: 6px 10px; text-align: left; }
|
||||
td { background: var(--sp-white); color: var(--sp-black); border-bottom: 1px solid var(--sp-grey); padding: 6px 10px; }
|
||||
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); }
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 36 KiB |
@@ -3,7 +3,6 @@ marp: true
|
||||
theme: nova-sp
|
||||
paginate: true
|
||||
size: 16x9
|
||||
header: 'Nova — The Autonomous Cloud Delivery Platform'
|
||||
footer: 'Nova — The Autonomous Cloud Delivery Platform'
|
||||
---
|
||||
|
||||
@@ -45,7 +44,7 @@ Every hour a developer spends writing, deploying, fixing, or remediating infrast
|
||||
|
||||
---
|
||||
|
||||
## Slide 3 — Strategic Objectives + Anti-Goals
|
||||
## Slide 3 — Strategic Objectives
|
||||
|
||||
**4 Strategic Objectives:**
|
||||
1. **Zero-touch operations** — autonomy as the default, not the demo; stage-gate attestation (QA, SRE) remains human by design
|
||||
@@ -54,17 +53,22 @@ Every hour a developer spends writing, deploying, fixing, or remediating infrast
|
||||
- **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
|
||||
|
||||
**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.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
3. Not an upstream development platform (no product backlogs, IDE, code 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.
|
||||
|
||||
---
|
||||
|
||||
## 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.**
|
||||
|
||||
@@ -77,7 +81,7 @@ Every hour a developer spends writing, deploying, fixing, or remediating infrast
|
||||
|
||||
---
|
||||
|
||||
## Slide 5 — RACI: Who Owns What
|
||||
## Slide 6 — RACI: Who Owns What
|
||||
|
||||
**Four roles, one matrix — citizen developer owns FRs + UAT, platform owns NFRs + infra, quality engineering owns the gate evidence, SRE owns operational readiness.**
|
||||
|
||||
@@ -98,22 +102,21 @@ Every hour a developer spends writing, deploying, fixing, or remediating infrast
|
||||
|
||||
---
|
||||
|
||||
## Slide 6 — The Platform Pipeline
|
||||
## Slide 7 — The Platform Pipeline
|
||||
|
||||
**How intent becomes verified infrastructure — fail-fast policy scanning before the plan, runtime scanning after it.**
|
||||
|
||||

|
||||

|
||||
|
||||
- **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.**
|
||||
- **Dev is autonomous** (no stage gate); **qa/prod/dr require human attestation** (QA for quality, SRE for production readiness)
|
||||
|
||||
**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 7 — The Decision Ledger
|
||||
## Slide 8 — The Decision Ledger
|
||||
|
||||
**Every automated decision is captured, immutable, queryable — and accountable.**
|
||||
|
||||
@@ -125,15 +128,26 @@ Every hour a developer spends writing, deploying, fixing, or remediating infrast
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — The Attestation Matrix
|
||||
## Slide 9 — Attestation Matrix: QA
|
||||
|
||||
**The designed controls that keep humans at stage gates — structured, freshness-validated, 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. |
|
||||
|
||||
**Benefit:** QA signs off on quality before any promotion — the gate is explicit, not implicit.
|
||||
|
||||
---
|
||||
|
||||
## 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. |
|
||||
| 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. |
|
||||
@@ -148,36 +162,34 @@ Separation-of-duties on prod: the approver cannot be the same person who built t
|
||||
|
||||
---
|
||||
|
||||
## Slide 9 — Telemetry & Live Ops
|
||||
## Slide 11 — Telemetry & Live Ops
|
||||
|
||||
**Every metric in this deck is traceable to a real emitted signal — the live-ops dashboard makes operations visible in PowerBI.**
|
||||
|
||||

|
||||

|
||||
|
||||
- **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)
|
||||
- **Deliberately minimal** — Nova-native envelopes; no Kafka, no Prometheus, no ClickHouse. The cold store handles batch and historical analysis; the live-ops surface is built in PowerBI on the exported views
|
||||
- **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:** the architecture is the trust substrate — leadership sees the same numbers the platform produces, in PowerBI, with full traceability. Operations become visible.
|
||||
|
||||
---
|
||||
|
||||
## 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 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
|
||||
- **Easily queried for auditing** — queryable by run, by environment, by approver, and by outcome; the audit trail is a query, not a forensic exercise
|
||||
- **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 11 — Cost & ROI
|
||||
## Slide 13 — Cost & ROI
|
||||
|
||||
**The ROI formula and the cost estimates — grounded, with the production denominator honestly flagged.**
|
||||
|
||||
@@ -191,7 +203,7 @@ Separation-of-duties on prod: the approver cannot be the same person who built t
|
||||
|
||||
---
|
||||
|
||||
## 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.**
|
||||
|
||||
@@ -199,20 +211,18 @@ To be clear: these deferrals are *measurement infrastructure*, not the autonomy
|
||||
|
||||
| # | Deferred metric | Blocking work |
|
||||
|---|-----------------|---------------|
|
||||
| 1 | Live infrastructure health | Live AWS re-provisioning (currently torn down to zero-cost steady state) |
|
||||
| 2 | Live outbox write rate | Live AWS re-provisioning |
|
||||
| 3 | Tamper-evident ledger checkpoints | Audit-ledger build-out (Object Lock + signed checkpoints) |
|
||||
| 4 | Onboarding funnel (requested → granted) | Auto-grant implementation |
|
||||
| 5 | Drift auto-reversal | Drift-detection scheduler (not yet built) |
|
||||
| 6 | Live cost reconciliation | Live AWS re-provisioning + actual-spend feed |
|
||||
| 7 | SLA / unplanned downtime | Live AWS re-provisioning |
|
||||
| 8 | Predictive vs reactive ratio | ML anomaly-forecasting service (not yet built) |
|
||||
| 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:** 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 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 timeframe.**
|
||||
|
||||
@@ -231,7 +241,7 @@ Re-evaluation triggers: each blocking piece of work lifts on its own schedule; t
|
||||
|
||||
---
|
||||
|
||||
## Slide 14 — 12-Month Product Roadmap
|
||||
## Slide 16 — 12-Month Product Roadmap
|
||||
|
||||
**The product arc from pilot activation to integration — four quarters, four outcomes.**
|
||||
|
||||
@@ -248,14 +258,14 @@ Grounded in the four strategic objectives (autonomy, provable trust, ROI, integr
|
||||
|
||||
---
|
||||
|
||||
## Slide 15 — Quarter-by-Quarter Outcomes
|
||||
## Slide 17 — 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 ≥ 99% · Escalation < 0.1% · Accuracy ≥ 99.5% | Objective #1 — autonomy as the default |
|
||||
| **Q2** | Provable Trust | Tamper-evident ledger (Object Lock + signed checkpoints); daily checkpoints; live cost reconciliation | Decision Ledger Coverage 100% · Cost Savings ≥ 25% | Objective #2 — trust is the moat |
|
||||
| **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% | Objective #3 — CFO-pointable numbers |
|
||||
| **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) | Objective #4 — default substrate for agents |
|
||||
| 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.'"*
|
||||
|
||||
@@ -263,7 +273,7 @@ Grounded in the four strategic objectives (autonomy, provable trust, ROI, integr
|
||||
|
||||
---
|
||||
|
||||
## 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.**
|
||||
|
||||
@@ -275,7 +285,7 @@ Grounded in the four strategic objectives (autonomy, provable trust, ROI, integr
|
||||
|
||||
---
|
||||
|
||||
## 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.**
|
||||
|
||||
@@ -287,7 +297,7 @@ Grounded in the four strategic objectives (autonomy, provable trust, ROI, integr
|
||||
|
||||
---
|
||||
|
||||
## Slide 18 — Recap + Ask
|
||||
## Slide 20 — Recap + Ask
|
||||
|
||||
**The 4-beat recap + the business decision.**
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -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 ---
|
||||
|
||||
@@ -117,7 +117,6 @@ EXCLUDE_SCRIPTS=(
|
||||
sync_workflows.py
|
||||
attach_release_asset.py
|
||||
check_north_star_diff.sh
|
||||
render_deck.sh
|
||||
render_slides.sh
|
||||
)
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -202,7 +202,9 @@ def test_marp_deck_title_is_autonomous_cloud_delivery():
|
||||
|
||||
|
||||
def test_marp_deck_slide_count():
|
||||
"""REQ-245: 18 main slides + 1 appendix = 19 slides total."""
|
||||
"""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 ---
|
||||
@@ -210,8 +212,8 @@ def test_marp_deck_slide_count():
|
||||
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) == 18, \
|
||||
f"expected 18 main slides, found {len(main_slides)}: {slide_headings}"
|
||||
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)}"
|
||||
|
||||
@@ -265,4 +267,107 @@ 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"
|
||||
"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