Skip to content

Releases: ojassug/TokenDamper

v2.0.0 — the language list stops being hand-written

Choose a tag to compare

@ojassug ojassug released this 05 Oct 17:09
792aaa8

The final TokenDamper release. C and C# reduce under a new deep engine, which ships as its own package, tokendamper-deep. --mode now selects that engine. Nothing is scheduled after this release; DECISIONS §89 closes every held item, saying why it was held and what would have unblocked it.

Breaking

  • --mode selects the engine: fast (the default) or deep, on optimize only.
    • --mode bench and --mode optimize are now errors that name tokendamper bench and tokendamper optimize.
    • --engine-mode is withdrawn, and the error names --mode fast|deep.
  • app.mode and TOKENDAMPER_APP_MODE are ignored, with a one-line notice on stderr. Nothing ever read them. So do the variables withdrawn earlier (TOKENDAMPER_RISK_TOLERANCE, _MAX_OUTPUT_TOKENS, _MAX_LATENCY_MS, _TRACE_OUTPUT), which until now loaded silently.
  • The engine can also be set with engine.mode or TOKENDAMPER_ENGINE_MODE. If either resolves to deep, bench and mcp refuse to start, because neither runs the deep engine. The error names TOKENDAMPER_ENGINE_MODE=fast as the per-command override.

New: C and C# under --mode deep

npm install -g tokendamper tokendamper-deep
tokendamper optimize src/server.c --mode deep --target-reduction-ratio 0.3

At ratio 0.3, each corpus with its own fallback rate:

