Skip to content

Commit c3cff4f

Browse files
davidmatousekclaude
andcommitted
docs: close Feature 130 - update all documentation
Product (PM): docs/product/02_PRD/INDEX.md flipped row 130 Approved -> Delivered Architecture (Architect): docs/architecture/README.md ADR-022 added to ADR index, Last Updated bumped DevOps: docs/devops/README.md mmdc hard-prereq section, CI_CD_GUIDE.md workflow subsection, 01_Local/README.md mmdc bullet Retrospective: KB-029 Silent Dead-Code Fallbacks appended to INSTITUTIONAL_KNOWLEDGE.md BACKLOG: regenerated (53 issues total) Delivery document: specs/130-prd-130-fix/delivery.md created Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d35a667 commit c3cff4f

File tree

8 files changed

+220
-6
lines changed

8 files changed

+220
-6
lines changed

docs/INSTITUTIONAL_KNOWLEDGE.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,29 @@ Captured during structured delivery retrospective. Smooth sailing — everything
594594

595595
---
596596

597+
### KB-029: Silent Dead-Code Fallbacks Are Invisible Failure Modes — Delete, Don't Preserve
598+
599+
**Date**: 2026-04-11
600+
**Category**: Governance / ADR
601+
**Source**: Feature 130 delivery retrospective
602+
**Severity**: High (user-visible correctness regression)
603+
604+
**Problem**: Feature 112 (attack-path-pages) shipped a Typst "text-fallback" branch in `templates/tachi/security-report/attack-path.typ` that emitted raw `flowchart TD` Mermaid source inline when `@mermaid-js/mermaid-cli` (`mmdc`) was unavailable. The branch was gated by an `else if mermaid-text != ""` clause in the template and supported by a silent `shutil.which("mmdc")` early-return in `scripts/extract-report-data.py::render_mermaid_to_png()` that flipped every entry's `has_image` to `False`, printed a one-line warning, and continued. The pipeline reported exit 0. CI reported success. The only way a user discovered the broken output was by flipping through a board-ready PDF and seeing 40+ lines of raw Mermaid source where a rendered attack tree should have been. This directly blocked the flagship "show to exec board" deliverable from spec 112 and violated AC#2 (legibility at page size).
605+
606+
**Root Cause**: "Graceful degradation" became "silent failure" because the fallback branch was never reachable in any realistic user path — nobody runs `/tachi.security-report` *hoping* mmdc is missing and *hoping* the PDF ships with raw Mermaid source as a substitute. The fallback existed because the Feature 112 author treated it as a courtesy safety net. In practice it masked a prerequisite violation behind a success exit code. The same failure shape held for the rarer "mmdc installed but subprocess crashed" case: each failing entry was silently marked `has_image=False` and the same text fallback kicked in. Both modes violated SC-003 (legibility) and both were invisible to CI.
607+
608+
**Solution**: For CLI prerequisites that are actually required at runtime (not optional external APIs in the ADR-014 sense), enforce at two entry points — shell-level at the command file (mirroring the Typst check that already existed) AND Python-level at the function boundary (`shutil.which(...) → raise RuntimeError(...)`). Gate the check on input detection so projects without the triggering input are unaffected (mmdc check fires only when `attack-trees/` contains Critical/High findings). Delete the fallback branch outright — no placeholder, no comment, no "removed in NNN" stub. Document the rule in a governing ADR (ADR-022 is the first tachi ADR covering CLI-prerequisite posture). Prove backward compatibility with a byte-deterministic baseline pair under `SOURCE_DATE_EPOCH` (ADR-021) before and after the refactor: happy path must be byte-identical.
609+
610+
**Result**: 48/48 pytest green (9 new cases covering both preflight and mid-render aggregator). 5/5 byte-deterministic baselines remained byte-identical before/after the refactor — the happy path is provably unchanged. New fresh-install CI workflow on `ubuntu-latest` (no mmdc preinstalled) asserts the loud-failure path fires with all three canonical tokens in stderr, including a team-lead T4 enforcement assertion that fails the CI job if mmdc is unexpectedly present on PATH. The canonical install command `npm install -g @mermaid-js/mermaid-cli` appears in exactly 7 coordinated enforcement locations (extract-report-data.py raise, tachi.security-report.md shell echo, install.sh warning, README Prerequisites, test_mmdc_preflight.py assertion, tachi-mmdc-preflight.yml grep, ADR-022 decision body), verified by the T023 grep consistency check.
611+
612+
**When to Apply**: Any time the codebase adds a runtime CLI prerequisite (third-party binary, language runtime, renderer, compiler, tool that must be on PATH). The two-gate defense-in-depth pattern is now the tachi convention for CLI prerequisites, analogous to how Feature 054 Typst checks already work. If a third CLI prerequisite is ever added, per ADR-022 Future Work, extract an `install.sh` prerequisite helper — three data points is the minimum for meaningful abstraction. Do NOT preserve a fallback branch as a "courtesy" — if the fallback is worse than a loud error, delete it. A silent fallback that produces a broken-looking output is worse than no fallback at all.
613+
614+
**Tags**: #governance #adr #defense-in-depth #prerequisite-enforcement #fail-loud #cli-tools #feature-130
615+
616+
**Quality Score**: 9/10
617+
618+
---
619+
597620
## Bug Fixes
598621

