Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ three commits past it), and a bug report can name a release instead of a sha nob
Sections dated before 2026-09-19 predate the cycle and stay as they are.

## Unreleased
- fix(bin/context-audit.sh): **a Read `offset` or `limit` stored as a string no longer crashes the audit, and the script now exits 0 as its header promises.** Older transcripts store these as strings, sometimes as junk like `'30, 90'`, and `offset - 1` raised a TypeError in the embedded reader, which stopped the whole run. They are now read as numbers when they parse and fall back to the Read tool's defaults (offset 1, limit 2000) when they do not; if the reader ever dies on an unseen transcript shape, the script says the numbers are partial and still exits 0. Field run: 1,300 sessions and 724 subagent runs on a Mac (2026-08-27 to 2026-09-30), which crashed on the old version. — MendixMau
- fix(routing): **`learned-mcp-patterns.md` is no longer always-on in the build stage; it loads before the first MCP write in a session.** It sat in the Stage 5 baseline pack and in `mdl-agent`'s always-read rows, so every build session and every MDL helper agent carried ~4,900 tokens of MCP save/handoff rules and JSON payloads, including sessions that never open Studio Pro and cloud containers where MCP does not exist. Choosing the write mode is already Step 0 of `learned-mdl-preflight.md`, which stays always-on, so nothing is lost at the moment of choice; the MCP skill's trigger now names the moment it is needed (`mxcli --mcp` exec or a `pg_*`/`ped_*` call). Stage 5 pack: 74,055 → 71,443 words, 23 → 22 files; baseline 79,752 → 77,140 words. Found by the context report (`bin/context-audit.sh`, `bin/render-routing.sh --check`). — MendixMau
- new(bin/context-audit.sh): **what fills the context window, per file, from the real Claude Code transcripts on this machine.** `token-burn.sh` says how many tokens a project burned; this says which files burned them, so decisions about splitting, trimming or un-routing a skill rest on measured runs instead of `wc` on the skill files. It reports: the context size before any work (first call, input + cache, for sessions and for subagents separately); the instruction files loaded every run (CLAUDE.md, CLAUDE.local.md) and their size; every file read (Read tool and simple shell reads like `cat`, `sed -n`, `git show REV:path`, following `cd` and `VAR=`) with reads, sessions, total and per-read size, and re-reads within a session (paging through a file is not a re-read; asking for the same part again is); other tool output by tool; and each compaction with the files read before it. Project names are masked by default (`project-1/architecture/modules/*.md`), so the output is safe to paste; `--names` shows them locally. First field numbers, from a captured pipeline-start subagent: it starts at 52,503 tokens before reading anything, then reads the runbook in 6 pages with 2 repeats. Fixture: `tests/wave2/test-context-audit.sh` over a scrubbed real capture. — MendixMau
- fix(doctor, test-stack-up): **in a cloud container, a missing Docker daemon is now reported as normal, with the Docker-free route, instead of a warning that says to start it.** The Claude Code on the web container has the docker CLI but no daemon, and the agent cannot start one. Doctor used to WARN "docker daemon is not responding … sudo systemctl start docker", so sessions tried, failed, and reported "cannot start the docker daemon" as a blocker, until the user said to use `mxcli run --local`. Now the cloud lane prints: no Docker here, normal, do not try to start it; build check = exec.sh's mxbuild gate; run the app = `./mxcli run --local`. On a desktop (Docker or Podman, stopped or absent) the warning and start hint stay, plus one line saying a container is optional: the mxbuild gate needs none, and Studio Pro's Run Locally or `mxcli run --local` runs the app. The no-runtime text no longer says the build check needs Docker. `test-stack-up.sh` with the app down and no reachable Docker/Podman now stops with the Docker-free route instead of failing inside `mxcli docker run`. — MendixMau
Expand Down
16 changes: 14 additions & 2 deletions bin/context-audit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ if [ ! -d "$TRANSCRIPTS" ]; then
fi

require_py
# Exit 0 even if the reader dies on a transcript shape nobody has seen yet: say so, never fail.
"$PY" - "$TRANSCRIPTS" "$PROJECT_DIR" "$TOP" "$NAMES" "$TOOLKIT_ROOT" <<'PYEOF'
import json, os, re, shlex, sys
from collections import defaultdict
Expand Down Expand Up @@ -155,6 +156,14 @@ def transcripts():
if s.endswith(".jsonl"):
yield os.path.join(sub, s), True

def num(v, default):
"""A Read offset/limit as an int. Old transcripts store them as strings, sometimes as junk
like '30, 90' (field run 2026-09-30, 1,300 sessions: the arithmetic below crashed on one)."""
try:
return int(v)
except (TypeError, ValueError):
return default

def tok(n):
return (n + 3) // 4

Expand Down Expand Up @@ -271,8 +280,8 @@ for path, is_sub in transcripts():
if name == "Read" and inp.get("file_path"):
# a paged read (offset/limit) of the next part is not a re-read; the same part again is
pending[b.get("id")] = ("file", show(inp["file_path"], cwd),
"%s@%s+%s" % (inp["file_path"], max((inp.get("offset") or 1) - 1, 0),
inp.get("limit") or 2000)) # the Read tool's defaults
"%s@%s+%s" % (inp["file_path"], max(num(inp.get("offset"), 1) - 1, 0),
num(inp.get("limit"), 2000))) # the Read tool's defaults
elif name == "Bash":
f = shell_file(inp.get("command") or "", cwd)
pending[b.get("id")] = ("file", show(f, cwd), "sh:" + f) if f else ("bucket", "shell output (other)", None)
Expand Down Expand Up @@ -380,3 +389,6 @@ if compactions:
else:
print(" none")
PYEOF
rc=$?
[ "$rc" -eq 0 ] || echo "context-audit: the reader stopped early (exit $rc) on a transcript it could not parse — numbers above are partial. Please report it." >&2
exit 0
Loading