Single source of truth for which upstream (colby) version this Rust port is faithful to, and what has been ported / evaluated. The
colby-upstream-syncskill reads this first and updates it last. This is the project's memory — a good entry stops the next sync from re-investigating the same change.
-
Tracked colby release:
v1.6.1. All portable in-scope behavior audited through that release is closed: ported, already present, recorded N/A, or deferred by the owner, as the 2026-10-01 CLOSEOUT entry below lists. The official codegraph-rsv0.51.0binaries passed the release smoke recorded there. -
Last discovery audit: the
v1.6.1tagf4ddf508516332419ea3c95702810765936cf679, audited on 2026-09-30 inV1_6_1_AUDIT_2026-09-30.md: 113 commits from the previous boundary, 111 of them non-merge. -
Previous discovery boundary:
3ed73bc127323e63153bf6ec8354afa82ce36aaf(the 2026-09-15 main audit,POST_V1_6_MAIN_2026-09-15.md). -
Next discovery starts here:
f4ddf508516332419ea3c95702810765936cf679..origin/main. Do not re-triage the auditedv1.6.1range. -
Upstream repository: https://github.com/colbymchenry/codegraph.
-
Shipped in codegraph-rs
v0.52.0, 2026-10-01:- #286, which makes a full
synckeep whatindexkeeps; - #288, symlink following (#935, #770);
- #289, the #1878 git fast path for pending status.
This closes the two
v0.51.0exceptions, #770 and #1829/#1878. See the dated entries below, including thev0.52.0release record. - #286, which makes a full
-
Shipped in codegraph-rs
v0.52.1, 2026-10-01:- #291, the four port defects found by the retroactive review of the
v1.6.1port PRs, with extraction version 18; - #292, the Rust 1.98.0 toolchain and MSRV.
See the dated entries below, including the
v0.52.1release record. - #291, the four port defects found by the retroactive review of the
-
Shipped in codegraph-rs
v0.52.2, 2026-10-02: #295, five KEEP-RUST resolution divergences that fix the findings the retroactive review had kept at upstream behavior, with extraction version 19. See the dated entries below, including thev0.52.2release record. -
Shipped in codegraph-rs
v0.53.0, 2026-10-03:- #298 and #300, the browser viewer (UI family phase 1) behind
CODEGRAPH_UI=1, drawn to direction D with a light theme; - #303, which makes
syncre-resolve every edge a same-named candidate's arrival, departure or in-place change can move, so it equalsindex --forceagain; - #280's dependency updates, with extraction version 20.
See the dated entries below, including the
v0.53.0release record. - #298 and #300, the browser viewer (UI family phase 1) behind
-
Shipped in codegraph-rs
v0.53.1, 2026-10-03: #307, four KEEP-RUST resolution gates for Rust method calls whose receiver the extractor dropped, with extraction version 21. See the dated entries below, including thev0.53.1release record. -
Shipped in codegraph-rs
v0.53.2, 2026-10-03: #310, mimalloc as the global allocator of the static musl Linux builds. It is a release-build fix, not an upstream port, and changes no graph output. See the dated entries below, including thev0.53.2release record. -
Shipped in codegraph-rs
v0.53.3, 2026-10-03: #314. The kind column ofsearch,callers,calleesandimpactis padded the way upstream pads it, and the store tests' lock probes use their caller's bound. It is a parity fix, not an upstream port, and changes no graph or JSON output. See the dated entries below, including thev0.53.3release record. -
UI family, phase 1 (browser viewer): started after the owner selected the Penpot direction D design on 2026-10-02. The viewer — the
codegraph-uiserver over upstreamv1.6.1'sui/frontend, behindCODEGRAPH_UI=1as upstream gates it — is ported, restyled to direction D with a light theme, and shipped inv0.53.0; see the 2026-10-02 and 2026-10-03 viewer entries below. The graph-semantic families F1–F12 that shipped beside it (framework navigation edges and routers, the synthesis layer and its schema, cross-tier channels, server route naming, the explore Flow, the React Native bridge) remain deferred, scheduled as phases 2–4: F10/F11 first, then F1–F6 with Screens and Steps, then F7–F9 and F12.
The Rust product and upstream release versions are independent. This Current alignment block is the only place that states release parity; dated log entries below remain immutable historical evidence.
1.6.0 → 1.6.1 sync: COMPLETE (codegraph-rs
v0.50.3→v0.51.0). Every audited portable, in-scope behavior landed in six porting PRs (#275, #277–#279, #281, #282) on the #271 engineering baseline, and the officialv0.51.0binaries passed the release smoke in the 2026-10-01 CLOSEOUT entry below. The explicit exceptions are:
- The UI family is DEFERRED — the viewer and F1–F12, by owner decision (2026-10-01); see Current alignment above and the audit's re-triage table.
- #770 symlinked-directory watching was DEFERRED at
v0.51.0: the scan did not follow symlinks, so a watcher that did would have watched what was never indexed. It landed afterwards in #288, together with the #935 scan port; see the 2026-10-01 symlink entry below.- #1829 / #1878 git-stamped pending status was a full inventory at
v0.51.0, with the fast path deferred pending a measurement. The fast path landed afterwards in #289; see the 2026-10-01 pending-status entry below.- KEEP-RUST divergences are recorded row by row in the audit — among them a parameter-pack constructor declines its overload set (upstream admits it unbounded), a self-closing
<sqlMap/>is never a statement-map root, and athis.a.b.m()chain keeps its last segment. Three more came out of the retroactive review, in #291: a store initializer's own calls stay with the store, an explicitexport default NAMEbinding beats an exported component, and a trim note never claims that gap markers name every elided symbol. See the 2026-10-01 retroactive-review entry below. Five more, in #295, fix the findings that review had kept at upstream behavior: Zustand provenance for every store-action form, no unique-name guess for an unknowable receiver, three-valued whole#ifexpressions, whole-file include guards only, and literal paren constructions pastinitializer_listoverloads. See the 2026-10-02 entry.- The
1.5.0 → 1.6.0and older caveats below carry forward unchanged.
1.5.0 → 1.6.0 sync: COMPLETE (codegraph-rs
v0.48.2→v0.50.1). Every audited portable, in-scope behavior landed across the four waves, and the final official binary passed the release smoke described in the 2026-08-31 CLOSEOUT entry below. The explicit exceptions are:
codegraph contextremains DEFERRED — the deterministic context engine already exists asexplore; no external compatibility requirement has justified a second public output contract.- #1617 custom Lua module loaders remain DEFERRED — this is project-specific configurable synthesis and still lacks a real target project plus deterministic path/root contract.
- The older
1.4.1 → 1.5.0and1.2.0 → 1.4.1caveats below carry forward unchanged.
1.4.1 → 1.5.0 sync: COMPLETE (codegraph-rs
v0.42.1→v0.42.4). Every portable, in-scope behavior in that range has landed (see the 2026-08-02 CLOSEOUT entry below). Tracked parity is1.5.0with the following recorded caveats — this is "faithful to 1.5.0 for all portable in-scope behavior, with these explicit exceptions," not byte-for-byte everything:
- 26 DEFER items remain deferred — 19 resolution/store/synthesis perf strategies plus 7 sync/WAL scheduling strategies, all tuned to upstream's Node /
node:sqliteruntime (pool sizing, cgroup cache credit, macOSvm_statbudgets). They are byte-identical to graph output, so not parity blockers; re-derive each from a Rust profile before porting rather than transcribing upstream's constants.2adc7f6(WAL truncate only at parked barriers) flips from a perf item to a CORRECTNESS item the moment timer-triggered truncation is adopted here.0682137is N/A (packaging-rooted) — we ship a nativecodegraph.exe, never a.cmdshim, so writingcodegraph.cmdwould name a nonexistent file.- Both formerly-open triaged issues have SHIPPED — #1495 Kotlin callable signatures in
v0.42.6(a documented DIVERGENCE from upstream, not a port), and #1482 / #1482b TS export-alias resolution plus.js→.tsspecifier substitution inv0.42.8. Both are golden-affecting and carry new fixtures; see the 2026-08-04 entry.- The
1.2.0 → 1.4.1caveats below all still hold and carry forward unchanged.
1.2.0 → 1.4.1 sync: COMPLETE. Every portable, in-scope behavior in that range has landed (see the 2026-07-17 CLOSEOUT entry below). Tracked parity is
1.4.1with the following recorded caveats — this is "faithful to 1.4.1 for all portable in-scope behavior, with these explicit exceptions," not byte-for-byte everything:
- Framework-resolution bridges deferred per-language — ArkUI dispatch (ArkTS), Nix module-system synthesis, Terraform module-boundary wiring, Erlang OTP behaviour/gen_server/spawn-MFA bridging, CFML
<cfscript>-in-tag/cfquery/receiver-type resolution. The port keeps its single concreteFrameworkResolver(GodotResolver); extraction for all these languages is fully ported.- COBOL and VB.NET permanently deferred — no usable
tree-sitter-cobolcrate on crates.io (name-squat stub) and notree-sitter-vbnet/-vbequivalent at all; adding either would require vendoring a git grammar, which violates this project's no-vendored-grammar invariant.- Prompt-hook telemetry excluded by policy — the confidence-gate mechanics (#1126/#1136/#1138/#1144-1146) landed; all telemetry/usage-counter code was deliberately not ported (this project has no tracking pipeline).
- TS/Node-only items are N/A — event-loop yield points, npm/bundled-Node lifecycle steps, and other TypeScript-runtime-specific fixes have no Rust analogue and were recorded, not ported.
Note: the two version numbers are independent. This line is the only place that records colby parity — do not infer it from
Cargo.toml.
Release-please PR #315
merged as 81bd7c711bb6fd680113f2a946e927d488c566d6, and tag v0.53.3 was cut
at that exact commit.
- The merge has the tree of the PR's head
b2f83bd,7e2db71…. - The owner re-ran the bot's CI run and approved the PR as code owner.
- The implementation PR #314 merged as
72eefae, with the tree of its reviewed head603286d. The kirocodex review passed in round 1, with no blocking items.
Release workflow run
37143381806
passed all twelve jobs on its first attempt.
- It ran over main CI run
37143381765, whose requiredCI Successpassed. - That run's informational Coverage job failed once, in
git_pending::tests::a_system_attributes_file_is_a_conversion_risk; see the entry on stand-in executables below. - The release was published at 2026-10-03T18:25:40Z UTC.
- The official
codegraph-0.53.3-x86_64-unknown-linux-musl.tar.gzdigest is769ca112ff554a82b9eabadabc11fa2f0322a40430e875244244a749e3330427.
Black-box acceptance of the downloaded release, against the official v0.53.2:
- Artifacts.
SHA256SUMSandgh attestation verifypassed for all six archives. The binary reportscodegraph 0.53.3, and its.commentsection names rustc 1.98.0. - The kind column. On the mini fixture,
v0.53.2printsfunctionadd;v0.53.3prints the kind padded to twelve columns in all four commands, for examplefunction runDemofromcallers. - JSON and graph. The
--jsonoutput of all four commands andcodegraph exportare byte-identical tov0.53.2's. - Index. An index built by
v0.53.2reportscurrenttov0.53.3; the extraction version is unchanged.
Not an upstream port: a parity fix. Upstream's CLI prints
node.kind.padEnd(12) before the name (src/bin/codegraph.ts at v1.6.1).
The Rust rows use the same {:<12}{} layout, but NodeKind's Display wrote
its name with write_str, which ignores the formatter's width, so search,
callers, callees and impact printed the kind and the name run together.
#314 makes NodeKind, EdgeKind, Language and ReferenceSubkind format
through Formatter::pad. Output written without a width is unchanged:
to_string(), --json and the index.
The same PR fixes the cross-process lock probes in the store tests. A probe
always tried the lock with an 80 ms deadline, whatever bound its caller passed.
The deadline was set before the child opened and validated the lock file, so on
a slow Windows runner a probe of a free lock reported TIMED_OUT, as it did on
main's CI at c03fcbd. Probes now take the caller's bound.
Not an upstream port. Three tests write a shell script and run it at once:
git_pending's fake git, git_pending_fast_path's hanging git, and cli_ui's
stand-in browser. When another thread of the same test binary forks while the
script is still open for writing, the child keeps the inherited descriptor until
it execs, and running the script meanwhile fails with ETXTBSY.
- The failure. Main's Coverage job on
81bd7c7failed this way:gitread the failed start as a failed git, andconversion_riskreturnedNone. - The reproduction. On Linux, 8 threads forking
/bin/truemade 313 of 3,000 fresh scripts fail to start. Starting each script once, retrying while the error isExecutableFileBusy, left 0 failures in the 7,500 starts that followed. - The fix. #317 (merged as
aef4efb) adds that warm-up to the three helpers. The hanging git now usesexec sleep 30, and its test checks that the 300 ms timeout actually elapsed; before, a failed start could make the test pass without the timeout ever running.
Release-please PR #311
merged as 0b97144c3bc3c45b07aa07206dc73443030f4d36 and cut tag v0.53.2 at
that exact commit, with the tree of its head f4e3103. The bot's CI run was
re-run by the owner. The implementation PR #310 merged as a52a64c, with the
tree of its reviewed head 9bbf9be; the kirocodex review passed in round 2
(1 → 0).
Release workflow run
37118263946
passed all twelve jobs on its first attempt, over main CI run
37118263952.
Its two musl build jobs compiled mimalloc's C through zig. The release was
published at 2026-10-03T11:14:07Z UTC. The
official codegraph-0.53.2-x86_64-unknown-linux-musl.tar.gz digest is
b4d55e4c998568877c0afc1032e05304e16cc1b55dd5626665d2154ee414c6d4.
Black-box acceptance of the downloaded release, against the official
v0.53.1:
SHA256SUMSandgh attestation verifypassed for all six archives. The binary reportscodegraph 0.53.2, and its.commentsection names rustc 1.98.0.- Allocator: both Linux binaries are statically linked and contain
mimalloc. The macOS and Windows binaries contain no
mimallocstring. - Speed: on the archive of
d26df90, three runs at 32 threads took 8.11–9.19 s againstv0.53.1's 110.1 s, 12.0–13.6× faster. Each was also faster than the same binary's 13.25 s at 4 threads. All eight timed runs exited 0 and produced the same graph. - Graph output: nodes, edges, unresolved references and file rows are
identical to
v0.53.1's.
Not an upstream port. The official Linux archives are static musl builds, and
indexing with them got slower as threads were added. musl's allocator
serializes threads, while extraction and resolution allocate in parallel
through rayon. On the owner's go-ahead the same day, #310 makes mimalloc the
global allocator on target_env = "musl" only:
- the
mimalloccrate 0.1.52 with featurev2, which bundles mimalloc 2.3.2 (MIT); - a target-gated dependency, so glibc, macOS and Windows builds keep their system allocator and their dependency graph;
- one
#[global_allocator]static in the shipped binary, which is also the daemon.
Why v2. With its defaults, v3 peaked at 740–750 MB at 32 threads. The crate exposes no feature for the settings that lower it, and a shipped binary cannot rely on environment variables. v2 peaked at about 500 MB with no tuning.
Measurement. The corpus is an archive of d26df90 (689 files, viewer
bundle excluded). The command is codegraph init with RAYON_NUM_THREADS set,
on a 32-core Linux host, with the Release workflow's toolchain (zig 0.15.1,
cargo-zigbuild 0.23.0, rustc 1.98.0). Each figure is wall time and peak RSS
from /usr/bin/time. Each cell is one run, except #310 at 32 threads, which
ran three times.
Every timed run had to exit 0 and produce the same complete graph (141,628
canonical rows, hashed after each run).
| threads | v0.53.1 (musl) |
#310 (musl) | local glibc build |
|---|---|---|---|
| 32 | 122.2 s / 249 MB | 7.98–8.42 s / 497–506 MB | 5.20 s / 354 MB |
| 4 | 68.1 s / 195 MB | 12.8 s / 252 MB | 12.1 s / 227 MB |
| 1 | 50.6 s / 188 MB | 36.0 s / 218 MB | 38.3 s / 200 MB |
Graph output is unchanged. Nodes, edges, unresolved references and file rows
match v0.53.1's over every non-timestamp column, so there is no
extraction-version bump and no golden change. Both musl targets were built
locally with that toolchain before merge; the aarch64 binary was built but
not run.
Review. The plan passed the kirocodex plan gate in round 2 (1 → 0); round 1 asked for the Chinese README mirror. The diff review passed in round 2 (1 → 0). Round 1 found that the timing harness could report a failed run as a time. The numbers above come from the fixed harness, which was shown to stop on a failed run, a missing index, and a different graph.
Release-please PR #308
merged as 4a6c21b1505af676248f731cf3738bdb0e700cc2 and cut tag v0.53.1 at
that exact commit, with the tree of its head 8c67fa4. The bot's CI run was
re-run by the owner. The implementation PR #307 merged as f9f96c3, with the
tree of its reviewed head ec1bf0f; the kirocodex review passed in round 2
(1 → 0).
Release workflow run
37104659922
passed all twelve jobs on its first attempt, over main CI run
37104659935.
The release was published at 2026-10-03T07:08:57Z UTC. The official
codegraph-0.53.1-x86_64-unknown-linux-musl.tar.gz digest is
f18521f187234d398627cfa69c4d8750c45d7e9600ecc7fd44377cd8caaaeabc.
Black-box acceptance of the downloaded release, against the official
v0.53.0:
SHA256SUMSandgh attestation verifypassed for all six archives. The binary reportscodegraph 0.53.1, and its.commentsection names rustc 1.98.0.- R2/R3:
root().join(name)beside the project's onlyjoinmethod bindsrootandLineIndex::joinunderv0.53.0, and onlyrootnow. - R1: a bare
helper()whose only namesake isStore::helperbinds that method underv0.53.0, and nothing now. - R4: an import-free
Err(1)besideenum Outcome { Ok, Err }bindsOutcome::Errunderv0.53.0and nothing now. Withuse crate::outcome::Outcome::Err;in scope,Err(2)binds it in both. - Upgrade: an index written by
v0.53.0(extraction 20) readsoutdatedand becomescurrentafter onesync.
On 2026-10-03 the owner asked for the cause of join, iter and as_str
topping this repository's most-called lists to be fixed where it is
statically decidable. The design passed the kirocodex plan gate in round 4
(6 → 1 → 1 → 0).
Cause. extract_call keeps a Rust receiver only in these cases:
- an identifier;
self;- one
self.<field>hop; - a
path::call()receiver.
Every other receiver leaves the bare method name: a plain call root(), a
deeper field chain, vec![…], ?, .await, indexing, or a chain broken
across lines. Upstream's tree-sitter.ts does the same. Resolution then treated
root().join(name) as a bare call, and the project's only join method won at
exact-match 0.9. That method is LineIndex::join, so 964 calls from 169 files
landed on it.
Upstream has no Rust counterpart to its JS/TS gates (#1987, #1714/#1857,
#1683). These rules are stricter than upstream v1.6.1 (f4ddf50):
| rule | a Rust calls ref |
binds |
|---|---|---|
| R1 | with neither receiver nor path (helper()) |
never a method |
| R2 | whose receiver was dropped (root().join(x)) |
only a method, never through use, never by a fuzzy guess |
| R3 | whose receiver was dropped, named in RUST_STD_METHODS (307 std names) |
nothing |
| R4 | bare Ok / Err / Some / None |
a project enum variant only when a use naming it, or a glob, is in its own block and module |
Shape. It is read from the source. The ref's column is the call
expression's start, so a bare call starts with its name. A dropped receiver
starts with something else, and its .name( follows within 4 KiB. An unknown
shape (no source, or a column off its line) keeps the old behaviour.
Measured on an archive of 6cc9507: old binary 0.53.0, new binary this
change, bundle excluded both times.
- 3,284 edges removed, each attributed to one rule: R3 2,743, R1 296, R4 193, R2 52.
- A hand review of 20 removed edges per rule found every one false.
- 48 edges added where a filtered candidate gave way to the right one. In 24 of
them a bare
node(…)now reaches the free fn instead of a same-named method. In 13,.extract(…)reachesFrameworkResolver::extractbecause R2 brought the candidates under the ambiguity ceiling. - 451 Method-shaped edges with project-specific names survive. About a third
of a 20-edge sample are third-party crate methods (
is_match,body) or a std type outside the list (SocketAddr::port): the known limit of a std list. - No golden of any corpus moved, and
syncafter movingLineIndex::joinequalsindex --force.
Release-please PR #299
merged as 2ca1fabb32cece7af4e6d337b9bf6cc0ba946ab5 and cut tag v0.53.0 at
that exact commit, with the tree of its head a9f3054. That head brought main
in through gh pr update-branch, so the release PR's CI tested the shipped
tree. The implementation PRs merged from their reviewed heads with identical
trees: #298 as 143752a, #300 as fee9ae7, #303 as a35e065.
Release workflow run
37094204307
passed all twelve jobs on its first attempt, over main CI run
37094204330.
The release was published at 2026-10-03T03:56:56Z UTC. The official
codegraph-0.53.0-x86_64-unknown-linux-musl.tar.gz digest is
b46c8d3cc37161a333daa53f4258727aae13de78fd37e315214451b5ac52d50f.
Black-box acceptance of the downloaded release, against the official
v0.52.2:
SHA256SUMSandgh attestation verifypassed for all six archives. The binary reportscodegraph 0.53.0, and its.commentsection names rustc 1.98.0.- Viewer gate: without
CODEGRAPH_UI=1,codegraph uiexits 1 with upstream's "not in this release yet" refusal. - Viewer: with it,
ui --read-only --port 0serves/under a CSP that allows fonts from'self'only,/api/statsnames the project, and/api/trailsanswersreadOnly: true. All 16 files of the bundle committed atv0.53.0are served byte-for-byte, so the build accepted in #300 is the one that shipped. Its CSS carries the Daylight tokens and its JS thecodegraph-ui.themechoice. - #303: a Rust project's
readcalls its ownokbeside a JavaScriptvar ok. Excluding the JavaScript file and syncing leavesread → okat confidence 0.4 underv0.52.2;v0.53.0gives 0.9, asindex --forcedoes. - Upgrade: an index written by
v0.52.2(extraction 19) readsoutdatedand becomescurrentafter onesync.
The imported frontend README described upstream's npm monorepo: its build, the
@colbymchenry/codegraph-ui package and its publishing, and engine files under
src/. It now describes this repository: make ui and make ui-check, the
committed bundle the crate embeds, the Rust files behind the server and the
engine, and what the Rust server does not send yet. Its frontend-design sections
are upstream's, with their paths, numbers and claims checked against this tree.
A later sync of upstream ui/ keeps this README rather than taking upstream's.
The ported viewer's frontend now carries the design the owner selected
(../design/viewer-d.md, direction D) on top of the
v1.6.1 import: tokens, type, shell, view layouts, states, responsive layouts
and a second, light token set (§3.6). This is codegraph-rs's own design, not an
upstream change: the wire contract, the routes and the server are untouched, and
the frontend's models keep upstream's behaviour — only the layout constants the
components measure against moved, each pinned by name in the suites.
A later sync of upstream ui/ therefore re-applies this layer rather than
taking upstream's paper/ink look. The visual differences from the boards, and
from upstream where they matter, are listed in ../ui.md under
"Direction D as built".
The viewer upstream ships in v1.6.1 — src/ui-server/** (the loopback JSON
API) and ui/ (the Svelte 5 frontend) — is ported for the first time. Plan:
ui-viewer-phase1, gate PASS in round 4.
Re-audit of the baseline (2026-10-02): the latest stable upstream tag is
still v1.6.1 (f4ddf508516332419ea3c95702810765936cf679); upstream main is
172 commits past it and unreleased, so the viewer is ported at v1.6.1. The
families that feed it stay scheduled:
| phase | families | what the viewer gains |
|---|---|---|
| 2 | F10 explore Flow section, F11 branch guards | when conditions on Symbol and Flow links; explore leads with the same flow search |
| 3 | F1 navigates edges and fan-out refs, F2–F6 routers (Expo, Next.js, React Router, TanStack, Vue/Nuxt) |
the /api/screens walk past its early return, and /api/steps |
| 4 | F7 synthesis layer, F8 cross-tier channels, F9 server route naming, F12 React Native bridge | synthesized dispatch hops, cross-tier steps |
| upstream surface | Rust target | disposition |
|---|---|---|
ui/ frontend (v1.6.1:ui, tree 7e3b440035f6745c546e5b10d92eba31144406c2) |
imported verbatim into ui/ (MIT, ui/LICENSE), then one change: createHttpAdapter omits steps |
PORT |
src/ui-server/{index,security,static,assets,open-browser}.ts |
crates/codegraph-ui (server, security, assets, browser): loopback bind with port fallback, Host/Origin/method/write-marker checks, raw-path refusals, containment chokepoint, CSP, embedded bundle |
PORT |
src/ui-server/api/* — stats, search, node (+ hierarchy), nodes, source (+ highlight), file, filecode, routes, entrypoints, map, deadcode, flow, trails (+ trail-store), events |
crates/codegraph-ui/src/api/*, wire shapes, limits, error codes and refusals as upstream |
PORT |
src/graph/{dead-code,named-symbol-flow,symbol-lookup,type-hierarchy}.ts, continuationsFrom, src/extraction/syntax-tokens.ts |
codegraph-graph::{dead_code, named_symbol_flow, symbol_lookup, hierarchy, flow_boundary}, codegraph-extract::syntax_tokens; store SELECTs in codegraph-store::viewer |
PORT |
findDynamicBoundaries / shortlistBoundaryCandidates |
codegraph-ui::api::boundary over explore's own codegraph_mcp::dynamic_boundaries scanner |
PORT |
the events source watcher's notify-only syncFn |
codegraph_watch::WatchOptions::observe_only, additive |
PORT |
codegraph ui / web, viewer-gate.ts |
codegraph-cli ui command, gate before Cli::parse() |
PORT |
/api/screens walk, /api/steps, when conditions |
Screens answers upstream's own no-navigates early return; Steps is a JSON 404; conditions are absent — phases 2 and 3 (F1–F6, F11) |
DEFER |
countImplementers, buildTypeHierarchy's overrides: false |
used only by codegraph_explore |
N/A here |
CODEGRAPH_VIEWER_PATH |
the bundle is embedded in the binary | N/A |
KEEP-RUST, as this index holds the facts: an unresolved import is listed by the
binding it names, not the module specifier; routes come from this port's
resolvers (React, Vue, NestJS — not Express or Go); there are no synthesized
dispatch edges, so no dashed via … flow hop and no Go implicit
implementations in a hierarchy; the flow's directed walk sees every
(callee, kind) pair get_callees reports rather than one row per neighbour.
Tests port upstream's suites case by case: crates/codegraph-ui/tests/*.rs
(ui-server-api, ui-server, routes, ui-trails, ui-events-api,
ui-map-api, ui-flow-api, ui-filecode-api, the server half of
ui-entrypoints-api, the engine halves of type-hierarchy, dead-code and
ui-highlight), crates/codegraph-cli/tests/cli_ui.rs (cli-ui-command and the
gate), and ui/tests/ (the 17 frontend suites, the three mixed suites' model
cases among them). Golden extraction output is unchanged: no extraction,
resolution or schema change.
Release-please PR #296
merged as 36841bcd398ca0f9bd882a61075ef3a5708b957c and cut tag v0.52.2 at
that exact commit. Its implementation PR #295 merged as ff52e5c, from the
reviewed head 0d3a991 with an identical tree.
Release workflow run
36942112539
passed all twelve jobs on its first attempt, over main CI run
36942112580.
The release was published at 2026-10-01T23:54:19Z UTC. The official
codegraph-0.52.2-x86_64-unknown-linux-musl.tar.gz digest is
fc066b91ad587abd65cb602ccfde4b1a97b4d0dc5d97eff2813581638d25d62e.
Black-box acceptance of the downloaded release, against the official
v0.52.1, follows the table the plan for #295 fixed in advance:
SHA256SUMSandgh attestation verifypassed for all six archives. The binary reportscodegraph 0.52.2, and its.commentsection names rustc 1.98.0.- Zustand provenance:
runcallsfake.getState().reset()on anotherFactorystore anduseStore.getState().reset()on acreatestore. Its call targets go fromfake::reset,useStore::resettouseStore::reset. - Unknown receiver:
pool.submit(self.store.fetch)with an unannotatedstoregives one reference edge into the onlyStore::fetchbefore and none now. #if 1 || FLAG: theHOOKcall edge, which a definitely visible macro now suppresses, is gone.- Feature-flag default:
#ifndef FEATURE/#define FEATUREamong other code is no guard, souse2now calls the realHOOK2, wherev0.52.1had no edge. - Literal paren construction:
L value(1)besideL(std::initializer_list<int>)now callsL::L, theL(int)definition;v0.52.1declined. - Upgrade: an index written by
v0.52.1reads asoutdated, because the extraction version moved from 18 to 19.syncrebuilds it, and it then readscurrent.
The 2026-10-01 retroactive-review entry below kept five review findings at
upstream behavior. On 2026-10-02 the owner asked for all five to be fixed
beyond upstream v1.6.1 (f4ddf50). Their design passed the kirocodex plan
review in round 3, with blocking items 6 → 1 → 0. Each item below is a
KEEP-RUST divergence: stricter than upstream, or more exact. The extraction
version moves to 19, so an index built at 18 is rebuilt.
| Finding | Upstream f4ddf50 |
Port |
|---|---|---|
| #277: store actions | matchStoreAccessorChain checks Zustand provenance for selectors only, so otherFactory(() => ({ reset() {} })).getState().reset() binds |
Every store-action form needs a Zustand factory on the initializer's call path to the action function. That path is read by the parser, following the same search that finds the actions. The factories are create, createStore and createWithEqualityFn from zustand, zustand/vanilla or zustand/traditional, the default import, or a namespace member. A selector also needs a hook factory. A wrapped hook such as createSelectors(create(...)) now binds its selectors. |
| #278: method values | "Unknown receivers retain the old unique-or-drop discipline" | An unknowable Python or Go receiver leaves the value unresolved, even when one project method bears the name |
#282: #if |
condition reads a literal, one defined test or a bare name |
The whole expression is evaluated three-valued, with C precedence. &&/` |
| #282: guards | guardsItself reads any #ifndef X followed by #define X (empty) or #define X( as a guard and forces the branch active |
Only a whole-file include guard counts: the test is the first code line, the next directive is an empty #define X, and the matching #endif, with no #else/#elif at its depth, is the last code line. A feature-flag default and a fallback #ifndef MIN / #define MIN(a, b) stay undecided and keep the call. |
| #282: constructors | any constructor mentioning initializer_list declines the set |
T x(<literal>, ...), with no { in the arguments, drops the constructors whose first parameter is the list; a literal never converts to one. The rest compete by arity. Every other form still declines. |
Each fix was red first; the logs are in /tmp/evidence-p10/red-*.log.
Release-please PR #293
merged as 9ca7f9716de38828562295cdc79a3b5a99b52738 and cut tag v0.52.1 at
that exact commit.
Release workflow run
36879201833
passed all twelve jobs on its second attempt.
- First attempt: the exact-SHA CI gate failed. On main CI run
36879201821, Windows Clippy could not start sccache, because the Actions cache backend answered 503 (Egress is over the account). The release stayed a draft. - Second attempt: re-running that job passed, and the re-run gate then admitted the release. The six platform builds are from the first attempt.
The release was published at 2026-10-01T15:12:32Z. The official
codegraph-0.52.1-x86_64-unknown-linux-musl.tar.gz digest is
73bd59d46588467507152e2783cb06fd001187bc73f5a095b85708991326863d.
Black-box acceptance of the downloaded release, against the official
v0.52.0:
SHA256SUMSandgh attestation verifypassed for all six archives. The binary reportscodegraph 0.52.1, and its.commentsection names rustc 1.98.0, wherev0.52.0names 1.96.0.- Vue: two same-name functions on one line of a script block index as two
rows;
v0.52.0kept one. - Store initializer:
useStore = create(persist(..., { storage: createJSONStorage(...) }))callscreate,createJSONStorageandpersist;v0.52.0recorded no call. - Default binding: in a React
.jsmodule,consumecallsuploadthroughexport default Api;v0.52.0made it call the componentScreen. - Trim note: a windowed explore says gap markers name elided symbols "only where room allowed".
- Upgrade: an index written by
v0.52.0reads asoutdated, because the extraction version moved from 17 to 18.syncre-extracts it, and it then readscurrent.
The owner asked for a kirocodex review of the large PRs that merged before
large changes needed one. The goal gate reviewed each merged commit against its
parent at high effort, with the PR description as the claims under review.
Then every blocking item was checked against main (c00aa2b) and upstream
v1.6.1 (f4ddf50).
| PR | Verdict | Blocking items | Outcome |
|---|---|---|---|
| #271 | PASS | 0 | — |
| #275 | PASS | 0 | — |
| #277 | FAIL | 2 | one fixed, one kept at upstream behavior |
| #278 | FAIL | 4 | two fixed, one kept at upstream behavior, one about evidence only |
| #279 | PASS | 0 | its one defect, the full-sync scope, was already fixed by #286 |
| #281 | FAIL | 1 | fixed |
| #282 | FAIL | 3 | all three kept at upstream behavior |
Fixed in #291, extraction version 18:
- #1349 gap. The Vue extractor mints its own script-block functions and
still called
generate_node_iddirectly. Two same-name declarations on one line therefore shared an id, and the store kept one row. Upstream reaches its allocator by delegating Vue scripts to its tree-sitter extractor. The port now usesNodeIdAllocatorthere, with the same block-relative line and UTF-16 column. - KEEP-RUST: a store initializer's own calls stay with the store. After
#277, an exported store's inline actions were function nodes, and the rest of
the initializer went unwalked.
create,persistand their options' calls were lost; the port had recorded them before #277. Upstream skips the initializer the same way (membersExtractedSeparately). The walk now skips only the extracted action values, and it treats the factory closure as the store's body, so a curriedcreate<S>()(...)mints no function named after the store. - KEEP-RUST: an explicit
export default NAMEbinding beats an exported component. The React resolver mints component nodes inside.jsand.tsmodules. Upstream's lookup (defaultComponent ?? defaultExportBindingNode ?? defaultFnClass) bound a default import to the module's first exported component. In a module exportingfunction Screen() { return <div /> }besideconst Api = { upload }; export default Api,Api.upload()became a call toScreen, and theuploadedge was lost. - KEEP-RUST: the trim note never claims that gap markers name every elided
symbol. A gap marker names what it hides only from the budget its file has
spare. The tail marker after a dropped or windowed cluster names nothing, and
a dropped file appears only in the pointer list. Both tiers' notes, like
upstream's (
tools.ts:1302,:7272), still said the markers named what was elided. They now say the markers name what room allowed.
Kept at upstream behavior. Each of these review findings describes upstream's own design, and in each case the upstream source says why:
- #277:
.getState().member()binds for a store built by any factory, not only Zustand'screate. Upstream'smatchStoreAccessorChainchecks Zustand provenance only for selectors. The member must still sit in that holder's own object literal. A provenance gate would also dropzustand/vanilla, wrapped and locally re-exported stores. - #278: an unknown receiver falls back to a project-unique method name ("Unknown receivers retain the old unique-or-drop discipline"). This predates #278.
- #282:
#ifreads a literal, onedefined()or a bare name, so a compound condition is unknown and keeps the call.#ifndef Xfollowed by an empty#define Xreads as the guard idiom (guardsItself). Anyinitializer_listconstructor declines its overload set, because the reference carries arity, not the brace or paren form.
The fourth #278 item asked for an exact-head evidence artifact. #278 merged
after CI run 36798356332 passed on a tree-identical head.
Release-please PR #287
merged as 4986722e08feca1b39c0aa885eb608d608244e4d and cut tag v0.52.0 at
that exact commit.
Release workflow run
36854318561
passed all twelve jobs:
- release-please, the source gate, and the tag check;
- the exact-SHA CI gate, over main CI run
36854318393; - six platform builds;
- asset attachment and publish.
The release was published at 2026-10-01T11:28:53Z. The official
codegraph-0.52.0-x86_64-unknown-linux-musl.tar.gz digest is
91668069f916e15330bd819a63d4d898ad7129657dbf18a78072f6b730732d09.
Black-box acceptance of the downloaded release:
SHA256SUMSandgh attestation verifypassed for all six archives, and the binary reportscodegraph 0.52.0.- #935: on the probe layout
{src/real/a.ts, src/afile.ts -> real/a.ts, src/linkdir -> real, src/extlink -> ../../outside/lib},initindexessrc/afile.ts,src/extlink/out.tsandsrc/real/a.ts, wherev0.51.0indexed onlysrc/real/a.ts. - #286: after
initandsync,.cache/a.tsis still indexed. - #1878: in a git repository, an edit committed after
initis reported bystatusas modified, and the git record is present. - Upgrade: an index written by the official
v0.51.0binary reads ascurrentunderv0.52.0, with nothing pending, andsyncreindexes nothing. The extraction version is unchanged.
Owner decision, 2026-10-01: port #1878's fast path. The design passed the kirocodex plan-convergence review in round 4.
#289 keeps the full inventory as the reference answer. A full build or full sync
records, under project_metadata key git_pending_state:
- the commit it started at;
- every path that may differ from that commit: paths git reported dirty, rows whose stat moved during the build, and paths a fresh scan and the database disagree on.
Incremental syncs add the paths they handle. status then classifies only git's
candidates plus the recorded paths, by the full inventory's own rules.
KEEP-RUST:
- One record, not two keys. Upstream keeps a commit key and a dirty-path key.
- Race guards: the stat-moved and fresh-scan comparisons.
- Declines to the full inventory, beyond upstream's missing- or
unknown-stamp checks:
- a changed scope;
- an index built through symlinks;
- submodules;
- an untracked nested repository;
assume-unchangedorskip-worktreeentries;- an ignored path the scan keeps (the scan honors only the root
.gitignore); - content or name conversions that let git call changed bytes clean:
core.autocrlf, any gitattributes source,core.ignorecase,core.precomposeunicode. Windows CI caught this: a revert rewrote LF as CRLF whilegit statusstayed clean; - a git timeout.
Measured on the code at 742bcb4, release build, warm cache, five runs after
a warm-up, codegraph status . --json. The corpus was a generated repository of
40,000 TypeScript files on ext4, on a 32-CPU Linux host. Medians, with
min–max:
| Scenario | Fast path | Full inventory |
|---|---|---|
| Clean | 212 ms (208–215) | 266 ms (264–266) |
| 18 committed edits | 211 ms (206–219) | 263 ms (262–264) |
Both columns reported the same pending changes in every run.
The 2026-06-24 v1.0.1 → v1.1.0 entry below records "In-root symlink indexing
(#935)" as ALREADY-HAVE. That was wrong. The official v0.51.0 binary indexed
only src/real/a.ts from
{src/real/a.ts, src/afile.ts -> real/a.ts, src/linkdir -> real, src/extlink -> ../../outside/lib},
because the scan skipped every symlink. That row stays as written; this entry
supersedes it.
The owner decided on 2026-10-01 to follow symlinks by default, as upstream does,
including targets outside the project. Its design passed the kirocodex
plan-convergence review in round 3. #288 ports both behaviors: the scan follows
symlinked files and directories (#935), and the watcher watches what the scan
reached (#770). A binary built from the PR indexes src/afile.ts,
src/extlink/out.ts and src/real/a.ts from the same tree. src/linkdir adds
nothing, because the real src/real wins.
KEEP-RUST divergences:
- Precedence: a directory is scanned once, under the logical path with the
fewest symlink hops, ties going to the smallest path. Upstream's winner
depends on
read_dirorder. - Targets that are not followed: a link to the project root or an ancestor
of it, a link into the canonical
.gitor a reserved index root, and a missing or unreadable target. Upstream re-walks a parent tree under an ancestor link, and skips.gitand data directories by entry name only. - Retargets keep
syncequal toindex --force: a full build records its links underproject_metadatakeyfollowed_links. Full sync andstatusre-read every path behind a new, retargeted or retyped link, and behind every link when the record is missing. - The watcher takes its links from the scan. It narrows them by its stricter policy, so it never watches a path the scan did not reach. Native-recursive backends add up to 256 supplemental watches; that cap matches upstream. An edit to a file link's target re-indexes the link.
- Known limitation, as upstream: a file link whose target lies outside every scanned directory is not watched; the next full sync picks it up.
#286 (f23b0bd) fixed a pre-existing v0.51.0 defect found along the way. A
full sync judged scope with the watcher's stricter policy, so it deleted indexed
files under .cache, vcpkg_installed, the other watch-only defaults, and
top-level .codegraph-* directories.
Goldens: all 19 re-indexable corpora are byte-identical; they contain no symlinks. The change ships in the next release.
2026-10-01 — CLOSEOUT: v1.6.0 → v1.6.1 sync COMPLETE in codegraph-rs v0.51.0 (tracked parity advanced to v1.6.1)
The v1.6.1 range (3ed73bc..f4ddf50, 113 commits) was audited on 2026-09-30
in V1_6_1_AUDIT_2026-09-30.md, which records
every row's disposition and landing PR. The owner decided two questions on
2026-10-01: #1349's node-id collision handling is ported (a colliding later
declaration gains a column suffix; the formula is otherwise unchanged), and
the UI family is deferred to the next round.
The work landed in seven squash-merged PRs:
- #271
79cb21c— engineering baseline: CI and release hardening, checksum-verified installers; - #275
f8e6039— the 2026-09-15 main-range product work, re-based onv1.6.1's final shapes; - #277
4231ee5— receiver evidence, Zustand and object-literal bindings, extraction recall; - #278
227f1d2— node identity (#1349), traversal depth, method values, handler recall; - #279
bc301b9— I/O safety, lifecycle recovery, MyBatis and Liquid recall; - #281
678927c— explore: line anchors and exact targets, named-file budget, same-basename pins, honest completion notes, named gaps, empty-result diagnostics; and - #282
34bc8dc— C/C++ translation-unit macro visibility and constructor overloads.
Extraction moved from version 12 to 17. Extraction goldens changed only where a
port meant them to: #275 added the Scala and Dart corpora (17 → 19 re-indexable
corpora) and grew the TypeScript (14 → 16 files), C-family (19 → 23 files) and
Rust corpora; #277 regenerated the TypeScript references and the Python nodes,
edges and references; #278, #279, #281 and #282 left all 19 corpora
byte-identical. MCP structural fixtures changed three times: #275
(codegraph_callers gained its file parameter in tools/list), #278
(callers and callees now follow instantiates edges, upstream #774/#804, so
the codegraph_callees, codegraph_node and codegraph_explore fixtures show
runDemo constructing Counter), and #281 (the initialize instructions
bullet).
Two release-gate defects surfaced on the way and were fixed before the release:
#283 3183b93 kept two
Windows-only test flakes (a same-nanosecond temp directory, a two-second full
sync wait) off main CI, and
#284 e973f12 exempted
.github/scaffold.json from oxfmt, because release-please's JSON updater
rewrites it in a shape oxfmt rejects. The release PR's CI went green (run
36824289185)
once its branch was updated with #284, and its merge needed a code-owner approval:
the mainPR ruleset still requires code-owner review, which the CODEOWNERS
comment says it should not while the repository has one maintainer.
Release-please PR #272
merged as 4ce8813441d4a4064f0d553f7e766c095ea400ed and cut tag v0.51.0 at
that exact commit. Release workflow run
36825202787
passed all twelve jobs — release-please, the source gate, the exact-SHA CI gate
over main CI run
36825202832,
the tag check, six platform builds, asset attachment and publish — and
published the release at 2026-10-01T06:42:29Z. The official
codegraph-0.51.0-x86_64-unknown-linux-musl.tar.gz digest was
f7efb5b106f885ca080d727697d8e2db53de1da374e803b54e41ad740775460d.
Black-box acceptance of the downloaded release:
SHA256SUMSverified all six archives, andgh attestation verifyverified all six againstsunerpy/codegraph-rust; the binary reportscodegraph 0.51.0;- a fresh
initof the mini fixture indexed three files at extraction version 17;search addandcallers addfound the function, and the line-anchoredexplore "src/math.ts:1 add"reported1 file pinned from the query; and - an extraction-version-12 index written by the official
v0.50.3binary was reported bystatusas outdated withsyncas the recovery;syncmigrated it in place to version 17 with noinit. In the migrated index a function-like#defineis aconstantwhose call stays unresolved, andWidget item;reaches the out-of-line definition through the default declared on its prototype. A copy of the same version-12 index at another path is refused as belonging to a different location, withinitas the recovery.
Tracked release parity advances to v1.6.1; the next discovery starts at the
v1.6.1 tag.
A fresh upstream clone confirmed that the newest formal release is still
v1.6.0, while main advanced from
6a056ec5db35172f9dc348f87b54ea415aa5169e to
3ed73bc127323e63153bf6ec8354afa82ce36aaf. The exact unreleased range is 119
commits across 373 changed files (+86,127/-1,745).
The dated report
POST_V1_6_MAIN_2026-09-15.md partitions every
commit family and records PORT, ALREADY-HAVE, N/A, and DEFER decisions.
It identifies real Rust correctness/safety and CLI/MCP/installer gaps, but none is
marked LANDED by this audit. The large browser viewer/Screens/Steps family is
explicitly deferred to an owner-selected Penpot design and a stable upstream
baseline; it is not mixed into core parity work.
Because upstream has no post-1.6 tag, tracked release parity remains v1.6.0.
Only the discovery boundary advances to 3ed73bc.
Rust PR #258, merged as
4e0cbad8aa2225d133675235df290f6c262b8ba9 from implementation commit
3f723014955badc1fc00e195b9766e07e57c3a22, shipped the three frozen Wave 3
PORT families: upstream bc89480, 0d17dfd, and a5c2709.
The shipped behavior is:
- Codex supports location-aware global and project-local install, detect,
print-config, and uninstall flows. A local install writes
.codex/config.toml, project-rootAGENTS.md, and.agents/skills/codegraph, preserves unrelated TOML/marker-external user text, and explains Codex's project-trust requirement. Local uninstall does not touch the global layer; init -y/--yesis an intentionally behavior-neutral unattended-bootstrap compatibility flag.install -i/--initinitializes the current directory only after installer success, remains effective when no agent target is selected, returns before initialization under--print-config, and invokes init withtarget=noneso it cannot duplicate local agent configuration; and- a bare stdio MCP launch walks upward first, then performs the bounded
workspace-root scan only when the launch directory has a workspace manifest
or
.git. It adopts exactly one indexed child, starts that project's normal daemon/watcher/catch-up path, reports zero/multiple candidates without guessing, preserves explicitprojectPathauthority, and keeps global no-path HTTP behavior unchanged.
Wave 3 deliberately keeps extraction version 12, the node-id formula, every
graph row, and all extraction goldens unchanged. Local make ci, the pre-push
gate, PR CI run
33422822781,
post-merge main CI run
33423660004,
and its release-please workflow
33423660035
all passed.
Release-please PR
#259 merged as
1264493b42d7aaccd4498580685fddd074e7c356, cut tag v0.50.0 at that exact
commit, and release/tag CI run
33424831118
plus release workflow
33424831111
passed all six platform builds, the CI gate, checksum generation, and publish.
The official codegraph-0.50.0-x86_64-unknown-linux-musl.tar.gz digest was
081a6d51440a505dbb26ccaf0041022921d57e46bce1478d7ddf639562e2c547.
Black-box acceptance of that downloaded v0.50.0 binary proved the Wave 3
features, but also found two defects that prevented final closeout:
- raw
codegraph exportJSON ordered otherwise-identical edges by SQLite insertion order, so incrementalsyncandindex --forcediffered byte-for-byte even though their canonical graph content matched; and - text
statuscorrectly detected an extraction-version 11 index as outdated, but incorrectly described it as uninitialized and recommendediniteven though ordinarysyncperformed the supported migration.
Patch PR #260, merged as
6108538b8c32efabaf975d70bbde58712037d84a from commit
1bcf5856940178388bb217e62d4cb6dff8bb9ede, adds a deterministic semantic edge
sort to export and changes outdated text guidance to codegraph sync. The
patch changes no extraction version, schema, node-id, golden, or Skill content.
Focused tests, workspace tests, make ci, the pre-push hook, PR CI run
33429410706,
and post-merge main CI run
33430264430
all passed, including native Windows. Release workflow
33430264432
then created the patch release PR without prematurely building assets.
Release-please PR
#261 merged as
02c535999189b7d4517d8c6bbdf08d82575eb4c2, cut tag v0.50.1 at that exact
commit, and final CI run
33431047600
plus release workflow
33431047589
passed. The Release is neither draft nor prerelease and contains all six
platform archives plus SHA256SUMS. The official
codegraph-0.50.1-x86_64-unknown-linux-musl.tar.gz digest is
dd8d2c0f7deb19752639c3f4e16127cf47c584577ae5b67b5464403de818ff25,
matching both SHA256SUMS and GitHub's asset digest.
Final black-box acceptance used that downloaded v0.50.1 static binary:
codegraph --versionreturnedcodegraph 0.50.1with no logger-init banner;status,init -y,sync,index --force,search,explore, andnodeall succeeded on extraction version 12;- a comment-only edit followed by
syncand a freshindex --forceproduced raw exports with identical SHA256379dbcfd439a9616c5d0c19f35d5f42b9173cb2bed5e805c76108aa7809e952c; - a real extraction-version 11 index reported
Recovery: run codegraph sync ..., then migrated to version 12 through ordinarysync; - MCP
initializenegotiated2026-07-28,tools/listreturned the expected tool surface, and queries succeeded with a read-only permanentindex.lock; - Codex global/local install, print-config, uninstall, trust guidance, user
config preservation,
install --yes --init, no-init, print-only, and no-target bootstrap branches all passed; - unique-child adoption started the daemon/watcher and automatically indexed a
new function;
alpha, betaambiguity was reported in sorted order, explicitprojectPathbypassed it, and an un-gated parent did not scan downward; - an isolated HOME upgraded the real Skill from
0.48.1to0.50.1, previewed the full+70 -4diff, reachedup to date, and preserved a subsequent local edit by refusing to overwrite it without--force; - Zuno install/uninstall preserved unrelated JSON, existing target print-config output stayed compatible, and shell completion succeeded on a 1 MiB thread stack.
While validating this closeout documentation, Windows CI exposed a test-only
temporary-database collision: the two parallel go_multi_module Tier 6 tests
could receive the same coarse wall-clock value and therefore open the same
SQLite path, producing UNIQUE constraint failed: schema_versions.version.
Rust PR #263, merged as
be0da2dffe65ffde6892e44c3d2e8d5366e1f07f from commit
6ef62963f85fbeafdf6bd05c1d09f8f867c0b060, adds a process-local atomic nonce
and a deterministic same-clock regression test. It changes no product
behavior, version, extraction, schema, node-id, graph row, golden, or Skill.
Local make ci, the pre-push gate, PR CI run
33436085651,
and post-merge main CI run
33437015489
all passed, including the complete native Windows job.
A final live upstream refresh found release v1.6.0, main still exactly
6a056ec5db35172f9dc348f87b54ea415aa5169e, and #1626, #1616, and #1617 still
open upstream. The Rust port has shipped the first two issue fixes; #1617 and
codegraph context remain DEFER. All 15 audited PORT families plus those two
issue fixes are now shipped, so tracked colby parity advances from 1.5.0 to
1.6.0. The next discovery boundary remains
6a056ec5db35172f9dc348f87b54ea415aa5169e.
Rust PR #255, merged as
036330cfe26aae0e775d8847bc030414f9479013 from implementation commit
1e114cdfa7263837b9e90930cae568b5787c80f1, shipped all three frozen Wave 2
PORT families: upstream 238dbc5 + ccb0295, 9219967, and 1d9de88.
The shipped behavior is:
- Explore recognizes bounded explicit source paths, normalizes quoted,
backticked,
./, Windows,:line, and#Llineforms, pins exact/suffix matches ahead of fuzzy results, reports unmatched explicit paths, and adds extensionless kebab basenames plus camelCase Variable/Constant seeds; - case-insensitive exact-name supplements use
lower(name) = lower(?), with planner regressions provingidx_nodes_lower_nameis used for hits, misses, and filtered queries; and - ordered ranking-only
deprioritizerules load from.codegraph/codegraph.jsonfirst and[indexing].deprioritizelast, use last-match-wins!patternexceptions, apply only the documented path and exact-name penalties, and refresh for every long-running MCP search/explore request.
This wave deliberately keeps extraction version 12, the node-id formula, graph
rows, and every golden artifact unchanged. Direct node/file lookup and explicit
path pinning bypass ranking penalties. Local make ci, the pre-push gate, PR
CI run
33408838909,
post-merge main CI run
33409994677,
release-please PR CI run
33410032708,
and release/tag main CI run
33412026542
all passed, including native Windows.
Release-please PR
#256 merged as
1e938d0d975eb6f01fd82e3ab416a6722a468159, cut tag v0.49.0 at that exact
commit, and release workflow
33412026472
published only after CI Success, all six platform builds, asset upload,
checksum generation, and the publish gate passed. The official
codegraph-0.49.0-x86_64-unknown-linux-musl.tar.gz digest is
8aa3b5219054c772e2e8b86f9552a49e4a05eeb93e5e2d404e295aa05180fb27,
matching both SHA256SUMS and GitHub's asset digest.
Black-box acceptance used that downloaded static binary:
codegraph --versionreturned exactlycodegraph 0.49.0with no logger-init banner;status,init,sync,index --force,search,explore, andnodeall succeeded on an extraction-version 12 project;- a pinned
src/services/user-service.tssurvived a tight Explore budget, whilemissing/path.tswas reported as unresolved instead of becoming fuzzy query noise; Variable/Constant lookup also foundhttpClient; - JSON-only
archive/**ranking reduced an exact-name result from92.50074874522146to57.50074874522145, and a later TOML!archive/**rule restored it, proving JSON-then-TOML authority without reindexing; - one live MCP process completed
initialize,tools/list, search, and Explore; after the TOML exception was removed, its next search immediately movedarchive/buildProfile.tsbehind first-party source, proving request-scoped config refresh; - CLI queries still succeeded with the permanent
index.lockread-only; - an isolated HOME previewed the real
0.48.3 -> 0.49.0 (+31 -4)Skill diff, updated it, and then reportedup to date (0.49.0); and - isolated Zuno install/uninstall preserved unrelated JSON keys and another MCP entry, while its generated CodeGraph entry stayed unchanged.
Wave 2 is therefore shipped, not merely implemented. The remaining upstream
v1.6.0 backlog is the three Wave 3 PORT families. Tracked colby parity remains
1.5.0 until those ship; codegraph context and #1617 remain explicitly
deferred.
Rust PR #252, merged as
d42368c628820cfc49805d0384261e18e1c8e900, shipped all ten frozen Wave 1
items: upstream 41c1075, 12f7a59, 7963672, 278a8ed, 474f051,
d618d94, a740291, and cf1b0e3, plus open-issue fixes #1626 and #1616.
The implementation commit is 9d26c70; follow-up commits f9ee631,
4609c8f, and 6b6e0b5 lock the alias and watcher path semantics on native
Windows.
The shipped behavior is:
- Erlang function identity and resolution are arity-aware, including exports,
specs, local/remote calls,
fun, spawn/apply, binary-literal argument counting, and CLI/MCPmodule:function/aritylookup; - Rust methods are assigned only to statically safe
implowners, and exact single-hopself.field.method()calls resolve through declared field types without falling back to unsafe global same-name guesses; - JS/TS object-literal callable members resolve within their source ranges,
inherited
tsconfig/jsconfigaliases honor config-relative origins and bounded/cycle-safeextends, and.xsjs/.xsjslibparticipate in the documented JS import ordering; - full-source masked C-family header detection recognizes plain derived
class/structdeclarations without promoting comments, literals, bitfields, labels, or ternaries; - Python module aliases and Lua function expressions/table members gain their scoped callable/module bindings; and
- the watcher treats the selected index root's
config.tomlandcodegraph.json, plus the project-root.gitignore, as control files, atomically reloads scope/watch targets, and performs one dominating full reconcile while stale queued events are re-checked against the new scope.
Extraction version moved exactly once, from 11 to 12. The node-id formula is
unchanged. Expected golden growth is isolated to the C-family, Erlang, Python,
Rust, and TypeScript corpora, plus a new Lua corpus; docs/equivalence.md
records every regeneration recipe. Existing unaffected corpora remain
byte-stable. Local make ci, the pre-push gate, PR CI run
33399374332,
post-merge main CI run
33400228015,
and the release/tag CI run
33401044034
all passed, including native Windows.
Release-please PR
#253 merged as
14c8f7bf636b0d6b857a8fdeba618448eca028d8, cut tag v0.48.3 at that exact
commit, and release workflow
33401043968
published only after CI Success, all six platform builds, asset upload, and
checksum generation passed. The official
codegraph-0.48.3-x86_64-unknown-linux-musl.tar.gz digest is
f8d84244df59974734535d5c45d1ea9c63af5c4019e3f161dd9859a21c4cc287,
matching both SHA256SUMS and GitHub's asset digest.
Black-box acceptance used that downloaded static binary:
- a project initialized by the official
v0.48.2binary reported extraction version 11 asoutdated, then ordinarycodegraph sync .upgraded it to version 12 without requiringindex --force; status,sync,index --force,search,explore, andnodesucceeded; the incremental upgrade and full rebuild both produced 3 files, 11 nodes, and 13 edges for the smoke corpus;- TS inherited aliases/object members and Lua
local f = function/M.f = functionwere queryable with their expected call trails; - MCP
initializeandtools/listreturned protocol/tool results, and a query succeeded while another process held the permanentindex.lockshared; - an invalid runtime
config.tomlkept the previous watcher scope, while a valid exclusion removed the Lua file and clearing it re-indexed that file without restarting the server; - an isolated HOME installed Skill
0.48.2, reportedoutdated (0.48.2 -> 0.48.3), showed the complete--dry-run --diffwith+13 -0, updated successfully, and then reportedup to date (0.48.3); - the Zuno
--print-configcontract remained unchanged; and - normal CLI startup did not reintroduce the former
logger initializedbanner.
Wave 1 is therefore shipped, not merely implemented. The remaining upstream
v1.6.0 backlog is the six Wave 2–3 PORT families. Tracked colby parity remains
1.5.0 until those ship; codegraph context and #1617 remain explicitly
deferred.
Upstream 838006c947ebe69407e8f64ba756f97132f411f4 fixed the process-crash
class caused by deeply recursive native walkers. Rust PR
#249, merged as
22f9753049d91ccad11ffb30184ee4799182b519 (implementation commit 53360d9),
implements the portable behavior with a deterministic design rather than copying
upstream's platform stack-pointer / wasm fallback:
- an iterative preflight rejects logical named-node depth above 256 before any recursive semantic traversal;
- the main walker and function-body walker share a fail-closed runtime depth
latch, while Rust's inert single-child
expression_statementgrammar wrapper is folded so 200 levels of ordinary source nesting remain valid; - an over-limit file contributes no partial nodes, edges, or unresolved references, records one stable file error, and does not stop sibling files;
- incremental
syncremoves the file's previous graph and is canonically identical to a freshindex --forcefor the same final filesystem state.
Coverage includes 30,000-level C, C++, Rust, TypeScript, and Python inputs on a
1 MiB test thread, the exact inclusive 256/257 boundary, per-file isolation, and
the incremental/full-rebuild equivalence oracle. Local make ci, the pre-push
gate, PR CI, and post-merge main CI all passed. This change deliberately keeps
extraction version 11 and changes no golden artifact or node-id formula.
Release-please PR
#250 merged as
b53d0e64f4334cba38ec018c9277051aa645951a, cut tag v0.48.2 at that exact
commit, and published the Release only after CI Success plus all six platform
builds, asset upload, and checksum generation passed. The published Release has
the expected six archives plus SHA256SUMS. The official
codegraph-0.48.2-x86_64-unknown-linux-musl.tar.gz digest is
b37af51df668121a635c6a04decd87dcc90a1067230125b56bb6d94690a423ef, matching
both the uploaded checksum file and GitHub's asset digest.
Black-box acceptance used that downloaded static binary, not a local build:
codegraph --versionreturned exactlycodegraph 0.48.2with no logger-init banner;status→init→searchsucceeded on a clean project;- replacing an indexed C file with 30,000 nested compounds and running
syncremoved its stale symbol, preserved the healthy sibling, and recorded exactlyAST nesting exceeds safe traversal limit (256): deep.c; - the stable files/nodes/edges/unresolved-ref projection then matched a fresh
index --forcebyte-for-byte; - a query still succeeded with a clean index's permanent
index.lockmade read-only; - MCP
initializeandtools/listreturned protocol/tool results; and skill update --global --dry-run --diffreported0.48.1 -> 0.48.2 (+7 -0)for every installed supported agent without writing files.
Wave 0 is therefore shipped, not merely implemented. Tracked colby parity still
remains 1.5.0 until the remaining Wave 1–3 v1.6.0 PORT families land.
Before implementation began, both repositories and the three load-bearing open issues were refreshed against their live GitHub state:
- codegraph-rs
mainand the latest published release are bothv0.48.1(e5350b3c6eb6312cfae86f2353375e4bfb5e9a3f); - upstream's latest release remains
v1.6.0, and upstreammainis still exactly6a056ec5db35172f9dc348f87b54ea415aa5169e; - the diff after the audit boundary is empty, so the 15 PORT families below do not need re-triage;
- #1626 (Python aliases), #1616 (Lua function expressions), and #1617 (custom Lua loaders) remain open. The first two stay in the implementation backlog; #1617 stays explicitly deferred.
This refresh changes only the Rust implementation/release baseline. It does not
rewrite the 2026-08-27 audit evidence, and tracked upstream parity remains
1.5.0 until the portable v1.6.0 backlog lands.
Upstream released v1.6.0 on 2026-08-26. The earlier post-v1.5.0 audit
covered exactly 104 commits through c6aaa20358cd6adcd04b87bdef8e5803ad146f3a;
that count was re-verified before this round. The fresh range through current
upstream head 6a056ec5db35172f9dc348f87b54ea415aa5169e is exactly 28 commits
(27 through the release tag plus one docs-only follow-up), 100 files,
+6900/−575.
The complete classification, local source evidence, open-issue triage, and
recommended implementation waves are recorded in
V1_6_TRIAGE_2026-08-27.md.
The highest-priority item is native tree-walker depth protection: upstream
demonstrated a process-level stack-overflow crash on deeply nested source, and
the Rust walker still recurses without a guard. The graph-correctness wave then
contains Erlang arity identity, two Rust method-resolution fixes, JS/TS
object-literal namespaces, inherited TS aliases, C++ .h detection, Python
import aliases, Lua function-expression callables, and live watcher-scope
refresh. Retrieval/UX work follows.
One measured performance regression is also now pinned: the Rust database
already has idx_nodes_lower_name, but its case-insensitive exact-name query
uses COLLATE NOCASE and scans nodes; lower(name) = lower(?) seeks the
expression index. That upstream change is a real PORT item, not an
already-present optimization.
No source port was implemented in this audit. The next upstream discovery diff
starts after 6a056ec5; implementation work starts from the linked report.
2026-08-20 — post-v1.5.0 unreleased range TRIAGED and CLOSED, six tiers SHIPPED (v0.43.2 → v0.46.1; tracked parity stays 1.5.0)
git ls-remote --tags still reports v1.5.0 as upstream's newest tag, so a
version-delta sync had nothing to pull. But main had accumulated 104
unreleased commits past that tag (43 source files, +5737/−368), and issues
#1496–#1566 / PRs #1402–#1564 had never been triaged. "No new version" is not
"no new content" — that is the lesson worth carrying into the next sync.
Three parallel triages ran (extraction/kernel, explore/MCP, issues/PRs), and
every disposition below marked MEASURED was reproduced against a built binary
before being acted on. Tracked parity stays 1.5.0: none of these releases is a
port of an upstream release range.
| release | PR | what landed | upstream refs |
|---|---|---|---|
v0.43.2 |
#209 | one shared file-classification signal across every surface | #1507 + the path table behind #1500 |
v0.43.3 |
#211 | stop binding calls, imports and supertypes to coincidences | #1496, #1566, #1537/#1536 (PR #1538) |
v0.44.0 |
#213 | unions, unit structs and COM interface as containers |
PR #1516, #1513/PR #1514, #1519 |
v0.44.1 |
#215 | imported members, cross-module Go calls, declaration initializers | #1518, #1521, #1510/PR #1511, #1524, #1512, #1504, #671 |
v0.45.0 |
#217 | Tauri commands bound to their invoke call sites |
#1543 |
v0.46.0 |
#220 | generated files detected by their content banner | #1500, 57e0854 |
v0.46.1 |
#223 | a named symbol always renders; real budget accounting | CG-38/36/30/28/26/31 |
v0.43.2 also carried h2 0.4.16 for RUSTSEC-2026-0258 — unrelated to the
sync, but it is why that release exists at that moment: the advisory published
mid-round and turned CI red on a lockfile nobody had touched.
| claim | verdict |
|---|---|
Store::nodes_by_name lacks ORDER BY, so sync and rebuild can bind different same-name targets (upstream CG-33) |
ALREADY-HAVE. Both production resolution contexts sort candidates themselves — context.rs:111,125 and snapshot_context.rs:118-124 call order_candidates / order_candidates_pub, keyed (file_path, start_line, start_column, id): upstream's key plus an extra total-order id tie-break. MEASURED twice — sync and index --force both bind caller.run → pct@alpha.ts even when sync's rowid order puts zeta first. |
the explore staleness banner can be truncated away by our own budget logic |
ALREADY-HAVE. The banner is prepended after truncation: cut_at_section_boundary → mark_surviving_explore_citations(kept_prefix_len) → with_staleness_banner. A cut section's citation is dropped first, so the banner correctly omits it. Pinned by the pre-existing staleness_banner_omits_a_citation_removed_from_the_final_response. The agent had conflated the in-section inline warning with the top-level banner. |
CG-27 — treating function/method as >50% envelope containers so inner
closures rank independently. Upstream measured and rejected it
(91cb5b4:docs/benchmarks/explore-factory-closure-cg27.md): delivered chars
7,539 → 397, inner closures 7/11 → 0/11, ~5,200 of a 5,601 reservation unused.
The cautious variant moved nine queries by 68 → 69 definitions total. Our
envelope drop stays limited to is_container. The real defect it exposed —
a trivial cluster winning on density while the answer cluster is dropped whole —
is tracked separately as the Tier 5 explore work.
- Self-hosted telemetry (
49c11fc, Cloudflare D1 + a password-gated dashboard replacing PostHog) and #1509's request for a Qdrant/vector-RAG integration. Both are permanent divergences:scripts/guardrail.shis a CI gate rejecting qdrant/lancedb/candle/onnx/ort, byte-stable output is incompatible with a nondeterministic retrieval stage, and our indexing path makes no network call. Nothing vector-related is merged upstream yet — the stance is recorded now so it is a decision rather than a surprise.package.jsonin this range adds no AI dependency.
#1532 (FTS5 absent from official Node builds — we compile it into rusqlite),
#1558 (V8 spread-arg limit), #1559 (V8 RegExp code space — the regex crate has
no such budget), #1544/#1547/#1564 (Vapor regex catastrophic backtracking —
regex is linear-time by construction), #1553 (V8 4 GB heap), #1549
(git ls-files --recurse-submodules on git <2.34 — we never call it),
#1476/#1477 (npm CVEs), #1550 (npm platform bundle).
#1555 (C/C++ hex-blob header stall — a 360 KB header with 60,000 0x..
initializers indexed in 326 ms), #1522 (16-char raw-string delimiter — both
functions extracted), #1505 (400-function anonymous namespace — all 402
extracted), #1565 (init/sync symbol-count divergence — our byte-equality is a
gated invariant). #1560 (JSX synthesis fabricating edges in a pure C/C++ index)
cannot occur: we have no synthesis pass at all. The flip side is that we lack
jsx-render edges entirely — a separate known gap.
Upstream is only now adding GDScript (#1499), which we shipped with a full framework resolver (F1 autoload calls, F2 signal handlers, F3 impact/affected unification) and a byte-stable golden corpus.
The explore budget/selection epic shipped as v0.46.1, which closes the range.
Its review took eight rounds, and the reason is worth recording: the whole-file
rule returns a complete section before any budget or focus logic exists, and
its line and character thresholds are independent — so a named symbol could
vanish by two unrelated routes. A file that passes both gates has a complete
section built and then rejected whole, where no clustering-path fix can reach it;
a file that passes the line gate but fails the character gate falls through to
clustering and is rejected there. Both produced the same 615 bytes with zero
sections that CG-38 exists to prevent, which is why the port needed two
separate regression tests rather than one.
CG-27 is recorded above as measured-and-rejected by upstream, and is not
ported. The 26 DEFER items and the permanently-N/A 0682137 recorded in earlier
entries are unchanged.
The 26 DEFER items and the permanently-N/A 0682137 recorded in earlier entries
are unchanged.
2026-08-04 — the two open triaged issues SHIPPED, plus two project-local fixes (v0.42.5 → v0.42.8; tracked parity stays 1.5.0)
Four releases. Two of them close the issues the 2026-08-02 CLOSEOUT left open
(#1495, #1482 / #1482b); the other two are project-local — a reverted
invention and the Godot-team liaison doc's only P1. Tracked parity stays
1.5.0: none of the four is an upstream-range port. #1495 is a documented
divergence FROM upstream; #1482/#1482b close upstream-triaged ISSUES rather than
upstream commits; and v0.42.5/v0.42.7 have no upstream counterpart at all. A
future sync must not read these four releases as parity movement.
Every release published with isDraft=false and 7 assets (6 platform binaries +
SHA256SUMS). Final workspace test count after v0.42.8: 127 suites / 3134
passed / 0 failed.
| release | our commit | what it fixed |
|---|---|---|
v0.42.5 |
5aff695 (PR #190) |
index root restored from .codegraph-v2 to .codegraph, with takeover of a pre-existing legacy database |
v0.42.6 |
81628f2 (PR #192) |
#1495 Kotlin callable signatures — a DIVERGENCE from upstream |
v0.42.7 |
20e3f9d (PR #194) |
per-state CLI diagnostics when an index is unreadable (liaison-doc P1) |
v0.42.8 |
4a17919 (PR #196) |
#1482 / #1482b TS export-alias resolution + .js→.ts specifier substitution |
v0.42.5 — a project-local invention reverted. .codegraph-v2 was never an
upstream port: upstream's src/directory.ts:12 has always used .codegraph. Two
blockers had to fall together. IndexPaths::resolve rejected any current root
overlapping a legacy root, and the fixed .codegraph was always in that set, so
naming it made every resolve fail. And a .codegraph written by v0.40.4 or by
the upstream tool has no state slots, so it classifies Missing while its database
exists — a state the write gate refused. An explicit init now takes such a
database over under the one exclusive lease it already holds, logging what it
replaced. Only Missing qualifies: Building, Corrupt, and Future still
fail closed, so a running builder never loses its work. CODEGRAPH_DIR also
returned to upstream's meaning — a plain project-local join, not a
<name>-v2-<64 hex> sibling.
v0.42.6 — #1495, and why it is a DIVERGENCE, not a port.
KotlinSpec::get_signature returned None unconditionally because upstream's
kotlin.ts:232-242 looks the parameter list up through a grammar FIELD the Kotlin
grammar does not expose, so upstream's own hook always returns undefined and this
port mirrored it faithfully. The fix reuses a pattern already in the same file:
declared_return_type_node walks named_children and matches on KIND, sidestepping
the missing field. It emits raw parameter text plus the declared return type when
written. Primary constructors stay class details; lambdas, accessors, and anonymous
functions stay outside the node set. EXTRACTION_VERSION 3 → 4. The new
reference/golden/kotlin/ fixture guards five shapes (explicit, inferred, generic,
multiline nullable, extension) plus a primary-constructor negative.
v0.42.7 — the message was the bug, not the permission. The liaison doc's only
P1: an interrupted index --force leaves the namespace in building, and every
read then refused with "CodeGraph not initialized" pointing at init. Twelve
commands shared that one message because resolve_required_project collapsed six of
the seven lifecycle states into a single bool. Each state now names its own remedy;
reads still fail closed everywhere. status adds recovery guidance for building
but only when a shared lease is free — a real build holds the namespace
exclusively, and telling someone to rebuild mid-build would destroy work in
progress. unlock works in building, clearing a stale daemon pid record and the
transient lock, then reporting that the state is still building.
The doc's own suggestion was REFUSED, with measurements. It proposed rolling the
newest building slot back to the previous current. But begin_from_authorization
publishes phase=building durably before any destructive database work
(crates/codegraph-store/src/rebuild.rs:324-330), so the older slot describes a
database that no longer exists. Measured aftermath: db 4096 bytes / nodes=0
versus 1098/1221 intact. Presenting that as Current would turn every query into a
silent empty answer.
v0.42.8 — #1482 / #1482b, two independent misses. export const a = fn,
export { fn as a }, and export default fn each publish a local declaration
under a different name, and an importer using that name resolved to nothing — so
the original looked uncalled. Re-export extraction now records local aliases
alongside the cross-file forms, and the export lookup follows them back.
Separately, .js specifiers never reached their TypeScript source: NodeNext
requires import './foo.js' even when the file is foo.ts, but the candidate
builder only APPENDED extensions. A specifier ending in a JS-family extension now
tries the matching TypeScript extension first (.js/.jsx → .ts/.tsx/.d.ts,
.mjs → .mts, .cjs → .cts), falling back to the append behaviour. When both
foo.js and foo.ts exist, TypeScript wins. Scoping is pinned by tests walking
Language::ALL: only TypeScript and Tsx substitute, and only the four ECMAScript
languages extract a local alias. EXTRACTION_VERSION 4 → 5. The new
reference/golden/typescript/ fixture carries four positives and three negatives.
The 26 DEFER items remain deferred — 19 resolution/store/synthesis perf
strategies plus 7 sync/WAL scheduling strategies, all tuned to upstream's Node /
node:sqlite runtime, byte-identical to graph output, to be re-derived from a Rust
profile rather than transcribed. 2adc7f6 becomes a CORRECTNESS item if
timer-triggered truncation is ever adopted here. 0682137 stays N/A
(packaging-rooted — we ship a native codegraph.exe, never a .cmd shim). Full
text in ## Current alignment above.
Both cost real investigation and would otherwise be re-derived.
- Python has no export semantics — already recorded in the 2026-08-02 batch-4
export-semantics finding above, and it stayed load-bearing here: it is what makes
#1482's alias work TypeScript-scoped rather than generic.
find_exported_symbolrequiresis_exported, and the Python spec never sets it — upstream included. - The double-buffered state slots carry STATE, not DATA. This is exactly what made the liaison doc's rollback suggestion unsafe, and it generalizes: any future "just roll back to the previous slot" idea faces the same problem, because the slot is a phase record, not a snapshot of the database it describes.
All four batches of the 1.4.1 → 1.5.0 round have shipped, across codegraph-rs
v0.42.1 → v0.42.4. Batch 4 was the last portable in-scope item, so by this
ledger's own rule — parity advances only when every portable, in-scope behavior in
the range has landed — tracked colby parity advances from 1.4.1 to 1.5.0. The
bucket tables, the post-v1.5.0 triage, and the open-issue triage live in the
AUDIT entry directly below; this entry is the batch index plus the exceptions that
a future sync actually needs.
Every release tag is v<version>, each published with isDraft=false and 7
assets (6 platform binaries + SHA256SUMS). Final workspace test count after
batch 4: 128 suites / 3127 passed / 0 failed.
| batch | release | upstream | our commits | what it actually fixed |
|---|---|---|---|---|
| 1 | v0.42.1 |
572d22b |
88e7773 (PR #178), 148090b, c167412, 374d4ff |
The Codex TOML block finder deleted trailing [[...]] blocks. Our find_next_table_header was the pre-fix logic verbatim, reproduced with the shipped 0.42.0 binary: uninstall --target codex silently destroyed a user's [[mcp_servers.other.env]] block. The fix also handled a column-0 decoy inside a """ string and an indented-header duplicate |
| 2 | v0.42.2 |
f2a5df3, f6ac7b3, issue #1473 |
4e18f94, 20e07e1, fea40a2 (PR #181) |
Three honesty defects — see below |
| 3 | v0.42.3 |
02c0e2c |
3fe9b55 (PR #184) |
A killed session left an uncheckpointed -wal that SQLite kept at its high-water mark forever |
| 4 | v0.42.4 |
38580e0 |
3860880 (PR #186) |
Python class-as-value idioms produced no edges, so callers on a DRF serializer showed nothing |
Batch 2 — three honesty defects. Lookups silently substituted a different
symbol (callers ad answered with add's rows); drifted files were sliced at
stored line numbers; blast radius claimed "no covering tests" after checking only
direct callers. Now: a non-exact lookup REFUSES (CLI non-zero pointing at
codegraph query; MCP isError: true pointing at codegraph_search); freshness
is fail-closed via SourceFreshness::{ProvenFresh, PossiblyDrifted}, comparing
size + millisecond mtime and hashing only on a stat mismatch, then emitting a
drifted file whole up to 2000 lines or omitting it entirely; coverage walks 3
caller hops under a 64-lookup budget and reports what it searched. The staleness
banner docs/mcp.md had promised now exists. One audited golden movement:
reference/golden/mcp/codegraph_explore.json, 4 blast-radius lines re-worded, the
rest byte-identical.
Batch 3 — WAL residue, measured not assumed. On 0.42.1 a 9 204 112-byte
residue stayed at exactly that size through a sync touching one line, and six
interrupted rounds ratcheted 5 702 112 → 6 439 592 → 6 760 952 bytes.
journal_size_limit is now set on both write-connection configuration points from
the same wal_valve_threshold_bytes() the valve uses — one concept, one env var
(CODEGRAPH_WAL_VALVE_MB) driving pragma, valve, and status warning. sync and
index fold a leftover WAL before their writer opens the DB, requiring proof the
previous daemon owner is dead AND a bounded exclusive lease, and reporting a heal
only when the fold actually completed. status degrades to a read-only diagnostic
on the typed CurrentWithDatabaseSidecar refusal, showing DB and WAL sizes without
counts and never checkpointing. Golden-neutral. Parts (c) and (e) are N/A: the only
watchdog here watches the parent pid and holds no Store, and every tracing sink
already emits RFC3339 via local_timer().
Batch 4 — Python class-as-value, four gates moved together. The capture spec
did not dispatch return_statement; the extraction gate admitted only same-file
functions/methods; and resolution accepted only function targets at both the name
matcher and the import fast path. Python now accepts class targets at both
resolution sites through ONE shared predicate; methods stay excluded everywhere;
every other language's kind filter is untouched. EXTRACTION_VERSION 2 → 3. The
new reference/golden/python/ fixture guards six positives (return, assignment
RHS, registry pair, call argument, list literal, imported class as value) and two
negatives (tuple return, bare method name).
Batch 4 export-semantics finding — record this, it will save a future sync a
day. The plan initially assumed the imported case resolves through the import
fast path. It cannot. find_exported_symbol requires is_exported
(crates/codegraph-resolve/src/import_resolver.rs:1476, :1489, :1496) and the
Python spec has no override, inheriting the unconditional false at
crates/codegraph-extract/src/spec.rs:106 — measured zero is_exported Python
nodes in both the mini and python goldens. Upstream is identical:
python.ts implements no isExported, and import-resolver.ts:94 does
if (!n.isExported) continue, so upstream's own DRF assertion also comes from the
name matcher's unique-name path. The import-side kind gate still mirrors upstream
but is DEAD for Python; its test states plainly that it hand-builds a state real
indexing cannot produce.
The full text is in ## Current alignment above. In short: 26 DEFER items
remain (19 resolution/store/synthesis perf strategies + 7 sync/WAL scheduling
strategies, all Node-runtime-tuned, byte-identical to graph output — re-derive from
a Rust profile, and treat 2adc7f6 as a correctness item if timer-triggered
truncation is ever adopted); 0682137 is N/A (native .exe, no .cmd shim);
and #1482 / #1482b (TS rename-through-alias false zeros + .js→.ts specifier
resolution) and #1495 (Kotlin signatures always absent) were left open at the
time of writing — both have since shipped, in v0.42.8 and v0.42.6
respectively (see the 2026-08-04 entry).
Every single review rejection across all four batches reduced to the same thing in
different clothing: an assertion whose premise does not hold. Batch 2 needed
three F2 rounds — code claiming freshness it had not proven, a completeness claim
keyed only on a budget while errors were swallowed, and a liveness gate inferring
section survival by string-matching its own response text. Batch 3's plan took four
momus rounds plus an F2 round — a test asserting SQLite clips at
wal_checkpoint(RESTART) when the clip actually lands on the next resetting write,
an acceptance criterion the fix deliberately eliminates, observability that does not
exist outside the process, and a SAFETY comment claiming a mutex established a
precondition it did not once Store::open began reading the env var. Batch 4's plan
carried three false premises about resolver reachability, caught only because the
golden audit refused to bend the artifacts to fit the plan, then three F2 rounds on
stale comments and citations. Two mechanical rules fell out of it, both invisible to
the compiler and to every test: widening a filter makes the comment above it
false, and inserting a doc section makes every line-range citation below it
false.
2026-08-02 — AUDIT 1.4.1 → 1.5.0 + post-1.5.0 triage; batches 1–2 LANDED (parity stayed 1.4.1 at the time of writing — superseded by the CLOSEOUT entry above)
A full audit of the 1.4.1 → 1.5.0 range plus the 6 unreleased commits above
v1.5.0, and a triage of colby's open issues. Tracked parity deliberately does
NOT advance: by this ledger's own definition — "all portable in-scope behavior
landed" — two portable items from the 1.5.0 range and four from the issue triage
are still open. Parity advances only when they land or are re-classified with
evidence.
A bookkeeping defect this audit found and is correcting: PR #173
(5d795a5, released in v0.41.0) landed a large slice of the 1.5.0 range with a
10 070-line evidence ledger at docs/upstream-sync/V1_5_PORTABLE_FIXES.md, but
never recorded a disposition here. The sync happened; the ledger entry did
not. That is exactly the failure this file exists to prevent — the next sync would
have re-investigated all 86 commits from scratch.
| bucket | count | notes |
|---|---|---|
| COVERED by a PR #173 batch | 11 | C++ operator calls / template-arg stripping / namespace prefixing (B1-B3), C attribute-macro blanking (B4), imported-singleton + literal-receiver resolution (C1-C2), row-id ref cleanup (C3), node -f source body (A4), multi-hump field queries (A2), plus includeIgnored and directory-delete watch semantics verified equivalent |
| NOT COVERED — portable | 2 | 41c2029 Go field-chain validated type inference (no Go receiver inference in codegraph-resolve); d6efd43 NO_COLOR / --no-color / piped-stdout policy (no such flag in codegraph-cli, though the CLI has no colouring dependency at all, so this may be "behavior naturally satisfied, flag absent" rather than a defect — verify before implementing) |
| NOT COVERED — N/A | 47 | 21 docs/CI/chore/release; 10 R7b <lang> walker commits that vendor tree-sitter grammars as C — violates this project's no-vendored-grammar invariant, and all 11 of those languages are already supported natively via crates.io grammars; 8 R1-R7a Node→napi-rs kernel migration; 8 upstream-only product/UI surfaces (clack UI, node:sqlite warnings, CodeGraph Pro signup, npm OIDC/provenance, Go route framework resolver we do not have) |
| NOT COVERED — DEFER | 26 | 19 resolution/store/synthesis perf策略 + 7 sync/WAL scheduling策略, all tuned to upstream's Node/node:sqlite runtime (pool sizing, cgroup cache credit, macOS vm_stat budgets). Byte-identical to graph output, so not parity blockers. Re-derive from a Rust profile before porting; 2adc7f6 (WAL truncate only at parked barriers) becomes a CORRECTNESS item if we ever adopt timer-triggered truncation |
R7b languages verified already present in crates/codegraph-extract/src/lang/:
Dart, Scala, Lua, Luau, R, Kotlin, Swift, PHP, Ruby, C#, Rust — 11 of 29 total
language extractors.
| sha | disposition | rationale |
|---|---|---|
572d22b TOML block finder preserves trailing [[...]] |
PORTED — this batch, 88e7773 |
Our find_next_table_header was the pre-fix logic verbatim, and reproduced with the shipped 0.42.0 binary: uninstall --target codex silently deleted a user's [[mcp_servers.other.env]] block |
f2a5df3 never serve a mis-sliced body from a drifted file |
PORTED — batch 2, v0.42.2 |
Our exposure was WORSE than upstream's: read_project_source sliced current bytes at indexed lines with no freshness check, and the staleness banner promised at instructions.rs:63 had no implementation anywhere |
f6ac7b3 blast radius follows caller chains |
PORTED — batch 2, v0.42.2 |
CALL_DEPTH = 1 plus an unconditional "; ⚠️ no covering tests found"; codegraph affected already BFSed correctly, the MCP renderer did not |
02c0e2c bound the WAL after a killed session |
PORTED — batch 3, v0.42.3 |
No journal_size_limit on any write connection, and no heal-at-open at the CLI mutation entry points. The audit's belief that the #1231 valve was bulk-index-only was WRONG and batch 3 corrected it: the valve already fired from three write paths — full index (crates/codegraph-cli/src/main.rs:4765,4776), the resolution tail (crates/codegraph-resolve/src/resolver.rs:1527), and migration (crates/codegraph-watch/src/migrate.rs:156,161) — so it did bound WAL growth across long write phases. What it never covered is the residue a KILLED session leaves behind: no path folded a WAL orphaned by a process that died mid-write, and nothing reclaimed its high-water mark. Part (c) (watchdog progressPaths) is N/A because the only watchdog here is the proxy's parent-pid watcher, which just sets a shutdown flag and holds no Store (crates/codegraph-daemon/src/proxy.rs:575-599), so there is no progressPaths to extend. Part (e) (daemon.log ISO timestamps) is N/A because local_timer() already emits RFC3339 with a UTC fallback on every tracing sink (crates/codegraph-core/src/logger.rs:93-118) |
38580e0 Python bare class refs → references edges |
PORTED — batch 4, v0.42.4 (isolated) |
All four gates were pre-fix. The ONLY item in this round that moves reference/golden/; land it alone so a golden diff has exactly one possible cause |
0682137 Claude prompt hook as codegraph.cmd |
N/A (packaging-rooted) | We ship a native codegraph.exe (install.ps1:34,144-150), never a .cmd shim; Git Bash resolves the bare name to .exe natively, so writing codegraph.cmd would name a nonexistent file |
- #1473 callers/callees/impact silently answer for a DIFFERENT symbol —
reproduced on CLI AND MCP.
exact_or_top_matchesfalls back tomatches.first()with no note, and--strictonly fires on an EMPTY result, so a substituted non-empty answer passes it. Highest-value: fails toward confident wrongness, and it is the default. → batch 2, LANDED inv0.42.2. - #1482 / #1482b TS rename-through-alias loses caller/impact edges
(
export const a = fn,export { fn as a },export default fnall produce a false zero), and.jsspecifiers never resolve to.tsbecauseextension_resolutiononly APPENDS. Golden-affecting. → LANDED inv0.42.8(4a17919, PR #196). - #1495 Kotlin signatures always absent — our
get_signaturedeliberately mirrors upstream'sundefinedwithNone; the fix pattern already exists ten lines away in the same file. Cheap, no Kotlin golden exists yet. → LANDED inv0.42.6(81628f2, PR #192), as a documented divergence from upstream. - ALREADY-HAVE, verified: #1455 (exact-name ranking shipped in
v0.42.0— but it changedsearchRANKING, so it does NOT close #1473's separate resolution path), #1451 (our sync gate is content-hash, no atime anywhere), #1447/#1445 (full Godot resolver + golden fixtures — we lead upstream here), #1464 (Qoder installer target), #1441 (javadoc already innodeoutput). - TS-only: #1443 (our binary is not inside a node-manager shim tree), #1465
(our MCP engine is request-scoped on
spawn_blocking, not one event loop), #1454 (our prompt hook walks UP only — N/A by absence), #1461 (no Spring route extraction exists).
Ports 572d22b, plus two further defects that hands-on QA surfaced in the same
function. Both were silent user-data loss, and the second was made reachable
by the first fix:
- a col-0
[mcp_servers.codegraph]inside a user's"""was accepted as our header, so the end scan started mid-string and deleted to EOF — 249 bytes → 167, unterminated string, exit 0 with "Updated", on a bareinstall --yes; - an indented header was not matched at all, so install appended a duplicate and
the config stopped parsing (
duplicate key codegraph in table mcp_servers) — pre-existing, reproduced identically with the shipped 0.42.0.
make ci 128 suites / 3097 passed / 0 failed (+26 tests), reference/ untouched,
scope confined to crates/codegraph-cli/. Four Final-Wave gates APPROVED; F3 ran
a ~60-fixture matrix over three rounds and is what found both extra defects.
Ports f2a5df3 and f6ac7b3 from the 1.5.0 range plus issue #1473 from the
triage above. Each was an honesty defect — the graph asserting something it
had not established:
- #1473 silent symbol substitution. A lookup matching no exact symbol fell
through to the top-ranked fuzzy result, so
callers adanswered with rows belonging toadd. CLI lookup commands now exit non-zero pointing atcodegraph query; MCP returnsisError: truepointing atcodegraph_search. Exact matching was widened toqualified_nameand Godot resource paths so the supported dotted-name and.tscnlookups survive. Decision A1 chose REFUSE over annotate; A2 froze--strict(its 5 consumers are byte-unchanged). f2a5df3drifted source served at stored line numbers, returning a different symbol's body. A request-memoized probe compares size + millisecond mtime first and hashes only on a stat mismatch (decision B1). A drifted file is emitted whole up toFILE_MODE_MAX_LINES = 2000or omitted with a notice — never sliced (B2).docs/mcp.mdhad documented a staleness banner that nothing produced; B3 made it real. Case 3 of the issue was deliberately NOT implemented.f6ac7b3unmeasured coverage denial. Blast radius claimed "no covering tests" after inspecting direct callers only. It now walks callers through hop 3 under a 64-lookup budget with an uncapped frontier and a 2-file display cap (C1), and reports what it actually searched.
Five review-found defects in the fixes themselves, all in codegraph-mcp:
freshness defaulted to fresh when the FileRecord was missing / the query failed
/ the read failed (reachable — sync deletes the file record before upserting
nodes and re-inserts it last, so a concurrent reader sees nodes whose file has no
record); the oversized branch compared size alone, so a same-size rewrite read
as fresh; a swallowed get_callers error still produced the strong three-hop
claim; a duplicated whole-file-fits predicate diverged from the rendering decision
at the trailing-newline boundary, banner-listing a 2000-line file whose source was
omitted; and the first liveness gate inferred section survival by matching
#### {path} — in the response text — source bytes as a control channel,
spoofable by a marker literal in a retained file (this repo's own test source
contains one). Freshness is now fail-closed via
SourceFreshness::{ProvenFresh, PossiblyDrifted}, and banner liveness comes from
cut_at_section_boundary's surviving-prefix length plus per-section offsets.
make ci 128 suites / 3110 passed / 0 failed. Each fix RED-proven by isolated
revert. cut_at_section_boundary's new (String, usize) signature is
byte-identical to the old output (200k randomized inputs, 0 mismatches); the
section-offset formula and its <= predicate likewise (200k combinations, 0
errors). One audited golden movement:
reference/golden/mcp/codegraph_explore.json, 4 blast-radius lines re-worded
(⚠️ no covering tests found → no tests found within 3 caller hops), the rest
byte-identical. instructions.rs, initialize.json, codegraph-store/, and
codegraph-core/ untouched. Four Final-Wave gates APPROVED — F2 took three rounds
and is what found all five extra defects; F3 hands-on QA covered CLI and real MCP
stdio across six drift scenarios (and established that MCP drift cases need
--no-watch, since a background re-index legitimately clears the drift).
Parity did not advance at this point. Batch 3 (02c0e2c WAL
journal_size_limit + heal-at-open) and batch 4 (38580e0 Python bare class refs
— the only golden-moving item, to land isolated) were still open; both have since
shipped, and the CLOSEOUT entry above advances parity to 1.5.0.
The 1.2.0 → 1.4.1 sync program evaluated on 2026-07-10 is now finished. Every
chosen PORT item landed, the DEFER phase ran to completion across nine
releases, and the two structurally-blocked languages (COBOL, VB.NET) are
recorded as permanently deferred. Tracked colby parity advances from 1.2.0 to
1.4.1. This entry is the compact index; each release has its own detailed
LANDED entry below (and Release D/E have their own dated entries further down)
— read those for the per-item disposition tables.
Full release table, v0.28.3 → v0.39.0:
| Release | Item(s) shipped |
|---|---|
v0.28.3 |
fix(cli): cold-start MCP handshake race (pre-program fix, not part of the chosen subset) |
v0.28.4 |
fix(ci): release CI gate + de-flake reopen test (pre-program fix, not part of the chosen subset) |
v0.29.1 |
Release A — #1187 orphaned-ref heal-on-sync, #1200/#1185 daemon lifecycle backstops, #1231 WAL-valve (bulk-index half) |
v0.30.0 |
Release B — #1063 codegraph.json include list |
v0.30.1 |
Release C — #1220 PHP $this->prop->method() declared-type resolution |
v0.31.0 |
Release D — C++ namespace-qualified names + template-arg call linking, #1158/#1159/#1133 UE reflection-macro recovery + .h C-vs-C++ detection, #1124 Lua/Luau annotation self-match gate |
v0.31.1 |
DEFER E — #1212 bounded-memory resolution tail: large-graph streaming fallback + WAL valve extended into the resolution write loop (most of #1212 was N/A for Rust; only these two sub-parts were portable) |
v0.32.0 |
DEFER F — prompt-hook confidence-tiered gate: #1126 multilingual structural-keyword gate, #1138 stem-bounding, #1136 confidence-tier mechanics (query-time vocab substitution, no schema change), #1144/#1145/#1146 segment-match integrity — all telemetry excluded |
v0.33.0 |
DEFER G — Metal (.metal) + CUDA (.cu/.cuh) via the existing tree-sitter-cpp grammar (no new Language variant) |
v0.34.0 |
DEFER H1 — ArkTS (.ets) via tree-sitter-arkts; ArkUI dispatch/callback-synthesis bridges deferred |
v0.35.0 |
DEFER H2 — Solidity (.sol) via tree-sitter-solidity; fully self-contained, nothing deferred |
v0.36.0 |
DEFER H3 — Nix (.nix) via tree-sitter-nix; module-system/callback-synthesizer bridges deferred |
v0.37.0 |
DEFER H4 — Terraform/HCL (.tf/.tfvars/.tofu) via tree-sitter-hcl; module-boundary TerraformResolver deferred |
v0.38.0 |
DEFER H5 — Erlang (.erl/.hrl) via tree-sitter-erlang; OTP behaviour/gen_server/spawn-MFA bridges deferred |
v0.39.0 |
DEFER H6 — CFML/ColdFusion (.cfc/.cfm/.cfs) via dual-grammar tree-sitter-cfml; <cfscript>-in-tag delegation, cfquery, and framework/receiver-type resolvers deferred |
Permanently deferred (H7/H8) — no crates.io grammar available:
| Item | Reason |
|---|---|
COBOL (.cbl/.cob/.cpy) |
tree-sitter-cobol on crates.io is a name-squat stub (768 bytes, println!("to come!"), no real grammar, no tree-sitter dependency). Adding COBOL would require vendoring a git grammar, which violates this project's no-vendored-grammar invariant. Deferred until a real crate ships. |
VB.NET (.vb) |
No crate exists on crates.io at all — tree-sitter-vbnet/-visual-basic/-vb are absent; the only near-match, tree-sitter-vb6, is VB6, not VB.NET. Same no-vendor blocker. Deferred. |
Parity caveats (see ## Current alignment above for the full text):
framework-resolution bridges deferred per-language (ArkUI, Nix module-system,
Terraform module-boundary, Erlang OTP, CFML receiver-type); COBOL/VB.NET
permanently deferred for lack of a crates.io grammar; prompt-hook telemetry
excluded by policy; TS/Node-runtime-only items recorded as N/A. Everything else
portable and in-scope for 1.2.0 → 1.4.1 has landed.
2026-07-17 — LANDED DEFER item H6: CFML / ColdFusion (.cfc/.cfm/.cfs, #1153 816bacb) via the dual-grammar tree-sitter-cfml crate — the EXTRACTION SLICE only, scope B (<cfscript>-in-tag delegation + cfquery + framework/receiver-type resolvers deferred)
Landed DEFER item H6 — the scope-B extraction slice of the upstream
816bacb ("feat(extraction): add CFML/ColdFusion language support (#1153)").
CFML is a NEW Language::Cfml variant backed by the DUAL-GRAMMAR
tree-sitter-cfml = "0.26.30" crate (crates.io; bundles a cfscript script
grammar + a cfml tag grammar + a cfquery SQL dialect; LanguageFn ABI — no
vendored grammar/wasm). CFML has two syntaxes: a first-token sniff
(is_bare_script_cfml, BOM+ws+comment skip → first token != '<') picks the
dialect+grammar PER FILE. This is expressed through a new defaulted
LanguageSpec::tree_sitter_language_for_source(&self, source) trait hook
(default = self.tree_sitter_language()); only CfmlSpec overrides it, so all
41 other specs are byte-identical. Bare-script files (.cfs + bare .cfc/.cfm)
parse with cfscript and drive the generic type-set dispatch; tag files parse
with the cfml tag grammar and are handled by the Language::Cfml-guarded
visit_cfml_node walker extension.
| Upstream hunk | Disposition | Notes |
|---|---|---|
types.ts: 'cfml'/'cfscript'/'cfquery' in LANGUAGES |
PORT (one variant) | ONE Language::Cfml maps all three extensions; cfscript/cfquery are internal grammar handles. Language::ALL 41→42, LANGUAGE_STRINGS 41→42 in lockstep |
grammars.ts: .cfc/.cfm→cfml, .cfs→cfscript EXTENSION_MAP + display |
PORT | "cfc" | "cfm" | "cfs" => Language::Cfml in builtin_language_for_ext; as_str "cfml" |
grammars.ts: 3 vendored wasm + ABI-15 branch |
N/A | port pins tree-sitter-cfml from crates.io — no vendored wasm |
cfml-extractor.ts: isBareScriptCfml dialect switch |
PORT | is_bare_script_cfml first-token detector; drives tree_sitter_language_for_source + visit_cfml_node dialect gate |
cfml-extractor.ts: extractBareScript (delegate to cfscript, file-name component) |
PORT | cfscript type-set config drives generic dispatch; emit_cfml_script_component renames the unnamed component/interface from the file + script-style extends→Extends |
cfml-extractor.ts: extractTagBased walkProgram/extractComponent/extractFunctionTag/tagAttr |
PORT | visit_cfml_node tag walk: cf_component_open_tag→Class (name attr/file, extends/implements refs, following-sibling body via cfml_consumed_until), cf_function_tag→Method/Function |
cfscript.ts: getVisibility/getSignature/extractImport/classifyClassNode |
PORT | CfmlSpec overrides (visibility from access_type, signature from parameters, imports, interface-vs-class) |
cfml-extractor.ts: delegateScriptTag (<cfscript> body re-parse) |
DEFER | needs a 2nd in-tree parse the one-spec-one-grammar engine lacks |
cfml-extractor.ts: delegateQueryTag / cfquery.ts (LANGUAGE_CFQUERY) |
DEFER | cfquery SQL-body extraction — same 2nd-parse limitation |
| CFML framework resolver (#1152/#1154/#1155: dotted/relative inheritance, receiver-type inference) | DEFER | no 2nd FrameworkResolver; port keeps its single GodotResolver |
__tests__/extraction.test.ts (+308) |
DEFER | re-implemented as Rust unit + golden tests |
Golden impact: .schema byte-stable (language is a stored TEXT VALUE, not DDL —
schema_parity green, colby.schema.sql byte-identical); the eleven existing
goldens (cpp/godot/ruby/mini/metal/cuda/arkts/solidity/nix/terraform/erlang)
byte-neutral (none holds a .cfc/.cfm/.cfs file, no regen); one NEW cfml
golden (reference/golden/cfml/, corpus crates/codegraph-bench/fixtures/cfml/
— script Base.cfc, tag Widget.cfm, bare-script Gadget.cfs) carries the only
"language":"cfml" string. Both extends Base refs RESOLVE to Base.cfc as
EDGES; Gadget.doThing's helper() call is the sole unresolved refs.json row.
The DEFERRED <cfscript>-in-tag / cfquery / framework-resolver edges are never
emitted. Extraction-tier add matching the port's other 28 grammar-backed Tier-1
languages (same discipline as ArkTS H1 / Solidity H2 / Nix H3 / Terraform H4 /
Erlang H5).
Tracked colby parity stays 1.2.0 (advances to 1.4.1 only once the full
1.2.0..1.4.1 PORT/DEFER subset lands — this is one item of that subset).
2026-07-16 — LANDED DEFER item H5: Erlang (.erl/.hrl, #1165 6511722) via a dedicated tree-sitter-erlang grammar — the EXTRACTION SLICE only (behaviour/gen_server/spawn-MFA framework bridges deferred)
Landed DEFER item H5 — the extraction slice ONLY of the upstream 6511722
("feat(extraction): add Erlang language support with OTP behaviour/gen_server
bridging (#1165)"). Erlang is a NEW Language::Erlang variant backed by a NEW
grammar crate (tree-sitter-erlang = "0.19.0", crates.io, WhatsApp/ELP grammar;
LanguageFn ABI — no vendored grammar). Erlang is form-based (a function's name
lives on its function_clause, the grammar emits one fun_decl per clause,
record_decl carries fields as direct children, -spec/-callback/type bodies
parse as call nodes), so ERLANG_SPEC has all-empty C-family type-sets (only
package_types/import_types wired, as upstream) and the extraction is driven
entirely by a Language::Erlang-guarded visit_erlang_node walker extension.
| Upstream hunk | Disposition | Notes |
|---|---|---|
types.ts: 'erlang' in LANGUAGES |
PORT | new Language::Erlang variant; Language::ALL 40→41, LANGUAGE_STRINGS 40→41 in lockstep |
grammars.ts: .erl/.hrl EXTENSION_MAP + Erlang display |
PORT | "erl" | "hrl" => Language::Erlang in builtin_language_for_ext |
erlang.ts erlangExtractor config (fun_decl/record_decl/type_alias/opaque/import_attribute/pp_include(_lib), packageTypes: module_attribute, name/body/params fields) |
PORT | ERLANG_SPEC wires package_types+import_types; the C-family type-sets stay empty (form-based) |
erlang.ts handleFunDecl clause-merge dedup |
PORT | visit_erlang_fun_decl tracks (last_fn_name, last_fn_id); a same-name continuation fun_decl attaches to the existing node |
erlang.ts handleRecordDecl (struct + direct-child fields) |
PORT | visit_erlang_record_decl |
erlang.ts handleTypeAlias/handlePpDefine |
PORT | TypeAlias / Constant, type-position call children NOT descended |
erlang.ts spec/callback type-position guard |
PORT | both consumed without descent — -spec f(integer())->integer(). mints no integer call ref |
tree-sitter.ts erlang extractCall: local call→calls, remote mod:f→mod::f, ?MODULE:f→bare |
PORT | erlang_call_ref_name (reads module qualifier from the PARENT remote node) |
tree-sitter.ts internal_fun/external_fun→references, record-expr forms→references |
PORT | function VALUES + record USAGES are References, not Calls |
erlang.ts handleBehaviour (-behaviour(x)→implements) |
DEFER | non-Godot framework resolution; the port has one concrete FrameworkResolver (GodotResolver) |
tree-sitter.ts gen_server call/cast(?MODULE|?SERVER)→handle_call/handle_cast (resolveErlangGenServerTarget) |
DEFER | framework bridge |
tree-sitter.ts spawn/apply/proc_lib/timer/rpc MFA-argument callee lift (ERLANG_MFA_CALLS) |
DEFER | framework bridge |
tree-sitter.ts macro_call_expr use-site→-define constant linking + ERLANG_PREDEFINED_MACROS |
DEFER | macro use-site call chain; the -define Constant symbol is still emitted |
erlang.ts handleAppResourceTuple (.app/.app.src {application,...} wiring) |
DEFER | framework/resource resolution |
__tests__/*.test.ts (resolver + extraction) |
DEFER | re-implemented as Rust unit + golden tests |
Golden impact: .schema byte-stable (language is a stored TEXT VALUE, not DDL —
schema_parity green, colby.schema.sql byte-identical); the ten existing
goldens (cpp/godot/ruby/mini/metal/cuda/arkts/solidity/nix/terraform)
byte-neutral (none holds a .erl/.hrl file, no regen); one NEW erlang golden
(reference/golden/erlang/, corpus crates/codegraph-bench/fixtures/erlang/m.erl)
carries the only "language":"erlang" string. Its local g() self-call and the
foo.hrl include resolve as EDGES; the remote other::h (the other module is
absent from the fixture) is the sole unresolved refs.json row; the DEFERRED
behaviour/gen_server/spawn-MFA/.app edges are never emitted. This is an
extraction-tier add matching the port's other 27 grammar-backed Tier-1 languages
(same disposition as ArkTS H1 / Nix H3 / Terraform H4 deferred bridges).
Tracked colby parity stays 1.2.0 (advances to 1.4.1 only once the full
1.2.0..1.4.1 PORT/DEFER subset lands — this is one item of that subset).
2026-07-15 — LANDED DEFER item H4: Terraform/HCL (.tf/.tfvars/.tofu, #1173 6c24f4b) via a dedicated tree-sitter-hcl grammar — the EXTRACTION SLICE only (module-boundary framework resolver deferred)
Landed DEFER item H4 — the extraction slice ONLY of the upstream 6c24f4b
("feat(extraction): add Terraform/OpenTofu language support with module-boundary
bridging (#83, #310, #648 — carries #706) (#1173)"). Terraform is a NEW
Language::Terraform variant backed by a NEW grammar crate
(tree-sitter-hcl = "1.1.0", crates.io, Apache-2.0; LanguageFn ABI — no
vendored tree-sitter-terraform.wasm). HCL is intentionally generic — every
top-level construct is a block distinguished only by its first identifier
child — so there are no C-family type-set node kinds; TERRAFORM_SPEC has
all-empty type-sets (faithful to upstream's empty terraformExtractor config) and
the extraction is driven entirely by a Language::Terraform-guarded
visit_terraform_node walker extension (the same custom-visitor pattern as
visit_nix_node). Per-item disposition:
upstream (6c24f4b) |
disposition | notes |
|---|---|---|
types.ts: 'terraform' in LANGUAGES |
PORT | new Language::Terraform variant; Language::ALL 39→40, LANGUAGE_STRINGS 39→40 in lockstep |
grammars.ts: .tf/.tfvars/.tofu EXTENSION_MAP + Terraform display |
PORT | "tf" | "tfvars" | "tofu" => Language::Terraform in builtin_language_for_ext |
grammars.ts: vendored tree-sitter-terraform.wasm ABI-15 branch |
N/A | port pins tree-sitter-hcl = "1.1.0" from crates.io — no vendored wasm |
languages/index.ts: register terraformExtractor |
PORT | TERRAFORM_SPEC (empty type-sets) + spec_for_language arm + parse_language (queries.rs) |
terraform.ts visitNode: block-type dispatch resource/data→class, module→module, variable/output→variable, provider→namespace, locals→constant; plain traversal refs |
PORT | visit_terraform_node + visit_terraform_locals + emit_terraform_references_in_body + the pure pub(crate) AST helpers in lang/terraform.rs |
terraform.ts emitModuleWiring: module.M:file/:var.X/:output.X :-scoped refs |
DEFER | feeds the deferred TerraformResolver; a module block still emits its Module symbol + plain body refs |
terraform.ts .tfvars top-level-assignment var.X ref |
DEFER | feeds the deferred .tfvars ancestor-walk; .tfvars files still index as Language::Terraform file nodes |
terraform.ts qualifyReference module.M:output.<out> scoped half |
DEFER | plain module.M PORTED; the :output scoped half feeds the deferred resolver |
resolution/frameworks/terraform.ts (+195): TerraformResolver (directory-scoped resolution, :-scoped bridge, .tfvars walk) |
DEFER | the port has exactly one concrete FrameworkResolver (GodotResolver); a second is out of scope for the extraction-tier program |
resolution/frameworks/index.ts (+3): register terraformResolver |
DEFER | nothing to register |
resolution/index.ts (+6): terraform directory-scoping gate |
DEFER | resolution-tier gate |
__tests__/frameworks-integration.test.ts (+131), __tests__/extraction.test.ts (+290) |
DEFER | resolver tests / re-implemented as Rust unit + golden tests |
Golden impact: .schema byte-stable (language is a stored TEXT VALUE, not DDL —
schema_parity green, colby.schema.sql byte-identical); the nine existing
goldens (cpp/godot/ruby/mini/metal/cuda/arkts/solidity/nix)
byte-neutral (none holds a .tf/.tfvars/.tofu file, no regen); one NEW
terraform golden (reference/golden/terraform/, corpus
crates/codegraph-bench/fixtures/terraform/main.tf) carries the only
"language":"terraform" string in the corpus. Its plain traversal refs with a
unique same-file target resolve via the existing generic qualified-name matcher
(var.region ×3 → the variable, aws_s3_bucket.b → the resource, module.vpc →
the module — all EDGES), leaving the undeclared aws_kms_key.logs as the sole
unresolved refs.json row; the DEFERRED emitModuleWiring :-scoped refs and
.tfvars var ref are never emitted. This is an extraction-tier add matching the
port's other 26 grammar-backed Tier-1 languages (same disposition as ArkTS H1's
deferred ArkUI bridges + Nix H3's module-system synthesizer).
Tracked colby parity stays 1.2.0 (advances to 1.4.1 only once the full
1.2.0..1.4.1 PORT/DEFER subset lands — this is one item of that subset).
2026-07-15 — LANDED DEFER item H3: Nix (.nix, #1190 7f32513) via a dedicated tree-sitter-nix grammar — the EXTRACTION SLICE only (module-system bridges deferred)
Landed DEFER item H3 — the extraction slice ONLY of the upstream 7f32513
("feat(extraction): add Nix language support with module-system option wiring").
Nix is a NEW Language::Nix variant backed by a NEW grammar crate
(tree-sitter-nix = "0.3.0", crates.io, MIT; LanguageFn ABI — no vendored
wasm). Because Nix is an expression language with no C-family
class/struct/method/enum node kinds, NIX_SPEC has all-empty type-sets
(faithful to upstream's empty nixExtractor config) and the extraction is driven
entirely by a Language::Nix-guarded visit_nix_node walker extension (the same
custom-visitor pattern as visit_gdscript_node). Per-item disposition:
upstream (7f32513) |
disposition | notes |
|---|---|---|
types.ts: 'nix' in LANGUAGES (after 'solidity') |
PORT | new Language::Nix variant; Language::ALL 38→39, LANGUAGE_STRINGS 38→39 in lockstep |
grammars.ts: '.nix': 'nix' EXTENSION_MAP + Nix display |
PORT | "nix" => Language::Nix in builtin_language_for_ext |
languages/index.ts: register nixExtractor |
PORT | NIX_SPEC (empty type-sets) + spec_for_language arm + parse_language (queries.rs) |
nix.ts visitNode: binding→function|variable, curried lambda signature, inherit, apply→calls/imports, import/callPackage/imports-list paths |
PORT | visit_nix_node + emit_nix_file_import + the pure pub(crate) AST helpers in lang/nix.rs |
resolution/callback-synthesizer.ts (+178) |
DEFER | the port has no callback-synthesis subsystem |
resolution/index.ts (+31): lexical-scope resolution gates |
DEFER | Nix let/with/rec scope-aware resolution — resolution tier |
resolution/import-resolver.ts (+34): module-list wiring |
DEFER | binds imports/modules path refs; the EXTRACTION emits them, the RESOLVER wiring is deferred |
db/queries.ts (+15) getNodesByNamePrefix + mcp/tools.ts (+31): option-path lookup |
DEFER | query surface feeding the deferred option-path synthesizer |
src/index.ts (+5): module-lists glue; __tests__/nix-option-synthesizer.test.ts |
DEFER | synthesizer glue + its tests |
Golden impact: .schema byte-stable (language is a stored TEXT VALUE, not DDL —
schema_parity green, colby.schema.sql byte-identical); the eight existing
goldens (cpp/godot/ruby/mini/metal/cuda/arkts/solidity)
byte-neutral (none holds a .nix file, no regen); one NEW nix golden
(reference/golden/nix/, corpus crates/codegraph-bench/fixtures/nix/) carries
the only "language":"nix" string in the corpus. Its imports/callPackage
path refs resolve in-corpus (the referenced .nix files exist), so refs.json
retains only the three unresolved Calls refs — the DEFERRED module-system
synthesizer / import-resolver wiring binds nothing new. This is an extraction-tier
add matching the port's other 25 grammar-backed Tier-1 languages (same disposition
as ArkTS H1's deferred ArkUI bridges).
Tracked colby parity stays 1.2.0 (advances to 1.4.1 only once the full
1.2.0..1.4.1 PORT/DEFER subset lands — this is one item of that subset).
2026-07-15 — LANDED DEFER item H2: Solidity (.sol, #1170 1441933) via a dedicated tree-sitter-solidity grammar — the WHOLE commit (all extraction; nothing deferred)
Landed DEFER item H2 — the FULL upstream 1441933 ("feat(extraction): add
Solidity language support (.sol)"). Unlike H1 (ArkTS, which deferred a
callback-synthesizer slice), the whole Solidity commit is EXTRACTION — there is
no bundled framework-resolution / runtime-dispatch layer, so nothing is
deferred for H2. Solidity is a NEW Language::Solidity variant backed by a NEW
grammar crate (tree-sitter-solidity = "1.2.13", crates.io, MIT; LanguageFn
ABI — no vendored wasm). Per-item disposition:
upstream (1441933) |
disposition | notes |
|---|---|---|
types.ts: 'solidity' in LANGUAGES |
PORT | new Language::Solidity variant; Language::ALL 37→38, LANGUAGE_STRINGS 37→38 in lockstep |
grammars.ts: '.sol': 'solidity' EXTENSION_MAP |
PORT | "sol" => Language::Solidity in builtin_language_for_ext |
languages/index.ts: register solidityExtractor |
PORT | SOLIDITY_SPEC + spec_for_language arm + parse_language (queries.rs) |
solidity.ts: contract/library/interface/struct/enum node-kind sets |
PORT | contract/library → Class, interface → Interface, struct → Struct, enum → Enum (generic dispatch) |
solidity.ts: synthetic ctor/fallback/receive names (resolveName) |
PORT | SOLIDITY_SPEC::resolve_name |
solidity.ts: getSignature (walk direct parameter/return_type_definition/visibility/state_mutability) |
PORT | params are direct children, not a parameters field |
solidity.ts: visitNode inheritance (inheritance_specifier) |
PORT | walker D3 (user_defined_type ancestor → Extends; resolver promotes to Implements for interfaces) |
solidity.ts: visitNode state-var/struct-member/event/error → field |
PORT | walker D5 direct-name field fallback (+ D10 for file-level event/error) |
solidity.ts: visitNode enum_value |
PORT | walker D6 bare-text enum_value → EnumMember |
solidity.ts: file-level constant_variable_declaration |
PORT | walker D8 Solidity arm in extract_variable → Constant |
solidity.ts: extractImport (source string) |
PORT | SOLIDITY_SPEC::extract_import |
tree-sitter.ts: extractDecoratorsFor modifier_invocation → calls |
PORT | walker D7 header modifier_invocation → Calls (NOT Decorates) |
is→implements reclassification + import resolution |
EXISTING RESOLVER | served by resolver.rs:1231-1247 + name matcher + import resolver — zero new resolve-tier code |
Golden impact: .schema byte-stable (language is a stored TEXT VALUE, not DDL —
schema_parity green, colby.schema.sql byte-identical); the seven existing
goldens (cpp/godot/ruby/mini/metal/cuda/arkts) byte-neutral (none
holds a .sol file, no regen); one NEW solidity golden
(reference/golden/solidity/, corpus crates/codegraph-bench/fixtures/solidity/)
carries the only "language":"solidity" string in the corpus. Being fully
self-contained, its refs.json is empty and edges.json holds the resolved
Implements (Token → IERC20) + Calls (transfer → onlyOwner,
transfer → Transfer) edges. This is an extraction-tier add matching the port's
other 24 grammar-backed Tier-1 languages.
Tracked colby parity stays 1.2.0 (advances to 1.4.1 only once the full
1.2.0..1.4.1 PORT/DEFER subset lands — this is one item of that subset).
2026-07-15 — LANDED DEFER item H1: ArkTS (.ets, extraction slice of #1186 9915221) via a dedicated tree-sitter-arkts grammar
Landed DEFER item H1 — the extraction slice ONLY of the upstream ArkTS
(HarmonyOS / OpenHarmony .ets) support. Unlike Metal/CUDA (item G), ArkTS is a
NEW Language::ArkTs variant backed by a NEW grammar crate
(tree-sitter-arkts = "0.2.0", a TypeScript-superset fork that parses the ArkUI
@Component struct syntax tree-sitter-typescript cannot). Per-item disposition:
upstream (9915221) |
disposition | notes |
|---|---|---|
types.ts: 'arkts' in LANGUAGES |
PORT | new Language::ArkTs variant; Language::ALL 36→37, LANGUAGE_STRINGS 36→37 in lockstep |
grammars.ts: '.ets': 'arkts' EXTENSION_MAP |
PORT | "ets" => Language::ArkTs in builtin_language_for_ext; plain .ts stays TypeScript |
languages/index.ts: register arktsExtractor |
PORT | ARKTS_SPEC + spec_for_language arm + parse_language (queries.rs) |
arkts.ts: structTypes: ['struct_declaration'] |
PORT | @Component struct → NodeKind::Struct via the existing extract_struct path (no walker change) |
arkts.ts: callTypes — the 'call_expression' element |
PORT | call_types = ["call_expression"] |
arkts.ts: callTypes — arkui_component_expression/leading_dot_expression |
DEFER | ArkUI component-instantiation / attribute-chain dispatch |
arkts.ts: extractModifiers/collectDecoratorNames decorator hook |
DEFER | feeds the deferred state→build() synthesizer; extract_modifiers left at trait default |
tree-sitter.ts: arkts extractCall branch (attribute chains, .onXxx) |
DEFER | ArkUI resolution heuristics |
state→build() re-render, emitter emit→subscriber, router→@Entry bridges |
DEFER | callback synthesizer the port lacks |
ohpm oh-package.json5 workspace-package import resolution |
DEFER | import-resolver feature |
$r/$rawfile intrinsics, web-family/value-ref/re-export gates |
DEFER | resolution-side gates |
index_state / index-completeness guard |
DEFER | unrelated subsystem |
Golden impact: .schema byte-stable (language is a stored TEXT VALUE, not DDL —
schema_parity green, colby.schema.sql byte-identical); the six existing
goldens (cpp/godot/ruby/mini/metal/cuda) byte-neutral (none holds a
.ets file, no regen); one NEW arkts golden
(reference/golden/arkts/component.ets) carries the only "language":"arkts"
string in the corpus. Rationale for the DEFER slice: the port has no
callback-synthesizer subsystem and treats every non-Godot framework's
runtime-dispatch layer as out of scope (consistent with Godot being the ONE
concrete FrameworkResolver). This is an extraction-tier add matching the port's
25 other grammar-backed languages.
Tracked colby parity stays 1.2.0 (advances to 1.4.1 only once the full
1.2.0..1.4.1 PORT/DEFER subset lands — this is one item of that subset).
2026-07-14 — LANDED DEFER item G: Metal (.metal, #1121 cc89146) + CUDA (.cu/.cuh, CUDA-lang parts of #1172 e1a8d88) via the existing C++ grammar
Landed DEFER item G — the two cheapest deferred languages from the
1.2.0..1.4.1 subset. Both ride the ALREADY-PRESENT tree-sitter-cpp grammar
(no new grammar crate) and map to Language::Cpp (no new Language variant,
so .schema + Language::ALL len 36 are byte-stable). Per-item disposition:
| upstream | what it is | disposition | golden impact |
|---|---|---|---|
#1121 cc89146 .metal→cpp map |
Metal Shading Language extension mapping | PORT (engine.rs builtin_language_for_ext) |
NEUTRAL for existing fixtures; NEW metal fixture |
#1121 cc89146 blankMetalAttributes |
offset-preserving .metal-gated [[attribute]] blank (prevents spurious extends) |
PORT (lang/cpp.rs blank_metal_attributes) |
NEUTRAL (gate proven: [[nodiscard]] in .cpp byte-identical) |
#1172 e1a8d88 .cu/.cuh→cpp map |
CUDA extension mapping | PORT (engine.rs) |
NEUTRAL for existing fixtures; NEW cuda fixture |
#1172 e1a8d88 blankCudaConstructs |
specifier + __launch_bounds__ + brace-balanced <<<…>>> launch blank (offset-preserving) |
PORT (lang/cpp.rs blank_cuda_constructs) |
NEUTRAL (content/ext-gated; no CUDA markers in existing fixtures) |
#1172 e1a8d88 looksLikeCudaSource |
strong content markers (__global__/__device__/__constant__/cudaStream_t) |
PORT (lang/cpp.rs looks_like_cuda_source) |
NEUTRAL |
#1172 e1a8d88 preParseCSource |
C-detected .h headers get the content-gated CUDA blank |
PORT (lang/c.rs CSpec::pre_parse) |
NEUTRAL |
#1172 e1a8d88 recoverCppMacroDefinedName |
name-in-first-arg macro-kernel recovery (DEFINE_FLASH_FORWARD_KERNEL(name, …); gtest/pybind bail) |
PORT (lang/cpp.rs + CppSpec::resolve_name) |
NEUTRAL (narrow gate; NEW cuda fixture guards it) |
#1172 e1a8d88 namespace-prefix + template-arg call strip |
(Release D Items 1+2) | EXCLUDE — already landed in Release D | n/a |
#1172 e1a8d88 cppLocalFnPtrs local-fn-ptr launch dispatch (auto k = &fn<…>; k<<<…>>>(…)) |
narrow real-world pattern, per-body binding map | DEFERRED within G (recorded gap; primary launch edges resolve without it) | n/a |
Enabling change: threaded file_path: &str into the LanguageSpec::pre_parse
trait method (was path-less) — the faithful analogue of upstream's optional
filePath param, needed for the Metal .metal gate. Default body ignores the
path; CsharpSpec gains an unused _file_path, CppSpec/CSpec use it.
New golden fixtures: reference/golden/metal/ (shader.metal) and
reference/golden/cuda/ (kernel.cu), wired into equivalence.rs mirroring the
cpp pair. The cpp/godot/ruby/mini goldens are byte-identical (no regen).
See docs/equivalence.md "Metal fixture" / "CUDA fixture" for the regen recipe.
Tracked parity STILL 1.2.0 — advances to 1.4.1 only in the final ledger step
once ALL PORT/DEFER items land.
2026-07-14 — LANDED DEFER item F: prompt-hook confidence-tiered gate (#1126 + #1138 + #1136 mechanics; telemetry EXCLUDED; golden-neutral)
Landed DEFER item F — the prompt-hook gate improvements from colby
1.2.0..1.4.1 — turning codegraph prompt-hook from a bare unconditional
codegraph_explore forwarder into a three-tier confidence gate. All telemetry is
EXCLUDED by maintainer decision (this port has no tracking pipeline and this
change introduces none). Per-item disposition (each cited to the upstream diff):
| upstream | what it is | disposition | golden impact |
|---|---|---|---|
#1126 317e7f4 |
multilingual structural-keyword gate (WORDS + STEMS + UNSEGMENTED, Unicode bounds) | PORT (structural_gate.rs) |
NEUTRAL (pure gate logic in the CLI path) |
#1138 713ab7a |
right-bound call/trace/affect/connect stems (callus/Connecticut don't fire) |
PORT (folded into structural_gate.rs) |
NEUTRAL |
#1136 e699ee9 mechanics |
confidence-tiered injection (HIGH full-explore / MEDIUM pointer / silent); tokens | PORT-minus-telemetry | NEUTRAL (MEDIUM tier derived at query time — see below) |
#1136 name_segment_vocab table + schema v7 + write path |
index-time materialized vocab | N-A (design-substituted) — replaced by query-time derivation from distinct_non_file_node_names; NO table, NO migration |
NEUTRAL by substitution (a table would break schema_parity) |
| #1136 gate telemetry / #be55b93 | anonymous gate-outcome usage counters | EXCLUDE-telemetry | n/a (not ported) |
| #35611b9 #1144 | skip file/import-only names as surfaced symbols | PORT (isSegmentableKind gate in distinct_non_file_node_names + representative pick) |
NEUTRAL |
| #35611b9 #1145 | English-plural variant folding correctness (segment_lookup_variants) |
PORT (segments.rs) |
NEUTRAL |
| #35611b9 #1146 | co-occurrence variant folding (a plural pair of one word ≠ a two-word match) | PORT (in-Rust word fold in get_segment_matches) |
NEUTRAL |
| #35611b9 #1141/#1142 | updateNode vocab write / heal-if-empty | N-A — no write-path vocab in the query-time design | NEUTRAL |
What landed (all in crates/codegraph-cli, plus one read-only store query):
structural_gate.rs (the multilingual WORDS/STEMS/UNSEGMENTED term lists copied
verbatim from directory.ts, matched with lookaround-free capture-class
boundaries since Rust regex has no lookbehind; has_structural_keyword;
extract_code_tokens), segments.rs (split_identifier_segments,
normalize_prose_word, extract_prose_candidates + full ENGLISH_PROSE_STOPWORDS,
segment_lookup_variants), segment_match.rs (get_segment_matches + the
SegmentMatch struct — Tier-A co-occurrence + Tier-B rare-word, ported from
index.ts), and distinct_non_file_node_names in codegraph-store (the
golden-neutral query-time substitution for the index-time vocab table).
cmd_prompt_hook now parses the Claude {prompt,cwd} JSON payload (raw-string
fallback preserved), honors the CODEGRAPH_NO_PROMPT_HOOK/CODEGRAPH_PROMPT_HOOK
kill-switch, and runs the HIGH → MEDIUM → silent gate.
Telemetry is EXCLUDED in full — no counter, no gate() recording, no
DO_NOT_TRACK surface, nothing that phones home. The schema version 7 is unchanged:
NO name_segment_vocab table and NO migration were added — the
MEDIUM tier is derived at query time from existing node names, so
reference/golden/colby.schema.sql and all golden fixtures stay byte-identical
(schema_parity + cargo test -p codegraph-bench green, NO regen). No new
AI/vector/LLM crate (guardrail clean); the two added deps (regex,
unicode-normalization) are plain-text crates.
Outcome: DEFER-F is CLOSED. This is a golden-NEUTRAL, telemetry-free feat:
release. Tracked parity advances toward 1.4.1 for the prompt-hook gate surface;
the segment-vocab table remains intentionally N-A by query-time substitution.
2026-07-14 — LANDED DEFER item E: #1212 (a3f9008) bounded-memory resolution tail (2 PORTs; golden-neutral)
Re-evaluated DEFER item E — a3f9008 "bounded-memory yielding pipeline tail +
daemon session fixes (#1212) (#1226)" — after a momus review. #1212 is MOSTLY
N/A (its TS event-loop yields and OOM'd synthesizers do not exist in this port),
but it has a REAL, golden-neutral Rust port. 7-part classification (each cited
against the current tree):
| # | #1212 sub-part | verdict | cited Rust evidence + one-line rationale |
|---|---|---|---|
| 1 | event-loop yield points in 31 synthesis passes | N/A (TS-only) | Rust resolution is rayon data-parallel (resolver.rs resolve_chunk_parallel → .par_iter().map().collect() over the Sync snapshot), not a JS event loop; no in-process liveness watchdog a synchronous span blocks. No analogue to await yieldPoint(). |
| 2 | whole-graph snapshot OOM — kotlin getAllNodes() 2M-node array |
PORT (reachable + streamable) | SnapshotResolutionContext::from_store (snapshot_context.rs:92-174) does store.all_nodes() (:94) then materializes every node across six whole-graph maps + build_edge_adjacency (:347-363) reads all_nodes() again — O(graph)×copies at kernel scale. StoreResolutionContext (context.rs:28-63) already gives byte-equivalent ordered lookups over bounded LRUs, so a large-graph fallback bounds memory to batch + LRU. LANDED. |
| 3 | kotlin expect/actual SQL-side filter | N/A (pass absent) | No kotlin expect/actual synthesizer exists in codegraph-resolve. |
| 4 | c-fnptr LRU-bounded caches | N/A (pass absent) | No C function-pointer dispatch synthesizer exists (#932 is DEFER). |
| 5 | spring reads each .java once, not twice |
N/A (pass absent) | Only per-ref Spring DI receiver-typing exists (name_matcher.rs), not a whole-repo publishEvent event→listener synthesizer. |
| 6 | runMaintenance off-thread + post-index WAL checkpoint |
ALREADY-HAVE (valve) + PORT (extend to resolution loop) + N/A (worker offload) | WAL valve landed R-A/#1231 (queries.rs checkpoint_wal_if_over), but was called ONLY in spill-replay (main.rs:3525/:3536), NOT the batched-resolution write loop. LANDED: the valve now also fires after each resolution-batch write. The worker-thread offload is N/A (no main-thread heartbeat). |
| 7 | daemon socket-handoff race + pool.ready gate |
ALREADY-HAVE / N/A | The active daemon path (session.rs serve_session_async) reads the hello + all bytes from one long-lived buffered reader — no Node stream-mode discard. #1200/#1185 already landed R-A. pool.ready is a Node cold-start tweak, no analogue. |
LANDED PORTs (both golden-neutral, memory/IO only):
- Large-graph streaming fallback —
resolver.rsresolve_and_persist_batched_inner(shared by the public wrappers): when node count>= RESOLVE_STREAMING_NODE_THRESHOLD(default1_000_000, overrideCODEGRAPH_RESOLVE_STREAMING_THRESHOLD), resolve each batch SERIALLY through a per-batchStoreResolutionContextover the live store instead of theSnapshotResolutionContext+ rayon path. Prior-batchimplements/extendsedges are committed before the next batch reads them, soget_supertypessees the same cross-batch growthbuild_edge_adjacencyprovides. Same rowid cursor, persistence order, deletion order, marker, and #750/#808 passes. The default threshold is high enough that normal repos ALWAYS keep the unchanged snapshot path (byte-identical output; every golden fixture exercises it). - WAL valve in the resolution write loop — the same env-gated
store.checkpoint_wal_if_over(wal_valve_bytes)(TRUNCATE-only, row-neutral) now fires after each resolution-batch write, bounding WAL growth through the resolution tail, not just spill-replay.CODEGRAPH_NO_WAL_DEFER/CODEGRAPH_WAL_VALVE_MBgovern it exactly as before.
Golden-verification bridge: the dual-path equivalence test
streaming_fallback_matches_snapshot_across_multiple_batches (resolver.rs
tests) forces batch_size 1 (≥2 batches, asserted) with a cross-batch
Sub extends Base / sub.ping() case, runs BOTH paths on separate identical
stores, and asserts nodes/edges/unresolved_refs byte-identical — so the
snapshot path's golden verification transitively covers the fallback. A deliberate
fallback perturbation was confirmed to fail the assertion (teeth), then reverted.
wal_valve_fires_during_resolution_batch_writes asserts the valve fired DURING
resolution (telemetry counter) and that the resolved graph is byte-identical valve
on vs off. cargo test -p codegraph-bench passes with NO regen; goldens unchanged.
Tracked parity STILL 1.2.0 — advances to 1.4.1 only in the final ledger step
once every PORT item lands.
2026-07-14 — LANDED Release D: C++ namespace/template resolution + UE macro recovery + .h detection + Lua gate
Ports the C++ half of the 1.2.0..1.4.1 PORT subset plus the folded-in Lua
resolve fix. Tracked parity STILL 1.2.0 — it advances to 1.4.1 only in the
final ledger step once every PORT item lands. Five upstream items landed:
- C++ namespace-block qualified names +
ns::fn()resolution (frome1a8d88, the CUDA commit):codegraph-extract/walker.rsgains anamespace_prefixstack pushed onnamespace_definition(prefix-only, no namespace node — avoids the #1093 crowd-out) and seeded intobuild_qualified_name.ns::fn()calls resolve for free via the existing qualified-name matcher (no resolver change). C++17namespace a::b {included; anonymous namespaces fall through to bare names. - C++ template-arg call linking
fn<T,256>()(frome1a8d88):extract_callstrips template args on C++/C callees via the existingstrip_cpp_template_args(the #1043 base-class normalization), excludingoperator</operator<<. - #1158 /
8e697a0— UE in-body reflection-macro recovery:CppSpecnow overridespre_parsewith three offset-preserving byte-blanking passes (blank_cpp_api_prefix_macros,blank_cpp_inline_annotation_macros,blank_cpp_annotation_macro_calls), eachcontains-gated so macro-free C++ is byte-identical. The look-ahead boundaries upstream used are reimplemented in code (theregexcrate has none). - #1159 / #1133 /
c049d9e—.hC-vs-C++ detection:looks_like_cpp/looks_like_objcsniff the 8 KB source prefix insideextract_sourceand reclassify a.hfrom C to C++/ObjC. The path-onlydetect_languageand its watch/cli/resolve callers are UNCHANGED (they pass no source, so default-C holds — matching upstream). - #1124 /
e53968c— Lua/Luau annotation self-match gate: the shipped Rust pattern was a broken lookahead port ((?!is silently.ok()-dropped by theregexcrate), soobj:Method()still self-matched. Fixed CODE-SIDE:local_receiver_type_patterns_taggedtags the annotation regex andinfer_local_receiver_typerejects the capture vialua_annotation_is_method_callwhen a Lua call form ((/"/'/[/{) or a[\w.]continuation follows.
Two discoveries worth recording: (a) the namespace + template-arg-call code lives
in the CUDA commit e1a8d88, whose CUDA (blankCudaConstructs,
looksLikeCudaSource) and local-fn-ptr (cppLocalFnPtrs) slices were
DELIBERATELY EXCLUDED (they belong to a future CUDA release); (b) the pre-existing
Rust Lua pattern was a broken lookahead port, fixed with a code-side gate rather
than an (unsupported) regex look-ahead.
Golden: a DELIBERATE cpp fixture BUMP. The corpus gained namespaced.cpp,
templated_call.cpp, and ue_actor.h; the diff is exactly (i) Tpl/Tpl::wrap
→ ns::Tpl/ns::Tpl::wrap (node-ids stable — name is unqualified), (ii) the
Q : ns::Tpl<int> base migrating unresolved→resolved (Extends edge appears,
ref leaves refs.json), and (iii)-(iv) the three new files' additive
file/symbol/Contains records + the intended ns::compute() / process<int>() /
UFoo→UObject edges. godot/ruby/mini goldens byte-identical.
Ran Workflow A's diff step against the live upstream delta,
git diff v1.2.0..v1.4.1 -- src/ (76 files, +10965/−1209). The range is
dominated by 11 new language grammars and a prompt-hook feature suite — bulk
that doesn't map cleanly to this port — so the portable high-value subset out
of it is small. Two items from this range are already landed under other
entries: #1043 (C/C++ templated-base inheritance, v0.27.0) and #1064 (explore
change-surface rescue, v0.28.0) — both recorded above, not repeated here.
Tracked parity stays 1.2.0; the table below is the chosen PORT set, in
progress across four releases (A/B/C/D), plus the ALREADY-HAVE / N-A / DEFER
dispositions for everything else in range.
PORT (chosen, in progress)
| upstream # / commit | title | Rust target | golden impact | disposition |
|---|---|---|---|---|
#1220 / 70b1be6 |
PHP $this->dep->method() resolves via property declared type |
codegraph-resolve/name_matcher.rs + codegraph-extract PHP field types |
golden bump | PORT (Release C) |
#1231 (WAL-valve half) / a11a439 |
defer WAL checkpoint write-back during bulk index (CODEGRAPH_NO_WAL_DEFER / CODEGRAPH_WAL_VALVE_MB) |
codegraph-store/connection.rs |
golden-neutral | PORT (Release A) |
#1187 / 4c15f84 |
orphaned unresolved-ref sweep so an interrupted index heals on sync + partial-index status warning | codegraph-watch/sync.rs, CLI status, MCP status |
golden-neutral | PORT (Release A) |
#1200 / 356f5f7 |
daemon inactivity backstop gated on client liveness | codegraph-daemon/lib.rs |
golden-neutral | PORT (Release A) |
#1185 / c9f8c0e |
reap server when launcher killed during startup + CODEGRAPH_STARTUP_HANDSHAKE_TIMEOUT_MS backstop |
codegraph-daemon/spawn.rs |
golden-neutral | PORT (Release A) |
C++ namespace-block qualified names + ns::fn() resolution + template-arg fn<T,256>() call linking (part of 1.3.0, code in e1a8d88) |
— | codegraph-extract/walker.rs (namespace prefix + template-call strip; name_matcher.rs unchanged) |
golden bump (cpp fixture) | LANDED (Release D, 2026-07-14) |
#1158 / #1159 / #1133 (8e697a0, a9e8fa4, c049d9e) |
recover heavily-reflected Unreal Engine C++ classes (in-body reflection macros, member-level *_API, mid-line UMETA/UPARAM/UE_DEPRECATED, .h C-vs-C++ detection through export macro) |
codegraph-extract/lang/cpp.rs (pre_parse blanking) + engine.rs (.h content sniff) |
golden bump (cpp fixture) | LANDED (Release D, 2026-07-14) |
#1124 / e53968c |
Lua/Luau capitalized obj:Method() misread as type annotation |
codegraph-resolve/name_matcher.rs |
golden-sensitive (Lua edges) | LANDED (Release D, 2026-07-14; golden-neutral — no Lua fixture) |
#1063 / 2a06d9a |
codegraph.json include list to force gitignored first-party source in |
codegraph-core/config.rs + codegraph-extract scan + codegraph-watch policy |
golden-neutral | PORT (Release B) |
#1182 / f5edf8c |
iBatis2 <sqlMap> coverage + MyBatis quote/comment robustness + dup-id |
codegraph-extract/embedded/mybatis.rs |
golden bump | PORT (low; optional) |
#1243 / 4782394 |
MCP update-available notice (background, once/day, honors DO_NOT_TRACK / CODEGRAPH_NO_UPDATE_CHECK) |
codegraph-mcp/engine.rs status |
golden-neutral | PORT (low; UX) |
ALREADY-HAVE
| upstream # | what it does | Rust evidence |
|---|---|---|
| #1129 / #1130 | typed-param receiver inference | name_matcher.rs:765-833, landed R5 (v0.26.0) — Rust already covers more languages than this upstream change adds |
| #1240 | incremental cross-file re-resolve | codegraph-watch/sync.rs + queries.rs already re-resolve in both directions |
| #1235 | closure-collection scan across all languages | no Rust analogue exists for this to duplicate — the described failure mode cannot occur here |
N/A (TS/Node-only)
| upstream # | why it doesn't apply |
|---|---|
| #1231 (parse-timeout half) | worker-clock race is a Node worker/coordinator artifact; Rust indexing is rayon in-process with compiled-in grammars — no separate worker clock to race |
| #1238 | npm self-shadow — npm-specific install-path collision, no Rust analogue |
| #1071 | uninstall binaries — npm/install.sh lifecycle step, not applicable to the cargo-installed/binary-download build |
| #1238 | install --refresh — npm reinstall flow, no Rust analogue |
| #1238 | Windows npm.cmd shim handling — npm-only |
| #1180 | Spring config-key scan — this port has no Spring config-key resolver at all; not a gap this upstream fix closes |
| #1156 | gitignored child-repo offer — no embedded-repo discovery mechanism exists in this port (already recorded as an architecture gap in earlier entries) |
DEFER
| item | why deferred |
|---|---|
| 11 new languages (Nix, ArkTS, Terraform, CUDA, Solidity, Erlang, VB.NET, COBOL, CFML, Metal + iBatis2 counted as low PORT above) | each needs a grammar crate + LanguageSpec + golden fixture; Metal/CUDA are cheapest (ride the existing C++ grammar) |
| prompt-hook suite (#1126 / #1136 / #1138 / #1141-1146 + telemetry) | large surface; telemetry conflicts with this project's no-tracking posture — if pursued, cherry-pick the multilingual/plain-words gate WITHOUT the telemetry half |
| #1252 | explore NL-word guard — Rust explore is FTS-seeded, not token-seeded, so applicability is low; KNOWN_DIFFS.md already records relevance re-ranking as intentionally not ported |
| #1212 | |
| #1114 | dead reasoning-offload cleanup — Rust never had the reasoning-offload feature, so there's nothing to remove |
Outcome: tracked parity remains 1.2.0. A 4-release PORT program is in
progress: Release A is a golden-neutral robustness bundle (#1187 + #1200 +
#1185 + #1231's WAL-valve half); Release B is #1063 include; Release C is
#1220 (PHP property-typed receiver); Release D is C++ namespace/template
resolution + Unreal Engine macro recovery. A DEFER phase follows (snapshot-OOM
#1212, the prompt-hook suite minus telemetry, then the 11 new languages).
Tracked version advances to 1.4.1 only once the chosen PORT items above
actually land; the three low/optional items (#1124, #1182, #1243) may fold into
a related release round or be individually deferred at that time.
Ports upstream 2b256b9 (fix(explore): surface a named method's buried signature type (#1064), shipped in colby 1.1.5) into this project's
deterministic explore, adapted to the query/ranking spine (no RWR/graph-mass
score exists here). Extraction is UNCHANGED — the signature edge the rescue
follows (References, function→param-type) already exists for TS/TSX, proven by
a live 2-file repro; extraction-widening to emit TypeOf/Returns for more
languages is DEFERRED.
| Round | Upstream | Disposition | codegraph-rs | Notes |
|---|---|---|---|---|
| B | #1064 / 2b256b9 |
PORT | v0.28.0 |
codegraph-mcp/src/engine.rs find_relevant_context: (1) named-seed tier de-noise — only the top callable seed + any seed with caller-count ≥ 25% of the max is tiered, so a low-centrality namesake can't flood the tier; (2) change-surface rescue — from each tiered callable seed, follow outgoing signature edges (References/TypeOf/Returns) to TYPE-kind nodes; a type whose file is BURIED (not a seed file AND < 2 query-term hits) is inserted + marked rescued_files so finalize floats it to a new TOP tier (3). Deterministic: candidates sorted by (file, line, id) before insert; no HashMap/HashSet iteration reaches output. Query/ranking-side only → golden unchanged (the mini golden's Counter add runDemo query has only primitive number param types, so the rescue never fires). |
Ported the actionable subset of the 1.1.2..1.2.0 upstream delta, in six
momus-approved, individually-released, Final-Wave-gated rounds (each: TDD ≥95%
patch coverage → golden regen where extraction/resolution changed → 4-reviewer
Final Wave → own fix:/feat: release). Schema round ran first so later rounds
regenerated golden against the final schema.
| Round | Upstream | Disposition | codegraph-rs | Notes |
|---|---|---|---|---|
| R0 | #1034 | PORT | v0.25.2 |
UNIQUE edge-identity index + migration v7 (dedup keep-lowest-id then create index). .schema golden bump; golden fixtures had no dup edges so edges.json unchanged. |
| R1 | #1045, #1047, #1127 | PORT | v0.25.3 |
query drops nonsensical NNNN% score (raw score kept in --json); Android res/ default-excluded (res/raw + src/main/resources kept; .gitignore ! negation now honored); auto-sync backs off + disables after repeated non-contention failures. Query/config/watch only — no golden. |
| R2 | #1086, #1087, #1089, #1090 (#1088 lock-test) | PORT | v0.25.4 |
impact keeps direct edge to already-reached node; callers/callees keep multi-KIND edges; hard node-limit enforced per-insertion. Query-side; golden unchanged. |
| R3 | #1093, #1096, #1061, #1035, #1100-#1103 | PORT | v0.25.5 |
C++ extraction: skip bodiless forward decls (C/C++-gated; Kotlin/Scala kept), conversion-operator names, export/visibility-macro class recovery, stack/brace construction Instantiates, inline-specifier-macro name/return-type recovery. Guarded by unit tests; retroactively byte-guarded by the reference/golden/cpp/ fixture added with #1043 in v0.27.0. |
| R4 | #1110 | PORT | v0.25.6 |
Ruby receiver.method calls now emit edges (Const.new→Instantiates, else→Calls); bare include/extend/prepend unchanged. Added a Ruby golden fixture (reference/golden/ruby/) + equivalence test. |
| R5 | #1108, #1125, #1112, #1079 | PORT | v0.26.0 |
Receiver-type inference generalized beyond C++ to TS/JS/Python/Java/C#/Kotlin/Swift/Go/Rust/Dart/Scala/PHP (local-var + typed-param); Lua : / R $ / Pascal . separators; same-file preference in 3 method-call paths. All validated via resolve_method_on_type (wrong guess → no edge). Mini golden's 3 local-var instance-method edges rose 0.8→0.9 to match upstream 1.2.0's receiver-inference confidence. |
DEFERRED (recorded, not ported):
- #1043 /
703629e— C/C++ inheritance from a templated base.This project has no general C++PORTED in codegraph-rsbase_class_clauseinheritance extraction yetv0.27.0(general C++base_class_clauseextraction + template stripping; added a C++ golden fixture). - #1064 —
explorechange-surface rescue. PORTED 2026-07-07 (explore-side only, over the existingReferencessignature edge; see the 2026-07-07 entry above). Extraction-widening (emitTypeOf/Returnsfor more languages) stays DEFERRED — not needed for the TS/TSX value.
ALREADY-HAVE (verified, no work): #1088 (node-id visited dedup, locked with a test in R2), #1046 (explore count).
N/A (no Rust analogue): #1044 (CLI node subcommand — MCP file-mode already works), #1091 (index watchdog yield), #1092 (Windows console-flash windowsHide), #1041 & gitlink nested-repo items, dfe13b0 (MCP worker pool), and all install.sh / npm / PATH-shadow / bundled-Node items (the Rust build has no npm/install.sh).
This is a targeted downstream forward-port, NOT a full upstream sync. Tracked
colby parity stays 1.1.2 — this entry does not advance it.
Commit 35935be (branch feat/mcp-autodetect-no-default-tools) ports two
upstream behavioral fixes that were missing from this Rust port, driven by issue
#94 (通义灵码/Lingma shows 0 tools when no -p is given):
- colby #964 (PR #966) —
tools/listALWAYS returns the visible tool surface, even when no default project is resolved. The prior Rust behavior returned an empty array ([]) for the no-default path, which is the #94 root cause. - colby #993 (PR #1007) — when no default project resolves,
projectPathis added to each tool'sinputSchema.requiredarray (a schema-level nudge so a roots-less client's agent supplies the path per call). When a default project IS resolved,projectPathstays OPTIONAL (byte-identical to the indexed case).
Supersedes the 2026-06-28 d3179f5 ALREADY-HAVE disposition (see triage
table below at line 60): that entry called our "hide all tools when no default
project" behavior "stronger" than upstream's d3179f5 approach, but that
hide-all is the #94 root cause. We now adopt colby's always-list (#964) +
required-projectPath (#993) instead.
Golden artifacts stayed byte-identical — the change only affects the no-default
path, which no golden frame exercises (git diff reference/ empty). make ci
green; cargo test -p codegraph-bench green; docs/upstream-sync/KNOWN_DIFFS.md
untouched.
| item | disposition | note |
|---|---|---|
| colby #964/PR#966 | PORT (landed) | tools/list always returns visible tools; Rust dispatch arm in server.rs changed from Value::Array(Vec::new()) to schemas::visible_tool_definitions_requiring_project_path() on the no-default path. |
| colby #993/PR#1007 | PORT (landed) | with_required_project_path() pure fn injects "projectPath" into each tool's inputSchema.required; fires only on the no-default branch; idempotent. |
d3179f5 (superseded) |
SUPERSEDED | The prior ALREADY-HAVE disposition (2026-06-28) incorrectly called hide-all "stronger". The hide-all behavior was the #94 root cause and is now reversed. |
Shipped the portable subset of v1.1.1..v1.1.2 in PR #90 → release v0.20.0
(three feature commits + one Windows-clippy fixup). Tracked parity advanced to
1.1.2. Golden impact: the ONLY reference/ change was
reference/golden/mcp/tools_list.json (the deliberate readOnlyHint
annotations); the extraction corpus is byte-unchanged. make ci green, golden
oracle green, Final Verification Wave (F1 goal/constraint + F2 code quality +
F3 golden/invariant) all APPROVE.
| commit | landed as | disposition (final) | note |
|---|---|---|---|
a79fa51 |
feat(mcp) readOnlyHint annotations |
PORTED | all 10 source tool defs annotated {readOnlyHint:true, destructiveHint:false, idempotentHint:true, openWorldHint:false}; golden fixture + golden_mcp.rs assertion extended to compare annotations (load-bearing). |
f83a1ec |
daemon FS fallback | PORTED | bind_with_fallback walks a deterministic socket-candidate chain on bind failure; chosen socket persisted into the lock; all 4 client sites read recorded_socket_path (pid/lock stays at .codegraph/daemon.pid). golden-neutral. |
45d3293 pt1 |
name-ceiling | PORTED | AMBIGUOUS_NAME_CEILING=500 (env CODEGRAPH_AMBIGUOUS_NAME_CEILING); gates ONLY match_fuzzy + the multi-candidate find_best_match branch of match_by_exact_name. Edge-producing strategies untouched → golden edges byte-identical (verified). |
45d3293 pt2 |
[indexing] exclude |
PORTED | TOML exclude: Vec<String> (#[serde(default)]), root-relative patterns threaded via ExtractOptions through the filesystem walk; honored by index AND sync. Off-by-default. NO git-tracked framing (Rust has no git layer — D-Exclude). |
7a361ef |
docs for exclude |
PORTED | README + docs/cli.md/docs/mcp.md document exclude, readOnlyHint, daemon FS fallback. |
b3f59c7 |
Swift computed properties | PORTED | computed var body { ... } / accessors → property node, getter routed through the function-body walk; protocol var x { get } → property; stored/static unchanged. Golden-neutral (no .swift in the TS+Py corpus); locked by 5 new unit tests. |
dfe13b0 |
— | N-A | MCP read-tool worker pool. The Rust MCP server is synchronous single-stdin (server.rs); concurrent-call starvation cannot occur, so the fix has no Rust analogue. Not ported by design. |
703629e |
— | DEFER | C/C++ function-pointer command tables. Rust has no C/C++ resolver foundation; deferred as a future capability-build (user-approved exclusion from this batch). |
(ALREADY-HAVE / N-A items d3179f5, 30dc303, 9716fb2, b45f309 need no
action — see the triage entry below for evidence.)
Read the real per-commit diffs of the 11 meaningful commits in v1.1.1..v1.1.2
and classified each against the Rust code (file:line both sides). This is a
triage — tracked parity stays 1.1.1 until the PORT items land. Two highest-
stakes items cross-checked by hand (30dc303 SQLite, b45f309 prompt-hook).
| commit | what it does | Rust status | disposition | golden |
|---|---|---|---|---|
dfe13b0 |
MCP off-loads read-tool dispatch to a worker pool (fix concurrent-call timeouts) | MCP server is synchronous/serial (crates/codegraph-mcp/src/server.rs, engine.rs:60-81) — no worker pool |
PORT | none |
703629e |
C/C++ function-pointer command tables (macro-built / conditional / bare arrays) | No C/C++ resolver at all (extraction only; no frameworks/c*) |
DEFER | would change output |
b45f309 |
prompt-hook: structured detection for non-English prompts | No prompt-hook / front-load-hook feature in Rust (grep: only unrelated "structural" hits; installer only writes MCP config) | N/A | none |
d3179f5 |
require projectPath when MCP server has no default project |
Rust already stronger: hides all tools when no default project (server.rs:374-380) + errors on missing path (:439-455) |
ALREADY-HAVE | none |
45d3293 |
codegraph.json exclude config + resolver ambiguous-name ceiling (anti-wedge) + index watchdogs |
Rust config is .codegraph/config.toml with only ignore_dirs — no exclude; resolver has no name-ceiling (config.rs:48-58, resolver.rs:882-992) |
PORT | exclude none; name-ceiling may affect golden |
7a361ef |
docs for exclude |
depends on 45d3293 landing first | DEFER | none |
f83a1ec |
daemon on ExFAT/FAT/network FS — socket/lock candidate fallback after bind failure | Rust only does tmp fallback for over-long Unix paths, binds a single socket, no bind-failure retry (daemon/src/paths.rs:24-31, lib.rs:259-270, lock.rs:66-71) |
PORT | none |
30dc303 |
chunk deleteResolvedReferences IN-list under SQLite param limit (public QueryBuilder API) |
Rust delete path binds per-row (queries.rs:677-693), structurally immune; chunking (SQLITE_PARAM_CHUNK_SIZE=500) already systemic |
ALREADY-HAVE | none |
b3f59c7 |
index Swift computed properties (computed→property, getter calls attributed) | Rust does not node-ify Swift computed properties (extract/src/walker.rs:149-160, lang/swift.rs) |
PORT | changes extraction → golden bump |
9716fb2 |
parallelize indexing via parse worker pool | Rust already parallel-indexes via rayon file-level parallelism (extract/src/engine.rs:21-36, 213-217) — different design, same capability |
ALREADY-HAVE | none |
a79fa51 |
MCP readOnlyHint/annotations so tools work in Cursor Ask mode |
Rust tools/list emits schema/value only, no annotations (server.rs:374-380) |
PORT | none |
PORT backlog from this range (pending user go-ahead), low-risk-first:
a79fa51MCP readOnlyHint annotations — golden-neutral, small.f83a1ecdaemon FS fallback chain — golden-neutral, daemon robustness.dfe13b0MCP read-tool worker pool — golden-neutral, concurrency.45d3293excludeconfig (+ later the resolver name-ceiling, which may touch golden).b3f59c7Swift computed properties — golden bump (extraction change), isolate.703629eC/C++ fn-pointer resolver — large; needs a C/C++ resolver foundation first.
No-action: d3179f5, 30dc303, 9716fb2 (ALREADY-HAVE); b45f309 (N/A); 7a361ef (DEFER until exclude lands).
Newest first. Each entry covers one sync of an upstream version range and records every meaningful change with its disposition: PORT (landed in Rust) · ALREADY-HAVE (port already implemented it) · N/A (TypeScript-only, no Rust analogue) · DEFER (real but postponed).
NOT an upstream sync. Two downstream-only features were added to this Rust
port that have no analogue in colby (verified against colby v1.1.1 HEAD on
2026-06-27: git grep over upstream src/ + CLI command inventory + docs/tests
found no orphan/dangling audit command and no Godot id-field / DSL-schema config).
Both are Godot-research conveniences requested by a downstream Godot/WorldFlipper
user; they do not change extraction output (golden byte-neutral). Tracked colby
version is UNCHANGED at 1.1.1 — these do not advance parity.
| feature (this port only) | disposition | rationale / golden impact |
|---|---|---|
Resource audit — read-only codegraph audit subcommand: orphan .tres/.tscn resources, dangling path references, reverse-dependency impact (crates/codegraph-graph/src/graph/mod.rs find_orphan_resources/find_dangling_references/resource_impact; crates/codegraph-cli/src/main.rs cmd_audit) |
DOWNSTREAM-ONLY | No upstream analogue. Pure read-only over the existing graph + on-disk existence checks — adds NO extraction, NO node/edge writes. Golden byte-neutral (git diff reference/ empty). Keyed on resource PATHS (godot resource files have no file: node; refs live in unresolved_refs). Separate audit subcommand leaves check byte-identical (committed snapshot test). Exclusions: .godot//addons/ prefix → godot:dynamic: → on-disk existence. |
Opt-in idFields DSL — capture bare/compound IDs in .tres [resource] bodies as godot:id:<kind>:<value> sentinel references via .codegraph/codegraph.json godot.dsl.idFields (crates/codegraph-resolve/src/frameworks/godot_dsl_config.rs, godot_resource.rs dsl_id_targets) |
DOWNSTREAM-ONLY | No upstream analogue (upstream has no godot id-field/schema config). Golden byte-neutral by two-part mechanism: (1) opt-in gating — fires ONLY when idFields is configured, and committed golden corpora have no such config; (2) sentinel-unresolvability — a colon-delimited godot:id:* literal can never name-match a node (match_fuzzy callable/type kinds only), so it stays in unresolved_refs, never becomes a golden edges row. No domain hardcoding — all field names/kinds/separators are project-supplied. |
Bundled fix: Godot DSL config resolved against PROJECT ROOT, not process CWD (FrameworkResolver::extract gains an additive project_root param; config_lookup_path) |
DOWNSTREAM-ONLY | Fixes a latent defect (shared by the pre-existing resourceFields): the framework resolver received a relative path and joined it onto CWD, so the per-project config was only found when CWD == project root. Now config lookup uses project_root.join(file_path) while node/ref attribution stays RELATIVE (golden-safe). Locked by an e2e CLI test that indexes from a foreign CWD. |
Outcome: two downstream-only Godot conveniences landed; colby parity unchanged
at 1.1.1. No golden impact, no upstream divergence (these are additive features
upstream does not have, not deviations from upstream behavior). Should a future
colby release add a comparable audit or id-schema feature, reconcile naming/shape
against these at that sync.
A small upstream patch release: two fix(...) commits plus release/changelog
chores. git diff v1.1.0..v1.1.1 against the live upstream source. No PORT
items — both fixes are either a TypeScript/Node-architecture-specific problem
with no Rust analogue, or behavior this port already has. The proxy half of #983
was verified line-by-line against codegraph-daemon::proxy::run_proxy and its
CLI callers before recording it as ALREADY-HAVE. Golden output untouched (no
extraction change in range). Tracked version advanced to 1.1.1 (upstream HEAD).
| upstream change | disposition | rust landing / rationale |
|---|---|---|
#983 (7c6417e) daemon half — release the lockfile when bind fails (e.g. AF_UNIX flaky on WSL2 /mnt DrvFs) so the next launcher doesn't spin on a stale lock (src/mcp/daemon.ts:183-198) |
ALREADY-HAVE | start_with_lock calls bind(&rendezvous)? with ?: a bind failure propagates up to the try_acquire_daemon_lock caller and the RAII lock guard releases the pid lock automatically — no stale lock pointing at a dying pid, no duplicate serve --mcp pileup. Structurally cannot leave a hung lock. |
#983 (7c6417e) proxy half — a daemon-socket error with no listener became a Node uncaughtException → process.exit(1), which the MCP client saw as a bare "Transport closed"; fix attaches a lifelong no-op error listener so it degrades to the in-process fallback (src/mcp/proxy.ts:135-145,323-336) |
ALREADY-HAVE (verified) | Node-specific defect with no Rust analogue. In run_proxy, every socket error is an explicit io::Result::Err, never an unhandled exception: connect failure → Err → CLI Err arm falls back to direct (main.rs:1350); hello-read failure → ? → same fallback; host→daemon write failure → pump_host_to_daemon Err → up_result? → fallback; daemon→host read failure → Err(_) => break (treated as EOF, clean exit). No path lets an unhandled socket error panic/exit the process, so the "Transport closed" symptom cannot occur. (Minor design difference: on a mid-session daemon drop the Rust proxy exits the stdio session for a clean client reconnect rather than hot-swapping to an in-process engine — a normal transport close, not a crash.) |
#980 (73bcc1a) extraction — respect .gitignore by DEFAULT for embedded-repo discovery: gitignored dirs holding nested .git repos are no longer walked/indexed unless opted in via codegraph.json includeIgnored (#970, #976; src/extraction/index.ts, src/project-config.ts) |
N/A (architecture difference) | colby's git ls-files-based discovery actively descended INTO gitignored dirs to find embedded .git roots (findIgnoredEmbeddedRepos), which over-indexed huge reference/data dirs of clones — the bug #980 fixes. This port's walker is a pure filesystem walk (scan_project/scan_dir, engine.rs:221-256): a gitignored dir is matched by is_ignored_by_patterns and the whole subtree is continued/skipped. There is no embedded-repo discovery and never was, so the Rust port has ALWAYS exhibited the #980-fixed default (respect .gitignore). Nothing to port. |
#980 new codegraph.json includeIgnored opt-in config field |
DEFER (no analogue yet) | This is a new feature (not the fix): opt-in to index gitignored embedded repos. It only has meaning alongside an embedded-repo / multi-repo-workspace discovery mechanism, which this port does not implement. Recorded as a known gap should a future "multi-repo workspace" direction be pursued; not actionable in this range. |
ec0c625 / 4077ed1 / 1e48861 version bump + CHANGELOG edits; __tests__/* (daemon-bind-failure, proxy-connect, include-ignored-config, multi-repo-workspace) |
N/A | release chores and TypeScript test files — no behavior to port. |
Outcome: tracked version is 1.1.1 (upstream HEAD). No PORT items in this
range; no golden impact (extraction output unchanged). The only deferred item is
the includeIgnored config field, which is inert without an embedded-repo
discovery mechanism this port intentionally lacks.
Next sync: when upstream publishes a tag > 1.1.1, run Workflow A from this
point (git diff v1.1.1..v<new>). Outstanding port backlog is unchanged: the
B-class extraction/framework golden-bump plan from the v1.1.0 range.
First true catch-up delta since the baseline: git diff v1.0.1..v1.1.0 against the
live upstream source. The headline of v1.1.0 is the issue-#411 live-watch daemon
architecture (a detached background daemon + thin per-client proxy sharing one file
watcher), plus a batch of extraction/framework upgrades. This sync lands the entire
A-class (daemon/proxy/watcher/robustness/UX — no extraction-output change, golden
byte-untouched) on branch feat/live-watch-daemon. The B-class extraction ports
(value-reference edges, framework dispatch synthesizers, etc.) are each recorded as
DEFER below: every one of them changes extraction output and therefore requires
a deliberate golden regeneration, so they are scoped to a separate future plan
rather than smuggled into this no-golden-bump sync.
| upstream change | disposition | rust landing / rationale |
|---|---|---|
Detached daemon process + launcher decision order (CODEGRAPH_NO_DAEMON opt-out, CODEGRAPH_DAEMON_INTERNAL be-the-daemon, no-.codegraph/→direct, else spawn+proxy) (src/mcp/index.ts:260-292, #411) |
PORT | select_serve_mode decision in cmd_serve + spawn_detached_daemon re-invokes the CLI with CODEGRAPH_DAEMON_INTERNAL=1, own process group (unix) / DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP (windows), stdio→.codegraph/daemon.log, child dropped (unref) — daemon survives the launcher (this plan T1/T2) |
Per-MCPEngine file watcher in serve --mcp, direct + daemon (src/mcp/engine.ts:178-240) |
PORT | one ProjectWatcher in cmd_serve (direct) and one in the daemon process (run_accept_loop, shared by N clients — the #411 collapse of N inotify sets to 1); never per-session (this plan T3/T4) |
| Non-blocking catch-up sync on open (#905) | PORT | background sync_project_once thread + Arc<AtomicBool> ready flag; the first tools/call never blocks on the reconcile (this plan T5) |
Reopen DB when .codegraph is replaced on disk (#925, src/db/index.ts) |
PORT | engine_for records the db file identity (unix inode / windows file_index()) at open and reopens the cached engine only on a true replacement — never on an in-place WAL write (this plan T6) |
Detached daemon needs a thin client proxy (local-handshake stdio↔socket pipe, hello-version verify, direct fallback, PPID watchdog, refcount-decrement-on-close) (src/mcp/proxy.ts:194-289, #277/#411) |
PORT | codegraph-daemon::proxy::run_proxy answers initialize/tools/list locally from this build's static constants, suppresses the daemon's forwarded initialize reply, forwards the rest line-framed, verifies hello → VersionMismatch falls back to direct (this plan T7) |
Daemon idle-linger + max-idle backstop (DEFAULT_IDLE_TIMEOUT_MS=300000, MAX_IDLE_MS=1800000, #692) (src/mcp/daemon.ts:60-72,505-521) |
PORT | run_accept_loop tracks last_active, exits when idle past CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS with zero clients, and on the CODEGRAPH_DAEMON_MAX_IDLE_MS backstop regardless of count (this plan T8) |
Dead-client sweep via a client-hello pid protocol (DaemonClientHello, CLIENT_HELLO_TIMEOUT_MS, DEFAULT_CLIENT_SWEEP_MS=30000, #692) (src/mcp/daemon.ts:103-127,569-624) |
PORT | optional {"hostPid":N} client-hello read from ONE long-lived BufReader (buffer-safe run_session_recv seam — no dropped JSON-RPC bytes), per-session pid in the registry, 30s sweep reaps peers failing is_process_alive (this plan T9) |
Watcher degraded handling — EMFILE/ENFILE degrade, ENOSPC warn-not-degrade, bounded exp lock-retry backoff (cap 30s), onDegraded/isDegraded (src/sync/watcher.ts +254, #891/#892/#893) |
PORT | WatchOptions gains on_degraded/on_sync_error; the notify Err arm is plumbed as LoopMessage::WatchError and classified via raw_os_error() (EMFILE 24 / ENFILE 23 → degrade; ENOSPC 28 → warn); surfaced to the agent via STDERR only so ToolResult bytes stay golden-identical (this plan T10) |
Custom file-extension→language mapping via project config ({"extensions":{".x":"lua"}}, mtime-cached, #906) (src/project-config.ts:1-155) |
PORT | net-new .codegraph/codegraph.json reader (mtime-cached) merged over builtin_language_for_ext; a hard skip-list gate makes an override unable to change any extension a built-in/embedded mapping already resolves — proven golden-safe by a hostile-remap test (.ts→lua ignored) (this plan T11) |
Front-load prompt-hook + Claude UserPromptSubmit installer hook (#964/#966, monorepo-aware) (src/installer/*, bin/codegraph.ts prompt-hook) |
PORT | hidden codegraph prompt-hook subcommand emits codegraph_explore-style retrieval to stdout (NO LLM — pure deterministic retrieval) + an opt-in Claude hook marker block in the installer (this plan T12) |
| Pare back the default MCP tool surface | ALREADY-HAVE | this port already exposes the intended tool set (the 8 colby tools + additive check/export); no further trimming needed |
| Bold labels instead of ATX headings in tool output | ALREADY-HAVE | the Rust tool formatters already emit bold-label framing; tool-output bytes already match the v1.1.0 shape |
| Re-resolve the project path on every call (#926) | ALREADY-HAVE | McpServer already resolves the path per request rather than caching a stale root |
| Cross-file caller edges preserved across re-index (#899) | ALREADY-HAVE | resolver.rs already retains cross-file caller edges through an incremental re-index |
| Stop auto-indexing on install | ALREADY-HAVE | this port's install only writes agent config; it never triggers an index |
React forwardRef/memo component detection |
ALREADY-HAVE | react.rs already recognizes forwardRef/memo wrappers |
| In-root symlink indexing (#935) | ALREADY-HAVE | the walker already follows in-root symlinks during indexing |
| Reasoning offload / CodeGraph AI managed tier / login / logout / usage / offload telemetry | N/A | barred by the no-AI/LLM guardrail (scripts/guardrail.sh); also removed upstream pre-1.1.0 via e5897d0, so there is nothing in the v1.0.1→v1.1.0 range to port |
git ls-files ./ self-entry handling (#936) |
N/A | architecture difference — the Rust walker does not enumerate via git ls-files, so the self-entry bug does not exist here |
| Index full-rebuild semantics (#874) | N/A | architecture difference — the Rust indexer already rebuilds fully on index --force; no behavioral gap to close |
| Submodule de-duplication (#945) | N/A | architecture difference — the Rust walker's submodule handling differs from the TS path; not the same bug |
| Same-file value-reference edges across 15 languages (#895/#897) | DEFER | changes extraction OUTPUT (new edges) → golden regen required; scoped to the separate B-class plan |
Framework dispatch synthesizers — GoFrame g.Meta (#747), Laravel event→listener, Sidekiq, MediatR, Spring publishEvent, Celery, Vuex, Pinia, RTK Query, redux-thunk, object-literal registry |
DEFER | each synthesizes new edges → extraction OUTPUT change → golden regen required; largest B-class surface (~1000+ LOC), separate plan |
| C/C++ function-pointer dispatch (#932) | DEFER | new dispatch edges → extraction OUTPUT change → golden regen required; separate B-class plan |
| Java Lombok synthesized members (#912) | DEFER | new synthesized member nodes → extraction OUTPUT change → golden regen required; separate B-class plan |
React styled() / JSX-file route detection (#841) |
DEFER | new nodes/edges → extraction OUTPUT change → golden regen required; separate B-class plan |
| C++ phantom-macro-function fix (#946) | DEFER | changes which function nodes are emitted → extraction OUTPUT change → golden regen required; separate B-class plan |
| Perf: O(K²) import-node resolution (#915) | DEFER | verify-if-applicable to the Rust resolver; if it reproduces, the fix may shift resolution output → treat as golden-sensitive in the separate B-class plan |
Outcome: tracked version is 1.1.0 (upstream HEAD). The full A-class live-watch
daemon stack landed (13 todos, T1–T12 implementation + this ledger) with golden
output byte-untouched — cargo test -p codegraph-bench (extraction golden) and
cargo test -p codegraph-mcp golden_mcp (MCP-response golden) pass unchanged, and
git status --porcelain reference/golden/ is empty. No AI/vector/LLM crate crept in
(scripts/guardrail.sh green). The B-class extraction/framework ports are
deferred to a separate future plan specifically because each one changes
extraction OUTPUT and therefore demands a deliberate golden regeneration — they are
recorded above so the next sync does not re-investigate them.
Next sync: when upstream publishes a tag > 1.1.0, run Workflow A from this
point (git diff v1.1.0..v<new>). The pending B-class golden-bump plan is the
outstanding port backlog from this range.
First ledger entry. This port was built directly against colby 1.0.1 (the
latest upstream tag), so this is not a catch-up delta but a baseline parity
audit confirming faithful coverage. Verified by cross-checking the live
upstream source (git clone @ 1.0.1) against this workspace.
| upstream surface | finding | disposition |
|---|---|---|
LANGUAGES (src/types.ts) — 32 languages |
this project's Language enum has all 32, byte-identical set (incl. c, r); zero diff either direction |
ALREADY-HAVE |
MCP tool set — 8 tools (search/callers/callees/impact/node/explore/status/files) |
this project exposes all 8 plus two additive own tools (check, export) — a superset |
ALREADY-HAVE |
SQLite .schema |
golden-anchored to colby 1.0.1 (reference/golden/colby.schema.sql); schema_parity test green |
ALREADY-HAVE |
| Golden extraction equivalence | crates/codegraph-bench/tests/equivalence.rs — 4 passed, 0 failed against the 1.0.1 mini golden |
ALREADY-HAVE |
| Per-language edge sets | 15 of 17 benchmarked languages byte-identical to colby 1.0.1; the 2 exceptions (Dart, Pascal function_ref shape) are deliberate, documented in KNOWN_DIFFS.md (Tier-3 allowed diffs) |
DEFER (documented) |
Outcome: tracked version is 1.0.1. No PORT items outstanding (upstream has
no release newer than 1.0.1). Two known per-language edge-set differences (Dart,
Pascal) remain intentionally deferred and are recorded in KNOWN_DIFFS.md — they
are golden-oracle-allowed Tier-3 diffs, not regressions. Golden + guardrail +
cargo test --workspace green.
Next sync: when upstream publishes a tag > 1.0.1, run Workflow A from this
baseline (git diff v1.0.1..v<new>).
Internal port commit, no upstream version bump. Closes the Unix-only IPC gap that
was the one outstanding platform limitation since the 1.0.1 baseline.
| upstream surface | finding | disposition |
|---|---|---|
src/mcp/daemon-paths.ts — named-pipe branch (\\.\pipe\codegraph-<hash>) on Windows, Unix socket on unix |
Rust port now matches: codegraph-daemon uses interprocess 2.4 local_socket — UDS on unix, named pipe on Windows; pipe name stored bare (codegraph-<sha256hash16>), GenericNamespaced prepends \\.\pipe\ at connect time |
PORT |
Windows process-liveness check (no kill -0 on Windows) |
process.rs cfg-split: unix uses rustix getppid + signal-0; Windows uses windows-sys OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION) + GetExitCodeProcess == STILL_ACTIVE |
PORT |
Stale-socket cleanup on unix (.sock unlink) |
cfg-gated to unix only; Windows pipe names are OS-reclaimed, no file to remove | PORT |
| MSRV declaration | bumped rust-version 1.70 → 1.75 in workspace Cargo.toml and both READMEs (interprocess 2.x requires rustc 1.75; actual toolchain was already stable/1.96) |
PORT |
| Prebuilt release matrix | x86_64-pc-windows-msvc added to release-please.yml; packaged as .zip via PowerShell Compress-Archive; upload-assets glob extended to dist/*.tar.gz + dist/*.zip |
PORT |
| CI gate | windows-latest job added to ci.yml; wired into ci-success as merge blocker; linux job gains a cargo check --target x86_64-pc-windows-msvc cross-check step |
PORT |
Outcome: Windows IPC gap is fully closed. The daemon start/attach/stop cycle,
named-pipe accept, lock contention, and ppid-watchdog behavior are all covered by
the windows-latest CI job. No upstream version change — this is Rust-side
infrastructure work matching the colby 1.0.1 cross-platform design.
Tracked colby version was 1.0.1 at the time of this entry (subsequently bumped
to 1.1.0 in the 2026-06-24 sync above).