feat(P01): render PPTX + CAP-042 + D-241 record + frontmatter-comment fix
- render_pptx.py: skip leading HTML comments before frontmatter (split_slides + parse_frontmatter) - docs/presentations/nova-leadership-deck.pptx: 7 slides, footer on every slide - STATE.md: CAP-042 row appended (leadership deck, single-shot, Aug 2026) - PROJECT.md: D-241 formal entry (single-shot, discrete, no compression) - smoke test exits 0 (all 6 assertions a-f pass) ---ci--- project: acdl phase: 1 milestone: v1.30 status: execute wave: 4 persona: backend-engineer + lead-developer ---/ci---
This commit is contained in:
@@ -691,6 +691,22 @@ New requirements REQ-354..REQ-369 + REQ-371 + REQ-363b — full text in
|
||||
|
||||
- **Decisions:** `D-241..D-243` (3 decisions, authored in CLARIFY).
|
||||
Max existing D = D-240 (v1.29). Next free: D-244.
|
||||
- **D-241** — Leadership deck is a single-shot, discrete, hand-
|
||||
authored artifact (NOT a compression of the existing citizen-
|
||||
developer pitch `nova-autonomous-cloud-delivery-marp.md`).
|
||||
Audience: Infrastructure & Operations leadership (CTO + VP
|
||||
Technology + Product Management). August 2026 presentation
|
||||
anchor + November 2026 runway anchor. The existing citizen-
|
||||
developer deck remains untouched. Overrides the post-v1.29
|
||||
STATE.md intake assumption 3.
|
||||
- **D-242** — Narrow `scripts/render_pptx.py` extension: accept an
|
||||
explicit source `.md` path + `--output` filename; render a
|
||||
right-aligned footer textbox on every slide (python-pptx does
|
||||
not read the Marp `footer:` directive). Non-REQ-372 prerequisite
|
||||
per spec §3.3 Edge 2.
|
||||
- **D-243** — Date anchor discipline: August 2026 is a month-only
|
||||
presentation anchor (no specific day); November 2026 is the
|
||||
runway anchor (~90 days).
|
||||
- **Capabilities:** `CAP-042` (1 capability, appended at ship).
|
||||
Max existing CAP = CAP-041 (v1.29). Next free: CAP-043.
|
||||
|
||||
|
||||
+2
-1
@@ -357,6 +357,7 @@
|
||||
| CAP-039 | Platform ops reposplit | v1.29 / `v1.28.6` | `nova-platform-ops` (out-of-band), `docs/operator-guide-platform-ops.md`, `docs/archive/nova-idp-cfn-v1.28.md` | REQ-369, REQ-OPS-GUIDE, D-232, D-235 | covered-reference | engineering (`acdl/acdl`, GitHub) ends at the artifact; operations (`nova-platform-ops`, Gitea-private, OPER-PRIV) begins at the live platform; tag-pin handoff; CFN archived; covered-reference REQs tracked via cutover gates |
|
||||
| CAP-040 | KJ substrate lockstep | v1.29 / `v1.28.6` | `nova-platform-ops` (out-of-band), `platform/abac/kj-version.txt`, `.github/workflows/publish.yml` | REQ-371, REQ-363, REQ-363b, D-238, D-239 | covered-reference | one ECR image digest shared by Lambda `image_uri` + Fargate task `image`; `lifecycle.precondition` on both resources at `terraform plan`; KJ-STATIC (`CGO_ENABLED=0`, `file(1)` asserts `statically linked`); no second pipeline, no second SHA pin |
|
||||
| CAP-041 | JWKS edge-only | v1.29 / `v1.28.6` | `nova-platform-ops` (out-of-band), `docs/operator-guide-platform-ops.md` | REQ-364, REQ-365, REQ-366, INV-18, D-233 | covered-reference | JWKS is the only public read surface; CloudFront + OAC (`AuthType: AWS_IAM`, NOT `NONE`, `OriginAccessControlOriginType: lambda`, `SigningBehavior: always`); direct Function URL → 403, via-CloudFront → 200; WAF rate-limit 3000/5min + AWSManagedRulesCommonRuleSet; ACM DNS-validated in us-east-1; Route53 A-alias |
|
||||
| CAP-042 | Leadership presentation deck (single-shot) | v1.30 / `v1.29.3` | `docs/presentations/nova-leadership-deck-marp.md`, `docs/presentations/nova-leadership-deck.pptx`, `scripts/check_leadership_deck.sh` | REQ-372.1..REQ-372.12, D-241, D-242, D-243 | local | Single-shot 7-slide PPTX deck for Infrastructure & Operations leadership (CTO + VP Technology + Product Management); presented August 2026; November 2026 runway anchor; discrete hand-authored artifact (NOT a compression of the citizen-developer pitch per D-241); rendered via existing `scripts/render_pptx.py` (narrowly extended per D-242); smoke test on-demand (NOT a CI gate); vision `[1]` grounding in slides 3/5/7 |
|
||||
|
||||
## Archive pointers
|
||||
|
||||
@@ -497,7 +498,7 @@ Locked Decisions: D-001..D-240 (full ledger in PROJECT.md + CLAR
|
||||
|
||||
Active Invariants: INV-1..INV-18 (full text above). New in v1.28: INV-12 (mode observability), INV-13 (mode determinism), INV-14 (credential type encodes role), INV-15 (no AWS-managed identity), INV-16 (Argon2id password storage), INV-17 (ABAC discipline fail-closed). New in v1.29: INV-18 (JWKS-EDGE-ONLY) + 10 NFR constraints (KJ-STATIC, KJ-LOCKSTEP, KJ-WARMUP-HEALTH, OPER-PRIV, IAM-NARROW, DRIFT-DETECT, IMPORT-IDEMPOTENT, TFM-HITL, JWKS-SLO, JWKS-ROTATION)
|
||||
|
||||
Standing Capability Gate: CAP-001..CAP-041 — all Verified (32 from v1.0..v1.27 + 6 from v1.28 + 3 from v1.29 covered-reference). Gate enforced by `core/regression_verify.py` + CI merge gates. CAP-033..038 added v1.28 (CLI surface, delegation AST, layer/wheel match, auth flow, KMS sign, PAT revocation). CAP-039..041 added v1.29 (platform-ops-reposplit, kj-substrate-lockstep, jwks-edge-only — covered-reference, live cutover pending operator action in nova-platform-ops).
|
||||
Standing Capability Gate: CAP-001..CAP-042 — all Verified (32 from v1.0..v1.27 + 6 from v1.28 + 3 from v1.29 covered-reference + 1 from v1.30 single-shot deck). Gate enforced by `core/regression_verify.py` + CI merge gates. CAP-033..038 added v1.28 (CLI surface, delegation AST, layer/wheel match, auth flow, KMS sign, PAT revocation). CAP-039..041 added v1.29 (platform-ops-reposplit, kj-substrate-lockstep, jwks-edge-only — covered-reference, live cutover pending operator action in nova-platform-ops). CAP-042 added v1.30 (leadership-deck — single-shot, on-demand smoke test, NOT a CI gate).
|
||||
|
||||
Anti-Goals Touched: `docs/vision.md` §7 / `NORTH_STAR.md` §Anti-Goals — (1) not an upstream dev platform; (2) not a general-purpose AI; (3) not a legacy infra bridge; (4) not a permissive delivery highway; (5) not a mutable audit log. v1.29 honored all 5 (no PDLC reach, narrow CLI autonomy, no VMs, ABAC fail-closed + HITL gates intact, immutable outbox).
|
||||
|
||||
|
||||
Binary file not shown.
+28
-8
@@ -70,13 +70,21 @@ def parse_frontmatter(md_text: str):
|
||||
(no nested structures) — sufficient for Marp deck frontmatter
|
||||
(marp, theme, footer, paginate, size). The `style:` block (multi-
|
||||
line `|`) is skipped (not needed by the python-pptx renderer).
|
||||
Skips leading HTML comments before the frontmatter fence.
|
||||
"""
|
||||
if not md_text.lstrip().startswith("---"):
|
||||
text = md_text.lstrip()
|
||||
# Skip leading HTML comments before frontmatter.
|
||||
while text.startswith("<!--"):
|
||||
end = text.find("-->")
|
||||
if end == -1:
|
||||
return {}
|
||||
text = text[end + 3 :].lstrip()
|
||||
if not text.startswith("---"):
|
||||
return {}
|
||||
end = md_text.find("\n---", 3)
|
||||
end = text.find("\n---", 3)
|
||||
if end == -1:
|
||||
return {}
|
||||
fm_text = md_text[3:end]
|
||||
fm_text = text[3:end]
|
||||
fm = {}
|
||||
in_multiline = False
|
||||
for line in fm_text.splitlines():
|
||||
@@ -104,14 +112,26 @@ def parse_frontmatter(md_text: str):
|
||||
|
||||
|
||||
def split_slides(md_text: str):
|
||||
"""Strip YAML frontmatter, then split the deck into slide source strings."""
|
||||
"""Strip leading HTML comments + YAML frontmatter, then split into slides.
|
||||
|
||||
A Marp deck may carry a header HTML comment before the frontmatter
|
||||
(e.g. the REQ-372 related-artifacts comment). Skip leading comments
|
||||
before detecting the `---` frontmatter fence.
|
||||
"""
|
||||
text = md_text.lstrip()
|
||||
# Skip leading HTML comments (<!-- ... -->) before frontmatter.
|
||||
while text.startswith("<!--"):
|
||||
end = text.find("-->")
|
||||
if end == -1:
|
||||
break
|
||||
text = text[end + 3 :].lstrip()
|
||||
# Strip YAML frontmatter (between first pair of `---` lines).
|
||||
if md_text.lstrip().startswith("---"):
|
||||
end = md_text.find("\n---", 3)
|
||||
if text.startswith("---"):
|
||||
end = text.find("\n---", 3)
|
||||
if end != -1:
|
||||
md_text = md_text[end + 4 :]
|
||||
text = text[end + 4 :]
|
||||
# Normalize slide separators. Marp uses `\n---\n` on its own line.
|
||||
parts = re.split(r"\n---\s*\n", md_text)
|
||||
parts = re.split(r"\n---\s*\n", text)
|
||||
slides = []
|
||||
for p in parts:
|
||||
p = p.strip("\n")
|
||||
|
||||
Reference in New Issue
Block a user