# architecture.md section reference Per-section rendering spec for `scripts/render_architecture.py::render`. One `# Architecture` H1, seven numbered `## N. ...` sections, plus one conditional "Dependency graph" appendix. Source of truth: the `metadata_tree.json` schema produced by `scripts/parse_wave.py` at the end of phase 9. **Source of truth: the live tree** — field shapes evolve as parse_wave learns new agent generations. When this doc disagrees with the `metadata_tree.json` written by `parse_wave.py` for an actual agent on your machine (under `~/.vibe/data/agentforce-architecture-analyze//__/`), trust the live tree. The Mermaid templates live at `assets/mermaid/*.mmd` and are the sole consumer of the renderer helpers; each `{{PARAM}}` contract is documented in the template's own header comment. --- ## Per-diagram node caps Default caps (override via `render(..., max_mermaid_nodes={...})`): | Diagram kind | Default cap | Over-cap behaviour | |---|---|---| | `flowchart` | 200 | summary placeholder + top-5 fan-out + catalog pointer | | `stateDiagram` | 40 | summary placeholder (no fan-out — states are not nodes) | | `sequenceDiagram` | 60 | summary placeholder + top-5 fan-out | | `graph` | 100 | summary placeholder + top-5 fan-out | Cap is measured in rendered elements (nodes + edges for flowchart/graph, messages for sequenceDiagram, states + transitions for stateDiagram). Above cap, the renderer emits a `> [diagram truncated: ...]` blockquote with the element count, the top-5 nodes by fan-out (when applicable), and a pointer to the catalog section that enumerates the same data without compression. --- ## 1. Header + agent overview **Purpose**: identify the agent and its planner in a single kv table. **Input fields** (`tree.agent.*`): - `api_name` — agent developer name - `version` — `v` label - `master_label` — human-readable name - `description` — prose summary - `agent_type` — `EinsteinAgentKind` / `EinsteinCopilotForSalesforce` / … - `type` — `ExternalCopilot` / `InternalCopilot` / … - `agent_template` - `bot_source` - `generation` — `classic` / `nga` / `search` / `byop` - `planner_name` - `planner_type` - `bot_id` Plus `tree._schema_version`. **Output shape**: `#

