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---
This commit is contained in:
Jon Chery
2026-08-11 23:54:47 +00:00
parent 0d22b89a7b
commit f496dd9c24
2 changed files with 871 additions and 137 deletions
+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>