599622
*No entries yet. Use `/kb-create` to add the first bug fix.*

docs/architecture/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Architecture Documentation - tachi
22

3-
**Last Updated**: 2026-04-10
3+
**Last Updated**: 2026-04-11
44
**Owner**: Architect
55
**Status**: Template
66

@@ -44,6 +44,7 @@ Significant technical decisions with context and trade-offs
4444
- `ADR-019-shared-definitions-and-model-field-governance.md` - Shared cross-agent definitions and model field governance (Feature 078)
4545
- `ADR-020-maestro-layer-classification.md` - CSA MAESTRO seven-layer taxonomy for agentic AI component classification (Feature 084; Revision History adds canonical layer rename rule for enum-value-only minor schema bumps in Feature 136)
4646
- `ADR-021-source-date-epoch-for-deterministic-pdf-comparison.md` - SOURCE_DATE_EPOCH reproducible-builds convention for byte-deterministic PDF baseline comparison (Feature 128)
47+
- `ADR-022-mmdc-hard-prerequisite.md` - `mmdc` (Mermaid CLI) as hard prerequisite gated on attack-tree detection; establishes fail-loud-on-missing-CLI posture with defense-in-depth preflight gates — first ADR governing CLI-prerequisite posture (Feature 130)
4748
- `ADR-NNN-decision-title.md` - Individual ADRs
4849

4950
### 03_patterns/

