Releases: GhostlyGawd/codeweb
Releases · GhostlyGawd/codeweb
Release list
codeweb v0.12.0
Added
- MCP-registry publishing is automated (
.github/workflows/mcp-registry.yml): every
published release now submitsserver.jsonto registry.modelcontextprotocol.io via GitHub
Actions OIDC — no browser login, no stored secret. The server name and the npm package's new
mcpNamefield carry the canonicalio.github.GhostlyGawd/codewebidentity (casing matched
to the namespace's existing registry listings); this release is the first whose npm tarball
ships themcpNameownership handshake the registry requires.
codeweb v0.11.0
Added
- A terminal-editorial redesign of the whole site (owner-approved mock). Near-black paper,
JetBrains Mono everywhere, a Doto dot-matrix wordmark and numerals, square corners, film
grain, viewfinder frame — and one accent, spent only on meaning. The homepage opens on the
live axios map withmerge()pre-selected and its 56-function blast radius lit in
chartreuse; the map itself went dithered (pixel-square nodes, stippled edges, HUD crosshairs).
Benchmark stats render as pixel-block meters (grep 44% vs codeweb 74%). Fonts are
self-hosted, same-origin; the social-preview card matches. - The report UI itself is redesigned to the same system. Domain bubbles became dithered
square blocks with their symbol count set inside; edges are straight stippled strokes with an
accent "blast" state, so a selection's impact reads at a glance; the selected node wears the
accent with a viewfinder frame. The masthead is a mono-caps HUD (pixel glyph, boxed tabs,
square search and buttons), findings badges are monochrome (accent = high-confidence only),
and every place a hue used to carry data — domain slots, matrix cells, treemap density — now
uses a luminance ramp, which survives every kind of color-vision deficiency by construction.
Dark is the default; light is an explicit paper mode andautofollows the OS. Labels get a
deterministic screen-space collision cull, so dense graphs stop rendering as label mush. - A README banner in the brand language (
assets/brand/banner.png): Doto wordmark, pixel
glyph, caps tagline, and a dithered mini-map with one accent-selected node. The pipeline
SVGs (demo.svg,pipeline.svg) and the homepage stage illustrations are redrawn in the
same square/stipple/single-accent language. - An unlisted npm-downloads dashboard at
/downloads.html: daily download counts of
@ghostlygawd/codewebover time, fetched client-side from npm's public API and drawn as a
dependency-free SVG. Built with the site but excluded from the sitemap and linked from nowhere.
Changed
- One ratified identity, on every surface (
CHARTER.md, new at the repo root, with a
CLAUDE.mdpointer so agents read it first). The job line — "Your agents break less code
and burn fewer tokens." — now leads the README, the site homepage, tagline, and og titles,
and the npm / plugin / marketplace / MCP-registry / GitHub-About listings;check-consistency
reads the line from the charter and fails any of those surfaces if it drifts. External review
is billed as a feature note, not a second mode. The support copy drops the "AI bills from
benchmarking" story, ruled fabricated in the charter's interview (C7): sponsoring supports
the project and sponsors get featured README/site placement, and the enterprise offer
softens to an email doorway — no price, no SLA claim.docs/ROADMAP.mdis rewritten to the
charter's Now/Next/Not-now with dated corrections, and the two strategy documents carrying
the fabricated cost premise now open with correction banners. - The funnel leads with the trial. A "Try it on your repo" section (the npx one-liner) sits
directly under the README hero, and the homepage hero carries the same command — seeing your
own repo mapped is the pitch. The axios case study is demoted from a bold callout to a plain
link under the screenshots. The README masthead drops the hero graphic and the decorative
engine/MCP/sponsor badges: a text wordmark, the tagline, and three badges (CI, npm, license). - Every screenshot and the live demo now show the redesigned report. The demo is the same
committed axios graph re-rendered through the new template (274 product symbols, 8 domains),
the five README/site screenshots are re-shot from it, the blast-radius caption now states
what the committed graph actually contains (27 call edges intoAxiosError— the old "58
users" figure doesn't match this artifact), and the injected demo nav matches the HUD
(caps, square, no pills). - Plain-language pass over the whole marketing funnel. The README, homepage, and plugin
listing now state what codeweb is instead of performing the problem — the rhetorical-question
opener and "Today…" windup are gone, and the proof bullets carry spec-sheet labels
(Correctness / Duplication / Speed at scale / Agent lift / Limits). Study apparatus left the
pitch too: the hero's grep-vs-codeweb benchmark table, the "referee"/"oracle" framing, and
the outbound vite/axios repo links are gone or moved behind the evidence ledger — the pitch
says what you get; the research page says how it was measured. The proof section is now
"Benchmarks": benefit-first bullets (callers found 44%→74%, impact answers at 1/126th the
tokens, renamed-duplicate detection text search can't do) with no meta-talk about our own
rigor — the 32/33 pre-registration story lives on the research page. Engineering properties
left the marquee: the DETERMINISTIC · READ-ONLY · ZERO-DEPENDENCY strip is gone from the hero
(README and hero.svg), and the plugin/marketplace listings say "27 MCP tools" — read-only and
zero-dep stay where the worry arises, in install and trust copy. Shorter sentences,
stats stated as outcomes ("+0.31 recall" now reads "with grep agents found 44% of a
function's callers; with codeweb, 74%. Your agents break code they don't see"), and the
MCP tool list regrouped by when agents meet each tool (which also
surfacescodeweb_explain, previously undocumented in the README). Density is now gated:
marketing paragraphs cap at ~55 words, enforced bytests/copy-density.test.mjs, with the
voice rules recorded inCONTRIBUTING.md. And the README is a landing page again: its
reference half — outputs, per-tool docs, the capability table, the full MCP tool groups, the
component tree — moved todocs/reference.md, linked per-job from the README (which drops
from ~650 to ~330 lines). Two overclaims corrected:
the homepage no longer calls 16k+ graphs "measured green" (the expand-all receipt says
green:falseat that scale), and the pre-registration page no longer says the full study
re-runs in CI (CI re-measures the standing budgets; the study re-runs viabench/run-all.mjs).
The stale "286-test suite" figure is dropped or time-qualified everywhere it appeared. - The regression gate is ONE verdict with a declared strictness knob.
gateVerdict(graph-ops)
now backs diff/CI, simulate, the post-edit hook, codemod, andreview --gate; payloads carry
verdict.check(orphan-gatevscall-caller-preflight), exported symbols that lost every
in-edge are LISTED and flagged exempt instead of silently dropped, and every doc states the real
rule. simulate/codemod speak for their own check instead of borrowing the gate's. run.mjsjoins the fleet's stream contract: results (the done block, or the new--json
one-liner) on stdout, progress on stderr; wrong-path targets exit 2, not the stage-failure code.codeweb_context:bodies: "windows"|"full"replacesfull's second meaning —fullis
the unabridged-list switch only. Agents wanting whole caller bodies passbodies:"full".- One pagination dialect over MCP:
offsethonored on risk/hotspots/break_cycles,
nextOffsetbeside everyremaining, reading_order surfaces its truncation, and the MCP layer
now rejects unknown argument names and non-boolean booleans the way the CLI always did. - The shared parser coaches: did-you-mean on unknown flags,
--flag=valueaccepted, and the
no-map cause+remedy is APPENDED to a tool's usage instead of replaced by it. - One name per concept: "domain" everywhere the report/brief/og said "areas"; deadcode's heading
hedges up front and shows theannotate --suppressdoor; "blast radius" defined at the lens,
settings, and optimize surfaces.
Fixed
find_similar.countis the true match total again (it reported the capped length), with
more.remainingwhen capped.- Three product-page tool cards rendered the literal word "undefined" (data key drift); the site
build now fails on a desc-less tool. - The CI gate action stamped "structural regressions" over setup failures — exit 2 now names the
shallow-checkout cause and remedy, ci-gate forwards the child's stderr tail, and the quickstart
bins exit 2 (never the regression code) on old Node. codeweb_mapfailures keep the extractor's escapes-first explanation instead of a beheaded
stderr tail recommending a flag the tool cannot pass.- The pre-edit hook no longer returns
permissionDecision: "allow"— it is advisory context only. - The SessionStart hook says one line (once per workspace) on an unmapped repo with source,
instead of the silence that read as "the plugin doesn't work". - annotate refuses to invent a fresh
.codeweb/in an unmapped cwd; refresh/fitness/placement/
codemod resolve graphs through the one loader. - Docs that lied outside the consistency sweep (README's gitignored "bundled sample", agent-tools'
stale tool count, tests/README's Node floor, the runbook's test count, marketplace.json's
version) — corrected and swept from now on; newdocs/cli.mdtables every bin, flag,
environment variable, and exit code; newCONTRIBUTING.md. site/data/product.json's (currently unrendered)elevatorstill said "24 deterministic MCP
query tools" — corrected to 27, andcheck-consistencynow scans every prose string in the
site data file so this class self-catches.
codeweb v0.10.0
Changed
- The last hand-rolled CLI flag loops now route through the shared
parseArgs(spec)(lib/cli.mjs),
so every front door enforces the one #24 unknown-flag policy — reject with usage, exit 2, never a
silent positional.explain.mjsanddiff.mjswere the live bug: a no-elsefor (const t of argv) { if (t === '--json') … else if (!t.startsWith('-')) pos.push(t) }swallowed a typo instead
of erroring, soexplain g.json sym --jsnoexited 0 as if the run were clean; both now exit
2 withunknown flag: --jsnoand the usage.brief.mjs/coverage.mjs/stats.mjsalready
died on an unknown flag but still hand-rolled the loop (now one spec apiece), and
bench-ts-engine.mjsswallowed an unknown flag into its target positional — a stray--engine
became the path (exit 1 "target not found"), the original #24 shape — now exit 2 with usage.
Accepted flags, positionals, and--help(exit 0) are preserved exactly;
tests/cli-unknown-flags.test.mjspins the failing→passing exit codes and the surviving legit
surface. (round 2, finding #39) - The post-edit structural-regression hook now extracts IN-PROCESS instead of spawning a child
node process — the last residual term of the hook fast-path floor. Enabled by #40 making
extract-symbolsimportable with a side-effect-free import, the hook lazily
import()srunExtract(after the inert-fire guard, so a no-op fire still pays nothing) and calls
it directly, killing the child node boot plus the fragmentstringify(child)+JSON.parse(hook)
round-trip across the process boundary. The symbol-set delta/splice against the #18a baseline
fragment isrunExtract's own warm-cache machinery (WS-D's #17 name-delta path) — the hook adds no
splice or invalidation logic, so the in-process fire runs exactly what IE-EQUIVALENCE proved
byte-identical. Measured at the 16.8k-symbol class (median-of-5, this box): no-change fire
1,089 ms → 698 ms (the forced-spawn path vs in-process on the same corpus; 0 extractor child
processes vs 1, strace-verified), under the 700 ms floor and down from #18a's 889 ms row. A
fail-open crash ladder keeps the guarantee:CODEWEB_HOOK_INPROC=0forces the old spawn (the
rollback lever), and any throw from the lazy import orrunExtracttriggers one spawn fallback,
bumped ashookInprocFallbacksso a silent divergence is ledger-visible. additionalContext is
byte-identical across both transports (path-parity test). (round 2, finding #18b) - The symbol extractor is being decomposed into testable, importable pieces (the tracked residual
of round-1 #25, now actually being closed). Stage 1: per-file call/ref/inherit derivation —
deriveFileEdges, the precision gate (alias > same-file > unique-in-package, drop-ambiguous, plus
the short-name / closure-local / role / rb-php filters) — moved verbatim out of the 1,400-line
orchestrator intoscripts/lib/edge-derive.mjsas acreateEdgeDeriver(ctx)factory
(import-resolve's proven template: explicit injected context, zero module-global reach-back). The
free-variable context was re-derived against the current engine, not the spec-time table:
injectedbyName,pkgOf,roleFor(the #10 ref role-gate),resolveFileMember,
closureLocalIds(the WS-D-review magnet fix),legacyFallback;KEYWORDS/parseSignature/
isTestFile/buildInnermostIndexare the lib's own pure-module imports;idFile(the id→file
split) is now defined there as one truth and imported back. Edge derivation is now unit-testable
in-process at function-call speed (tests/edge-derive.test.mjs, no spawn) while staying
byte-identical to the old inline function — proven by IE-EQUIVALENCE at 40 trials and a full
self-map cold+warm byte-cmp. Stage 2: the two remaining global-resolution passes joined the same
lib as pure functions —markPublicApi(the v10 public-API entrypoint walk, now doing no fs: the
orchestrator injectsreadPkg+ the stattedsourcesmap and applies the returned ids-to-stamp,
order-safe because the walk never readspub) andresolveTypedIntents(Java/C# typed-receiver
dispatch), which mechanically retires the finding's named shadowing smells (relloop-var vs the
rel()fn, afileslocal vs the global). Stage 3: the orchestrator now exposes
runExtract(opts)and its import is side-effect-free — argv parsing, everyprocess.exit, and
the--out/stdout writes moved to amain()reached only through the repo's proven
import.meta.urlguard idiom; the guard-path exits becameExtractErrorthrows with
byte-identical message text (usage / bad-engine / not-found / empty-tree / zero-symbols), which
main()prints and exits on. Run state that was module-global is nowrunExtractlocals; the WASM
parser engines stay memoized process-wide (the load promise is single-flighted, so concurrent
first-calls don't double-init).import('extract-symbols.mjs')now parses no argv, writes no
files, and never exits — the precondition for the in-process hook (#18b) and for running the
extractor under node:test's concurrent subtests. Stage 4a: the starter trio of spawn→in-process
test conversions —incremental-edges(the IE-EQUIVALENCE property sweep, the suite's dominant
wall term: its ~330-490 child launches at CI depth become function calls, cutting the test's own
wall ~4.5×, 12.9 s → 2.85 s at 40 trials — every assertion identical, theedged N/Mreads moved
from stderr to the returned banner, the fragment byte-compares toJSON.stringify(fragment), and
a new IE-INPROC-PARITY spawn keeps the CLI surface pinned byte-for-byte), pluscall-apply-chain
andtest-edges(extractor in-process, theirquery.mjsspawns untouched). Stage 4b: the
import/edge-precision + language-extraction family (18 more files) went in-process too, clearing
the plan's bar — 22 extractor-invoking spawn sites retired (the convertible subset dropped
80→58), and the dynamic extractor child-process launches during the incremental-edges run drop
from 116 to 1 at 10 trials (≈382→1 at 40-trial CI depth). Non-extractor spawns (query.mjs,
context-pack.mjs) and the CLI-surface owners (cli-front-door,empty-target) stay spawn-based.
(round 2, finding #40) - "Expand all symbols" no longer freezes the main thread: the force sim now seeds compactly, has a
real long-range term, and runs in interruptible slices so no single task blows a frame — plus the
receipt that judges it is measured honestly. The old anneal packed every symbol onto its area
bubble (radius-14 hatch) and repelled only within a 3×3 grid neighborhood, so the ONLY way the
layout could spread was an accidental ±185k-px explosion whose first step was one ~1.2s synchronous
task at 16.8k. Now symbols seed on a golden-spiral phyllotaxis hatch (near-equilibrium spacing), a
Barnes-Hut-lite far-field monopole (per-cell mass + center of mass, pushing every node from each
non-adjacent cell, with a 2×CUT coarsening latch when live cells exceed 4096) gives repulsion its
missing long-range term, andgStepbecamegStepChunk(deadline)— a cursor-driven state
machine that accumulates forces across slices with the grid/aggregate snapshot frozen per logical
step and exactly ONE integrate + alpha-decay per completed step, so slicing changes only WHEN work
runs, never the arithmetic (bitwise-equal to a whole-step run — pinned in the lab).gTickand the
reduced-motion loop drive it against their budgets; motion-safe settles now redraw at most once per
second as discrete progress stills. The result at 16.8k (node sim lab,bench/experiments/report-sim-lab.mjs):
the worst single uninterruptible task drops from 774 ms → 93 ms (≤ the 250 ms no-freeze floor) and
the ±185k spread compacts to ~230k px, while the per-step settled cost stays ~270 ms — the far
field is O(n·cells) and reaching the ≤50 ms/frame primary target at this scale needs a hierarchical
tree (a documented floor, per the finding's fallback: no task > 250 ms + interactive, not a pass).
The receipt (__codewebStage.expandAll) was rewritten from an unstable 10-frame sample that straddled
the explosion (508→116→37 ms across back-to-back calls) to a run-to-settle returning
{settledMsPerFrame, maxSingleStepMs, totalSettleMs, steps}, andreport-scale.mjsgates on both
settledMsPerFrame ≤ 50andmaxSingleStepMs ≤ 250. Layout stays a pure, bitwise-deterministic
function of (graph, interaction sequence) — seeded, noMath.random, insertion-order iteration.
(round 2, finding #35) - The interactive graph's draw loop got substantially cheaper per frame: theme colors are read once
per draw, edges stroke in exact style batches, and labels are screen-space-gated and capped. Every
labeled node used to callgetComputedStyle(up to one per symbol — 16.8k reads on a full 16.8k
draw);cvColors()is now hoisted to one call at the top ofgDraw(theme flips already redraw, so
it stays in sync). Edges stroked onebeginPath+strokeeach (104k strokes at 16.8k); they now
group into ≤432 exact style buckets keyedstate|bubble-pair|min(weight,72)— alpha saturates at
weight 29 and width at 72, so the key reproduces the old per-edge stroke/width byte-for-byte (a
50k-edge property test asserts equality), and each bucket strokes once. Labels used a world-space
radius gate (nd.r > 7.5, so a big node lost its label when zoomed out) with no cap; they now use a
screen-space gate (nd.r * cam.k > 7.5) and a per-frame cap of 300, picked by a position-independent
rank (bubbles > selection/search hits > screen radius, tie-break by id) so they never flicker across
anneal frames. The search highlight set is computed once inrefreshHits(stored id/domain Sets) and
reused bygDrawinstead of rescanning the active node set every frame.__codewebStage.drawOnce()
times ...
codeweb v0.9.0
Added
- Warm refreshes stop paying the AST tax (Spec A). The tree-sitter engine now initializes
lazily — a cheap availability probe decides cache namespaces and meta stamps up front, and
the WASM runtime loads only at the first file that actually needs a parse. AST products
(qualified methods, dispatch edges, exact per-node complexity) ride the scan cache, so a
warm cached extraction on codeweb itself dropped 1.89s → 0.38s (5×) with byte-identical
fragments — felt directly by the MCP auto-refresh, the post-edit hook, and every staleness
check. The banner now reports the tier's state (ast: loaded|idle|off). - The AST performance gate finally has a committed verdict
(bench/results/ts-engine-bench.json): cold extraction costs 3.6–4.3× regex
(~+1.35 ms/symbol, axios + self) — paid once per changed file — and the warm path is
engine-free, so default-on stands. Also fixes the bench's regex arm, which had silently
benchmarked tree-sitter against itself ever since the tier went default-on. - The pipeline memoizes its downstream stages (Spec B). cluster/overlap/optimize/report
are pure functions of the extracted fragment (+CODEWEB_*levers), so a re-run whose
fragment is byte-identical reuses their outputs — wall-time changes, never a byte
(property-tested modulo thegeneratedAtstamp). Extract itself now rides the scan cache
insiderun.mjs, making a no-change re-map of codeweb ~0.4s end to end.--full
forces a recompute. - Overlap survives monorepo scale — with declared caps. Mapping TypeScript's
src/
exposed two quadratic passes (overlap sat at 100% CPU for 8+ minutes): all-pairs body
confirmation inside huge same-name groups, and twin seeding through hub labels with
thousands of callers. Same-name groups now body-confirm on a deterministic 12-node sample
(the finding's evidence says so), >50-caller hub labels are excluded from twin seeding, a
200k global pair budget seeds smallest groups first, and 400+-line bodies shingle their
first 400 lines — every cap counted in the md header. Deterministic, reported, never silent. - Fixed: an input-dependent HANG in the shared tokenizer. The string-literal regex in
lib/shingles.mjs((?:\\.|(?!\1).)*) backtracked exponentially on unterminated-quote
content — one lone apostrophe in a big real-world body (TypeScript's testRunner fixtures)
pinned the whole overlap stage at 100% CPU for 15+ minutes. Replaced with a linear-time
matcher (each char consumed exactly one way) + a regression test; identical semantics.
Found by the Spec B scale test; this also protectsfind_similarand the edit-time
duplication check, which share the tokenizer. - The scale verdict is committed (
bench/results/scale-typescript.json): TypeScript
src/— 16,286 symbols, 44,640 edges, 709 files includingchecker.ts— maps in 43s
cold, 4s memoized re-run, queries answer in ~200ms on the 13.5MB graph, and the top
findings are real compiler duplication (substituteExpression×9, drifted). On that
evidencelib/shards.mjsis deleted: monolithic graphs hold with 10× headroom, the
sharding layer had zero consumers, and git history keeps it if a 100k-symbol case ever
materializes. - codeweb consolidated itself (
bench/results/self-campaign.json): the campaign's three
product-true merges are executed —findTarget(both hooks; the duplication had hidden
REAL drift, one hook's language list was seven languages stale),load()(diff/review →
the canonicalloadGraph, with better errors), andedgeKey(break-cycles/diff →
graph-ops, NUL-separated collision-safe variant). Before/after gate: −22 nodes, −2
duplication findings, coupling −25, zero structural regressions. The 65 DELETE steps
are honestly skipped as false orphans (walker closures dispatched through function tables —
exactly the--orphanscross-check caveat, applied to ourselves). npm run bench:all— the standing benchmark suite behind every published number
(Spec C): pipeline timings, a representative 12-call MCP session (bytes/≈tokens/validity),
per-tool response budgets, and the ts-engine gate, written tobench/results/benchmarks.json
(+ a site mirror). A new CI job runs it with--gate: budgets live inbench/budgets.json,
and breaking one fails the build.check-consistencynow also audits that every evidence
source cited by the ledger and README exists — claims physically can't rot.- Replay A/B gains cost-to-coverage (Spec D). The workflow runs cells sequentially and
records each cell's true token cost from the harness's ownbudget.spent()deltas (never
solver self-report); the analyzer reports per-condition means andcostToFullCoverageTokens
— the discriminator when both arms hit the coverage ceiling. Old cells without cost report
null and are counted, not fabricated. Corpus v3 is frozen after nine mining runs across
six repos (funnels committed asbench/results/replay-mine-*.json): the miner re-derived
the v2 task independently at a wider follow-up window (identical answer key — the instrument
reproduces its own ground truth), one new 4-caller candidate was rejected under
hand-verification (a feature-PR rewrite mentioning the symbol, not a caller fix), and the
corpus stays at one fully-verified task — honestly. True-breakage tasks are rare; that is
the finding. - Role overrides (Spec E).
codeweb.rules.jsongainsroles: [{glob, role}]— heuristics
can't know a repo's private layout, so the repo says it once and extraction honors it (first
match wins, invalid roles fail loudly, absent config is byte-identical to before). codeweb's
own config marksdocs/**asgenerated(it's the built website), completing the
vite-playground precision lesson on our own map. - Python, Go, and Rust join the dispatch tier (Spec F). Three vendored pinned grammars +
dedicated tree walkers wire the calls regex precision-gates away:self.m()/cls.m(),
Go receiver methods, Rustself.m(), and typed-receiver calls (p: Pipe,q Pipe,
p: &Pipe) resolved globally under the one-owner rule — ambiguity drops and is counted,
never guessed. Nodes stay byte-identical between engines; products ride the scan cache. - Caller-reliance contracts v2 (Spec G). The explain card (and the ambient pre-edit card)
now also reports: callers that try/catch or.catch()the symbol ("thrown types are
contract"), callees that mutate a named parameter ("callers share that object"), and callers
that null-check the result ("keep null/undefined returns possible"). Same conservatism as
v1 — line-visible evidence or no claim. - Type-3 (near-miss) clone detection (Spec H). The AST tier fingerprints each function's
statements (identifier/literal-normalized, order-independent multiset); overlap pairs bodies
sharing ≥70% of them — reordered or lightly-edited copies the exact and Type-2 passes cannot
see. A distinctnear-miss-clonefinding kind, REVIEW-only by construction, bounded and
deterministic. - Ruby, PHP, Kotlin, and Swift on the deterministic fast path (Spec I) — eleven native
languages. Discovery with owner-qualified methods (Rubydef self., Kotlin extension
fun Type.name, Swiftextensionmembers), visibility-as-export per language's own rules,
comment/string masking, precision-gated calls, test-role detection (spec/,_spec.rb,
*Test.php,*Tests.swift), and package manifests (Gemfile, composer.json, Package.swift).
Verified on sinatra (1,173 symbols), monolog (1,622), okio (3,874, mixed Kotlin+Java),
and Alamofire (2,616) — zero keyword phantoms, deterministic. - The report closes the loop to the editor (Spec J). The inspector shows
Open in editor
(vscode://file/...) once the viewer supplies their project root — stored in localStorage,
client-side only, because the shipped report still never embeds the absolute source path
(the standing privacy invariant, now pinned by a second test). - npm + VS Code distribution, prepared (Spec J). The package is publish-ready (
codeweb+
codeweb-mcpbins with shebangs, files whitelist, LICENSE, zero runtime deps — verified by
annpm packtest); the release workflow builds and attaches the.vsixto every GitHub
Release and carries npm/Marketplace publish steps that no-op untilNPM_TOKEN/VSCE_PAT
are configured. Publishing stays a human decision; the prep is done.
Changed
- The paper program is archived; the receipts stay.
paper/is retired frommain:
the runnable instruments and every frozen result (nulls and the discarded pilot included)
now live inbench/as the product's benchmark suite (bench/README.md,
node bench/run-all.mjs), and the site's Paper page is gone — the evidence ledger on the
Research page (now including the 2026 blind replay A/B null) plus the CHANGELOG's Research
notes are the public record. The manuscript, pre-registration (H1–H18), and figure
apparatus remain in git history, last present at tagv0.8.0. README and ROADMAP
rewritten to point at receipts instead of the manuscript.
codeweb v0.8.0
Added
- Java and C# call wiring (tree-sitter dispatch tier). The regex engine still finds every
symbol; for Java/C# files an optional AST pass now adds the call edges regex could never
claim safely:this.helper()calls inside a class, andreceiver.method()calls where the
receiver's declared type names exactly one class in the repo (two classes with the same name
→ the edge is dropped and counted in the banner, never guessed). Nodes are untouched —
identical between engines — so determinism holds. Grammars vendored from
@vscode/tree-sitter-wasm@0.3.1(scripts/grammars/PROVENANCE.mdrecords the ABI trap that
rules out the older grammar package). Spec:docs/specs/java-cs-tree-sitter.md. - The ledger now counts whether advice was FOLLOWED, not just delivered. When a pre-edit
card names caller files and a later edit in the same session touches one of them (30-minute
window, once per file, the changed symbol's own file excluded), the ledger bumps
cardCallersFollowedand the session brief reports "N card-named caller(s) followed" —
the difference between "we showed advice" and "the advice changed what happened."
Spec:docs/specs/card-correlation.md.
Research
- The replay miner is tested and honest about its funnel.
paper/experiments/replay-mine.mjs
(mines real commits that changed a function's definition and — per the repo's own later
fixes — missed caller files) gained a TDD suite on synthetic git histories
(tests/replay-mine.test.mjs, P1–P5) and a stage-by-stage funnel report. The tests + a
hand-audit of the first frozen corpus exposed and fixed three miner bugs: a prefilter that
silently zeroed every Java/C# candidate, a raw def-line comparison that read a prettier
reformat as a "signature change" (which had produced 2 invalid tasks), and instructions
truncated mid-hunk at 4KB (now: complete-or-rejected). Spec:docs/specs/replay-corpus.md. - The replay A/B protocol went blind before spending. The v1 pilot leaked its own answer
key three ways (the grading list pasted into solver prompts, self-reported coverage, and
full-history isolation that let solvers read the historical fix commit). It is preserved —
discarded — inpaper/results/replay-ab-pilot.json; the v2 harness solves in a
history-free export of the base revision and the workflow itself computes coverage as
filesChanged ∩ missedByChange. Spec amendments:docs/specs/replay-run.md. - Replay A/B result: both arms at ceiling (honest null). The v2 corpus froze at ONE
fully-verified task — axiosbuildFullPathgainingallowAbsoluteUrls, where the real 2025
change missed 2 of its 3 caller files and axios needed two follow-up PRs (#6810, #6814).
Blind-replayed 4× per arm: all 8 cells covered both missed files with 0 structural
regressions — with or without codeweb. On a 3-caller single-package change, a capable
agent's grep saturates; the historical miss does not reproduce, so ambient context is
bounded near zero on this task shape. The run proves the instrument (leak-free,
fixed-function grading, ambient engagement verified in every treatment cell — the card's
caller list matched ground truth exactly) and shows guarded mining makes true breakage
tasks RARE: 2 of 3 v1 tasks and the only new candidate died under scrutiny. Discriminating
between the arms needs many-caller cross-package tasks or cost-to-coverage metrics —
recorded as the corpus growth path. Full data:paper/results/replay-ab{,-raw}.json.
codeweb v0.7.1
Fixed
- README screenshots crop to content. The regenerated shots were uniform full-page
frames — squeezed into README boxes, the matrix rendered ~170px wide and the blast
shot's inspector was unreadable.scripts/screenshot.mjsnow crops each frame to what
it shows: the graph to its drawn bounding box, the blast shot to the LIT selection
(tracked from the draw pass) + inspector at a tighter zoom, the matrix to its table +
legend. README display sizes and the stale corpus line ("274 symbols across 8
domains" → the real 334/11) synced; shots remain one-command regenerable.
codeweb v0.7.0
Changed (the report finally looks like the product it is)
- A validated color system replaces generated hues. Area colors were
hsl(i × 137.5°)—
unbounded spun hues; the treemap ramped green→red at full saturation (measured deutan
ΔE 2.2 — invisible to red-green-deficient viewers). Now: a fixed-order 8-slot categorical
palette validated against the actual dark surface (worst adjacent ΔE 8.4 protan / 19.3
normal, all ≥3:1; 9th+ areas fold to neutral), a single-hue slate→red lightness ramp for
duplication density (with an on-canvas legend), reserved status colors for finding
severity, and the brand lime demoted to what it should be: UI accent (selection, focus),
never a data series. - The graph is drawn like a product. Focus + context replaces expand-everything: every
area starts as a bubble and clicking one expands ITS symbols in place — the all-at-once
hairball is impossible unless explicitly asked for. Curved weight-scaled edges; node fills
with darker same-hue rings; halo labels in the real UI font (the canvas font stack fell
back to a serif before); the tangle color only appears where it means something; search
reveals a hidden symbol's area instead of saying "no matches"; positions persist across
expansions; layout is seeded — the same repo always draws the same map. - Treemap/matrix polish: cell gaps + rounded corners, styled area headers with color
chips, readable in-cell numbers (they were dark-on-dark), chip legends instead of prose. - First paint earns its pixels: the inspector opens with the repo overview (largest
areas, findings counts, how-to-read) instead of "Pick an item"; engine jargon moved out
of the masthead into a tooltip; a logomark anchors the header. - Deterministic demo shots (
scripts/screenshot.mjs): staged states (top hotspot
selected, its area expanded, inspector populated) at 2× retina with fixed framing — every
committed screenshot (assets/screens/) regenerates from the real report in one command.
The live demo (docs/demo/) rebuilt on the new template.
codeweb v0.6.0
Added
- The local outcome ledger (
scripts/stats.mjs,npm run stats): codeweb now counts what
it actually does during real work — session briefs injected, pre-edit cards delivered,
post-edit checks run, regressions flagged before landing, queries served, auto-refreshes —
written by the hooks and the MCP server beside the graph (stats.json). Strictly local
(never transmitted; counter names + integers only;CODEWEB_NO_STATS=1disables), fail-open
by construction. The brief carries a one-line receipt ("codeweb this month: …") — the value
made visible where it accrued.
Research
- Evidence program moves into the product (
paper/STATUS.md): the manuscript is frozen as
a reproducible artifact; claims live in the site's evidence ledger + these Research notes. - Replay benchmark (
paper/experiments/replay-mine.mjs+replay-ab.workflow.js): mine
git history for commits that changed a depended-on signature and provably missed caller
files a later commit had to fix — each hit is a task with a built-in answer key (no invented
tasks, no floor effect). First verified mining run on axios (1,647 commits, funnel reported
at every stage): 2 ground-truth tasks, e.g.forEach— 9 caller files, 8 missed, fixed in a
follow-up. The replay workflow runs control vs ambient codeweb over the mined set, graded on
historical-miss coverage + the deterministic gate.
codeweb v0.5.0
Added (fewer mistakes per token)
- Day-one briefing (
codeweb_brief, 24th MCP tool +scripts/brief.mjs+ a SessionStart
hook): one ~2KB page — areas with summaries, the most depended-on symbols, entry points
(heuristic), test layout, known issues — injected automatically when a session starts in a
mapped repo. Replaces the first 20-50k tokens of exploratory orientation with pre-computed
answers; served in-process from the cached graph. - Caller-reliance contracts (
lib/reliance.mjs): the explain card (and therefore the
pre-edit hook, which embeds its summary) now reads the actual call sites and says what
callers depend on — destructured/member-accessed result fields ("callers use {timeout,
retries} — keep those"), awaited fraction, and the argument-count range in use. Targets the
most common breaking edit: changing a return shape a caller still destructures.
Conservative: only call-site-line patterns count; no sites → no claim. - Confidence calibration (extractor v10): symbols reachable from a package entrypoint
(package.json main/module/browser/bin/exports, followed through named + star re-export
chains) are stampedpub— "0 in-repo callers" on a public symbol now answers with
"⚠ public API — external callers likely; renames are breaking" instead of false confidence.
Files using dynamic dispatch (computed member calls, getattr, non-literal require, emitters)
are recorded inmeta.dynamic, and empty callers/dependents answers cite them ("absence of
callers is weaker evidence"). Confident answers stay caveat-free — no noise.
Research
- H18-v2 prepped (
paper/experiments/agent-ab2-ambient.workflow.js+agent-ab2.README.md):
the agent A/B rerun as one funded command — v1's null was a floor effect (both arms ~0
regressions on easy tasks), so v2 pre-registers hard tasks (graph-verified fan-in ≥ 5 /
shape changes) and an AMBIENT treatment arm mirroring what the hooks now inject (brief +
explain cards with reliance/caveats — context delivered, not offered). The analyzer takes
raw/out paths so v1 results stay frozen.
codeweb v0.4.0
Added
- Java + C# on the deterministic fast path (extractor v8): class/interface/enum/
record/struct discovery with visibility-as-export, owner-qualified method ids
(constructors included), Allman-brace + expression-bodied members (C#),extends/
base-list inheritance edges, control-flow phantom guards, Maven/Gradle test-layout
and*Test.java/*Tests.csrole detection, and pom.xml / build.gradle / .csproj
package boundaries. Verified on square/javapoet (497 symbols, 0 phantoms, 0.7s) and
restsharp/RestSharp (1,542 symbols, Allman style, 0.9s). Method-dispatch recall
(obj.Method()) stays precision-gated as in the JS regex tier — a tree-sitter tier
for Java/C# is the next increment.
Added (recall ceiling + ambient loop)
- Tree-sitter tier default-on when web-tree-sitter is installed (
--engine regex
opts out; absent dependency degrades to regex byte-identically). Class-field arrow
methods survive the AST handoff. - Barrels are dependents (the measured recall gap):
export { X } fromedges the
barrel's<module>to the resolved symbol;export * fromchains resolve
transitively AND edge the barrel to the target module. Oracle A/B moved from
recall 0.94 to 1.00 (precision 0.94 vs grep 0.87) on both the fixed and a
fresh-seeded 30-task sample. - Ambient loop: the pre-edit hook now injects the ~1KB explain card (identity, top
callers, tests) instead of a pointer — blast radius arrives with zero agent
discipline; the MCP server auto-refreshes a stale graph inline (~1s incremental,
throttled, CODEWEB_NO_AUTOREFRESH=1 opts out) before structural queries, and
per-DIRECTORY mtime stamps make brand-new files trip the staleness check (per-file
stamps cannot see a file that didn't exist).
Added (the proof, the surfaces, the last query family)
codeweb bench(scripts/bench.mjs,npm run bench): the oracle A/B packaged as a
one-command benchmark on YOUR repo — context cost per dependents task + blast-radius cost
always; recall/precision graded by the TypeScript LanguageService whentypescriptis
resolvable; ripgrep optional. The engine moved verbatim intoscripts/lib/bench-core.mjs
(the paper experiment is now a thin wrapper over it — reproduction against the committed
canonical run is byte-identical), so published numbers and user-generated numbers can
never measure different things.- The gate now posts its review:
ci-gate --mdrenders the structural delta (blocking
regressions, new cycles/duplications, symbols that lost all callers, renames-not-churn)
as a budgeted digest and thecodeweb gateworkflow posts/updates it as a sticky PR
comment on pass AND fail — visible where reviewers already look, verdict unchanged. - Editor CodeLens (
editor/vscode-codeweb): zero-dependency VS Code extension showing
N callers · blast Mabove every mapped symbol from the nearest.codeweb/graph.json
(identical semantics tocodeweb_callers/codeweb_impact), click-through to
report.html#s=<id>. codeweb_find— concept search (23rd MCP tool +scripts/find.mjs): free text
("where is retry handled?") → ranked symbols, deterministically — camelCase/snake_case
token match with light stemming over identifiers/files/domains, weighted by exports,
role (tests only when asked for), and fan-in. Served in-process from the cached graph,
budgeted, staleness-annotated. Closes the last gap: every other query tool needs a name;
this one turns an idea into the right starting symbol.
Research
- Oracle A/B (
paper/experiments/oracle-ab.mjs, results in
paper/results/oracle-ab.json): dependents-discovery graded by the TypeScript
compiler's own reference finder over 30 seeded vite symbols — codeweb recall 0.94 /
precision 0.89 at 1/3 of an idealized grep's context cost (0.8KB vs 2.5KB per
task); blast-radius ("what transitively breaks") in one ~1KB call vs a recursive
grep loop's ~130KB (126× on the canonical run, simulated generously for grep). Mechanical and
reproducible — complements (does not replace) the frozen frontier-agent pilot,
whose run stays the evidence for agent-loop behavior (+0.27 recall, ~44% fewer
tokens). The 6/30 under-recalled symbols are the known dispatch/re-export gap.