Private
Public Access
0
0

chore(audit): switch output format from JSON to custom postfix DSL

Per user direction ('make a custom DSL ideal for recording the
call-graph or other metrics', 'I want a post-fix heiarchy', 'JSON
is ill-performant'): replaced JSON serializer with a custom
postfix (RPN) DSL tailored to the audit's record shapes.

THE CUSTOM DSL
- Postfix (operands before operator); no brackets, braces,
  commas, or colons.
- Length-prefixed lists: N items followed by 'list' word.
- Tagged records: each 'word' is a constructor with a known
  arity (action=3, fn=3, call=1, mut=3, exp-op=5, pair=2, int=1).
- Whitespace-tokenized; bare atoms unquoted; double quotes
  only when whitespace/special chars present.
- nil for null; backslash for line comments; true/false for bool.
- Trivial parser (~30 lines): _tokenize_dsl splits on
  whitespace and respects quotes + comments; parse_dsl
  walks tokens and evaluates tagged words against a known
  arity table (DSL_WORD_ARITY).
- Round-trips: to_dsl(profile) -> parse_dsl(to_dsl(profile))
  yields the same in-memory structure.

DELIVERABLES (updated spec + plan)
- src/code_path_audit.py: to_dsl, dump_dsl, parse_dsl,
  _tokenize_dsl, to_tree (prefix-tree text renderer),
  to_markdown, to_mermaid.
- Output: .dsl files (machine) + .tree (human prefix view) +
  .md (summary tables) + .mmd (Mermaid diagrams).
- No new pip dependencies; pure stdlib.

WHAT STAYED
- The 7 cost classes (file_io, network, ast_parse, json_io,
  pickle, deep_copy, loop_amplified) and 5 mutation kinds
  are unchanged. The json_io cost class is for JSON file
  I/O the audit detects, not the output format.
- 36 tests total (15 + 8 + 10 + 3 across the 4 implementation
  phases).
This commit is contained in:
2026-06-07 12:17:56 -04:00
parent 5f29c4b1b9
commit ad13007352
2 changed files with 375 additions and 109 deletions
@@ -9,7 +9,7 @@
## Overview
Build `src/code_path_audit.py` — a data-oriented static-analysis tool that audits the 3 major actions (AI message lifecycle, discussion save/load, GUI startup) for expensive operations, redundant calls, and pipelining candidates. The output (JSON + markdown + Mermaid) is the artifact that informs pipeline-pruning decisions; the actual code changes are a follow-up track (`pipeline_pruning_20260607`).
Build `src/code_path_audit.py` — a data-oriented static-analysis tool that audits the 3 major actions (AI message lifecycle, discussion save/load, GUI startup) for expensive operations, redundant calls, and pipelining candidates. The output (custom postfix `.dsl` data + markdown + Mermaid + prefix tree text) is the artifact that informs pipeline-pruning decisions; the actual code changes are a follow-up track (`pipeline_pruning_20260607`).
Per the user's framing: "anything that can even remotely smell as an expensive bulk action or major action that takes more than 10-40 microseconds." The audit focuses on **expensive** operations (file I/O, network, AST parsing, big loops, anything that smells like a bulk action) inside the 3 actions — not on every state mutation. The cost model is heuristic, calibrated by a runtime-profiling follow-up (`pipeline_runtime_profiling_20260607`) that catches the cases static analysis can't resolve (C-extension cost, import cost, JIT effects, decorator-driven dispatch).
@@ -34,13 +34,13 @@ The MMA worker spawn action is **out of scope** for this track (per user: "keepi
- A state-mutation index per function (5 mutation kinds: `attr_write`, `container_mutate`, `file_write`, `ipc_emit`, `global_write`).
- An expensive-ops index (7 cost classes, with a heuristic data-size estimate).
- A per-action traversal API (`trace_action(action, max_depth=10) -> ActionProfile`).
- An output suite: JSON data files + markdown summaries + Mermaid per-action call graphs.
- An output suite: custom postfix `.dsl` data files + markdown summaries + Mermaid per-action call graphs + prefix-tree text view.
- A CLI (`python -m src.code_path_audit --action <name>`) and an MCP tool (`code_path_audit(action_name, max_depth)`).
- The actual audit run on the 3 actions, with the report committed to `docs/reports/code_path_audit/2026-06-07/`.
## Goals
1. **Produce a queryable artifact.** The JSON output is the source of truth; markdown + Mermaid are for human review. Re-run after any `src/` change to see drift.
1. **Produce a queryable artifact.** The custom postfix `.dsl` output is the source of truth; markdown + Mermaid + prefix-tree text are for human review. Re-run after any `src/` change to see drift.
2. **Surface the top-N optimization candidates per action.** The `summary.md` ranks candidates by potential data-transform load reduction. This is what the user will use to decide which pruning/optimization work to do next.
3. **Data-grounded design.** The audit's data structure is the spec; the heuristics and the threshold are module-level constants tunable from one place.
4. **Reusable across actions.** The `trace_action` API takes any `Action` (entry point + description). Adding a 4th action (e.g., MMA worker spawn, when it's no longer cold) is one `Action(...)` declaration.
@@ -154,7 +154,7 @@ The user can extend with more actions later (e.g., MMA worker spawn when it's no
CLI:
```bash
uv run python -m src.code_path_audit --action ai_message_lifecycle [--depth N] [--json] [--markdown] [--mermaid]
uv run python -m src.code_path_audit --action ai_message_lifecycle [--depth N] [--dsl] [--tree] [--markdown] [--mermaid]
```
MCP tool (for agents):
@@ -166,16 +166,43 @@ Generated artifacts (all under `docs/reports/code_path_audit/<YYYY-MM-DD>/`):
| File | Format | Purpose |
|------|--------|---------|
| `call_graph.json` | JSON | Full call graph (all of `src/`) |
| `expensive_ops.json` | JSON | Expensive ops index (per-file, per-function) |
| `state_mutations.json` | JSON | State mutations index (per function) |
| `actions/<action>.json` | JSON | Per-action profile (machine-readable) |
| `actions/<action>.md` | Markdown | Per-action human-readable summary |
| `call_graph.dsl` | Custom postfix DSL | Full call graph (all of `src/`); machine-readable, parses in ~30 lines |
| `expensive_ops.dsl` | Custom postfix DSL | Expensive ops index (per-file, per-function) |
| `state_mutations.dsl` | Custom postfix DSL | State mutations index (per function) |
| `actions/<action>.dsl` | Custom postfix DSL | Per-action profile (machine-readable) |
| `actions/<action>.tree` | Prefix tree (text) | Per-action human-readable tree (for human review) |
| `actions/<action>.md` | Markdown | Per-action summary + table (for code review) |
| `actions/<action>.mmd` | Mermaid | Per-action call graph (visual) |
| `summary.md` | Markdown | Top-level cross-action summary + ranked optimization candidates |
| `optimization_candidates.md` | Markdown | Ranked list with: candidate, current cost, proposed reduction, effort, priority |
The two follow-up tracks consume the JSON files; the markdown is for human review.
The two follow-up tracks consume the .dsl files; the markdown + tree are for human review.
**The custom DSL is postfix (RPN) with length-prefixed lists** — no brackets, no braces, no commas, no colons. Each "word" is a tagged constructor that consumes a known number of args from the stack (e.g., `fn` consumes 3, `exp-op` consumes 5, `mut` consumes 3, `N list` consumes N items). Whitespace-tokenized. Strings are bare atoms when they have no whitespace; quoted only when needed. `nil` for null. `\` for line comments. The DSL is deliberately NOT strict Forth — it's a custom postfix format tailored to the audit's record shapes (function, call, mutation, expensive op, pair, list).
Example of a single FunctionNode record:
```text
\ FunctionNode: fqname file line fn
"src.ai_client.AIClient.send" "src/ai_client.py" 100 fn
"build_file_items" call
"process_response" call
"self.history" attr_write 110 mut
"open" file_io 100 120 exp-op
```
**The prefix tree renderer** is a separate human-readable view of the same data — top-down, `├─`/`└─`/`│` box-drawing, scannable. Generated by a recursive walker. Inlined in the markdown reports (optionally produced as `actions/<action>.tree` for tooling).
**Why custom postfix DSL (not JSON, not s-expressions, not strict Forth):**
- **Not JSON** (JSON is ill-performant: quoting, escaping, hash table allocation, no streaming).
- **Not s-expressions** (the bracket version drifts back toward s-exprs; the user wanted postfix specifically).
- **Not strict Forth** (the user wants a format ideal for call-graph recording, not a Turing-complete Forth program).
- **Postfix** (per user: "I want a post-fix heiarchy"): stack-based, no delimiters to count.
- **Length-prefixed lists** (standard postfix solution for nesting): `N list` consumes N items, unambiguous.
- **Trivial parser** (~30 lines: split + walk + evaluate tagged words against a known arity table).
- **Compact**: ~30-40% fewer characters than JSON for the same data.
- **Streamable**: no need to parse the whole file to find a record; you can scan for tags.
- **Extensible**: add new metric types by adding new tagged words (`metric(name value sample_size)`, `histogram(buckets)`, etc.).
## Verification (TDD per `conductor/workflow.md`)
@@ -185,7 +212,8 @@ Unit tests in `tests/test_code_path_audit.py`:
- `ExpensiveOpIndex` detects each of the 7 cost classes on synthetic source.
- `StateMutationIndex` detects each of the 5 mutation kinds on synthetic source.
- `trace_action` produces an `ActionProfile` for a synthetic action whose expected cost is computable by hand.
- JSON output round-trips (deserialize → same structure).
- Custom postfix `.dsl` output round-trips (parse_dsl(to_dsl(profile)) == in-memory structure).
- Prefix tree renderer produces well-formed box-drawing output for the 3 per-action reports.
- Markdown output is well-formed (header per section, table per category).
- Mermaid output parses as valid Mermaid syntax.
@@ -202,7 +230,7 @@ Manual verification: the report is the deliverable. A Tier 2 Tech Lead + user re
2. feat(audit): add trace_action + ActionProfile + cost model
- src/code_path_audit.py (extends with action tracing)
- tests/test_code_path_audit.py (integration tests)
3. feat(audit): add JSON / markdown / Mermaid output
3. feat(audit): add custom postfix DSL writer + parser + tree renderer / markdown / Mermaid output
4. feat(audit): add MCP tool + CLI surface
5. docs(audit): run audit on 3 actions; commit report
- docs/reports/code_path_audit/2026-06-07/* (the deliverable)
@@ -218,7 +246,7 @@ Each commit message includes a `git notes add -m "..."` summary per `conductor/w
|------|-----------|--------|------------|
| Heuristic cost model is imprecise; reported "expensive" ops aren't actually expensive at runtime. | Medium | Medium (false positives dilute the report) | `EXPENSIVE_THRESHOLD` is a module-level constant; the runtime-profiling follow-up calibrates it. |
| AST walking misses dynamic patterns (eval, getattr, decorator-driven dispatch). | Medium | Medium (under-estimates some calls) | Document the limitations in the report's caveats section; the runtime-profiling follow-up catches these. |
| Mermaid diagrams exceed renderable size for deep actions. | Medium | Low (visualization only) | Default `max_depth=5` for `--mermaid`; full graph available as JSON. |
| Mermaid diagrams exceed renderable size for deep actions. | Medium | Low (visualization only) | Default `max_depth=5` for `--mermaid`; full graph available as `.dsl`. |
| The 3 actions' entry points are not exactly the functions the user has in mind. | Medium | Low (the report is the artifact; user can re-run with different entry points) | Document the chosen entry points in the report; CLI/MCP tool accepts any fully-qualified function name. |
| Report is too large to review (thousands of expensive ops). | Low | Medium | Per-action scoping; default `--depth 5`; ranked optimization candidates in `summary.md` make the top-N obvious. |
| Existing `derive_code_path` is the de-facto call-graph tool and the new one is redundant. | Low | Low (the new one is a strict superset) | `derive_code_path` stays as a thin wrapper around `code_path_audit.trace_action` for backward compat, OR gets a `@deprecated` shim. |