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:
@@ -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. |
|
||||
|
||||
Reference in New Issue
Block a user