Compare commits

...

6 Commits

Author SHA1 Message Date
Jon Chery b8fbd995a9 docs(P00): grill — 4 revisions applied (PROCEED-WITH-REVISIONS, 0.78)
Nova Slides Render / render (push) Failing after 57s
10 axes reviewed. 6 PASS, 4 REVISE. Overall: PROCEED-WITH-REVISIONS.
Empirically cleared (not assumed): image format (plain <img src>, conf
0.95) + Marp <div> passthrough (rendered test, conf 0.95). Versioning
clean (no v1.22.* tags, conf 1.0). Test inversion risk fully enumerated
(conf 0.9).

Revisions (binding):
G-001 (0.85): purge 'penetrate' repo-wide (docs/ + .ciagent/), not just
  docs/presentations/. RESEARCH.md/PLAN.md/GRILL.md exempt as decision-
  history. P4 verify becomes grep -ri penetrat docs/ .ciagent/PROJECT.md
  .ciagent/CLARIFY.md -> nothing.
G-002 (0.85): serialize P3->P4 (not parallel). P4's parser depends on
  P3's stable render_slides.sh; P4's trimmed deck is what P3b's parser
  consumes. C8 parallelization overruled.
G-003 (0.80): split P3 into P3a (inline_images.py + render_slides.sh +
  pyproject — low-risk) + P3b (render_pptx.py + parser +
  attach_release_asset.py — high-risk, isolated). Both serial in Wave 3.
G-004 (0.80): merge P5+P6. NFR docs milestone; dedicated review/ship
  phase is ceremonial. P5 absorbs review/audit/ship. Net phases 7->6.

Revised phase/tag plan:
v1.22.0 P0 -> v1.22.1 P1 -> v1.22.2 P2 -> v1.22.3 P3a -> v1.22.4 P3b
-> v1.22.5 P4 -> v1.22.6 P5 (final = milestone release).

---ci---
project: acdl
phase: 0
milestone: v1.23
status: grill
---/ci---
2026-08-12 00:05:34 +00:00
Jon Chery ea44fdb9d6 docs(P00): grill v1.23 — PROCEED-WITH-REVISIONS (4 binding revisions)
Adversarial red-team review of the v1.23 Nova Deck Cleanup & Python PPTX
plan (7 phases, 5 waves). Overall verdict: PROCEED-WITH-REVISIONS (conf 0.78).

Empirically verified (P0 risks cleared):
- Image format: rendered HTML uses plain <img src="assets/png/...">, no
  xlink:href → inline_images.py regex will match (Axis 4 PASS, conf 0.95)
- Marp <div> passthrough: minimal test deck through marp-cli@4.5.0 confirms
  <div class="benefit"> passes through verbatim (Axis 6 PASS, conf 0.95)
- Versioning: no v1.22.* tags exist (Axis 10 PASS, conf 0.95)
- Test inversion list complete (Axis 3 PASS, conf 0.92)

