Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b8fbd995a9 | |||
| ea44fdb9d6 | |||
| e14818875c | |||
| f496dd9c24 | |||
| 0d22b89a7b | |||
| 75e9e479db |
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
# CLARIFY — v1.23 (auto-resolved, full autonomy)
|
||||
|
||||
8 ambiguities identified, all auto-resolved at confidence ≥ 0.6.
|
||||
No human escalation (full autonomy). All decisions logged below.
|
||||
|
||||
## C1 — Speaker notes source for HTML comments (conf 0.95)
|
||||
**Ambiguity:** The plain `.md` has `> **Speaker notes:**` and
|
||||
`> **Transition:**` blocks per slide; talking points live in a separate
|
||||
file. Which content goes into the `<!-- ... -->` comments?
|
||||
**Resolution:** Extract `> **Speaker notes:**` and `> **Transition:**`
|
||||
blocks from the plain `.md` and embed each slide's as
|
||||
`<!-- Speaker notes: ... -->` before the next `---` separator. Talking
|
||||
points come from `talking-points.md` (the 3-6 bullets per slide)
|
||||
embedded as `<!-- Talking points: ... -->`. Both are Marp HTML comments
|
||||
(excluded from slide rendering; the `talking-points.md` stays as the
|
||||
standalone synced aid).
|
||||
|
||||
## C2 — python-pptx dependency placement (conf 0.9)
|
||||
**Ambiguity:** `pyproject.toml` has `[project.optional-dependencies]`
|
||||
`test`. Where does `python-pptx` go?
|
||||
**Resolution:** Add a new optional-dependency group
|
||||
`slides = ["python-pptx>=0.6.23"]`. Keeps the base `dependencies`
|
||||
minimal (the render script is a docs-only concern, not a runtime
|
||||
dep). CI installs via `pip install -e .[slides]`. The `render_pptx.py`
|
||||
script imports `pptx` at module load (not a hard failure if absent —
|
||||
the script prints a clear "pip install -e .[slides]" message and exits
|
||||
1).
|
||||
|
||||
## C3 — Benefit callout markdown representation (conf 0.9)
|
||||
**Ambiguity:** Marp markdown can't natively produce arbitrary `<div>`.
|
||||
How is the `.benefit` class applied?
|
||||
**Resolution:** Use Marp's HTML-in-markdown support — write benefit
|
||||
lines as `<div class="benefit">text</div>` directly in the markdown
|
||||
(Marp passes through HTML blocks). The inline `style:` block targets
|
||||
`.benefit`. The `**Benefit:**` prefix is removed.
|
||||
|
||||
## C4 — Image inlining MIME types (conf 0.95)
|
||||
**Ambiguity:** What MIME types does `inline_images.py` handle?
|
||||
**Resolution:** The deck references `.png` files only (mermaid
|
||||
renders). `inline_images.py` MIME-sniffs by extension:
|
||||
`.png`→`image/png`, `.svg`→`image/svg+xml`, `.jpg/.jpeg`→`image/jpeg`,
|
||||
`.gif`→`image/gif`; fallback `application/octet-stream`. Only relative
|
||||
`src="assets/..."` paths are inlined (absolute/`http(s)://` URLs are
|
||||
left alone).
|
||||
|
||||
## C5 — render_slides.sh step ordering (conf 0.9)
|
||||
**Ambiguity:** Where do the new inline-images + python-pptx steps go?
|
||||
**Resolution:** Step 1 mermaid → PNG (unchanged); Step 2 MARP → HTML +
|
||||
PPTX (drop `--theme`); Step 3 inline images into HTML; Step 4
|
||||
python-pptx → `*-python.pptx`; Step 5 stage all. The inline step runs
|
||||
only on the HTML (not the PPTX — both PPTX formats embed media in
|
||||
their zip by construction).
|
||||
|
||||
## C6 — "penetrate" absence test scope (conf 0.95)
|
||||
**Ambiguity:** How is "penetrate" absence asserted?
|
||||
**Resolution:** `grep -ri penetrat docs/presentations/` returns nothing
|
||||
(covers `.md`, `-marp.md`, `talking-points.md`, `.html`; `.pptx` is
|
||||
binary so excluded). A new test `test_no_penetrate_term` asserts this.
|
||||
|
||||
## C7 — attach_release_asset.py dual-PPTX (conf 0.85)
|
||||
**Ambiguity:** Does the release attach both PPTX files?
|
||||
**Resolution:** Yes — attach both `.pptx` (MARP image-of-slide) and
|
||||
`-python.pptx` (structured). Minimal change: loop over both filenames.
|
||||
The MARP PPTX remains the "primary" attachment (first); the python
|
||||
PPTX is secondary (comparison artifact).
|
||||
|
||||
## C8 — Wave ordering (conf 0.85)
|
||||
**Ambiguity:** Can P1 (consolidate) and P2 (style) parallelize?
|
||||
**Resolution:** No — both edit `-marp.md` with a serial dependency: P1
|
||||
establishes the single doc (deletes the plain `.md`, adds HTML-comment
|
||||
speaker notes); P2 edits that single doc's frontmatter + benefit
|
||||
callouts. Order: P1 → P2 → (P3 + P4 parallel: P3 edits
|
||||
`scripts/inline_images.py` + `render_pptx.py` + `render_slides.sh` +
|
||||
`pyproject`; P4 edits the deck markdown — zero file overlap) → P5 →
|
||||
P6. P3 depends on P2's render-script `--theme` drop. P4 depends on
|
||||
P1's consolidated doc.
|
||||
+176
-866
File diff suppressed because it is too large
Load Diff
+169
-137
@@ -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 P0–P-final).
|
||||
|
||||
### backend-engineer
|
||||
- **Domain:** Python render scripts + bash + tests + CI
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** ["python-pptx", "bash", "pytest", "marp-cli", "mermaid-cli", "base64/re/mimetypes (stdlib)"]
|
||||
- **Constraints:** ["pin CLI versions (no @latest in workflows-src/slides.yml — currently unpinned, must fix)", "python-pptx>=0.6.23 minimum", "stdlib-only for inline_images.py (no external image lib)", "tests must catch the theme-default + inline-style regression (the gap that let v1.22's standalone-theme drift through)", "no raw curl with shell-env tokens"]
|
||||
- **Territory:**
|
||||
- `scripts/inline_images.py` (NEW — stdlib base64 image inlining into rendered HTML)
|
||||
- `scripts/render_pptx.py` (NEW — structured editable PPTX via python-pptx)
|
||||
- `scripts/render_slides.sh` (update: drop --theme nova-sp-theme.css; add inline_images.py + render_pptx.py invocations)
|
||||
- `scripts/attach_release_asset.py` (extend to accept multiple file paths: both .pptx + -python.pptx)
|
||||
- `tests/test_slides_pipeline.py` (REQ-262 successor — invert theme tests, retarget CSS tests to inline style block, delete source-md tests, update slide count)
|
||||
- `workflows-src/slides.yml` (add python-pptx install step; pin @latest → @4.5.0/@11.16.0; add -python.pptx to commit list)
|
||||
- `pyproject.toml` (add python-pptx>=0.6.23 to [project.optional-dependencies] test)
|
||||
- **Reason:** Owns the Python render scripts (`inline_images.py` is
|
||||
stdlib regex + base64; `render_pptx.py` is python-pptx — a backend
|
||||
Python library, not a frontend framework). The render_slides.sh
|
||||
updates (drop `--theme`, add the two Python script invocations) and
|
||||
the CI YAML (add python-pptx install, pin versions, add
|
||||
-python.pptx to commit list) are backend/scripting tasks. The test
|
||||
suite updates (invert the theme-default test, retarget CSS tests to
|
||||
the inline `style:` block, delete the source-md tests) are the gap
|
||||
that let v1.22's standalone-theme drift through — backend-engineer
|
||||
owns closing it. python-pptx is new to v1.23; backend-engineer's
|
||||
frameworks list gains it.
|
||||
- **Phase-specific flag:** none (active for P2 scripts, P5 tests; light
|
||||
touch on P0/P-final).
|
||||
|
||||
## Deactivated personas
|
||||
|
||||
### frontend-engineer
|
||||
- **Active:** false
|
||||
- **Domain:** frontend
|
||||
- **Frameworks:** ["react", "next.js"] (inert — no territory)
|
||||
- **Constraints:** ["component-first", "server-components", "minimal-client-js"] (inert)
|
||||
- **Territory:** [] (no territory in v1.23)
|
||||
- **Reason:** v1.23 has no frontend; decks are markdown + Marp inline
|
||||
CSS (lead-developer territory); deactivated per PERSONAS.md
|
||||
v1.17/v1.18/v1.22 precedent. The inline `style:` block is a Marp
|
||||
frontmatter stylesheet (CSS rules in the markdown frontmatter), not
|
||||
a React/Next.js component system — it stays lead-developer
|
||||
territory. No reactivation trigger.
|
||||
|
||||
### data-engineer
|
||||
- **Active:** false
|
||||
- **Domain:** data
|
||||
- **Frameworks:** [] (inert)
|
||||
- **Constraints:** [] (inert)
|
||||
- **Territory:** [] (no territory in v1.23)
|
||||
- **Reason:** v1.23 has no schema/DB/ORM changes. The milestone is
|
||||
docs + Python scripts + bash + tests + CI only. No reactivation
|
||||
trigger.
|
||||
|
||||
## Roster decisions
|
||||
|
||||
### D-163 (0.95): Inline Marp `style:` block is lead-developer territory, not frontend-engineer
|
||||
The inline `style:` block in the Marp frontmatter is a static CSS
|
||||
stylesheet (a block of CSS rules in the markdown frontmatter, applied
|
||||
by Marp to the rendered slides), not a React/Next.js component system.
|
||||
The v1.17/v1.18/v1.22 precedent (decks are markdown = lead-developer
|
||||
territory; the theme CSS is a Marp stylesheet, not a frontend framework
|
||||
— D-148) extends to the inline `style:` block. frontend-engineer's
|
||||
frameworks (react, next.js) are irrelevant to Marp frontmatter CSS.
|
||||
**Decision:** inline `style:` block stays lead-developer territory.
|
||||
Confidence 0.95 — the only counter-argument is that CSS is "frontend,"
|
||||
but Marp frontmatter CSS is a static stylesheet authored in the
|
||||
markdown source, not a component system.
|
||||
|
||||
### D-164 (0.90): No new personas for v1.23
|
||||
The work is markdown + inline CSS + Python scripts + bash + tests + CI
|
||||
YAML + README. All of this is within the two active personas' range
|
||||
(lead-developer: markdown + CSS + README + metadata; backend-engineer:
|
||||
Python + bash + tests + CI). Creating a separate "slides-engineer" or
|
||||
"pptx-engineer" persona would fragment ownership of the deck markdown
|
||||
(lead) and the render scripts (backend). The python-pptx work is
|
||||
unambiguously backend (a Python library + script), even though the
|
||||
slide layout decisions within `render_pptx.py` are co-owned with lead-
|
||||
developer. **Decision:** no new personas. Confidence 0.90 — follows
|
||||
v1.22 D-149 precedent.
|
||||
|
||||
### Territory-overlap resolution (co-ownership)
|
||||
|
||||
| Path | Primary | Co-owner | Why |
|
||||
|------|---------|----------|-----|
|
||||
| `scripts/render_pptx.py` | backend-engineer (Python code + python-pptx API) | lead-developer (slide layout decisions: which image where, font sizes, bullet structure) | The script is backend (Python); the slide-by-slide layout decisions within it are design decisions that reflect lead-developer's deck ownership. `warn` enforcement — cross-territory edits logged, not blocked. |
|
||||
| `scripts/render_slides.sh` | backend-engineer (bash script) | lead-developer (the inline `style:` block content it renders) | The script is backend; the CSS it renders is lead-developer's. |
|
||||
| `tests/test_slides_pipeline.py` | backend-engineer (test code) | lead-developer (assertions reflect deck structure + inline CSS) | The test code is backend; the assertions (slide count, inline style rules, theme-default) reflect lead-developer's deck/CSS decisions. |
|
||||
| `docs/presentations/README.md` | lead-developer (process narrative) | backend-engineer (build commands + render script invocations) | The process narrative is lead; the build commands + script names are backend. |
|
||||
|
||||
## Domain priority (v1.23)
|
||||
|
||||
`lead-developer → backend-engineer`
|
||||
|
||||
Rationale: the deck markdown consolidation + inline CSS (lead) is the
|
||||
binding constraint — the render scripts (backend) can't be finalized
|
||||
until the deck structure is stable (slide count, inline style). The
|
||||
inline `style:` block must be ported + verified before the render
|
||||
pipeline (HTML + PPTX) is re-run. Backend (scripts + tests + CI)
|
||||
follows once the deck + CSS are settled. The dual-PPTX pipeline is
|
||||
wired last, once the deck renders clean with the inline style.
|
||||
|
||||
---
|
||||
|
||||
## Historical rosters
|
||||
|
||||
<details>
|
||||
<summary>v1.22 roster (Nova Deck Layout Fix) — superseded by v1.23</summary>
|
||||
|
||||
### Active personas (v1.22)
|
||||
|
||||
### lead-developer
|
||||
- **Domain:** coordination + deck content
|
||||
- **Active:** true
|
||||
@@ -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 P0–P7).
|
||||
|
||||
### backend-engineer
|
||||
- **Domain:** backend
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** ["mcp (Python SDK v2)", "pydantic", "jsonschema", "urllib"]
|
||||
- **Constraints:** ["api-first", "strict-typing", "plugin-registry extensible (D-140)", "stdio now / HTTP-ready (D-135)", "no stack traces to citizen developers (REQ-218)"]
|
||||
- **Territory:**
|
||||
- `mcp/atelier/server.py` (REQ-223)
|
||||
- `mcp/atelier/plugins/**/*.py` (REQ-223 — principles.py, validation.py)
|
||||
- `mcp/atelier/vendor/**` (REQ-224 — vendored Atelier snapshot)
|
||||
- `mcp/atelier/VERSION.md` + `mcp/atelier/README.md` (REQ-224)
|
||||
- `scripts/update_atelier_vendor.sh` (REQ-224)
|
||||
- `core/submission_readiness.py` (REQ-218 — the validator, invoked as `contract_ingestor.py --check-readiness`)
|
||||
- `scripts/render_deck.sh` (REQ-228 — HTML + PPTX render)
|
||||
- `scripts/attach_release_asset.py` (REQ-228 — Gitea release asset upload)
|
||||
- `core/submission_readiness.py` (REQ-218)
|
||||
- `scripts/render_deck.sh` (REQ-228)
|
||||
- `scripts/attach_release_asset.py` (REQ-228)
|
||||
- `tests/test_atelier_mcp.py` (REQ-225)
|
||||
- `tests/test_submission_readiness.py` (REQ-220)
|
||||
- `docs/submission-readiness.md` (REQ-219 — reason-code catalog section; co-owned with lead-developer for the narrative)
|
||||
- **Reason:** Owns the MCP server (plugin-registry, stdio, vendored
|
||||
Atelier), the submission-readiness validator (extends
|
||||
`contract_ingestor.py --check-readiness`, D-133), the render/attach
|
||||
scripts (D-142 trigger), and the two new test files. The MCP
|
||||
plugin-registry (D-140) is a backend pattern — no separate
|
||||
mcp-engineer persona is created; backend-engineer owns it.
|
||||
- **Phase-specific flag:** none (active for P1 deck-render, P3 validator,
|
||||
P5 MCP server, P6 scripts).
|
||||
|
||||
### data-engineer
|
||||
- **Domain:** data
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** ["jsonschema", "dynamodb (item shape)"]
|
||||
- **Constraints:** ["schema-first", "superset-gate NOT duplicate (PROJECT.md hard constraint)", "W3.E per-env mandatory table is the source of truth"]
|
||||
- **Territory:**
|
||||
- `schemas/**` (REQ-217 — `submission-readiness.schema.json` is the new schema; existing schemas untouched)
|
||||
- `core/lambda/contract_ingestor.py` (the `--check-readiness` subcommand wiring, D-133 — the validator is in `core/submission_readiness.py` but the ingestor dispatches to it; co-owned with backend-engineer)
|
||||
- **Reason:** Owns the submission-readiness JSON Schema (REQ-217) — it
|
||||
is a schema artifact, data-engineer territory. The schema is a
|
||||
*superset gate above* `contract.schema.json`, not a duplicate (it
|
||||
references contract fields, does not redefine them). The
|
||||
per-env-mandatory table comes from W3.E (the locked decision). The
|
||||
ingestor wiring is co-owned with backend-engineer (the dispatch point
|
||||
is backend; the schema it validates against is data).
|
||||
- **Phase-specific flag:** none (active for P3 schema + ingestor wiring).
|
||||
- `schemas/**` (REQ-217)
|
||||
- `core/lambda/contract_ingestor.py` (co-owned with backend-engineer)
|
||||
|
||||
### Deactivated personas (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
File diff suppressed because it is too large
Load Diff
@@ -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` (P1–P5) →
|
||||
> `v1.22.6` (P6 final = milestone release).
|
||||
|
||||
Driven by user feedback that the deck looked "out of whack" and the
|
||||
desire to return to the clean, well-formatted style of the old
|
||||
`the-developer-experience.html`. Investigation revealed the "clean"
|
||||
reference was itself MARP output (using Marp's built-in `default` theme
|
||||
+ an inline `style:` block); the current deck's standalone
|
||||
`nova-sp-theme.css` re-derives all base spacing from scratch and had a
|
||||
zero-padding bug (fixed in v1.22, but the standalone approach is
|
||||
fragile). The milestone delivers:
|
||||
|
||||
- **Single-document consolidation** — `*-marp.md` becomes the sole
|
||||
source of truth; the plain `.md` is deleted; speaker notes + talking
|
||||
points are embedded as Marp HTML comments.
|
||||
- **Clean style restoration** — revert to `theme: default` + inline
|
||||
`style:` block (S&P palette); `nova-sp-theme.css` retained as a
|
||||
reference, retired from render.
|
||||
- **Self-contained HTML** — base64-inline all images for
|
||||
redistribution.
|
||||
- **Parallel python-pptx generator** — structured, editable, S&P-themed
|
||||
PPTX alongside the MARP image-of-slide PPTX.
|
||||
- **Targeted word-count trim** + "penetrate" term removal.
|
||||
|
||||
**Phase count:** 7 (P0 pre-execution + 5 execution + 1 final).
|
||||
|
||||
**Hard constraints:**
|
||||
- DO NOT change the deck narrative or the 4-beat arc (Problem → Solution
|
||||
→ Proof → Roadmap + Ask) — only trim word count.
|
||||
- DO NOT re-introduce badges, version strings, or internal citations.
|
||||
- DO NOT remove MARP — it stays for HTML + PPTX; python-pptx runs in
|
||||
parallel.
|
||||
- `nova-sp-theme.css` is retained (not deleted) as a styling reference.
|
||||
|
||||
### Requirements
|
||||
|
||||
New requirements REQ-263..REQ-275 — see `REQUIREMENTS.md` §v1.23.
|
||||
Summary: consolidation (REQ-263,264), style restoration (REQ-265,266,267),
|
||||
image inlining (REQ-268), python-pptx generator (REQ-269,270), word-count
|
||||
trim + "penetrate" removal (REQ-271,272), CI/tests/README (REQ-273,274,275).
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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"],
|
||||
|
||||
Reference in New Issue
Block a user