` with api_name + version, followed by a 2-col markdown table. **Empty/degenerate cases**: - Missing `api_name` / `version` renders `?` in the H1 (not `None`). - Any missing field renders `-` in its row — not empty, because GitHub table rendering collapses empty cells and the row loses alignment. --- ## 2. Anatomy summary **Purpose**: one-paragraph executive summary plus health callouts. **Input fields**: - `tree._kind_counts` — preferred source for topic / action / flow / apex / prompt counts. - `tree.depth`, `tree.node_count` — size metrics. - `tree._partial`, `tree._partial_reason` — health flag + prose reason. - `tree._pending_fetches` — `{"FLOW":[...],"APEX":[...], "PROMPT_TEMPLATE":[...],"STANDARD_ACTION":[...]}`. Count determines the "pending fetches: N" line in the callout. - `tree._unresolved` — triggers a second warn callout with the count. - `tree.agent.planner_name` — missing -> warn callout. **Output shape**: `## 2. Anatomy summary` + paragraph + zero-to-three blockquote callouts. Callouts render as `> **Health: PARTIAL.**` / `> **Health: WARN.**` prefixes with bullet sub-lines. **Empty/degenerate cases**: if `_kind_counts` is absent, the walker supplies counts from its own pass over the tree. Zero topics is valid (SequentialPlannerIntentClassifier). --- ## 3. Action tree **Purpose**: the full declared action tree as a flowchart with per-topic subgraphs, plus a deterministic ASCII appendix for diff review. **Input fields**: - Walker-derived `topics[]` -> one subgraph per topic. - Walker-derived `edges[]` -> `parent_api_name --> child_api_name`. - `node._cycle_back_to` -> dotted back-edge `A -.->|cycle_back_to: X| B`. - Planner-level actions (top-level `GEN_AI_FUNCTION` with no parent topic) -> synthetic `_plannerActions` subgraph. **Output shape**: ` ```mermaid ` block with `flowchart TB` + subgraphs + edges, followed by a `
` with ASCII-tree appendix. When above cap, the mermaid block is replaced with the truncation placeholder; the ASCII appendix still renders. **Empty/degenerate cases**: - No topics, no planner actions -> `%% no topics` + `%% no edges` mermaid comments; diagram still parses. - Cycle annotations render in both the mermaid (dotted edge) and the ASCII appendix (`[cycle]` marker on the node line). --- ## 4. Topic anatomy **Purpose**: per-topic detail dump. One H3 per topic with a bullet list of actions. **Input fields**: - Walker-derived `topics[]` with `api_name`, `label`, `actions`. - `topic.raw.master_label` (preferred) or api_name for the label. **Output shape**: `## 4. Topic anatomy` + one `### \`\`` block per topic + kv list (`- Label:`, `- Action count:`, `- Actions:` with sub-bullets). **Empty/degenerate cases**: 0 topics -> `_No topics defined (planner exposes actions directly)._` italic fallback. This is the expected case for `SequentialPlannerIntentClassifier`. --- ## 5. Action catalog **Purpose**: flat markdown table of every declared action. **Input fields**: - Walker-derived `actions[]` with `api_name`, `topic`, `raw.unwraps_to`. **Output shape**: 3-col table (`Action | Topic | Unwraps to`). Unwraps column renders as `KIND \`api_name\`` when `unwraps_to` is present, `-` otherwise. Planner-level actions show `(plannerAction)` in the topic column. **Empty/degenerate cases**: no actions -> `_No actions declared._` italic fallback. --- ## 6. Data flow / context propagation **Purpose**: show which slot values propagate from user utterance through the planner into each action. **Input fields**: - Walker-derived `topics[]` and `actions[]`. - `action.raw.planner_attr.variable_name` + `planner_attr.data_type` — labels the edge `A -->|var: Type| B`. When absent, the edge is bare. **Output shape**: `flowchart LR` via `load_mermaid("data_flow", ...)`. Skeleton: `User` -> `Planner` -> each `Topic` -> each `Action` under that topic. **Empty/degenerate cases**: no planner_attr metadata -> every edge is bare. 0 topics -> only `User --> Planner` renders (no action-level edges). Above cap -> truncation placeholder. --- ## 7. Flow / Apex / Prompt catalogs **Purpose**: per-artifact detail section for every backing flow, apex class, and prompt template referenced by any action. **Input fields**: - Walker-derived `flows{}`, `apex{}`, `prompts{}`, keyed on api_name. - `node.signature` (or `_signature` fallback) — signature block. **Output shape**: `### Flows` / `### Apex classes` / `### Prompt templates` H3 buckets, each containing `#### \`\`` + a fenced signature block or `_Signature not captured._` fallback. Prompt templates render as a flat bullet list (signature capture is per-template prose, not a flow/apex shape). **Empty/degenerate cases**: no backing artifacts in the tree -> `_No backing artifacts in tree._` italic fallback. --- ## 8. Unresolved refs + artifact pointers **Purpose**: surface every `_unresolved[]` entry and point at the sidecar files the reader can open. **Input fields**: - `tree._unresolved[]` — list of `{kind, api_name, reason}` records. **Output shape**: Either a 3-col `Kind | Api name | Reason` table or an `_No unresolved references._` italic fallback. Followed by an `### Artifact pointers` sub-heading with a bullet list of relative paths (tree JSON, manifest, summary). **Empty/degenerate cases**: always renders — the artifact-pointer list is unconditional. --- ## Conditional: Dependency graph **Purpose**: rendered only when `tree._unresolved[]` is non-empty OR the tree contains cycle annotations. Shows cross-artifact dependencies plus the unresolved nodes as dashed-outline markers. **Input fields**: - Walker-derived `edges[]`. - `tree._unresolved[]` — each becomes a `:::unresolved` styled node. - Walker-derived `cycles[]` — each becomes a dotted back-edge. **Output shape**: `graph LR` via `load_mermaid("dependency_graph", ...)`. Includes a `classDef unresolved` class marker at the bottom of the template so unresolved nodes render with `stroke-dasharray`. **Empty/degenerate cases**: not rendered at all when both conditions are false. Above the `graph` cap -> truncation placeholder replaces the mermaid block.