docs/devops/01_Local/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
- **jq**: JSON processor, required by `.aod/scripts/bash/run-state.sh` for the Full Lifecycle Orchestrator (`brew install jq` on macOS, `apt-get install jq` on Linux)
2020
- **GitHub CLI (`gh`)**: Used by `make init` to auto-create a GitHub Projects board for backlog tracking. Requires the `project` OAuth scope (`gh auth refresh -s project`). If not installed or not authenticated, init continues without creating the board. Install via `brew install gh` on macOS or see [cli.github.com](https://cli.github.com)
2121
- **Typst CLI**: Required by `/tachi.security-report` for PDF generation. Install via `brew install typst` on macOS, `cargo install typst-cli` on Linux, or `winget install typst` on Windows. If not installed, the `/tachi.security-report` command displays platform-specific install instructions and halts. See `templates/tachi/security-report/` for Typst template sources
22-
- **Mermaid CLI (`mmdc`)**: Optional. Used by `scripts/extract-report-data.py` to render Mermaid attack tree diagrams to PNG for the Attack Path Pages section of the PDF security report (Feature 112). Requires Node.js. Install via `npm install -g @mermaid-js/mermaid-cli`. If not installed, the extraction script logs a warning and the attack path pages omit rendered diagram images while retaining narrative and remediation content. Only relevant when the scanned project contains an `attack-trees/` directory
22+
- **Mermaid CLI (`mmdc`)**: **Hard prerequisite when scanning projects that contain an `attack-trees/` directory with Critical/High findings** (Feature 130, [ADR-022](../../architecture/02_ADRs/ADR-022-mmdc-hard-prerequisite.md)). Used by `scripts/extract-report-data.py::render_mermaid_to_png()` to render Mermaid attack tree diagrams to PNG for the Attack Path Pages section of the PDF security report (Feature 112). Requires Node.js. Install via `npm install -g @mermaid-js/mermaid-cli`. If not installed and attack trees are present, the `/tachi.security-report` pipeline fails loud at the preflight gate with a `RuntimeError` listing the install command — this replaces the pre-Feature-130 silent text fallback which produced broken PDFs with raw Mermaid source dumped verbatim. For projects WITHOUT an `attack-trees/` directory, mmdc remains unused and the pipeline continues to run unaffected. `scripts/install.sh` emits a best-effort courtesy warning at setup time if mmdc is absent. See `README.md` `## Prerequisites` section for per-OS install commands and the CI acceptance test at `.github/workflows/tachi-mmdc-preflight.yml`
2323

2424
### make init Personalization
2525

docs/devops/CI_CD_GUIDE.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,62 @@ permissions:
239239

240240
---
241241

242+
### tachi mmdc Preflight Gate (Feature 130)
243+
244+
**Best For**: Proving the `/tachi.security-report` preflight gate fires on a fresh runner where `@mermaid-js/mermaid-cli` (`mmdc`) is intentionally absent
245+
246+
Feature 130 introduced a CI acceptance test at `.github/workflows/tachi-mmdc-preflight.yml` that verifies the fail-loud preflight behavior documented in [ADR-022](../architecture/02_ADRs/ADR-022-mmdc-hard-prerequisite.md). This workflow is **not** a general CI/CD pipeline — it is a single-job verification that the pipeline aborts non-zero when `mmdc` is absent and the scanned project contains attack trees.
247+
248+
**Workflow File**: `.github/workflows/tachi-mmdc-preflight.yml`
249+
250+
**Trigger**: Pull requests touching any of:
251+
- `scripts/extract-report-data.py` (the preflight gate lives in `render_mermaid_to_png()`)
252+
- `templates/tachi/security-report/attack-path.typ` (Typst template that consumes rendered diagrams)
253+
- `scripts/install.sh` (courtesy warning signal)
254+
- `.claude/commands/tachi.security-report.md` (shell preflight gate)
255+
- `README.md` (Prerequisites section)
256+
- `.github/workflows/tachi-mmdc-preflight.yml` (the workflow itself)
257+
258+
**Runner**: `ubuntu-latest` — intentionally chosen because `ubuntu-latest` ships WITHOUT `@mermaid-js/mermaid-cli` preinstalled (plan.md spike S3 confirmed). Do NOT switch to a custom image that preinstalls mmdc — that would silently validate the happy path instead of the loud-failure path this workflow is designed to exercise.
259+
260+
**Job Steps**:
261+
262+
1. **Checkout repository** — standard `actions/checkout@v4`
263+
2. **Set up Python 3.11** — via `actions/setup-python@v5`
264+
3. **Set up Typst** — via `typst-community/setup-typst@v5` (must NOT transitively install Node.js tooling; see T4 enforcement below)
265+
4. **Diagnostic: show mmdc absence** — logs `which mmdc` output for human-readable CI debugging (architect refinement R3)
266+
5. **Enforce mmdc absence (T4 / plan Risk #6)** — **team-lead T4 enforcement assertion** that fails the job if `command -v mmdc` unexpectedly succeeds. This guards against future upstream changes (e.g., a new major version of `typst-community/setup-typst` that transitively installs Node.js tooling, or a GitHub Actions runner image update that adds mmdc to the base image) that would silently break the spike-S3 assumption and make the subsequent preflight test meaningless. If this assertion ever fires, treat it as a high-severity CI infrastructure bug — do NOT install mmdc to "fix" it.
267+
6. **Run `scripts/extract-report-data.py` against `examples/mermaid-agentic-app/`** — direct Python invocation with `--target-dir`, `--output`, `--template-dir`. Slash commands cannot run in CI, so we invoke the script directly. The `mermaid-agentic-app` example contains an `attack-trees/` directory with Critical/High findings, so the preflight gate is expected to fire. Expected exit code: non-zero. Captures stdout+stderr to `/tmp/out.txt` for the next step.
268+
7. **Assert canonical error tokens present** — greps `/tmp/out.txt` for three tokens from the canonical preflight `RuntimeError` message:
269+
- `@mermaid-js/mermaid-cli`
270+
- `npm install -g @mermaid-js/mermaid-cli`
271+
- `Attack path rendering`
272+
273+
Each token is grepped individually so a missing token produces a specific, actionable error message. This is the **seven-location canonical command consistency** guarantee — the install command appears in exactly 7 enforcement locations across the codebase (extract-report-data.py raise, tachi.security-report.md shell echo, install.sh warning, README Prerequisites, test_mmdc_preflight.py assertion, tachi-mmdc-preflight.yml grep, ADR-022 decision body). Any drift fails this workflow.
274+
275+
**Required Permissions**:
276+
```yaml
277+
permissions:
278+
contents: read
279+
```
280+
281+
**No Repository Secrets Required**: The workflow uses only `GITHUB_TOKEN` implicitly via `actions/checkout@v4`.
282+
283+
**What This Workflow Does NOT Test**:
284+
- Happy-path rendering when `mmdc` IS installed (covered by local pytest suite `tests/scripts/test_mmdc_preflight.py` and backward-compatibility baselines in `tests/scripts/test_backward_compatibility.py`)
285+
- Non-attack-tree projects (covered by the backward-compatibility baseline suite — 5 example PDFs remain byte-identical without mmdc required)
286+
- Mid-render failures (covered by the 5 aggregator tests in `tests/scripts/test_mmdc_preflight.py`)
287+
288+
**Infrastructure Impact**: No new environment variables, Docker services, or deployment changes. The workflow runs entirely within GitHub Actions using the standard `ubuntu-latest` image.
289+
290+
**Related Files**:
291+
- `scripts/extract-report-data.py` (`render_mermaid_to_png()` is the enforcement point)
292+
- `tests/scripts/test_mmdc_preflight.py` (9 local tests: 4 preflight + 5 mid-render aggregator)
293+
- [ADR-022](../architecture/02_ADRs/ADR-022-mmdc-hard-prerequisite.md) (hard-prerequisite posture decision)
294+
- `specs/130-prd-130-fix/plan.md` (spike S3 and Risk #6 mitigation)
295+
296+
---
297+
242298
### Python Test Harness (pytest)
243299

244300
**Best For**: Validating deterministic data extraction scripts, command dispatch, PDF page positioning, and golden-file comparisons for tachi pipeline outputs

docs/devops/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,39 @@ See [CI/CD Guide](CI_CD_GUIDE.md) for detailed configuration and changelog secti
163163

164164
---
165165

166+
## Mermaid CLI Hard Prerequisite (Feature 130)
167+
168+
Feature 130 upgraded `@mermaid-js/mermaid-cli` (`mmdc`) from an optional nice-to-have to a **hard prerequisite** for `/tachi.security-report` when the scanned project contains an `attack-trees/` directory with Critical/High findings. Prior to Feature 130, absence of `mmdc` produced a broken PDF with raw Mermaid source dumped verbatim into the Attack Path Pages section. The pipeline now fails loud and fast with a preflight gate instead.
169+
170+
### Enforcement Points (defense-in-depth)
171+
172+
| Enforcement Point | Location | When It Fires |
173+
|-------------------|----------|---------------|
174+
| Shell preflight gate | `.claude/commands/tachi.security-report.md` Step 1 | Command-level check before Python is invoked |
175+
| Python preflight gate | `scripts/extract-report-data.py::render_mermaid_to_png()` via `shutil.which("mmdc")` | Script-level check before any rendering is attempted |
176+
177+
Both gates are **conditionally active** — they fire only when `attack-trees/` contains Critical/High findings. Projects without attack trees are unaffected, preserving backward compatibility for the majority of threat-modeling workflows.
178+
179+
### New CI Workflow: `tachi-mmdc-preflight.yml`
180+
181+
A new GitHub Actions workflow at `.github/workflows/tachi-mmdc-preflight.yml` runs on `ubuntu-latest` (which ships without `mmdc` preinstalled — confirmed by plan.md spike S3) and asserts the pipeline aborts non-zero with three canonical tokens in stderr. This is the fresh-install acceptance test for Feature 130. The workflow includes a **team-lead T4 enforcement assertion** that fails the CI job if `mmdc` is unexpectedly present on `PATH` — this mitigates the risk that a future GitHub Actions runner image change or a transitive install via a Typst action ships with `mmdc` preinstalled and silently validates the happy path when we intended to validate the loud-failure path.
182+
183+
See [CI/CD Guide — tachi mmdc Preflight Gate](CI_CD_GUIDE.md#tachi-mmdc-preflight-gate-feature-130) for trigger paths, step-by-step breakdown, and the T4 rationale.
184+
185+
### Developer Setup Signal
186+
187+
`scripts/install.sh` emits a courtesy warning at setup time if `mmdc` is absent from `PATH` (`command -v mmdc`). This is a best-effort early signal, not the enforcement point — the per-command preflight gates remain the authoritative check. See `README.md` `## Prerequisites` section for per-OS install commands (`npm install -g @mermaid-js/mermaid-cli` on macOS/Linux/WSL).
188+
189+
### Related Architecture Decision
190+
191+
[ADR-022 — Mermaid CLI Hard Prerequisite](../architecture/02_ADRs/ADR-022-mmdc-hard-prerequisite.md) establishes the new rule: **pipelines are fail-loud when a required CLI is absent, gated on input detection**. ADR-022 is the first ADR in tachi governing CLI-prerequisite posture and cross-references ADR-014 (optional external APIs) and ADR-021 (determinism).
192+
193+
### Infrastructure Impact
194+
195+
No new environment variables, no Docker services, no staging/production deployment changes. Prerequisites live on developer machines and CI runners only. Developer-facing docs (`README.md`, `docs/devops/01_Local/README.md`) and CI workflow docs (`docs/devops/CI_CD_GUIDE.md`) are the touchpoints.
196+
197+
---
198+
166199
## Deployment Policy (MANDATORY)
167200

168201
**ALL deployments MUST go through the devops agent.**

docs/product/02_PRD/INDEX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
| # | Feature | PM | Architect | Team-Lead | Status | Date |
88
|---|---------|----|-----------|-----------| -------|------|
9-
| 130 | [Fix Attack Path Mermaid Rendering](130-fix-attack-path-mermaid-rendering-2026-04-11.md) |||| Approved | 2026-04-11 |
9+
| 130 | [Fix Attack Path Mermaid Rendering](130-fix-attack-path-mermaid-rendering-2026-04-11.md) |||| Delivered | 2026-04-11 |
1010
| 136 | [MAESTRO Canonical Layer Correctness Fix](136-maestro-canonical-layer-correctness-fix-2026-04-10.md) |||| Delivered | 2026-04-10 |
1111
| 128 | [Executive Threat Architecture Infographic](128-executive-threat-architecture-2026-04-09.md) |||| Delivered | 2026-04-10 |
1212
| 120 | [Architecture Lifecycle Command](120-architecture-lifecycle-command-2026-04-09.md) |||| Delivered | 2026-04-09 |

docs/product/_backlog/BACKLOG.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Backlog
22

3-
> Auto-generated from GitHub Issues on 2026-04-11T14:38:34Z.
3+
> Auto-generated from GitHub Issues on 2026-04-11T16:30:50Z.
44
> Source of truth: GitHub Issues with `stage:*` labels.
55
> Regenerate: `/aod.status` or `.aod/scripts/bash/backlog-regenerate.sh`
66
@@ -44,15 +44,14 @@
4444

4545
| # | Title | Delivered | Retro | Updated |
4646
|---|-------|-----------|-------|---------|
47-
| | *No items in this stage* | | |
47+
| #130 | Fix attack path Mermaid rendering when mmdc is not installed (spec 112 follow-up) | 2026-04-11 || 2026-04-11 |
4848

4949
## Untracked
5050

5151
> These issues have no `stage:*` label. Add a label to track them in the lifecycle.
5252
5353
| # | Title | State | Updated |
5454
|---|-------|-------|---------|
55-
| #130 | Fix attack path Mermaid rendering when mmdc is not installed (spec 112 follow-up) | OPEN | 2026-04-11 |
5655
| #27 | Developer Guide: Automated Threat Modeling for Your Architecture | CLOSED | 2026-03-24 |
5756
| #18 | Feature: Threat Infographic Agent | CLOSED | 2026-03-23 |
5857
| #15 | Feature 007: Threat Report Agent & Attack Trees | CLOSED | 2026-03-23 |

0 commit comments

Comments
 (0)