Repository navigation
Conversation
3 tasks done
rapp992
pushed a commit
to Felag-Engineering/relay
that referenced
this pull request
Oct 9, 2026
Upstream moved the v1 tag to e2a55d2 (dtolnay/rust-toolchain#187, "Safely handle action inputs": multi-line-safe GITHUB_OUTPUT writes and argv-array rustup flags instead of string-built command lines). zizmor's online ref-version-mismatch audit now fails every PR's lint step because our six SHA pins, commented '# v1', point at the old head 7e38f4b. The new commit descends from the old pin and changes only action.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek (cherry picked from commit 0a3a00a)
4 of 5 tasks
bryanfawcett
added a commit
to mzizi-dev/mzizi
that referenced
this pull request
Oct 9, 2026
…able branch workflow audit (zizmor 1.30.1) failed on #111 and #112 with four high impostor-commit findings, all on dtolnay/rust-toolchain@89b1218 (# stable), used in ci.yml (three jobs) and supply-chain.yml. The action's stable branch is regenerated by force-push: git ls-remote shows stable at 686976e (2026-10-08) and 89b1218 (a 2026-10-01 'toolchain: stable' commit) is no longer in its history, so the pinned commit has no history in the repository. The failure is on staging's workflows, not in either pull request. Pinned instead to e2a55d2, the head of master and the v1 tag, which master's history keeps reachable, with toolchain: stable passed explicitly: master's action.yml differs from stable's only in toolchain being required (no default). git diff 89b1218 686976e shows the newer action only hardens its input handling (dtolnay/rust-toolchain#187). Measured: zizmor 1.30.1 --offline over .github/workflows: no findings (1 ignored, 8 suppressed). The online impostor-commit audit needs the workflow token and runs in CI. prettier 3.9.4 --check passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q1aSrvXhc8FYbBWpr8yFqx
rapp992
added a commit
to Felag-Engineering/relay
that referenced
this pull request
Oct 9, 2026
Upstream moved the v1 tag to e2a55d2 (dtolnay/rust-toolchain#187, "Safely handle action inputs": multi-line-safe GITHUB_OUTPUT writes and argv-array rustup flags instead of string-built command lines). zizmor's online ref-version-mismatch audit now fails every PR's lint step because our six SHA pins, commented '# v1', point at the old head 7e38f4b. The new commit descends from the old pin and changes only action.yml. Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek Co-authored-by: Claude <noreply@anthropic.com>
rapp992
added a commit
to Felag-Engineering/relay
that referenced
this pull request
Oct 9, 2026
…re-issued call never double-dispatches (#957) * relay: adopt Go 1.26.9 for twelve new stdlib advisories The pull-request govulncheck gate now fails every Go PR on twelve newly published standard-library advisories reached from the Relay's code: GO-2026-6599/6600 (html/template), 6603/6605/6609/6610/6611/6612/ 6613/6617 (net/http), 6607 (crypto/tls) and 6608 (net/textproto, mime/multipart). Go 1.26.9 changes each of those packages (e.g. the new 200-range cap on Range headers, GODEBUG httpservecontentmaxranges). Every go directive moves 1.26.8 -> 1.26.9: relay/go.mod and the five tools/* modules, so tools keep building with the module's toolchain. No dependency changes; go.sum files are untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek (cherry picked from commit e9c94f3) * relay: bump golang.org/x/net to v0.60.0 for four HTTP/2 server advisories After the Go 1.26.9 bump the gate still reports GO-2026-6603, 6611, 6612 and 6617 (HTTP/2 server: Trailer memory exhaustion, repeated initial-window changes, double flow-control refund, HPACK encoder race). The Relay reaches them through google.golang.org/grpc's use of golang.org/x/net/http2; x/net v0.60.0 changes exactly those server paths (deferred SETTINGS_HEADER_TABLE_SIZE application to the encoder, initial-window handling). Its go directive is 1.26.0, so nothing else moves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek (cherry picked from commit bb84eab) * ci: repin dtolnay/rust-toolchain to the current v1 (e2a55d2) Upstream moved the v1 tag to e2a55d2 (dtolnay/rust-toolchain#187, "Safely handle action inputs": multi-line-safe GITHUB_OUTPUT writes and argv-array rustup flags instead of string-built command lines). zizmor's online ref-version-mismatch audit now fails every PR's lint step because our six SHA pins, commented '# v1', point at the old head 7e38f4b. The new commit descends from the old pin and changes only action.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek (cherry picked from commit 0a3a00a) * feat(mcp): dispatch returns a Job handle once Tasks are persisted; a re-issued call never double-dispatches run_operation and raw_exec return the Job ID with job_status=running as soon as every Task is persisted (capability Service.Start), with wait_seconds (0-300) as the opt-in blocking form; an Account-scoped idempotency_key answers a re-issued call with the existing Job and never dispatches again. No spec claims promoted (execution.md is legacy). Closes #895 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek --------- Co-authored-by: Claude <noreply@anthropic.com>
rapp992
added a commit
to Felag-Engineering/relay
that referenced
this pull request
Oct 9, 2026
… under concurrent fan-out (#954) * relay: adopt Go 1.26.9 for twelve new stdlib advisories The pull-request govulncheck gate now fails every Go PR on twelve newly published standard-library advisories reached from the Relay's code: GO-2026-6599/6600 (html/template), 6603/6605/6609/6610/6611/6612/ 6613/6617 (net/http), 6607 (crypto/tls) and 6608 (net/textproto, mime/multipart). Go 1.26.9 changes each of those packages (e.g. the new 200-range cap on Range headers, GODEBUG httpservecontentmaxranges). Every go directive moves 1.26.8 -> 1.26.9: relay/go.mod and the five tools/* modules, so tools keep building with the module's toolchain. No dependency changes; go.sum files are untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek (cherry picked from commit e9c94f3) * relay: bump golang.org/x/net to v0.60.0 for four HTTP/2 server advisories After the Go 1.26.9 bump the gate still reports GO-2026-6603, 6611, 6612 and 6617 (HTTP/2 server: Trailer memory exhaustion, repeated initial-window changes, double flow-control refund, HPACK encoder race). The Relay reaches them through google.golang.org/grpc's use of golang.org/x/net/http2; x/net v0.60.0 changes exactly those server paths (deferred SETTINGS_HEADER_TABLE_SIZE application to the encoder, initial-window handling). Its go directive is 1.26.0, so nothing else moves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek (cherry picked from commit bb84eab) * relay(capability): re-check a Job's cancel immediately before each Task send Each dispatch worker's cancel check now runs inside the Router, serialised per Task ID, immediately before the TaskRequest is written to the Tunnel; a withheld Task resolves cancelled and never sent (MarkCancelledBeforeSend), and the Reconciler re-reads a Task's state before any resend. No spec claims (the execution spec is not migrated). Closes #943 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek * ci: repin dtolnay/rust-toolchain to the current v1 (e2a55d2) Upstream moved the v1 tag to e2a55d2 (dtolnay/rust-toolchain#187, "Safely handle action inputs": multi-line-safe GITHUB_OUTPUT writes and argv-array rustup flags instead of string-built command lines). zizmor's online ref-version-mismatch audit now fails every PR's lint step because our six SHA pins, commented '# v1', point at the old head 7e38f4b. The new commit descends from the old pin and changes only action.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek (cherry picked from commit 0a3a00a) --------- Co-authored-by: Claude <noreply@anthropic.com>
rapp992
added a commit
to Felag-Engineering/relay
that referenced
this pull request
Oct 9, 2026
…nly by clippy, fuzzable crates (#962) * ci: repin dtolnay/rust-toolchain to the current v1 (e2a55d2) Upstream moved the v1 tag to e2a55d2 (dtolnay/rust-toolchain#187, "Safely handle action inputs": multi-line-safe GITHUB_OUTPUT writes and argv-array rustup flags instead of string-built command lines). zizmor's online ref-version-mismatch audit now fails every PR's lint step because our six SHA pins, commented '# v1', point at the old head 7e38f4b. The new commit descends from the old pin and changes only action.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek (cherry picked from commit 0a3a00a) * refactor(daemon): Cargo workspace — relay-policy and relay-ops read-only by clippy, fuzzable crates relay-exec (sole spawning crate), relay-ops (write-banned) and relay-transport move out of daemon/src; step-1 guards extended to them, plus spawn, unsafe, ExecRequest and feature censuses. Closes #889 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017phewNxcFMxpU3ntX2TKek --------- Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 9, 2026
7 tasks done
epompeii
added a commit
to bencherdev/bencher
that referenced
this pull request
Oct 12, 2026
## Problem `Lint / Zizmor Online` fails on every pull request (for example run 37884500334 on #1153) with one medium finding, exit 13: ``` warning[ref-version-mismatch]: action's hash pin has mismatched or missing version comment --> ./.github/workflows/update_sandbox.yml:18:81 18 | - uses: dtolnay/rust-toolchain@7e38f4b # v1 | ^^ points to commit e2a55d2ffb04 ``` The upstream `v1` tag of `dtolnay/rust-toolchain` moved to `e2a55d2ffb04f378e9626c28d38b36d230d1e12f` on 2026-10-09 when dtolnay/rust-toolchain#187 merged. The job is `continue-on-error: true`, so it does not block a merge, but it is red on every open pull request. ## Change Repin `update_sandbox.yml` to the commit `v1` points at today and keep the `# v1` comment. This follows #987, #1045, and #1088, which tracked `v1` for this same pin, and `v1` is the only tag upstream publishes. The hash was resolved from the GitHub refs API. ## Upstream range `7e38f4b4...e2a55d2f` is three commits, all in `action.yml`, fixing the command injection reported in dtolnay/rust-toolchain#179: - Every input and the parsed toolchain move out of inline `${{ }}` expressions in `run:` scripts and into `env:` variables, quoted at each use. - The parsed `toolchain` output is written with a heredoc delimiter instead of `key=value`. - The separate step that built `--target`, `--component`, and `--allow-downgrade` strings is folded into the install step as a bash array. This call site passes only `toolchain: stable`, no targets or components, so it was never exposed, and it still runs `rustup toolchain install stable --profile minimal --no-self-update --force-non-host` followed by `rustup default stable --force-non-host`. No other workflow or composite action uses this action. ## Other moving refs Every other pin whose comment names a moving ref still matches it today: `rui314/setup-mold@10ca16bf # v1` (14 sites), `dawidd6/action-download-artifact@b6e2e706 # v21` (2 sites), and `superfly/flyctl-actions/setup-flyctl@ed8efb33 # master` (3 sites, the current `master` head). Nothing else needs a change. ## Verification zizmor 1.25.2, the version CI pins, from the same digest-pinned image `zizmor-action` runs (`ghcr.io/zizmorcore/zizmor:1.25.2@sha256:14ea7f5c...`), with the action's arguments (`--persona=regular --format=github`, plus `--no-online-audits` for the offline job): | Tree | Offline | Online | | --- | --- | --- | | `devel` | exit 0 | exit 13, `1 medium` (the finding above) | | this branch | exit 0 | exit 0, `No findings to report` | CI on this pull request is the final check.
MejiroRina
pushed a commit
to seiunx-dev/ci-templates
that referenced
this pull request
Oct 12, 2026
Moves the pin from 02cb101 to e2a55d2 (upstream master, also upstream v1). Upstream changes: inputs are passed through env and quoted instead of being interpolated into run: lines (dtolnay/rust-toolchain#187), and rustup toolchain install retries up to 4 times on release-server checksum failures (#186). No behaviour change for the toolchain / components / targets inputs setup-rust passes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UenSDaGVdAotkLspjNTnpu
coseto6125
added a commit
to coseto6125/egent-code-plexus
that referenced
this pull request
Oct 21, 2026
…PHP/Python flow, overlay parity, hook cd target (#853) * chore(deps): tree-sitter 0.27, ast-grep-core 0.51, cargo update, action pins - tree-sitter 0.26.13 -> 0.27.1 and ast-grep-core 0.45.2 -> 0.51.0 move together: ast-grep-core 0.51 requires tree-sitter ^0.27. The vendored tree-sitter-nim pin moves from ~0.26 to ~0.27 so one tree-sitter links. - tree-sitter 0.27 makes QueryMatch::captures private: 48 field reads become captures() calls. Node::child_count now returns u32 (tree-sitter#5313): 15 redundant `as u32` casts go. - cargo update moves the rest of the semver-compatible tree, including rmcp 3.6.0, tokio 1.54.0, toml 1.1.8. - Held back by upstream pins: cc 1.2.67 (tree-sitter-sequel ~1.2.1), psm 0.1.24 (pest =0.1.24), generic-array 0.14.7 (crypto-common =0.14.7). - Actions: rust-cache v2.9.3, action-actionlint v1.80.4, harden-runner v2.22.2, dtolnay/rust-toolchain stable head b725eda (includes dtolnay/rust-toolchain#187 input-handling hardening). * chore(deps): correct count in previous message: 45 captures() call sites, not 48 * test(mcp): pin rmcp 3.6 stdio line cap of 16 MiB rmcp 3.6.0 (modelcontextprotocol/rust-sdk#1049) drops an incoming stdio line over 16 MiB and keeps the session open. serve_stdio inherits it. Keep the new default: no ecp tool takes arguments near that size, and a peer that never sends a newline can no longer grow the buffer without bound. The test fails under an unbounded transport (checked with with_max_line_length(usize::MAX): the server answers id 2). * fix(deps): review follow-ups for the dependency upgrade - ecp-mcp: raise the rmcp floor from 3.4 to 3.6. serve_stdio's 16 MiB line cap and the test that pins it exist only from rmcp 3.6.0. - ecp-mcp: the serve_stdio comment states that a request on a dropped line gets no reply. - ecp-mcp test: build the oversized line as text, so the 16 MiB pad is allocated once instead of twice. - ecp-analyzer/Cargo.toml: the svelte ABI comment no longer names tree-sitter 0.26. * fix(registry): bump BUILDER_FINGERPRINT to schema12 for tree-sitter 0.27 tree-sitter 0.27 recovers some files with syntax errors into different trees than 0.26 did. On the 23-repo parity corpus the only change is nlohmann json.hpp: one friend operator< that 0.26 parsed as a declaration is now a function. A binary built from git at the same crate version would otherwise reuse L2 graphs and parse-cache entries built by tree-sitter 0.26. schema7 set the precedent for a grammar pin. * chore(deps): declare rust-version 1.90 for the workspace tree-sitter 0.27.1 and ast-grep-core 0.51.0 declare rust-version 1.90, so rustc 1.88/1.89 can no longer build ecp. Declaring it makes `cargo install egent-code-plexus` on an older rustc fail with a clear MSRV message instead of a dependency resolution error. * chore(deps): declare rust-version 1.91, not 1.90 clippy's incompatible_msrv check, run against rust-version 1.90, flags ecp-mcp/src/schema.rs: `TypeId::of` is stable in a const context since 1.91.0, and INT_TIDS / FLOAT_TIDS call it in a const. The dependencies need 1.90; the workspace's own code needs 1.91. The schema.rs comment said 1.85. * fix(resolution): keep same-name method overloads as named nodes The uid (kind, path, owner, name) carries no parameter signature, so `save(int)` and `save(String)` share one. Pass 1 kept the first and replaced every later one with an empty-name tombstone: no name, no owner, no HasMethod, no incoming edge. On .sample_repo that was 6595 of 58892 Java Method/Constructor nodes (11.2%), 982 of 7424 C#, 442 of 2871 Kotlin and 323 of 3572 TypeScript. `impact --target audit` listed a nameless caller and stopped there, because nothing called the tombstone. Pass 1 now keeps a later Method / Constructor overload as a node with the first one's name and owner, under `uid::overload(first, ordinal)`. It is registered by id only (`SymbolTable::register_overload`), so every name lookup and resolver tier still returns the first declaration and binding is unchanged. A Calls edge bound to the first now reaches every overload of the set with reason `call:overload_set` and unchanged confidence: the argument types that pick one are not parsed. Self-recursion is skipped per member, so `save(int)` delegating to `save(int, String)` keeps its edge to the sibling. Other collisions (`#ifdef` redefinitions, field reassignments) stay tombstones. class_membership gives each overload its own HasMethod edge. It also resolved a member by name alone, so a member landed on the first same-name declaration in the file whatever its owner: two classes' `__init__`, or a Rust trait's `fn save` ahead of `impl K`. A member now resolves to the declaration its owner matches. The query-time overlay mirrors all of it: the same uid numbering, later overloads kept out of every name tier (base ones found through `ArchivedZeroCopyGraph::is_later_overload`), constructor choice ignoring them, and the same Calls fan-out for virtual and clean base targets. BUILDER_FINGERPRINT moves to schema13 so cached graphs and parse caches rebuild. Tests: overload_members.rs covers the 14 mainstream languages (C checks that an `#ifdef` redefinition stays one node). Five tests that pinned the collapsed overload (one constructor call, one closure parent, one static-import target) now expect each overload. Three overlay parity tests compare the overlay against a full reindex by uid. * chore(blindspot): retire the method-overload dev-metric bucket Pass 1 keeps overloads as nodes and records no method-overload BlindSpot any more, so the bucket is gone from DEV_METRIC_BS_KINDS, the summary docs and help text, and its exclusion test. * fix(resolution): link each overload set once instead of fanning out calls Fanning each call out to every overload multiplied Calls by the set size. On .sample_repo Calls went from 198868 to 313695 (+58%): C# +211% (Newtonsoft XUnitAssert.AreEqual alone gained 27717 edges, about 30 overloads times its call sites), Java +96% (guava ImmutableList.of, 13 overloads). A call now binds the first overload only, as before this branch, with reason `call`. Instead, the first overload `References` each later one (reason `overload_set`, confidence 1.0): k - 1 edges per set. Upstream impact of a later overload reaches the set's callers through the first, one hop further than with the fan-out. A first overload delegating to a sibling needs no special case: the link already connects them. The overlay emits the same links for a dirty file's sets and drops the base ones sourced in it, as it does for closure references. The tests that pinned one constructor call per construction keep that contract. * fix(impact): name an overload set by its first overload Two same-file overloads share name, file and kind, so --file and --kind could not split them and `ecp impact save` failed as ambiguous. A later overload is reached through the first one (calls bind to the first, which references it), so resolve_candidates skips it as a target and as a same-name collision, as before the overloads were named. ecp path shares the resolver. * fix(inspect): report endLine 1-based like startLine inspect printed the raw 0-based span row as endLine, so a symbol ended one line before it started. routes' enclosing-scope check compared the same raw row against a 1-based line, rejecting a route on its scope's last line and never matching the single-line Const guard. * fix(resolution): prefer the caller's own member; bind duplicated trees to the nearest copy A member lookup took the first same-name declaration in the file, so a trait or interface declared ahead of the class won `self.save()` (Rust inherent methods, and the class's own member in the other languages, take precedence). A call into a source tree that exists twice (android/guava next to guava) was dropped as ambiguous; when every candidate is the same file under another root, the copy sharing the deepest directory with the caller now binds, at confidence 0.6 with reason call:nearest-copy, and a tie stays unresolved. Builder fingerprint +schema14. * fix(overlay): replay the qualifier tier for typed-receiver and static calls The overlay looked a qualified callee (K.save, K::st) up by its literal name and found nothing, so a dirty file lost every typed-receiver and class-qualified call the index binds at 0.85. resolve_callee now replays the index's Tier 2.5: find the qualifier's file (same file, import, unique global, module stem) and pick the member it declares, preferring the qualifier's own member. A qualified constructor type resolves its whole path before the last segment, as the index does. * test(resolution): one function per line in the Rust own-member fixture Calls are attributed to the first function on their line, so three functions on one line made audit, not run, the caller. Drop the overload_members comment the own-member rule made false. * fix(overlay): mirror own-member precedence and nearest-copy binding A dirty file's same-file call with several declarations of the name bound nothing, where the index binds the caller's own member; an ambiguous global call dropped every candidate, where the index binds the copy in the caller's tree. The overlay now passes the caller's owner into resolve_callee and picks the nearest copy with the index's confidence and reason. Calls reached through the receiver-typing ladder, which the overlay does not replay, stay a recorded divergence. * feat(analyzer): reference enum variants from the code that uses them No construction, read or pattern of an enum variant had an edge, so upstream impact on a variant reported dead code. Each function now References each variant it uses once per reason (enum_variant:use, enum_variant:pattern), resolved through the qualifier's type so a variant name shared by two enums binds the right one. Same commit fixes the enum's Defines edge binding a same-named variant of another enum. * test(routes): route on its scope's last line keeps the enclosing scope Red before 8e90271b: the raw 0-based end row put the route one line past its scope. * fix(verify-resolver): rank every resolving tier above Unresolved The dedup rank listed SameFile, ImportScoped and Global only, so QualifierScoped, TypeOwned, ModuleTree and NearestCopy tied with Unresolved and the first record of a key won. * chore: define the nearest-copy constants once; clear clippy findings heuristics.rs re-exports the ecp-core constants the overlay already uses, so the index and the overlay cannot drift apart. * test(overlay): close the nearest-copy divergences that already match Kotlin, C#, Python, Swift, Dart and Go record the qualified call by its bare member name, so it reaches the global tier the overlay replays. * chore(registry): builder fingerprint schema15 for enum variant references A graph built under schema14 lacks the enum_variant References edges and must not be reused. * fix(calls): attribute a call to its enclosing function by row and column Several functions on one line (minified JS, one-line C or Ruby definitions) sent every call on that line to the first function: attribution compared rows only. Containers and pending calls now carry (row, col) positions, and the two duplicate sweeps share enclosing_targets. * fix(receiver-types): scope locals and classes by row and column Local-type and class scopes keyed on rows, so on a line with two functions the second one's receiver read the first one's locals. Scopes now hold position ranges. span_area no longer flattens its ordering past column 10000. * fix(resolver): a same-file pick never guesses between unrelated owners Tier 1 bound the first same-name callable in the caller's file even when it belonged to another type, at confidence 1.0. prefer_owned now picks the caller's own member, then a base's member in heritage order, then a free function, then the sole owner's member, then the root of one hierarchy; two or more unrelated owners fall through to the later tiers. Tier 2.5, Tier 2.75 and MemberOwner::Any share the rule. * fix(resolver): an untyped receiver does not narrow a same-file pick by the caller's bases super(E, self).m() reaches Tier 1 as an untyped member call; walking the caller's heritage bound E.m, which the explicit two-argument form skips. * feat(graph): keep path aliases and supertypes in graph.bin; overlay fragments carry heritage and variant refs The overlay re-resolves dirty files without the index's alias table, supertypes, base names or enum variant uses, so it could not match a reindex. graph.bin v14 appends the alias and supertype tables; fragment format V4 adds heritage and variant_refs per symbol. VariantRef, its reasons and PathAliases move to ecp-core. BUILDER_FINGERPRINT schema16. * fix(csharp): resolve a type-name receiver as a type, through using aliases csharp_callee emitted StringAssert.AreEqual(..) as the bare AreEqual, so three same-file AreEqual owners left the same-file pick nothing to choose by. An identifier receiver that is neither a local nor a member of an enclosing type is now a FromReceiver site: the resolver takes it as a type when the project or an import names one (using Alias = Ns.T included), else as the bare member, as before. * feat(overlay): rebuild enum variant refs, heritage-tier calls, Rust use qualifiers and path aliases for dirty files A dirty file kept its stale enum_variant References and missed calls the index binds through a base class in another file, a Rust qualifier named by a use import, and a tsconfig paths alias. The overlay now replays those tiers in the index's order: variant refs per symbol with stale base edges masked, the heritage tier at 0.8 before the wildcard pass, the qualifier tier before the Rust module tree, and the archived alias table in every candidate walk. * fix(cpp): type field and untyped receivers, keep owners in macro-heavy class templates, read templated bases A member call on an untyped receiver went out as a bare name, so it looked like an implicit-this call. Class template members lost their owner when macros broke the parse (nlohmann basic_json), out-of-class definitions took no owner, a field receiver stayed untyped, and heritage dropped templated or qualified bases and emitted an empty-name class per extra base. * fix(parsers): keep the receiver kind of member calls in Swift, Ruby, Java, Kotlin, Dart and Python An untyped receiver went out as a bare name (Swift, Ruby), a type-name receiver was dropped (Swift, Kotlin, Dart, Python), and Java new T().m() and ((A) o).m() lost their type. Each now emits an untyped member site, a FromReceiver site the resolver may take as a type, or the typed callee. Swift members of extensions, protocol extensions and enums carry their owner, and Swift parameters are keyed by their internal name. * fix(resolver): namespace owners count as free, impl blocks reach their trait, member calls never bind a type The same-file pick read a C++/C#/Rust namespace owner as an unrelated type, an ownerless Rust impl member as a free function, and let an untyped member call fall into the constructor fallback or a free function. Type receivers of C#, Swift, Kotlin and Dart resolve as types; an untyped receiver is never narrowed by the caller's type or bases in any tier; a receiver-typed call never binds a free function. Heritage-bearing kinds (class, struct, interface, trait, enum) share one enclosing-heritage rule in ecp-core. * test(receiver-types): Swift and Ruby untyped receivers are untyped member sites * fix(resolver): an ownerless Rust impl method is not top level for import binding * fix(parsers): owners for Rust generic impls and enum members, path-qualified heritage, C++ ns::f() as a namespace function Members of impl blocks over generic, path-qualified or reference self types had no owner, so their uids collided; enum members had none in Java, Kotlin, Dart, PHP and Swift; impl fmt::Display recorded no heritage; an out-of-line void ns::f() was an ownerless Method. * fix(resolver): self calls bind their own type and impl block; Python modules stay reachable through untyped receivers Python self.m() is typed as the enclosing class, as Java this.m() is, so the untyped-receiver rule no longer strips its own type and bases. A Rust self.m() in one of several impl blocks for one type binds the caller's block, and a self type the index does not declare resolves in the caller's file. A Python untyped api.helper() may still reach another module's function. * feat(overlay): share the same-file pick and the receiver-typing ladder with the index The overlay re-implemented the index's tiers and drifted each time one changed. prefer_owned, member_call_admits and the receiver-typing ladder move to ecp-core behind PickFacts / TypeFacts; the index and the overlay both call them. The overlay now replays type receivers, untyped-receiver rules, the Kotlin extension fallback and the constructor-fallback gate, and KNOWN_DIVERGENCES for the ladder is empty. * fix(overlay): compare archived and owned node kinds through NodeKind * fix(overlay): bind JS/TS bare calls through the index's lexical scope Full indexing binds a bare JS/TS call to the innermost named function in scope before any name tier, and an ambiguous or unreachable one leaves only the named-import tier. The overlay had no such step; phase 2's same-file pick then bound one of two same-uid helper twins the index leaves unresolved. LexicalFunctions moves to ecp-core and both sides build it over one file's declarations. * fix(resolver): type a Python from-imported class receiver `from k import K; K.st()` resolved by the bare member `st`: 0.7 when the name was unique, and no edge at all once another class declared `st`. When the from-import's module file declares the receiver as a type (reexport::python_imported_type), the call now resolves as `K.st` through the qualifier tier, in the index and the overlay. A submodule still binds first; an object, a re-imported name or a library name keeps the bare member. A package attribute class that shadows a submodule now binds its own member (test renamed from keeps_previous_path). view.rs also carries the overlay half of the previous commit: the LexicalFunctions step before the call tiers, and span_of. CallSite docs: FromReceiver and UntypedMember list every language that emits them now. * chore(clippy): clear the branch's -D warnings findings * fix(php): type $this and self:: in a trait or an enum ClassContext held classes and interfaces only, so $this->m() inside a trait or an enum was an untyped member call. Once untyped calls stopped binding the caller's own type's members by name, every trait-internal call dropped (Laravel: ValidatesAttributes::requireParameterCount, ManagesFrequencies::spliceIntoPosition). Traits and enums now name the receiver as a class does: the trait's own members, the using class's members and an enum's own methods bind at the qualifier tier. * fix(php): a trait types $this only for the members it declares $this in a trait is the class that uses it. Typing every call as Trait.member lost the calls into the host class (Laravel HasUniqueStringIds::getIncrementing -> Model::getKeyName, 17 edges): the trait has no such member and no heritage reaches the host. The trait's and the enum's own members still bind through the type; any other member keeps the by-name route it had before. * perf(overlay): memoize the qualifier tier per file and build name candidates lazily A dirty-file overlay query on guava (4 dirty files) went from 26 ms to 38 ms over this branch. Memoizing qualified_callee per (file, imports, callee, target, heritage, Rust caller) and building clean_base only when a tier reads it brings it to 33 ms with byte-identical output. * perf(overlay): memoize Tier 3's global pick per file and callee Tier 3 filters every base node of the callee's name, and a file calls one common name at many sites: on guava 626 Tier 3 calls had 179 distinct (file, callee) pairs and took 8.7 ms of a 20 ms overlay build. Keying the pick by every input it reads brings a 4-dirty-file query from 37.5 ms to 30.8 ms (29 ms before this branch's overlay tiers), with byte-identical output. * fix(hook): resolve the repo from a leading cd in the Bash command A command such as cd "<repo>" && grep -rn X app run from another cwd gave no graph nudge, because the hook read the envelope cwd only. The last literal cd before the grep/rg segment now sets the resolution dir when it names an existing directory. A command without "cd" pays one substring check. * fix(flow): PHP static and member calls reach their callee; declarations are not values PHP scoped calls were evaluated as plain values, so a forward slice stopped at UploadFile::upload() imported by use. php.rs now models classes by lower-case FQN, binds use clauses (alias, grouped), and resolves Class::m, self::, parent::, static:: and $this-> through the parent chain. Declaration nodes no longer become value nodes, and structural nodes (namespace, class body, parameter lists, types) raise no unsupported_semantics boundary. The uncalled sweep runs the queried file's entry points first. * fix(routes): Laravel string handlers, group prefixes and per-route middleware Route::post('/upload', 'FileController@upload') reported an inline handler with no callers, prefix()->group() and group(base_path(file)) prefixes were dropped (/admin/import/award came out as /award), and no route carried its middleware. - 'Ctrl@m', [Ctrl::class, 'm'], invokable controllers and Route::controller()->group() get a HandlesRoute edge to the controller method: exact FQN under a known namespace (1.0), a repo-unique class name otherwise (0.9), nothing when ambiguous. - Closure groups, option-array groups and chained prefixes join into the path; an include group (base_path, __DIR__, withRouting) becomes an INCLUDE record that Pass 1.5 applies to the included file's routes. - Middleware (outer to inner) lives in a sparse route_middleware side table and shows as a middleware array in ecp routes. GRAPH_FORMAT_VERSION 14 -> 15 and BUILDER_FINGERPRINT +schema17, so existing graph.bin caches rebuild. * fix(flow): lower the queried file and its imports first; Python methods live on their class The AST budget is global and spent in corpus order, so on a 514-file Laravel repo the callee file of a cross-file static call (file #449) was cut to a bare root and the slice stopped at its use clause. The queried file now lowers first, then the files its imports name, breadth-first; the rest keep corpus order and max_steps stays the one limit. A Python class body runs in its own scope: methods are attributes of the class object, not bare module names, so a module-level get() no longer reaches a method get. self.m() and Box.m() resolve through the class, with superclasses and overrides, sharing classes.rs with PHP. * fix(routes): Laravel resource, match and any routes; included files, inherited actions and entry points - Route::resource / apiResource / resources (only, except, parameters, shallow, nested) emit Laravel's action set; match emits one route per verb, any one ANY route, and --method keeps ANY rows. - A route file without a framework import keeps its records when an admitted file includes it; a file declaring its own Route stays out. - Controller actions bind after the supertypes pass: own method, then one used trait, then one resolved parent. Bound methods get an EntryPoint marker in their own file. - TOON output joins middleware so the routes table stays tabular. BUILDER_FINGERPRINT +schema18: RawRouteScope gained needs_include. * fix(routes): pass named_child a u32 index * perf(flow): share unchanged frames between state snapshots Every fork and every sweep entry point deep-cloned all scopes and objects of the program, and restore deep-compared them. With PHP methods as functions the client Laravel query spent 6.2 s in 869 invokes. Frames is a chunked persistent vector of Rc scopes: a snapshot copies one pointer per chunk, a write un-shares one chunk and one scope, and restore/join visit only frames that differ. * docs(skill): ecp routes carries middleware and ANY routes * chore(clippy): clear the branch's -D warnings findings * fix(hook): only a cd that surely runs in the search's shell moves it A cd after ||, inside a pipeline or a background job, or ending an && chain the search is not part of, no longer re-roots the search. The scan stops at any rg/grep word (rtk proxy rg, git grep), matching extract_from_shell. A quoted '~/x' is a literal directory, not the home directory. Redirects such as 2>&1 and &>log no longer split segments. * fix(overlay): drop a dirty impl's old traits; clear qualified memo after supertypes; real 0.15.0 fixture - base_supertypes drops a trait that only the dirty file's archived impl gave, so impl A -> impl B binds B.m like a reindex (both kept when a clean impl also implements A). - QualifiedCache entries filled in the supertypes pre-pass read hierarchy_root before dirty_supertypes was set; clear the memo after set. - OverlayNames.same_file is a set: every reader only tests membership. - overlay_view_inputs reads a session written by the released 0.15.0 (format 3, v0.15.0+schema11) instead of one the new code built. - Doc and comment fixes: fragment format v4, same-file twin wording. * fix(routes): Laravel middleware exclusion, controller middleware, include fixes - dirname levels outside 1..=64 drop the include instead of overflowing. - withoutMiddleware / excluded_middleware remove middleware at promote time; variadic middleware('a','b') records every argument. - Controller middleware ($this->middleware with only/except, static middleware(), parent::__construct rules) appends to the route list. - A global 'use Route;' import no longer reads as the file's own router. - A group controller reaches an included file's bare actions. - A qualified action under a group namespace gets no second prefix. - Scopes past the include cap emit a laravel-include-scope-cap BlindSpot. - ANY answers Laravel's verbs only, in fetch lookup and routes --method. - The same path from two includes keeps the last registration. BUILDER_FINGERPRINT bumps to schema19; graph.bin layout is unchanged. * fix(flow): drop each tree after lowering; Python decorators and MRO; PHP namespace aliases - Trees are no longer held until lowering_order finishes: corpus order lowers while parsing, a queried file drives an on-demand BFS, and the PHP class map keeps names only (peak RSS was up to 7x the release). - staticmethod binds no receiver, classmethod binds the class, any other decorator leaves the call unresolved with an external_call boundary. - Inherited members follow C3 MRO; ambiguous hierarchies keep the union. - A field read walks the parent chain like a method call does. - A PHP anonymous class method no longer leaks into the outer scope. - The queried module initialises before the rest of the corpus. - PHP aliases and class names resolve per namespace block, case-insensitive. - A method sees functions declared later in the same file. - pass raises no boundary; .pyi uses Python semantics. * fix(resolver): no name-only binds for typed receivers; C++ out-of-line owners and scopes - A receiver typed to a declared class no longer binds to an unrelated same-file owner or a free function; the nearest ancestor's member wins, else the type ladder decides (languages with extension members excluded). - C++ out-of-line definitions take their qualifier as owner, so A::reset and B::reset no longer form a false overload set. - Kotlin/Dart: Other().m() types the constructor receiver; other computed receivers never bind to the caller's own member. - C++ lambda and catch parameters get their own scope; field tables are keyed by namespace path. - cpp recovery macro lookahead is memoised (was quadratic before budget). - extract_variant_refs carries the parent on its stack instead of calling Node::parent per identifier. - Constructors sharing the class name get HasMethod. * test(class_membership): same-named constructor now gets HasMethod The pinned test asked to be flipped once a multi-id-per-name lookup landed; member_node now resolves through first_declaration. * chore: clippy manual_contains and disallowed_names * fix(hook): fall back to the envelope cwd whenever the search directory is uncertain A cd that may not run in the search's shell, an unknowable target (cd -, $VAR, backticks, ~user, options, bare cd), a cwd-changing builtin other than cd (pushd, popd, source, eval, ...), a cd inside a subshell, or an unbalanced quote now yields no override instead of a stale one. A successful 'cd x || ...' skips its || operand, so 'cd x || exit; rg' searches x. Leading assignments and '{' groups keep the cd. * fix(resolver,flow): no guessed ancestor member; Rust-only impl drop; classmethod receiver; C3 memo - ancestor_member returns a member only when one declaring ancestor inherits every other declarer; otherwise the type ladder decides. - The overlay drops a dirty impl's old trait only for Rust types, so a Python class with the same name keeps its heritage. - self.cm() binds cls to the receiver's class objects, else stays an external_call. - C3 linearization memoises per lookup (a stacked diamond was 2^n). - Kotlin/Dart constructor inference yields to a same-named local. * fix(flow): string tokens and interpolation raise no unsupported_semantics Quote tokens, f-string interpolation, template substitutions and heredoc parts were 82% of the unsupported_semantics boundaries on ComfyUI and crowded real boundaries out of the returned set. Their values still merge; shell_command_expression and dynamic variable names keep their boundary. * fix(routes): controller middleware only when statically certain, else a BlindSpot - Static middleware() requires HasMiddleware on the class or an ancestor and exactly one top-level array return. - Constructor middleware is one ordered list; parent::__construct() inlines the parent's registrations at the call; a used trait's constructor wins over the parent's, as in PHP. - Closures, nested functions and anonymous classes are not scanned; a conditional or non-literal registration, or an out-of-graph parent/trait, adds no middleware and records laravel-controller-middleware-dynamic. - X::class resolves in its own file before dedupe and exclusion. - Only a global 'use Route;' is the facade; 'use Router;' binds a class. - A class-constant action in a controller group stays X@__invoke. - A repeated include scope keeps its last position; within one route file the last registration wins between a verb and ANY in fetch lookup. - Controller middleware merges once instead of sorted inserts (was N^2). * fix(routes): an unbound Laravel action is reported as unresolved, not inline Pass 1.95 records a laravel-unbound-action BlindSpot carrying the action text; ecp routes reports handlerKind unresolved_action with that text instead of claiming an inline closure (client: 'AuthController@logintest' to a missing method). * fix(resolver): a base's member yields to an earlier base's inherited one prefer_owned took the first declared base that owns the member, so a typed self.m() in D(B, C) with B(A) bound C.m although Python's MRO reaches A.m. A base now stands only when no earlier base reaches the member through its ancestors; otherwise the pick gives no edge. Also documents the controller middleware record markers on RawRoute::CONTROLLER_MIDDLEWARE. * fix(hook): tri-state cd target; unknown cwd suppresses graph hits A cd that may or may not run, an unknowable target, or a cwd-moving builtin now yields Unknown, and the hook prints no hits instead of falling back to the envelope cwd. Skipping a successful cd's || operand tracks { } / ( ) depth, and a cd inside an and-or list that ends in & stays in the background job. * fix(routes,receiver-types): codex round 3 findings - Laravel: a middleware or parent::__construct after a possible constructor exit becomes a laravel-controller-middleware-dynamic BlindSpot. - ANY precedence applies only to one file's registrations of the same raw URI, in linear time; cross-file order stays a union. - routes: an unbound action matches its registration by row and column. - Kotlin: a nested type's property no longer shadows an outer class. - Kotlin/Dart: a block-scoped local shadows only inside its block. * fix(hook,php,dart): codex round 4 findings - hook: a cd in the search's own background job applies; a quoted '{' or '(' in a skipped || operand opens no group. - Laravel: $exit and static::exit are not constructor exits. - Dart: each declarator of A a = A(), b = a.copy() binds before the next initializer. * fix(hook): a shell comment ends its segment An unquoted # at a word start runs to the newline, so a ( ; or quote in the comment no longer shifts subshell depth or segment bounds. * fix(hook): ${...} is opaque, a heredoc is unknown, # starts a word only after a metacharacter A # inside ${v:- #} or after a CR is literal, as in bash. A heredoc body is not modelled, so a command holding one yields Unknown and no graph hits. * perf(overlay): look up the qualifier's file stem before the member scan The named-file tier scanned every declaration of the member per qualified call (9 us on a common name such as add). The stem index is built once per overlay build, so the tier is one hash lookup per call. * fix(hook): a quote or escape inside ${...} makes the split unknown Also drop a needless borrow that clippy -D warnings rejects in the Laravel route test. * fix(hook): four cases that named a directory bash does not search - A brace inside ${...} makes the split unknown. - A cd or cwd builtin behind a prefix word (! cd, time cd) is unknown. - cd .. drops the last component of the logical path, as bash -L does. - A relative cd under an inherited or assigned CDPATH is unknown. * fix(hook): six more shapes that named a directory bash does not search Unknown for: a logical and a physical path that disagree, a glob in the cd argument, a line continuation, set -P / -o physical, and a cd or source behind a prefix word (! . file). CDPATH exempts only a first component of . or .., so cd .codex consults it. * feat(hook): name the cd target repo in the hits header; join line continuations Hits a leading cd moved to another repo now open with 'ecp graph hits in <dir>:', so the agent reads their paths against that repo and a wrapper no longer re-derives the directory. A backslash-newline outside single quotes joins its lines before the split, as in bash, so 'cd x && \' over two lines keeps its hits. After a prefix word only the command word is checked, so 'time git diff -- .' is not a source. * fix(hook): join line continuations before extracting the search pattern 'cd repo && \' then 'grep -rn X .' on the next line resolved the cd but found no grep word, so the hook printed nothing. * fix(hook): a comment's trailing backslash joins nothing; skip time options A '# old && \' comment line no longer swallows the next line's cd, and 'time -p . env.sh' is checked as a source. * fix(hook): a cd the search may not follow gives Unknown Codex round 13 found three shapes where the hook named the wrong directory: a search in a subshell that cds ((cd x && rg) | head), a cd after && whose list ends before the search (false && cd x && true; rg), and a newline after && that split the list (false &&\ncd x; rg). The same reasoning covers a cd in a { } group or compound command that closes before the search (a function body, a skipped operand, a group in a pipeline) and a cd in a loop. A cd after && now counts only when every operator up to the search is && or |. * fix(hook): else branches, command substitutions and rg lookups Codex round 14: a search in an else branch kept the cd of the then branch; m=$(cd x && rg ...) hid its cd behind the assignment; and 'command -v rg && cd x && rg Foo' stopped at the looked-up name, both for the cd target and for the pattern. runs_search now decides which rg / grep word runs a search, and both scans share it. A cd before else / elif, inside a case, or inside a backtick substitution gives Unknown. * style(hook): if let for the single compound opener arm * test(update): write the fake ecp from a child process test_run_skill_refresh_hung_child_times_out failed with 'Text file busy': another test thread forked while this process held the script open for writing, and the forked child kept the write fd until its own exec. A separate sh process now writes the script, so no test thread ever holds that fd. * fix(hook): |& is one pipe; git -C grep gives Unknown Codex round 15: 'cd x && git status |& head' split |& into a pipe and a background job, so the cd looked like another job's and the next rg got Unchanged. And 'git -C dir grep' searches dir while the hook took the envelope cwd (or an earlier cd). |& is now one Sep::Pipe, and a git grep behind -C / --git-dir / --work-tree gives Unknown. * fix(hook): --color values and rg --files are not the search term Codex round 16: 'rg --color never ... HookInput' extracted 'never', and 'rg --files -g ... | xargs grep HookInput' stopped at the listing rg and extracted 'xargs'. Value-taking long options join flags_with_values, and runs_search skips an rg that lists files, for both the term and the cd target. * fix(hook): the argument of cd grep is not the search Codex round 17: 'cd grep && rg -n main src' stopped at the directory name grep, so the cd never counted and the hook took the envelope cwd. runs_search now skips an rg / grep word that a cd or pushd names. * fix(hook): a & inside a group does not end the outer list Codex round 18: 'cd x && (git status & git diff & wait); rg Foo' took the first & inside the subshell as the end of the cd's and-or list, so the cd looked like a background job and the search got Unchanged. A list now ends only at a ; or & no deeper than the segment it starts at; group_marks runs once per segment. * fix(hook): background jobs by nesting level, compound commands included Codex round 19: 'cd x && { rg a; rg b; } & wait' put the search in the cd's own background job but compared inner list ends, so the cd was dropped; and 'cd x && if c; then d; fi & rg' ended the cd's list at the if's ; because depth counted only braces and parens, so the background cd reached the foreground search. other_job now walks from the cd to the search, closing one list level at each ; and reporting another job at the first & that ends a list around the cd. Depth counts if / case / loops through compound_marks, and command_words computes the prefix scan once per segment. * fix(hook): rg --version is not a search; a case with a cd gives Unknown Codex round 20: 'rg --version && cd x && rg Foo' stopped at the version query, so the cd never counted and the term became the cd path. And a case pattern's ) (Linux) make ;;) reads as a subshell close, which cancelled the case's depth and let a backgrounded cd reach the foreground search. runs_search now rejects --version / -V / --help, and --files / --type-list for rg, reading separators glued to a word (grep -V;). A command with a case and a cd before the search gives Unknown. * fix(hook): a } before a redirect closes its group Codex round 21: 'cd x && { git status; }>/dev/null 2>&1 & rg Foo' left the group open, because group_marks closed a } only before whitespace. The depth stayed at 1, the background & no longer ended the cd's list, and the foreground search got Dir(x). A } before > < & | ; ) now closes. * fix(hook): shell_words drops redirections with their targets Codex round 22: 'cd x>/dev/null && rg Foo' kept '>/dev/null' in the cd argument, so the directory looked missing and the hook took the envelope cwd; and 'if c; then d; fi>/dev/null &' hid the fi, so the depth stayed at 1 and the backgrounded cd reached the foreground search. shell_words now ends a word at an unquoted < or >, drops the redirection with its target and a leading fd number or &, and leaves <( / >( alone. Every scan that reads words (cd arguments, compound closers, the search term) sees the command the way the program does. * fix(hook): the term and the cd target read the same search segment Codex round 24: in a multi-line script, extract_from_shell read the whole command as one word list, so 'rg --files' on a later line made runs_search skip the first rg and the term came from the second search, while cd_target_with_home resolved the directory of the first. The term now comes from the first segment that runs a search, the same segment the cd target reads. * fix(hook): a search in a function body gives Unknown Codex round 25: 'scan() { rg Foo; }; cd x && scan' stopped the walk at the rg in the definition, before the cd, and returned Unchanged though the search runs where scan is called. A search at or after a function header (name(), name (), function name) now gives Unknown; the header must be the command word, so rg 'fn main()' still resolves. * fix(hook): spaced $( substitutions and redirects before a ~ argument Codex round 26: 'root=$( cd /main && pwd -P ); rg Foo' skipped the assignment word that opens the substitution and applied its cd to the parent shell; and 'cd 2>/dev/null ~/x && rg Foo' read the redirection as the raw cd argument, so the ~ looked quoted and the cd looked failed. An assignment holding ( now puts the segment's command in a subshell, and unquoted_tilde_arg skips redirections before the argument. * fix(hook): a skipped || operand ends after its compound closes Codex round 27: 'cd A || if test -d B; then cd B; fi; rg Foo' stopped skipping at the if's ; because the skip depth counted only braces and parens, so the fallback cd B looked sure and the search got Dir(B). The skip depth now counts compound opens and closes too. * fix(hook): every name a tool lookup lists is no search Codex round 28: 'command -v rg grep git; cd x && rg Foo' skipped the first name but took grep, the second, as the search, because runs_search read only the word before it. It now also reads the segment's command word: which / type / hash / whereis / cd / pushd, or command with a v / V flag, makes no rg / grep in that segment a search. * fix(hook): a search in a loop condition sees the loop's later cd Codex round 29: 'cd x && until grep -q w Cargo.toml; do cd ..; done' searched in x, then its parents, but the loop check read only the groups open before the search segment, which itself opens the until. The check now counts a loop the search segment opens. * fix(hook): GIT_WORK_TREE / GIT_DIR git grep; glued -e patterns Codex round 30: 'GIT_WORK_TREE=/main git grep Foo' searched /main while the hook took the envelope cwd, since only the -C / --git-dir / --work-tree options were read; and 'rg --regexp=Foo f' / 'grep -eFoo f' skipped the pattern word and took the path as the term. A git grep with GIT_DIR= or GIT_WORK_TREE= set in or before its segment now gives Unknown, and a pattern glued to -e / --regexp= is the term. * fix(hook): a cd to a directory missing now gives Unknown Codex round 31 came back clean but named a blind spot: 'mkdir -p x && cd x && rg Foo' and 'git worktree add ../wt && cd ../wt && rg Foo' make the directory before the cd runs, while the hook saw it missing, treated the cd as failed and returned Unchanged. A missing target now gives Unknown: the search either never runs or runs in a directory the command made. * fix(hook): Windows build and a plain cd-target path CI on windows-latest failed to compile the hook tests: the symlink test calls std::os::unix::fs::symlink. It is now #[cfg(unix)]. The same run showed the cd target would print as \\?\C:\... on Windows, since std canonicalize returns a verbatim path. The target and the test helper now use dunce::canonicalize, as repo_selector and git_cache already do, and the integration test reads the header from the parsed JSON so escaped backslashes do not hide it. * test(hook): the escaped-space cd case is POSIX-only windows-latest failed test_cd_target_quoted_cjk_path_with_spaces_resolves on its unquoted case, 'cd C:\...\業主\ 原始碼\... && rg Foo': bash reads every unquoted backslash there as an escape, so Unknown is the right answer on Windows. The two quoted cases passed there; the backslash-escaped case now runs on unix only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #179.