Added
- Bounded LSP pull-failure telemetry and lifecycle test seams (refs #1292, items 1 and 3)
- Occupancy and CPU-budget tests stay in the timing-sensitive Vitest project (refs #1230, #1081)
- Claude Code
Stophook drives the per-turn pass (#538) - Generic read-recording bridge for co-process extensions (#1265)
- tflint respects the project's linter policy (refs #1117)
- tflint honors a repo-root
.tflint.hcl(refs #1117) - Terragrunt linting and formatting
- Smells self-surfacing (refs #1123 item 3)
- Oxfmt formatting support for Svelte (refs #1134)
- Instance health + memory-attribution observability (refs #1123 item 2)
- Handle-origin tracer debug flag (refs #1123 item 4)
- Source-walk generated-artifact escape hatch (closes #1107, phase 2 of 2)
- Machine-wide test-suite lock (closes #1101)
- Source-walk skip observability (refs #1107, phase 1 of 2)
- LSP diagnostics content binding (refs #1095, first PR)
- Cascade adopts LSP diagnostics content binding (refs #1095, second PR)
- Project-level rule policy via
.pi-lens.jsonrules.<id>.disable/rules.<id>.select - Document the standing maintenance-routines menu (invoke-on-request)
- Ast-grep dogfood rules for raw JSON store writes and win32 path qualification (refs #1158)
- Helm chart linting (refs #1283, slice A)
- Session degradation telemetry in health and performance reports (refs #1292 items 4–5)
- Remaining silent degradation gates now surface in
pilens_health(refs #1292) - Deterministic LSP acquisition-race coverage (refs #1292)
- Weekly stale open-issue detector (closes #1323)
- Opt-in compact one-line tool result rendering (closes #1327)
- HostPorts capability boundary (refs #1358, S2)
- Global LSP configuration fallback (refs #870)
- Per-rule configuration controls (closes #444)
- Edit-batch read-guard observability (refs #1053)
- Review-graph call evidence (closes #1070)
Changed
- Safe dependency refresh for v4
- Installer probe-cache persistence now uses the shared durable-store protocol (closes #1212)
- Shared durable-store and atomic-stage protocols (refs #1212, closes #1209)
- Standalone managed-tool clients share one typed availability/install seam (closes #1290, refs #1214)
- Cooperative word-index startup work (closes #1224, closes #1225, closes #1226, refs #1215)
- Ruff and jscpd availability now use the shared dispatch checker, including typed missing-command installation, in-flight dedupe, …
- Review-graph persistence lifecycle telemetry (refs #1048)
- Prompt-cache context attribution (refs #1018)
- Friendlier AST search (refs #125)
- Document red-first regression-test and worktree-hygiene conventions
- Adopt commit-message and doc/prose (Google + STE) writing conventions
- Refresh README/docs for v4 and update contributors
- Dogfood the shape-2 path-semantics rule (refs #1158)
- Cooperative-budget acceptance coverage hardened (closes #1215)
- Per-entry changelog files end merge-train conflicts (closes #1321)
- TypeScript language services release idle program memory (refs #1332)
- Terminal behavior now follows the pi host's run mode (refs #1334)
- Enforce the host-SDK type-only import rule that keeps clean installs working (refs #1334)
- A formatter that exits nonzero is now reported as a failure (closes #1337)
- Re-home probe-cache ageing and cooperative yields (closes #1354)
- Warm dispatch, LSP async consumers, and formatter catalog lazily at session start (refs #1394 — Phase 2).
Removed
- Dead-code cleanup: 5 orphaned production modules + the
server-strategies.tsdeprecated shim (refs #1090)
Fixed
- Git guard closes shell-expansion and command-wrapper bypasses (refs #1084, PR #1395)
- LSP roots and per-session clients are conservatively bounded (closes #1325, refs #1126, refs #1129)
- Fully qualified Windows paths use one shared classifier (closes #1213)
- Kotlin formatter selection follows Spotless configuration deterministically (closes #1306)
- Managed npm clients see and execute off-PATH installs (closes #1289)
- Turn-end madge telemetry stays compact and its batch metadata is runtime-tested (closes #1250, #1251)
- Rule-policy normalization and source-filter matrices no longer drift (closes #1087)
- Smart-default formatters preserve existing indentation when a repository has no style configuration (closes #1144)
- Bus emitters no longer retain a stale session context after replacement (closes #1128)
- Durable disposition marks no longer lose sibling-process updates (closes #1202)
- Behavior-gating durable stores no longer lose sibling-process updates (closes #1202)
- Tool discovery caches now recover from session changes and deleted binaries (closes #1203)
- Managed ruff, jscpd, and madge installs are now actually used after auto-install (refs #1289)
- The shared async walk engine no longer reads directories synchronously (refs #1137, #1170)
- Direct-write cache stores now publish JSON atomically (refs #1239 #1205)
- Dispatch's install-failure suppression never cleared, and a completed install could keep serving a pre-install madge resolution (closes #1266, refs #1276)
- Orphan staging-file reaping no longer deletes legitimately named files (refs #1267, #1260)
no-bare-exceptandduplicate-function-arggrammar coverage, including a binding-aware fix for the broadened traversal (closes #1269, closes #1270)- Stop-hook turn-end residuals: stdin hang, invisible skips, unguarded client cwd, delivery-loss on the ack error path, and transcript rendering (refs #1271, #1272, #1273, #1274, #1275)
- Marksman silent-clean confirmation now requires a liveness check, so a wedged server is no longer rendered clean (refs #1277)
- Stop-hook turn-end findings are no longer lost when the client deadline wins (refs #1218)
- Markdown
lsp_diagnosticsnow preserves Marksman's authoritative silent-clean confirmation (closes #1253) - Turn-end madge resolved its command once per FILE, and a slow older pass could overwrite newer circular-dep state (refs #766)
duplicate-function-argno longer fires a false duplicate when a parameter's default-value expression references an earlier parameter name (closes #1256)- Autofix surfaces now apply the same config as the lint surfaces that reported the diagnostics (closes #1247)
- Three hand-rolled
.tmp-<pid>staging writers bypassedatomic-write.tsand never inherited the #1205 fix, and the fixed staging name still collided across worker threads (closes #1205, closes #1217, refs #1202) - The review graph's stale-stage sweep deleted OTHER modules' in-flight atomic-write staging files out of the shared project cache dir (refs #1206, #1202)
writeFileAtomicpublished torn files for concurrent same-process writes — the staging name was per-PROCESS, not per-CALL (refs #1205, #1202)- Dense word-index startup refresh no longer turns quadratic or monopolizes the TUI event loop (refs #1197)
- Windows bare-command resolution ignored the caller's child
PATH/PATHEXTand could reuse another environment's cached answer (closes #1199) project_report'stoDisplayPathhand-rolled relativization without the shape-awareisWindowsPathbranch, mis-rendering a Windows-shaped path as the full absolute path on Linux CI (closes #1194, refs #1163 #1152 #1024)trivy-config.test.tshardcoded a POSIX path literal (/tmp/main.tf), so it failed on a Windows dev machine while staying green on Linux CI (closes #1190, refs #1024)- Structural shape-5 hardening: LSP
touchFilenow returns a{ diags, inconclusive, binding }wrapper whose flags survive any copy by construction, plus a fail-closed graph-build-info guard (closes #1179, refs #1108 #1094 #1096) - Per-entry widget observation timestamps: a cross-file cascade merge no longer over-clears a whole footer record, dropping only the genuinely-stale entries (closes #1186, refs #1093 #1092 #1020)
- The
runtimeExitWindowbreaker map never dropped a stale/aged-out key, and its cooldown comment described the wrong call order (closes #1183, refs #1142 #1181) allowScriptsentries had drifted from what the declared dependency ranges actually resolve to, so npm v12's exact-version script-approval check saw stale pins (closes #1176)switch-case-terminationfalse positives for returning try/catch and exhaustive conditionals (closes #1079)- Non-enumerable side-channel flags — the shape-5 copy-loss sweep (refs #1108)
- LSP runtime-exit breaker missed persistent low-frequency crash loops (closes #1142, refs #1127 #1139)
- Closed out the three #1134 P3 tails left after #1138's Svelte oxfmt support (closes #1134)
- Rule-cache disk cache could replay a stale compiled rule set on a same-mtime+same-size rule-file edit (closes #1118, refs #1105 #878)
- Formatter definitions and
FORMATTER_POLICY_BY_EXTENSIONwere unbound hand-maintained inverse lists; added a bidirectional drift guard and fixed two latent mismatches (closes #1135; refs #1086 #1134 #883) - Pull-diagnostics entries never bound to document content, so they never demoted (closes #1104, refs #1095 #1096 #1100)
- Config caches gated freshness on mtime alone — the mtime-only cache-freshness class sweep (closes #1105)
- Windows drive-root & autofix-snapshot
readdirSyncblocked the event loop on slow cloud-backed dirs (refs #1137) session_start_sequence_readwas an unbounded synchronous blocking read on the session_start hot path (closes #1162)- Resource-sampler Windows CIM spawns were not
.unref()'d, the same one-shot-retention shape as the orphan reaper (refs #1155) toProjectRelativePathnever relativized a Windows-shaped path off native Windows (closes #1163, refs #1150/#1152/#1161/#1024)generated-artifacts.tsused module-defaultpath.basenameon Windows-shaped paths, under-detecting lockfiles/declarations off native Windows (closes #1161, sibling of #1150/#1152)- Quick-mode background warmup kept a one-shot
pi -p/--printprocess alive (closes #1154) detectFileRolemisclassified a Windows-shaped path off native Windows (closes #1152, latent sibling of #1150/#1151)- Orphan-reaper fire-and-forget PowerShell/
psspawns kept a completedpi --printalive past settle (closes #1153) - Persistence workers could keep completed one-shot processes alive (#1148)
normalizeFilePathmangled a Windows-shaped path on non-Windows OS (closes #1150)- Workspace-edit preflight: five contained P3 deferrals from #1085 (refs #1085)
- Workspace-edit CRLF boundary class + rename close-failure plaintext reopen (closes #1147, refs #1085)
- Post-init runtime exits now count toward the LSP circuit breaker (closes #1127)
terragrunt hcl fmtreported success when it never ran (refs #1117)- Runners reported a clean file on a non-zero exit with no output (refs #1117)
- Bare-binary GitHub release assets skip signature siblings
- Cascade fallback-display paths re-displayed bound-false LSP snapshots (refs #1104)
parseSymbolKeymis-parsed LSP-fallback symbol kinds (refs #1088)- Java try-with-resources suppression was dead (refs #1089)
- Raw NUL byte in
review-graph/builder.tsmade the file look binary to grep (refs #1088) buildCallGraphsame-file evidence accounting hardened + dead code removed (refs #1089)- JS destructured params dropped from
parameterCount(refs #1089) call-graph.ts's exportedCACHE_VERSIONrenamed toCALL_GRAPH_CACHE_VERSION- Dead SIGTERM→SIGKILL escalation guard on non-Windows kills (closes #1114)
- Micro-gap sweep: recorded coverage/observability/doc gaps (refs #1106, refs #1104)
- mtime-only cache freshness sweep (refs #1105)
- Test-role files no longer leak into collateral cascade/impact surfaces (closes #1080)
no-bare-except(Python, ast-grep) still flags dotted/qualified exception types as bare (closes #1031)- The warm IPC side-channel re-dispatched the same request on stray bytes (closes #1219)
npm run test:unitruns again, and actually excludes the integration filesloop_blockno longer reports a machine sleep or paging stall as a pi-lens synchronous block (refs #1122, refs #1123 item 1)runtime-tool-result.ts's three tool-result-turn maps now key throughPathKeyedMap(refs #1086, the #210/#1020/#1025 raw-path-key class)pi --print --no-sessionno longer hangs afteragent_settled— uncleared race-loser timers (refs #1097, recurrence of #22's symptom via a different handle)- Two more uncleared-race-timeout members closed out (closes #1109, sweep follow-up to #1097/#1110)
sg scanexit-1-with-matches is no longer misclassified as a CLI failure (refs #1087)- "Silencing is not fixing" now covers the whole suppression class, not just the policy member (refs #1087)
- Inline
pi-lens-ignorecomment tokens are now normalized like the diagnostic id (refs #1087) "disable": []/"select": []no longer warn spuriously (refs #1087)- Test-runner subcommands no longer lost during binary resolution (closes #1098)
- Call-graph persisted-cache validator and canonical-freshness invariant now have real test coverage (refs #1089)
module_report'scallGraph: truesurface gains coverage for thefile-capandidentity-missingunavailability reasons and theprovenance.callGraphfield (refs #1089; the Java try-with-resources regex and grammar co-load items remain open there)- Review-graph cache-identity guard now detects a stale graph instance instead of a vacuous schema-tag compare (refs #1088; the
parseSymbolKeyLSP-fallback-kind item remains open there) - Nested-link diagnostics no longer flag ordinary JSX wrappers (closes #1076)
- LSP workspace edits apply safely in declared order (refs #1053)
- LSP workspace-edit apply paths: reversed same-position inserts, win32 casing destruction, versioned-edit rejection, out-of-range clamping (closes #1085; P3-1 folded in, P3-2/3/4/5/6/7 deferred on #1085)
- Read-guard did-you-mean no longer quotes NFKC-normalized text as "current lines"
- Experimental git guard correctness (refs #1063)
- Stale cross-file footer diagnostics now clear (refs #1093, refs #1092)
- Class sweep: test fixtures hand-writing persisted-format version literals no longer go vacuous on version bumps (closes #1106; class generalized from #1089/#1082, fresh-risk flagged from #1096)
no-bare-exceptno longer flags subscripted exception specs (closes #1244)- Spawn failures now distinguish missing tools from invalid working directories (closes #1214)
- Per-issue close-keyword CI validation
- Recover stale git-guard blocker records (closes #1084)
- Cascade module source-file walk is memoized on the existing freshness seams (refs #1137)
- Review-graph supersession cleanup is deterministic (refs #1318)
- In-pi extension logging no longer corrupts the pi TUI layout (closes #1333)
- npx formatter fallback honors style-preservation gating (closes #1345)
- Formatter failures now appear in the diagnostics widget (closes #1346)
- Instance-registry liveness tests no longer depend on arbitrary runner PIDs (refs #1352)
- Trust-gated observability (refs #1334, #1358)
- BLIND WRITE no longer fires on self-authored files (closes #1364)
- Edit counts now match normalized file paths (closes #1369)
- Bound warm word-index memory (closes #1370, refs #1332)
- Latency-log hygiene (closes #1371)
- Review-graph size gates stop at the cap sentinel (closes #1372)
- Keep LSP roots inside the session project and coalesce nested marker clients (closes #1373, refs #1328)
- Telemetry phase pairing and attribution (closes #1374)
- Re-assert widget mounts after host UI replacement (closes #1381)
- Widget and inter-extension bus updates recover after session replacement (closes #1383)
- Deferred formatting uses bounded concurrency (closes #1387)
- Hardened codebase-model cache identity (closes #1388)
- Prevented consistency drift in language fixtures and extension handling (refs #1388)
- Canonicalized LSP edit merge buckets and call-graph path comparisons (refs #1388)
- Bound and idle-evict review-graph workspaces and authoritative project snapshots (refs #1389).
- Bound and evict rebuildable Tier 2 reverse-dependency, tree-sitter query, and workspace-topology caches while retaining …
- Bound Tier-3 process caches, prune expired negative LSP entries, decay widget/agent state, and close the cache audit (closes #1389).
- Scope session-start smell-tail diagnostics to the current session boundary (closes #1398)
- Unconfigured Python files are formatted again (refs #1144)
- Ast-grep console-rule exclusions (closes #965)
- Nullish equality exemptions (closes #966)
- Security-pin dependency handling (closes #968)
- Unsafe-boundary fallback detection (closes #969)
- Promise-returning async callbacks (closes #970)
- Native zizmor suppressions (closes #971)
- Named URL constants (closes #964)
- Opengrep LSP compatibility (closes #974)
- Workspace configuration responses (closes #983)
- Same-file diagnostic ordering (closes #1198)
- Bounded installer retries (refs #1222, #1223)
- Stabilize LSP workspace-edit occupancy (closes #1091)
Security
- Git guard command-injection hardening (refs #1084, PR #1395)
toPosix()/splitPathSegments()path primitives (#1193)- On-demand heap snapshots for retainer attribution (#1126)
- Guard hardening (refs #1084)
- Honor the pi host's project-trust decision before installing or spawning anything (refs #1334)
Contributors
- Apostolos Mantzaris (@apmantza)
- Nathan Cooke (@3choBoomer)
- Eli Stark (@white-hat)
- Mark Faga (@mjfaga)
- Marvin Aziz (@marvtub)
- Dominic (@aeturnal)
- Kenneth McCormick
- jiangmt
🙏 Thanks
Thanks to the external contributors in this release:
- @3choBoomer — #1264
- @aeturnal — #1149
- @AngriestBird — #1045, #1117, #1175, #1204, #1211, #1231, #1248
- @floatGray — #1051
- @marvtub — #1077
- @mjfaga — #1066
- @white-hat — #1254