corpus source: saved (fell back) tests: saved (fell back)
redis (C) 6.76% (34.3%) 32.04% (6.1%)
curl (C) 9.59% (30.8%) 35.76% (17.8%)
Newtonsoft.Json (C#) 20.12% (5.5%) 26.69% (0.6%)
jellyfin (C#) 21.46% (6.2%) 25.05% (11.7%)

A fallback is fail-open: you get your input back. C falls back most because TokenDamper refuses to drop a comment phrased as an instruction (always, must, do not), and C's block comments are full of them. In fast mode, C and C# are now validated by new bracket and quote lexers but never reduced. Those lexers flag 2 of 7,914 real C files and 0 of 6,230 C# files.

The default path moves for Python and TypeScript

  • Fast Python reads wrapped and async def headers (§83). On pip, the file route goes 17.75% → 19.53%. It costs fallbacks on async-heavy code: across three corpora, 2 recovered and 9 new. That trade was accepted on purpose.
  • A compound statement is one span (§86). Elision no longer leaves an else, catch, finally or do's while attached to a marker. On the main corpus, 29 rows change and none newly falls back. Adherence is slightly worse: TypeScript rows above 50% go 8 → 10.
  • The Python validator reads \ line continuations (§88). It had falsely flagged 1,110 of the 13,897 .py files in a CPython 3.12 install, against 2 now. On CPython's standard library, the file route goes 7.24% → 8.60% with no new fallbacks.

Not established

  • An install of tokendamper-deep on a platform without prebuilt grammar bindings. Prebuilds cover darwin, linux and win32 on x64 and arm64.
  • Deep through bench or MCP. It is refused rather than implemented.
  • Stdin for C or C# without --language.

The full record is DECISIONS §84–§89 and the CHANGELOG.

v1.8.0 — a description is not a directive

Choose a tag to compare

@ojassug ojassug released this 23 Sep 18:49
375e1ea

R2 and R3 of the road to v2.0 reach the registry, together. R2 stops the constraint gate firing
on descriptive comments and adds a per-file latency instrument. R3 adds the ParserAdapter seam and
an opt-in Deep path behind --engine-mode deep. Neither was released on its own, so upgrading from
1.7.4 delivers both.

What changes behaviour

  • More files reduce instead of falling back. A present-tense descriptive never/always is
    no longer read as a directive, as in // Should never happen, but we ... or never returns.
    The constraint gate therefore stops refusing the files that carry one. Over the frozen corpus,
    10 files that fell back now reduce, with 0 new fallbacks. Paired over the 507 rows that
    reduce in both arms, none changed a byte. A modal still fires on purpose: should never call this instructs. (DECISIONS §77)
  • Every trace carries a new parserCoverage block, the default fast path included
    (mode: "fast", registeredLanguages: [], backendAnswered: 0). Anything that parses the trace
    strictly sees a new field.
  • --engine-mode fast|deep is new on optimize. fast is the default and is what ran before.
    deep needs the companion package tokendamper-deep, which is not published until R4. From
    the npm package, --engine-mode deep therefore exits 1 with an error naming what it tried; it
    never falls back to Fast. Its "build it first" hint applies to a repository checkout, where
    deep mode runs once the workspace is installed and packages/deep is built. Measured there, it
    reduces Python more than Fast (17.75% → 22.26% on the frozen corpus) and TypeScript about the
    same. (DECISIONS §79–§81)

Also

  • A load-sensitive Gateway test is fixed. Its time-to-first-byte budget sat inside the
    distribution of its own first byte under load; the change is test-only.
  • The per-file latency harness (§76) and a corpus-recipe update, both under tools/, which the
    package does not ship.

Full detail, with the measurements, is in CHANGELOG.md.

On the version number

A minor, because the default path's output moves (§77). The same command over the same input emits
different bytes, which is this project's threshold for one (DECISIONS §53). Nothing was removed.

npm view tokendamper version is what says whether this has reached the registry — the tag does
not.
The publish is a separate, 2FA-gated step.

v1.7.4 — the backlog reaches the registry

Choose a tag to compare

@ojassug ojassug released this 19 Sep 10:13
2b5ba4e

The 2026-08-30 security remediation reaches the registry. Every finding in the seven-session
security review — the F, V and S series, including two independent falsification passes, one over
the findings and one over the fixes — plus three oxaudit.md tooling items (OX-L8, L17, L18) and
a restructured README.

If you are on 1.7.2, this delivers v1.7.3 as well. v1.7.3 was tagged 2026-09-01 and never
published. DriftCoverage.symbolBearingItems changes meaning there, on 254 of 580 corpus
rows — read the v1.7.3 changelog section if anything you own parses the trace.

What changes behaviour

  • The Gateway refuses an upstream redirect (S-04), returning a 502 naming the status where
    it previously followed one. Demonstrated end to end delivering x-api-key to a stand-in
    metadata listener; authorization was stripped only by undici implementing the Fetch spec's
    cross-origin rule, and x-api-key is a vendor header on no such list. Neither api.openai.com
    nor api.anthropic.com redirects an API POST, so nothing anyone does today changes — but an
    endpoint that does redirect now needs its destination configured as the upstream URL.
  • An unknown Gateway route no longer mints a session (S-01). 20 unauthenticated POSTs to an
    unknown endpoint previously produced 20 sessions, and 120 GETs naming chosen ids produced 100 —
    the store's entire cap. Reachable from a web page, because a no-cors GET sends no Origin
    header at all, so the origin gate never saw it.
  • GatewaySessionStore.getContent refuses a ref shorter than 12 characters (F-02). The prefix
    scan previously returned stored plaintext for any unique prefix, and ref= (empty) matched
    every hash. No shipping caller is narrowed — the only producer emits a 12-character prefix.
  • --diff-html writes its report 0600 (F-04), where it landed at 644. The report embeds
    every item's full before and after content.

Also fixed

Trace messages no longer quote the payload back at you: a JSON syntax error built its message
from V8's string, which embeds the input (S-03), and a dropped constraint directive was quoted
verbatim (F-05). Both are now built from a fixed vocabulary. A newline in a filename can no longer
forge an envelope header on either renderer (F-06, S-02). A signal no longer truncates the MCP
output stream (OX-L8). optimize <dir> warns when it ingests files git is ignoring (F-03).

Architecture import rules are now policed by the linter rather than only described, with no new
dependency, and npm run coverage exists — reporting only, deliberately not a build gate.

Full per-finding detail, with the measurements, is in CHANGELOG.md.

On the version number

This is a patch number over moved output, and that was an explicit call at ship time rather
than the rule changing.
Four changes clear this project's usual threshold for a minor — the
same command over the same input emits different bytes
: S-02 and F-06 escape envelope labels,
S-03 and F-05 rebuild trace messages, and OX-L8 stops a signal truncating the MCP stream.

The patch digit was chosen so that a ~1.7.2 range picks up a security release without
intervention. v1.6.1 is the precedent, and this is the second time. Do not read the digit as
evidence that nothing moved
— the changelog, CLAUDE.md and the status doc all say so.

Verification

All three version reporters agree on 1.7.4 — the built dist/src/version.js, package.json,
and the MCP serverInfo.version (there is no --version flag; it prints usage). Suite 936
passing / 2 skipped across 99 files
; typecheck, lint and build clean. npm pack --dry-run was
read before publishing: 223 files, 1.9 MB unpacked.

No corpus run, deliberately: this release adds no code, and a byte-identical result would have
been vacuous rather than reassuring.

v1.7.3 — a field named for symbols counts symbols

Choose a tag to compare

@ojassug ojassug released this 01 Sep 17:47
445b3ed

Read this if anything you own parses the trace.

DriftCoverage.symbolBearingItems changes meaning: it counted items an AST validator covered, and now counts items that actually yield symbols. The number moves on 254 of 580 corpus rows, always upward.

Numbered a patch because the optimized output does not move. outputSha is identical on all 580 rows, so the same command over the same input emits the same bytes on stdout. The change is confined to the diagnostic trace on stderr and in the MCP response.

If you consume only the optimized text, this release is inert for you. If you parse driftCoverage, treat it as breaking — the version number does not say so, and that is the one thing the digit understates.

What was wrong

The field was new Set(after.items.filter((i) => !unchecked.has(i.id))) — which is trace.astCoverage.checked arriving a second way, under a name asserting a fact about symbols that nothing had checked. tools/corpus-harness/measure.js recorded both, so every corpus run carried the same column twice under two names, and any comparison of them agreed by construction.

The two never had to agree: extractSymbols is regexes over content with no language gate, while selectValidator has four branches. Both directions are real:

  • Symbols without a validator. Go between §59 and §60 reported symbolsBefore >= 3 beside symbolBearingItems: 0 on all 80 frozen Go files. §60 gave Go a validator, which removed Go from that population without fixing the field.
  • A validator without symbols. Six of this repo's own barrels — src/index.ts, src/config/index.ts, src/core/model/index.ts, src/core/ledger/index.ts, src/bench/index.ts, src/bench/fixtures/index.ts — are validator-covered and yield no symbols. Those are precisely the files §28 and §33 exist to protect.

Why it survived: on a mixed bundle it was wrong in both directions at once, and the errors partly cancelled to a plausible-looking 2 where the truthful count was 3. Not obviously broken — quietly ratified, including by two tests that pinned the misnomer rather than the behaviour.

Measured

Corpus frozen at 1e0f71f: 290 files, 580 rows, ratio 0.3, both routes, 16 fields per row.

rows differing 254 of 580
fields differing symbolBearingItems only
direction 254 up, 0 down
rows with symbolsBefore > 0 beside symbolBearingItems: 0 254 → 0
outputSha identical on all 580

The differing buckets name the cause — tcl, c, shell, perl, rust, css, every language with no validator — plus 63 rows of typescript/stdin, this project's own language on its own second route.

extractItemSymbols splits the per-item body out so the count and symbolsBefore come from one pass; computed as a separate filter it cost a measured 19 ms of 196 ms on an 18-item bundle.

Also

Corrects a stale claim in CLAUDE.md: v1.7.0 was not the first npm release since 1.6.0 — it was never published either. v1.7.1 was. A tag in this repository does not imply a registry version; check npm view tokendamper version.

Verification

npm run typecheck, npm run lint, npm run build clean; 97 files / 867 tests passing. Built artifact reports 1.7.3 three ways.

Full changelog: https://github.com/Epichlo/TokenDamper/blob/v1.7.3/CHANGELOG.md

v1.7.2 — the package stops shipping its own test suite

Choose a tag to compare

@ojassug ojassug released this 01 Sep 16:58
1e0f71f

The published package no longer ships its own test suite. No runtime behaviour changes — every product file is byte-for-byte what 1.7.1 shipped; 285 files simply stop being published.

entries packed unpacked
1.7.1 508 778 KB 3.08 MB
1.7.2 223 497 KB 1.65 MB

What changed

npm run build used tsconfig.json, which covers src/ and test/ because npm run typecheck wants it to — a type error in a test is a real error. But the build shared that config, so tsc emitted dist/test/, and package.json files ships all of dist. Compiled suites were 46% of the unpacked package, against 210 entries for the product itself.

build now uses a new tsconfig.build.json that includes only src/. typecheck is unchanged.

All 285 removed entries are under dist/test/. Nothing was added, and dist/src/ is the same 210 files at the same paths — verified by diffing the emitted file list. The tarball ships 0 compiled test files.

Only emission narrows

Type coverage of the suite is preserved, and that was mutation-checked rather than assumed. With const x: number = "not a number" planted in a test file, npm run typecheck reports TS2322 and the build config ignores it. That coverage earns its place — it catches bad generics in suites that vitest runs green.

The trap this could have been

rootDir: "." is set explicitly in tsconfig.json, and that is the only reason narrowing include to src/** is safe. Unset, tsc infers the common root of its inputs — for a src-only build that is src/, relocating every output from dist/src/cli/main.js to dist/cli/main.js and breaking main, types and bin in a build that still succeeds. It is now pinned by a test rather than left as a coincidence.

The vitest dist exclude (audit OX-H3) stays, with its comment corrected rather than removed: npm run build no longer writes dist/test/, but tsc -p tsconfig.json without --noEmit still does.

Verification

npm run typecheck, npm run lint, npm run build clean; 96 files / 864 tests passing. Built artifact reports 1.7.2 three ways, and the CLI, MCP initialize and bench were each exercised against the slimmed dist/.

Full changelog: https://github.com/Epichlo/TokenDamper/blob/v1.7.2/CHANGELOG.md

v1.7.1 — the stray-suite guard walked a virtualenv

Choose a tag to compare

@ojassug ojassug released this 01 Sep 16:06
46690df

No runtime behaviour changes. One test file, and the version number needed to carry it.

v1.7.1 is the first npm release since 1.6.0. Neither 1.6.1 nor 1.7.0 was published to npm — both are GitHub releases only. Everything in their notes ships here, including oxaudit.md closing in full, Go elision, and the Gateway changes. Upgrading from 1.6.0? Read all three sections.

The fix

test-collection-scope's walk skipped .venv but not venv — and .gitignore:16 ignores venv/, which is the name tokendamper-benchmark/ actually uses. On any checkout where the benchmark harness had been set up, it descended 68,061 entries of a Python virtualenv.

Measured in the checkout that failed, same walk, only the skip set varied:

time entries strays
before 298 ms 68,593 0
after 3 ms 530 0

Strays 0 in both arms — it stops walking a dependency tree, it does not stop looking.

The symptom was a 5 s timeout, not an assertion, which is why it passed in isolation, in CI and in a fresh worktree: none of those has a venv. It surfaced only under prepublishOnly, which is that gate doing its job.

It was also a latent false positive, and that is the half worth keeping: any third-party package shipping a bundled foo.test.js would have been reported as a stray suite belonging to this repository. The cost of the miss was never only time.

Why this needed its own version

v1.7.0 was already tagged and released, and this fix changes the tarball — which is not obvious. tsc -p tsconfig.json compiles test/ as well as src/, and files ships all of dist, so the compiled suite is published: 285 of the tarball's 508 entries are compiled tests. A test-only change is not consumer-invisible in this repository.

Verification

npm run typecheck, npm run lint, npm run build clean; 95 files / 859 tests passing. The built artifact reports 1.7.1 three ways: dist/src/version.js, package.json, and MCP serverInfo.version.

Full changelog: https://github.com/Epichlo/TokenDamper/blob/v1.7.1/CHANGELOG.md

v1.7.0 — the audit closes, and an open relay refuses to start

Choose a tag to compare

@ojassug ojassug released this 01 Sep 15:25
e1364d5

oxaudit.md is closed in full, and this is the first npm release since 1.6.0.

v1.6.1 was tagged and released on GitHub but never published to npm — the audit work landed on main before the publish ran, which would have meant shipping different bytes under an already-tagged number. Everything in the v1.6.1 notes ships here. Upgrading from 1.6.0? Read both sections.

What changes under an existing user

Two things, and both are the decision rather than a side effect.

An exposed Gateway bind with no token now refuses to start. Running the Gateway on 0.0.0.0 (or any LAN address) without gatewayToken throws from start() instead of listening. That configuration was an unauthenticated relay: the gate enforced a token only if one was configured, so anything that could reach the port had its bodies forwarded to upstream providers, with no warning. Three ways forward:

  • set gatewayToken / TOKENDAMPER_GATEWAY_TOKEN;
  • bind a loopback host and reach it through a tunnel or an authenticating proxy;
  • set allowUnauthenticatedNonLoopback: true if an open relay is genuinely what you want.

tokendamper exec is unaffected — it binds loopback and generates a token — and loopback trust (audit C3) is untouched and asserted.

Plain tokendamper bench no longer executes fixture code through python. It reports a different quantity under the same field names: syntaxPassRate and passAt1Rate now come from validation, measured 0.6 against the execution-derived 1.0 on the bundled fixtures. Pass --evaluate-quality for the previous behaviour.

New in 1.7.0 — the last four audit findings (DECISIONS §70)

M15 bench quality evaluation is opt-in. Verified on the built artifact: plain bench writes 0 python-subprocess evaluations, --evaluate-quality writes 5.
M8 An exposed bind must be authenticated, or say explicitly that it should not be.
M9 + L13 A foreign Origin is refused on every bind; a foreign Host on a loopback bind, where DNS rebinding is the threat. GET /health returns {"status":"ok"} and no longer reports sessionCount.
M13 --minimum-confidence and --max-debt documented as inert on the CLI, pinned by a characterization test so a change making either live fails on purpose.

Two corrections came out of verifying before fixing. The audit asked for an OPTIONS/CORS handler — measured, the server already answered OPTIONS 405 with no Access-Control-* headers, and preflight was never the gap since a simple request skips it. And the recorded decision claimed non-browser clients send neither header: true of Origin, false of Host, which every HTTP/1.1 client sends.

Folded in from the unpublished v1.6.1

§61 Go elides — four languages reduce instead of three (27.46% on application Go) · §62 --trace-output and --mode explain withdrawn · §64 debtScore becomes a measurement, correlation 1.0000, having been pinned at its 35.00 clamp on 317 of 317 rows · §65–§68 four Gateway defects that reached provider traffic · §58 --keep-docstrings · §63/§69 the float pool and the OX LOW table.

Verification

npm run typecheck, npm run lint, npm run build clean; 95 files / 859 tests passing. The built artifact reports 1.7.0 three ways: dist/src/version.js, package.json, and MCP serverInfo.version.

Full changelog: https://github.com/Epichlo/TokenDamper/blob/v1.7.0/CHANGELOG.md

v1.6.1 — four languages reduce, and the dials that did nothing are gone

Choose a tag to compare

@ojassug ojassug released this 29 Aug 20:53
83d570a

Four languages reduce instead of three, and four Gateway defects that reached provider traffic are fixed. This release closes Lane A of oxaudit.md and all of Lane B except two items held open for a decision.

The one thing that can break a script

--trace-output is now Unknown argument, and explain is rejected rather than ignored from --mode, TOKENDAMPER_APP_MODE and the config file. Nothing that took effect stops taking effect — neither dial was ever read by anything — but a wrapper passing --trace-output stderr will now exit non-zero. A config file still carrying a traceOutput key keeps loading, and the trace itself has not moved: stderr, as always.

Numbered as a patch, but the output moved

Two changes here alter what the same command emits for the same input — Go now elides, and debtScore reports a measurement rather than a constant pinned at its clamp. Pin exactly if your tooling depends on byte-stable output or parses debtScore out of the trace.

What ships

§62 --trace-output / TOKENDAMPER_TRACE_OUTPUT withdrawn; explain rejected from --mode / TOKENDAMPER_APP_MODE / the config file. Both were parsed, validated and frozen onto ResolvedConfig — and read by nothing.
§59–§61 Go elides. 27.46% on application Go, 19.42% on the stdlib at target 0.3, against this repo's TypeScript at 21.22%. The 287-file main corpus is 574/574 byte-identical, because every Go path is gated on the language. _test.go is where most of the saving is: 26.88% against 14.42% for source.
§64 debtScore read exactly 35.00 on 317 of 317 rows carrying debt — the clamp ceiling — whether the file lost 4.7% or 66.8%. It now tracks the measured byte cut with correlation 1.0000, and all 578 rows stay byte-identical.
§65 One content: null message no longer zeroes a whole request's Gateway saving. The standard OpenAI tool-call shape produced a search string of "null" with quotes, missed, and discarded every other message's replacement — 8,685 bytes sent, 8,685 forwarded. Array content failed identically, which is why the fix is a structural span scan.
§66 The Gateway no longer truncates streaming responses after 30 seconds. A fetch signal keeps governing the response body stream after the promise resolves, so "stream": true answers died mid-generation — on precisely the traffic the Gateway intercepts by default. The budget is now time-to-first-byte.
§67 Within-payload deduplication works on the first turn. It was gated on the block also having been seen in a previous turn, a condition doing no safety work.
§68 Pricing a candidate region no longer registers it with the block store — 12 blocks registered against 5 emitted on a 12-region file.
§58 --keep-docstrings keeps a Python function's docstring when its body is elided. Off by default; measured at 14.2%–21.1% of the saving. Plus a CLI warning when the knapsack drops whole files to meet the budget.
§63, §69 The float pool and the OX LOW table, each closed against its own list — including the rows that were not fixed, recorded with the reason.

Also in this release

Nine post-v1.6.0 changelog entries had been written into the already-released ## [v1.6.0] section instead of [Unreleased]. Found by diffing that section against the v1.6.0 tag; it is now byte-identical to what v1.6.0 actually shipped, and those entries appear under the release that contains them.

Verification

npm run typecheck, npm run lint, npm run build clean; 91 files / 826 tests passing. The built artifact reports 1.6.1 three ways: dist/src/version.js, package.json, and MCP serverInfo.version.

Full changelog: https://github.com/Epichlo/TokenDamper/blob/v1.6.1/CHANGELOG.md

v1.6.0 — the audit is closed in full, and the bytes are the caller's

Choose a tag to compare

@ojassug ojassug released this 16 Aug 17:29
ddca1a7

Ships DECISIONS §54, §55, §56 and §57. max_audit.md had been declared closed twice while findings were open; this release carries the work that actually closed it, plus one defect found afterwards by pointing an MCP client at this repository's own source.

⚠️ The one change that can break a startup

An unrecognized TOKENDAMPER_* enum value is now a hard error instead of being silently ignored.

Nothing that worked stops working — the setting never took effect — but a stale or typo'd TOKENDAMPER_LOG_LEVEL=verbose that used to fall back to the default now fails at startup. Accepted values are named in the error. The affected variables are TOKENDAMPER_APP_MODE, TOKENDAMPER_PLANNER_MODE, TOKENDAMPER_TRACE_OUTPUT and TOKENDAMPER_LOG_LEVEL.

Fixed

The Gateway forwards the caller's bytes (§54, audit M7). When an elision fired, the proxy rebuilt the request with JSON.stringify and rewrote fields it had never touched:

client sent provider received
"temperature": 1.0 "temperature":1
"top_p": 1e3 "top_p":1000
"seed": 12345678901234567890 "seed":12345678901234567000

The first two are cosmetic. The third is a different number — an integer past 2^53 does not survive JSON.parse → JSON.stringify — so a provider was asked for a seed the caller never chose. Elided content is now spliced into the original bytes and everything else is left alone. Savings are measured on the bytes forwarded rather than on a bundle render (48.5% claimed against 47.1% actual, now 46.3% against 46.5%), and a forwarded body can no longer be larger than the one that arrived.

A file that documents the placeholder format is not a corrupted placeholder (§57). The corruption scan matched <BLOCK_HASH:([^>]+)> — any text up to the next > — so prose describing the legacy format was read as a hash, found missing from the store, and failed the whole run. src/core/elision/regions.ts reduced 29.60% on the CLI and 0% on MCP for this reason. 22 files in this repo carry such a string, and every one was unoptimizable over MCP, as is any documentation quoting the format.

A Python function whose body starts after a blank line is optimizable again (§55, audit L7). The body indent was read off the line after def without checking whether it was blank, so the region began at column 0 and the validator rejected the marker. Measured: 434 → 96 bytes without the blank line, 436 → 436 with it.

Line numbers survive a string line continuation (§55, audit L8). The TypeScript validator skipped escaped characters without counting an escaped newline, so every reported position after one read a line short.

Changed

Gateway savings measure the wire rather than the bundle render. Three dead metric fields removed. Three LOW findings (L4, L5, L9) are recorded at their sites with the reason they are acceptable rather than correct, and L6's "Branch & Bound" comment now names the 1/2-approximation guard the code actually implements.

Notes

max_audit.md is closed in full — every severity band. Getting there required two corrections to the claim that it was already closed: M7 sat behind a resolved conditional and entered no wave table, and the entire nine-row LOW table was never scheduled either. Both are recorded rather than quietly fixed, because an item that is in no table reads as done exactly like a check that never ran reads as a pass.

Also included: §56, the measured precondition for widening elision beyond TypeScript/JavaScript/Python. No behaviour change — it corrects a sequencing warning that was wrong in the dangerous direction and would have produced silent unmeasured elision.

Numbering. Per §53 the roadmap reserves no version numbers; a number is a fact about what shipped, assigned at ship time. Minor rather than patch because the same command over the same input emits different bytes; minor rather than major because nothing that worked stopped working.

677 tests, typecheck, lint and build green.

Full changelog: v1.5.0...v1.6.0

v1.5.0 — a comment narrates as well as instructs

Choose a tag to compare

@ojassug ojassug released this 12 Aug 17:09
678f583

The gate stopped refusing a file for its own commentary. CONSTRAINT_DIRECTIVE_LOST accounted for 29 of 29 code-bucket fallbacks on the frozen corpus — not drift, not AST. Inspecting what it was actually refusing, roughly twelve were sentences like:

"The MCP branch of runCli has always read these two" · "It never did: this branch bypassed pruning" · "could never have worked" · "a saving that never reached the wire"

Losing one of those costs a reader some history. Losing "never hash items matching preserveKinds" costs a caller a rule. The keyword is identical, and the gate refused the whole file for either.

Narrowed only where it is provably safe

This gate protects content, so a wrong call deletes an instruction rather than costing output size. Three limits: only never/always (so "must have been called before" is untouched); only perfect or past constructions (so "is always deterministic" keeps firing); and only when every keyword in the segment is narrative. Sixteen real instructions are pinned as a negative control — a rule that drops one of those is not a better rule at any reduction figure.

Measured — per-row, 576 rows, both routes, target 0.3

result
rows byte-identical 572 of 576
fallbacks fixed / new 4 / 0
newly reducing / stopped 4 / 0
rows already reducing that changed 0

TypeScript file route: 39 → 43 reducing, 16 → 12 fallbacks.

The caveat matters more than the headline

Python gained zero. All four recovered files are this repository's own source, which M11 measured as 32.8% comment prose written in a what-used-to-be-true style. The 6pp on the TypeScript bucket is the corpus-bias trap showing up as a favourable number — the harder direction to notice — not a portable estimate.

Also in this release

The roadmap reserves no version numbers (§53). v1.5.0 was held for "Granular Sub-Query Re-hydration", which unlike the previous three collisions is perfectly buildable and had simply not been built. Four reservations in four releases were wrong, each for a different reason, so a number is now a fact about what shipped, assigned at ship time.

Full reasoning: DECISIONS.md §52 and §53.