4 binding revisions:
- G-001: Purge "penetrate" from entire repo (docs/ + .ciagent/), not just
  docs/presentations/ — term appears in docs/scope.md:16, docs/vision.md:18,
  and all .ciagent/*.md
- G-002: Serialize P3→P4 — "zero file overlap" is false for verification
  (P3 parser depends on deck P4 trims; P4 verify render depends on P3's
  render_slides.sh being stable)
- G-003: Split P3 into P3a (inline_images + render_slides.sh + pyproject —
  low-risk) and P3b (render_pptx.py + parser — high-risk, 10+ markdown
  constructs + python-pptx XML constraints)
- G-004: Merge P5+P6 — P6 is ceremonial overhead for an NFR docs milestone;
  P5 absorbs review/audit/ship. Net phases: 7 (P1, P2, P3a, P3b, P4, P5+P6)

No escalations (all axes resolved at conf >= 0.78).

---ci---
status: grill
decisions:
  - G-001: Purge "penetrate" from docs/ + .ciagent/ (conf 0.85)
  - G-002: Serialize P3->P4 (conf 0.85)
  - G-003: Split P3 into P3a + P3b (conf 0.80)
  - G-004: Merge P5+P6 (conf 0.80)
escalations: []
2026-08-12 00:02:57 +00:00
Jon Chery e14818875c docs(P00): create phase plans — v1.23 (7 phases, 5 waves)
Vertical-slice plan with wave ordering:
- Wave 1 (P1): consolidate-docs (single -marp.md, delete plain .md,
  speaker notes + talking points as HTML comments).
- Wave 2 (P2): restore-clean-style (theme:default + inline style,
  retire nova-sp-theme.css from render, benefit callout .benefit class).
- Wave 3 (P3 + P4, parallel): inline-images + python-pptx-generator
  (new scripts, zero deck-markdown overlap) || trim-wordcount + remove
  'penetrate' (deck markdown, zero script overlap).
- Wave 4 (P5): ci-tests-readme (workflows, tests, README — depends on
  all above).
- Wave 5 (P6): final review + audit + milestone ship.

Tags on v1.22.x line: v1.22.0 (P0) -> v1.22.1..v1.22.5 (P1-P5) ->
v1.22.6 (P6 final = milestone release).

---ci---
project: acdl
phase: 0
milestone: v1.23
status: plan
---/ci---
2026-08-11 23:56:39 +00:00
Jon Chery f496dd9c24 docs(P00): research — v1.23 Nova Deck Cleanup & Python PPTX
10 findings grounding the v1.23 milestone plan:
- Marp default theme + inline style block (exact CSS from ref deck)
- HTML passthrough confirmed; python-pptx API mapped; stdlib image
  inlining sufficient; 12 tests need updating; attach script +
  slides.yml + README structure documented; persona roster (same as
  v1.22); 5 pitfalls identified.

---ci---
phase: 0
milestone: v1.23
status: research
decisions:
  - id: D-163
    decision: Inline Marp style block is lead-developer territory (not frontend-engineer)
    rationale: Marp frontmatter CSS is a static stylesheet, not a React/Next.js component system (D-148 precedent from v1.22)
    confidence: 0.95
    alternatives: [frontend-engineer owns CSS, custom slides-engineer persona]
  - id: D-164
    decision: No new personas for v1.23
    rationale: Work splits cleanly into lead-developer (markdown+CSS+README+metadata) and backend-engineer (Python+bash+tests+CI); python-pptx is backend
    confidence: 0.90
    alternatives: [custom docs/deck persona, pptx-engineer persona]
---/ci---
2026-08-11 23:54:47 +00:00
Jon Chery 0d22b89a7b docs(P00): clarify — 8 ambiguities auto-resolved (full autonomy)
8 ambiguities identified, all auto-resolved at confidence >= 0.6. No
human escalation (full autonomy). Decisions:
C1 (0.95): speaker notes + talking points embedded as Marp HTML comments
C2 (0.9): python-pptx in new pyproject optional-dep group 'slides'
C3 (0.9): benefit callouts as <div class='benefit'> (Marp HTML passthrough)
C4 (0.95): inline_images.py MIME-sniffs by extension (png/svg/jpg/gif)
C5 (0.9): render_slides.sh order: mermaid -> MARP -> inline -> python-pptx
C6 (0.95): 'penetrate' absence via grep -ri (text files only)
C7 (0.85): release attaches both PPTX (MARP primary, python secondary)
C8 (0.85): wave order P1 -> P2 -> (P3+P4 parallel) -> P5 -> P6

---ci---
project: acdl
phase: 0
milestone: v1.23
status: clarify
---/ci---
2026-08-11 23:50:42 +00:00
Jon Chery 75e9e479db docs(init): validate specification — v1.23 milestone (REQ-263..275)
Established active_milestone: v1.23 (Nova Deck Cleanup & Python PPTX).
NFR milestone (docs/render/test only; no features). Tags on v1.22.x line
(v1.22.0 P0 -> v1.22.6 P6 final = milestone release). Branch:
milestone/v1.23-deck-cleanup-python-pptx.

Added REQ-263..275 to REQUIREMENTS.md covering:
- Consolidate docs: single -marp.md source of truth, delete plain .md,
  speaker notes/talking points as Marp HTML comments, keep
  talking-points.md as synced standalone aid (REQ-263,264)
- Restore clean style: theme:default + inline style block (S&P palette),
  retire nova-sp-theme.css from render (keep as reference), benefit
  callout restyle (REQ-265,266,267)
- Inline images: scripts/inline_images.py for self-contained
  redistributable HTML (REQ-268)
- Python PPTX generator: scripts/render_pptx.py structured editable
  S&P-themed PPTX via python-pptx, both PPTX outputs produced + attached
  (REQ-269,270)
- Trim word count: targeted ~20-30% trim on verbose slides, remove
  'penetrate' term (REQ-271,272)
- CI/tests/README: workflows install python-pptx, tests updated,
  README rewritten (REQ-273,274,275)

Driven by user feedback: deck looked 'out of whack'; wanted to return to
the clean style of the old the-developer-experience.html. Investigation
revealed the 'clean' reference was itself MARP output (default theme +
inline style); the standalone nova-sp-theme.css approach was fragile.

---ci---
project: acdl
phase: 0
milestone: v1.23
status: specify
---/ci---
2026-08-11 23:49:45 +00:00
10 changed files with 1793 additions and 2418 deletions
+6 -25
View File
@@ -1,28 +1,9 @@
{
"phase": 6,
"stage": "complete",
"milestone": "v1.22",
"phase_role": "final",
"phase": 0,
"stage": "grill",
"milestone": "v1.23",
"phase_role": "pre_execution",
"attempts": 0,
"updated_at": "2026-08-11T15:30:00Z",
"milestone_complete": true,
"tag": "v1.21.6",
"requirements": ["REQ-254","REQ-255","REQ-256","REQ-257","REQ-258","REQ-259","REQ-260","REQ-261","REQ-262"],
"release": {
"forge": "gitea",
"releases_created": true,
"release_ids": {
"v1.21.0": 621,
"v1.21.1": 622,
"v1.21.2": 623,
"v1.21.3": 624,
"v1.21.4": 625,
"v1.21.5": 626,
"v1.21.6": 627
},
"milestone_release_id": 627,
"pptx_asset_id": 98,
"pptx_download_url": "https://git.cloudinit.dev/attachments/fe691962-4f4e-4321-ab5d-c2bb8c3fd6ad"
},
"notes": "v1.22 milestone complete. Tag v1.21.6 (milestone release). Merged to main + pushed to origin. All 7 Gitea releases created (ids 621-627). PPTX attached to milestone release (asset id 98). All milestone branches deleted. 9 requirements complete (REQ-254..262). 32 slide tests pass (23 original + 9 new). 94 key-file tests pass. Pipeline check exit 0. Next milestone starts fresh."
"updated_at": "2026-08-11T23:30:00Z",
"project": "acdl"
}
+76
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+169 -137
View File
@@ -1,32 +1,174 @@
---
project: acdl
milestone: v1.22
milestone: v1.23
generated_at: 2026-08-11
generator: lead-developer
verification_toolchain:
typecheck: "python3 -m py_compile tests/test_slides_pipeline.py"
test: "pytest tests/test_slides_pipeline.py # REQ-254..262"
build: "bash scripts/render_slides.sh nova-autonomous-cloud-delivery # HTML + PPTX"
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.22 is the Nova Deck Layout Fix — a docs-only NFR milestone. Two
active personas: lead-developer (theme CSS + deck markdown + talking
points + README + .ciagent metadata), backend-engineer (render scripts
+ tests). frontend-engineer stays deactivated (decks are markdown =
lead-developer territory, per v1.17/v1.18 precedent). No data-engineer
(no schema/DB changes). No new personas (the work is CSS + bash +
markdown + pytest, all within the two active personas' range).
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.22 Nova Deck Layout Fix)
# ACDL — Persona Roster (v1.23 Nova Deck Cleanup & Python PPTX)
> v1.22 roster. Two active personas + one deactivated. This is a docs-
> only NFR milestone: the work is theme CSS, render scripts, mermaid
> diagrams, deck markdown, and tests. frontend-engineer stays
> deactivated (decks are markdown = lead-developer territory, per
> v1.17/v1.18 precedent). No data-engineer (no schema/DB changes).
> 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 P0P-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
@@ -65,61 +207,13 @@ verification_toolchain:
backend/scripting tasks.
- **Phase-specific flag:** none (active for P2, P5; light touch on P0/P6).
## Deactivated personas
### D-148 (v1.22): Theme CSS is lead-developer territory, not frontend-engineer
### D-149 (v1.22): No new personas for v1.22
### 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.22)
- **Reason:** v1.22 has no frontend; decks are markdown (lead-developer
territory); deactivated per PERSONAS.md v1.17/v1.18 precedent. The
theme CSS is a Marp stylesheet, 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.22)
- **Reason:** v1.22 has no schema/DB/ORM changes. The milestone is
docs + scripts + tests only. No reactivation trigger.
## Roster decisions
### D-148 (0.95): Theme CSS is lead-developer territory, not frontend-engineer
The `nova-sp-theme.css` is a Marp stylesheet (CSS for a markdown-to-
slide renderer), not a React/Next.js component system. The v1.17/v1.18
precedent (decks are markdown = lead-developer territory) extends to
the deck's CSS theme. frontend-engineer's frameworks (react, next.js)
are irrelevant to Marp CSS. **Decision:** theme CSS stays lead-developer
territory. Confidence 0.95 — the only counter-argument is that CSS is
"frontend," but Marp CSS is a static stylesheet, not a component system.
### D-149 (0.9): No new personas for v1.22
The work is CSS + bash + markdown + mermaid + pytest. All of this is
within the two active personas' range (lead-developer: CSS + markdown +
mermaid; backend-engineer: bash + pytest). Creating a separate "css-
engineer" or "slides-engineer" persona would fragment ownership of the
theme CSS + deck markdown (both lead-developer) and the render scripts
+ tests (both backend-engineer). **Decision:** no new personas.
Confidence 0.9.
### Territory-overlap resolution (co-ownership)
| Path | Primary | Co-owner | Why |
|------|---------|----------|-----|
| `docs/presentations/assets/mmd/*.mmd` | lead-developer (mermaid re-layout) | backend-engineer (re-render via render_slides.sh) | The .mmd content is lead-developer (diagram narrative); the PNG re-render is backend-engineer (script invocation). |
| `tests/test_slides_pipeline.py` | backend-engineer (test code) | lead-developer (assertions reflect deck structure) | The test code is backend; the assertions (slide count, theme rules, aspect ratios) reflect lead-developer's deck/theme decisions. |
---
## Historical rosters
</details>
<details>
<summary>v1.18 roster (Citizen Developer & Production-Grade Guidance) — superseded by v1.22</summary>
<summary>v1.18 roster (Citizen Developer & Production-Grade Guidance) — superseded</summary>
### Active personas (v1.18)
@@ -139,94 +233,32 @@ Confidence 0.9.
- `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 P0P7).
### 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 (v1.18)
### 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 (v1.18)
### 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 (v1.18)
| 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. |
### D-143 (v1.18): Fold mcp-engineer into backend-engineer
</details>
+410 -1389
View File
File diff suppressed because it is too large Load Diff
+45
View File
@@ -1532,3 +1532,48 @@ New requirements REQ-254..REQ-262 — see `REQUIREMENTS.md` §v1.22. Summary:
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` (P1P5) →
> `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).
+124
View File
@@ -1904,3 +1904,127 @@ assert 20 main + 1 appendix.
| 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 |
+702
View File
@@ -2568,3 +2568,705 @@ All 5 CLARIFY decisions are grounded in these findings:
- 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.
+84
View File
@@ -2070,3 +2070,87 @@ release). **DONE.**
`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).
+1 -1
View File
@@ -8,7 +8,7 @@
],
"active_project": "acdl",
"active_projects": ["acdl"],
"active_milestone": "v1.22",
"active_milestone": "v1.23",
"autonomy": {
"level": "full",
"escalation_hooks": ["deploy", "delete_data", "merge_to_main"],