Skip to content

Prepare v1.2.3 with native watcher, reclamation, and query fixes - #207

Merged
Shengyu Fu (shengyfu) merged 31 commits into
mainfrom
shengyfu-large-worktree-native-watching
Oct 18, 2026
Merged

Shengyu Fu (shengyfu) merged 31 commits into
mainfrom
shengyfu-large-worktree-native-watching

Conversation

@shengyfu

@shengyfu Shengyu Fu (shengyfu) commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Summary

Prepare v1.2.3 with the qualified native corrections missing from main:

  • Use minimal covering recursive subscriptions on Windows/macOS instead of pre-enumerating every directory under a 100-ms planning deadline. Preserve bounded non-recursive Linux/Android registration, metadata/ignore coverage, actual subscription accounting, explicit fallback, and drain.
  • Preserve bounded collection verification progress when an atomic idle-stop probe is refused by other activity.
  • Read sibling query candidates in batches of at most 64 while retaining root/generation pins, per-candidate deadlines, final ancestor verification, and failed-read invalidation.
  • Project compact per-file line/match counts without serializing unused content rows. Preserve totals, binary behavior, legacy replies, malformed-response rejection, and the response cap.
  • Before its holding:true handshake, tgrep shared owner-hold writes one {"ok":false,"error":...} stdout line carrying a typed claim failure, so supervising clients can act on catalog contention without parsing stderr. Exit status, stderr, the success handshake and SQLite limits are unchanged.
  • Retain strict managed-routing/readiness and bounded collection-continuation fixture corrections. Bump the workspace, first-party lock records, and release examples to 1.2.3.

The Windows publication/CRLF accounting and replacement/allocation-watermark corrections from #205 are already in main and are not duplicated. Original qualified commits and the current main remain in the history.

Preserved contracts

No downstream invocation or resource-policy change is required for native watching. The default watch/max-view policy, worker/resource limits, operation/query deadlines, 64-MiB response cap, ownership/authentication, containment, and reader/root-handle drain remain unchanged. Genuine native errors or exhausted OS resources still trigger fallback.

The owner-hold change adds no retry, timeout, writer serialization or collection change. The 250-ms catalog writer wait, the owner guard and its lifetime, exit status 2, the stderr diagnostic and the success handshake are unchanged. Clients that accept only holding:true still fail closed.

Healthy native views remain event-driven and also receive serving periodic full verification for SHARE-7. Once --poll-interval seconds (default 120) have elapsed since the last completed full pass, the scheduler queues a verify: true reconciliation under the existing operation, deadline and resource budgets. Queries continue using the published snapshot while an unchanged pass runs. A detected difference closes readiness and publishes a repair; deadline exhaustion or cancellation leaves the view ready but unverified and retries after the next interval. This recurring full-tree read is an intentional behavior and resource change in this PR, not part of the immutable benchmark. The downstream real-corpus witness remains a separate qualification gate. Explicit polling, watcher-failure fallback, explicit refresh, and --no-index retain their documented meanings.

Follow-up corrections

Current head is 300b1c6ce5995a4ae31ded6419b18be5c034032d. Its delta from the sealed-source integration commit 1877ee647ad72f3bd933025783c570dc59eed4ca is three test-only commits plus one production protocol change (300b1c6, described in the next section). The sealed 1877ee6 executable does not contain it:

  • d123abc01765a5b11a772830af4b9dce16dd76de: the old oversized-response test required -c to scan even though compact counts intentionally remain indexed. Preserve the raw full-content cap error and byte-for-byte CLI content fallback parity, then separately require compact indexed counts and exact filename/count parity. The original failed assertions on all three CI platforms are retained.
  • 586c6e5b2d9ca2a71c0e42c23db27250eaa12619: correct the macOS-only staging fixture. macOS deliberately discards verified prefixes after each authorized truncation. Re-verifying the original 3/2-MiB stages after every 64-KiB truncation exceeds the fixed 128-pass allowance; this caused the d123abc macOS failure, with zero stages removed instead of two.
  • 288c08770ea90129507045888c74235a7986ed51: add two Linux-only regressions that deterministically reproduce the local lease failures described below (no production change).
  • 300b1c6ce5995a4ae31ded6419b18be5c034032d: frame typed owner-hold failures before the handshake (production change, below).

The corrected macOS fixture uses 768/512-KiB temporary stages and two 2.5-MiB pinned generations. All assertions, concurrency, the 128-pass bound, the 200-ms/4-page/256-KiB per-pass bounds, and the 8-MiB staging/16-MiB storage allocation stay unchanged. The original Windows/Linux inputs are unchanged. It still proves initial pressure, retained progress across busy probes, complete reclamation, exact byte accounting, pinned-generation integrity, reopened admission, and restart persistence.

A conservative-prefix diagnostic reproduced the old macOS fixture's zero-versus-two failure and passed the corrected geometry. Restoring the original idle bug still failed both prefix-preservation assertions. Those diagnostics are not substituted for native macOS qualification.

Owner-hold pre-handshake failure frame

A downstream Windows integration run killed and replaced a managed daemon. An independent client's shared owner-hold then lost the catalog writer race: OwnerGuard::claim takes BEGIN IMMEDIATE with the fixed 250-ms busy wait and returned a typed busy/catalog-io/retryable/not-committed error. The CLI reduced that to exit 2 and tgrep: catalog-io: database is locked. A client that retries only structured retryable, not-committed failures, and does not text-match stderr, correctly treated it as unknown and stopped. Released v1.2.2 has the same path.

300b1c6 keeps the typed classification. When OwnerGuard::claim fails before the handshake, owner-hold writes exactly one newline-terminated compact JSON line to stdout, using the managed RPC failure envelope, then exits as before:

{"error":{"category":"busy","committed_state":"not-committed","detail":"database is locked","reason_code":"catalog-io","retryable":true},"ok":false}
  • The error object is the managed failure as returned (category, reason_code, retryable, committed_state, detail, plus operation_id/current_version when present). Retryability is never inferred. Claim acquisition writes nothing to the catalog.
  • Framed examples: busy/catalog-io, busy/owner-guard-already-held (another live holder), busy/namespace-admission-<state>, and non-retryable stale-identity failures such as owner-lifetime-ended.
  • No line is written for claim-file open/read/size/parse failures (including unknown fields), or for any failure after holding:true. Write errors on the frame are ignored; exit 2 and stderr remain.
  • A client may reuse the same claim only for retryable:true with committed_state:"not-committed", after confirming that helper exited, within its existing bounds. A missing or unparsable line, or any other classification, is a failed handshake.

Local CLI-boundary evidence on Windows (actual source of 300b1c6):

Check Result
New tests with only the product change reverted Both failed: exit 2 and stderr as expected, but stdout had 0 lines instead of the frame
Restored change: all six owner-hold CLI tests 6 passed
cargo fmt --all -- --check; Clippy for tgrep-cli with all targets, test hooks, -D warnings Passed

owner_holder_frames_catalog_contention_and_the_same_claim_then_holds holds an SQLite immediate transaction on the fixture's own catalog until the failed helper exits, asserts the single busy/catalog-io/retryable/not-committed frame with no holding line, then releases it. The same claim file then gets the normal handshake, registers, releases, and exits successfully on stdin EOF. owner_holder_frames_typed_refusals_without_inferring_retry_safety covers a live second holder (owner-guard-already-held, holder unaffected), a non-retryable owner-lifetime-ended frame after the guard ended, and malformed/unknown-field claims with empty stdout.

Actual-head validation

All GitHub checks on 300b1c6 pass after one Windows test-job re-run; the attempt-1 failure is retained and unexplained (see the table). The local Linux lease failures below are attributed to an external on-access reader on the local WSL host. This PR remains draft because of the release boundaries at the end.

Source and scope Result
300b1c6: full CI matrix, Linux/macOS/Windows tests Linux and macOS passed. Both new owner-hold tests passed on all three platforms. Windows attempt 1 failed managed::faults::control_unlink_crashes_preserve_sibling_proofs_and_credit_only_the_ended_owner: shared_daemon/managed.rs:728, "stopped daemon did not exit" (82 passed, 1 failed). That assertion's 10-s budget starts at the first stop-if-idle request, so the log cannot separate busy-retry time from exit time. The test claims owners in process and never runs shared owner-hold; the daemon shutdown path is unchanged from v1.2.2 and 288c087. The message does not appear in the previous 40 failed CI runs. Attempt 2 passed (83 passed). The attempt-1 failure is retained and not explained here.
300b1c6: Clippy, formatting, Windows release build and all three lifecycle measurement jobs Passed
300b1c6 actual source, local Windows: the six owner-hold CLI tests 6 passed; both new tests failed with only the product change reverted
288c087: full CI matrix, Linux/macOS/Windows tests Linux and macOS passed, including both new lease regressions on hosted Linux. Windows attempt 1 failed managed::bounded_ignore_inputs_preserve_scan_parity_and_leave_sibling_views_serviceable (shared_daemon/managed.rs:664, attach operation-deadline). The new tests are Linux-only, so Windows built the same code as 586c6e5. Attempt 2 passed. The attempt 1 failure is retained and not explained here.
288c087: Clippy, formatting, Windows release build and all three lifecycle measurement jobs Passed
586c6e5: full CI matrix, Linux/macOS/Windows tests Passed on all three platforms
586c6e5: native macOS core suite, including the corrected staging regression 478 passed, 1 existing ignored
586c6e5: all three native lifecycle measurement jobs Passed
586c6e5: Windows Rust 1.88 release build, Clippy, formatting, code analysis and CLA checks Passed
586c6e5 actual source: local Windows original two-thread core selection 97 passed
586c6e5 actual source: local Linux original two-thread core selection 98 passed, 2 failed, 1 existing ignored (external on-access reader on the local host; see below)
Historical 1877ee6: broader focused Windows qualification 257 passed, 1 existing ignored
Historical 1877ee6: broader focused Linux qualification 254 passed, 1 failed, 2 existing ignored
Historical 1877ee6: exact unsigned Windows executable without test hooks 7 native-watch/fallback, strict routing/count, migration/idle, and collection/replay tests passed

The immutable local executable remains attributed to 1877ee6, not the newer heads; it does not contain the 300b1c6 owner-hold frame. It reports CLI/FileVersion/ProductVersion 1.2.3 (fixed version 1.2.3.0), SHA256 51d30a8de3e9234766300d65c72b0339a11fc2f3bf03694ccea61a237f6014e4. Its strict native fixture used three worktrees with 1,281 directories each and subscription counts [1, 2, 2]. It is a local unsigned PR build, not an official release; no sealed artifact was rebuilt or overwritten.

Local Linux lease failures: external on-access reader

On 1877ee6, the original two-thread union failed managed::collection::tests::busy_idle_probe_preserves_cached_proof_for_external_work at collection.rs:463, the resumed collection's errors == 0 assertion. The error was member-verification-invalidated: "the exclusive file lease was broken or revoked", with zero verification/deletion credit and discarded cached proof. One 586c6e5 run failed the same assertion and also failed competing_control_cleanup_keeps_the_selected_object_pending_and_resumable with member-writer-or-mapping-active. Neither failure exceeded its elapsed budget.

These errors are the product's mappings of the two kernel outcomes when another process opens a freshly written file while the product holds, or tries to take, its Linux F_WRLCK verification lease. A read open downgrades the lease to F_RDLCK, and check_protection rejects it as broken. An open file description present at acquisition makes F_SETLEASE return EAGAIN, which is reported as busy. In both cases the product fails closed as designed. The broken-lease failure was directly correlated below; the EAGAIN failure matches the probe's refused acquisitions but was not separately correlated in the test selection.

Evidence (the test-selection runs kept the original two-thread concurrency, assertions and bounds):

  • Without tgrep. A standalone probe writes a file of about 128 KiB, closes it, reopens it read-only and takes a write lease. An unprivileged inode fanotify mark, which opens no file, recorded another process opening, reading and closing most files a median of about 6 ms after the write. With no delay, the lease was broken or refused in 190/200 trials on the owned ext4 directory, 200/200 on /tmp, 169/200 on /dev/shm tmpfs and 108/200 on a private user-namespace tmpfs. All but one anomaly coincided with that foreign read. Delaying the lease by 4, 8, 16, 32, 64 or 128 ms (100 trials each) or 1 s (60 trials) after the write produced no anomalies; the foreign read then completed before acquisition. The reader is outside the distro's PID namespace and adds newly created mounts to its watch set. This is consistent with the host's endpoint-protection real-time scanning for WSL; the attribution is circumstantial.
  • Direct correlation in the original selection. A disposable, never-committed diagnostic copy logged lease acquisitions, detected breaks, and other-process opens of each leased inode and generation. It ran six predetermined baseline/diagnostic pairs of the same binary, without retries or early stopping: 0/6 baseline and 1/6 diagnostic runs failed. In the failing run, the payload's lease was detected broken (F_RDLCK) 62 ms after acquisition. The only other-process events in that run were FAN_OPEN/FAN_CLOSE_NOWRITE on that exact inode and generation. The open event is delivered after the break because Linux emits fsnotify_open only after break_lease lets the blocked opener proceed, once the holder releases the broken lease. The failing test spawns no process, and no helper-spawning test is scheduled that early.
  • Hosted CI. Hosted Linux runners passed these tests on d123abc and 586c6e5. The three-platform 1877ee6 failures were the obsolete oversized-count CLI assertion.

No fixture-global collision or product descriptor-lifetime defect was found. Accepting a downgraded lease, retrying until success, serializing tests, raising budgets or changing host security policy would weaken the protection or the qualification, so none was done. The failing evidence is retained. Local two-thread Linux qualification on hosts with on-access scanning remains environment-limited; hosted Linux CI is the clean actual-head evidence.

Deterministic CI reproduction

288c087 reproduces both kernel outcomes in-process on Linux, with no scanner, delay or retry. Each test re-runs itself in a child test process (like the existing writer-break lease test) so that descriptors inherited by concurrently forked tests cannot interfere. A non-blocking read-only open stands in for the external reader:

  • foreign_reader_breaks_the_cached_lease_and_collection_fails_closed: after a retained 4096-byte cached prefix, the foreign open fails with EWOULDBLOCK (proof of the live exclusive lease) and downgrades the lease. The next pass reproduces the observed signature: errors == 1, member-verification-invalidated, category stale-identity, detail "the exclusive file lease was broken or revoked", zero verification and reclaimed bytes, cached proof discarded, and payload bytes intact. A fresh pass then removes the object with exact byte credit.
  • foreign_reader_at_lease_acquisition_keeps_collection_busy_and_retryable: an open reader at acquisition reproduces member-writer-or-mapping-active, category busy, retryable, with zero verification/reclamation. The object stays PendingDeletion and the payload remains on disk. After the reader closes, the next pass removes it with exact byte credit.

These are passing regressions that assert the observed fail-closed signatures and recovery; they do not make CI fail. On the local scanner host, 20/20 runs of both tests passed with CI's two test threads. An earlier draft used a 128-KiB payload for the broken-lease test, and its recovery pass failed in 11 of 15 isolated runs. In a separate 10-run diagnostic batch, 9 runs failed the same way; in each, the recovery pass's lease break was followed by an other-process FAN_OPEN on the exact inode and generation, during chunked truncation. In the passing run, the foreign open fell between leases. That is the same external reader, so the committed test uses an 8193-byte payload to shorten that window; no assertion was removed. The full local managed::collection and authentication_native set passed (20 tests).

Original selection:

cargo test --locked -p tgrep-core --features managed-test-hooks --lib -- \
  --test-threads=2 rooted::tests:: live::tests:: worktrees::tests:: \
  managed::work::tests:: managed::collection::tests:: \
  managed::maintenance::tests:: idle

Release boundaries

This PR remains draft. The local Linux lease failures are classified as external-environment interference, not a product defect. The Windows attempt-1 failures on 288c087 (attach operation-deadline) and 300b1c6 (daemon exit after stop-if-idle) remain unexplained. Downstream consumption of the owner-hold frame is not part of this PR. Serving periodic verification is implemented and covered by generated tests, but the parent-owned real-corpus witness is not qualified: the recorded run observed a completed verification receipt and later failed its strict readiness assertion with ready=false; the invalidation trigger was not established. This remains an open qualification boundary, not evidence that green CI closes the corpus gate. Real-corpus parity/performance and retained-cache outcomes remain parent-owned as well.

No release workflow was changed or dispatched. Only a normal PR branch was pushed, without tags; signing remains opt-in. This PR does not merge, create a tag, sign binaries, or publish v1.2.3. Maintainer review and the normal release/signing process remain necessary.

Shengyu Fu (shengyfu) and others added 25 commits October 14, 2026 15:44
Reverify closed managed members against their original bounded block proofs under native write/delete exclusion. Keep the original seal, identity and ownership checks, and charge generation verification to its existing work permit. Reject timestamp-restored rewrites and unverified reobservations; add native metadata-only and protection regressions.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: cff18193-91c7-4186-9e2d-7dfa8433e29d
Reuse the existing WorkPermit deadline and checks for admitted Windows verification. Bound only unreserved observations with current policy, and cover a policy timeout reduction after admission.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: cff18193-91c7-4186-9e2d-7dfa8433e29d
Release extraction headroom and consumed input tables instead of retaining cumulative per-posting estimates. Admit hash-table growth with old and replacement capacity both charged, preserve content and mask semantics, and cover CRLF checkpoint/refresh under the existing budget.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: cff18193-91c7-4186-9e2d-7dfa8433e29d
Use bounded recursive-root subscriptions on Windows and macOS while retaining per-directory accounting elsewhere. Preserve native coverage after kernel-initiated watch retirement, expose subscription counts, and cover default-budget multi-worktree events, metadata, fallback, and cleanup.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Update both first-party lockfiles and release instructions; preserve historical v1.2.1 deprecation and candidate evidence.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: cff18193-91c7-4186-9e2d-7dfa8433e29d
Cherry-picked-from: 2f9d21f
Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Size replacement growth after removing old entries from the unpublished clone. Track backing-capacity watermarks for retained maps, posting sets, and bookkeeping instead of releasing tombstone storage. Add deterministic red/green replacement and deletion regressions, rehash/pressure coverage, and changed-CRLF checkpoint parity.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: cff18193-91c7-4186-9e2d-7dfa8433e29d
Cherry-picked-from: 6627cef
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Resume collection only from an evidenced bounded continuation, preserving exact reclamation accounting and native sharing assertions. Discard epoch-proven CLI fallback scans and wait within the existing managed busy budget before comparing indexed results. Add deterministic deadline and real native Git-exclude controls, and clarify the lifecycle contracts. Production code and the sealed 4e2a2a8 candidate are unchanged.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Discard cached member authentication only after other shutdown blockers are clear. Preserve natural expiry, active verifier protection, and existing resource limits. Cover bounded stage reclamation, unchanged-cap readmission, restart persistence, and generated-store cleanup.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 23051c7b-9d3c-4f54-9d4e-72897ee5a82a
Amortize rooted ancestor opens across consecutive sibling candidates without reordering results. Reuse reconciliation readers while preserving snapshot validation, generation and root pins, final ancestor checks, query deadlines, and response limits. Keep singleton candidates on the direct rooted path.

Add local, legacy, and managed scan-parity coverage plus containment, failure-classification, and pin-lifetime regressions.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 417710f4-d898-45a9-ade1-dd8f33592373
Send the effective line-count mode to servers and omit unused matching-line payloads for both count modes. Preserve original match statistics, binary visibility, multiline line-count semantics, legacy ordinary-server rendering, and existing response limits.

Validate projected rows before scope filtering or output, and cover malformed replies, exact byte budgets, dense counts, and local/ordinary/shared route parity.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 417710f4-d898-45a9-ade1-dd8f33592373
Integrate current main without rewriting the exact native watcher, reclamation, rooted query batching, count projection and qualification commits. Upstream's Windows publication/CRLF corrections are already present. Bump the workspace and first-party lock versions and release examples; apply rustfmt-only layout to the supplied reclamation tests. No production reimplementation, release workflow or freshness policy change.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Preserve full-content response-cap rejection and compare fallback output byte-for-byte with a scan. Assert compact count replies stay on the shared daemon and preserve filename/count parity.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
macOS deliberately discards verified prefixes after each truncation. Use smaller temporary stages and adjust pinned generations only on macOS, preserving pressure/recovery assertions, the 128-pass bound, all per-pass/resource limits, and the original Windows/Linux fixture inputs. A conservative-prefix model reproduces the old failure and the corrected fixture still fails against the pre-fix idle behavior.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
An external on-access reader that opens a verified member breaks or refuses
the collection's exclusive F_WRLCK lease. Reproduce both variants in-process
on Linux, isolated in a child test process, and assert the observed
fail-closed signatures followed by recovery once the reader is gone.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
A typed OwnerGuard::claim failure in `tgrep shared owner-hold` was flattened
to exit 2 plus stderr text, so a supervising client could not distinguish
retryable not-committed catalog contention from an unknown failure.

Before `holding:true`, write exactly one newline-terminated
`{"ok":false,"error":...}` stdout line carrying the managed failure as
returned, then keep the existing exit status and stderr diagnostic.
Claim-file read/size/parse errors stay unclassified and unframed, and no
failure after the handshake is framed. The success handshake, guard
lifetime and SQLite writer/busy limits are unchanged.

Add CLI-boundary regressions: a held catalog writer yields a busy/catalog-io
retryable not-committed frame, and the same claim then holds and exits on
stdin EOF; a live holder yields owner-guard-already-held; an ended lifetime
yields a non-retryable stale-identity frame; malformed claims emit no frame.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Healthy native-watched managed views had no periodic full verification,
so a silently missed watcher notification could leave results stale
indefinitely. Once the existing --poll-interval has elapsed since a
view's last completed full pass, the scheduler now queues one ordinary
reconcile operation with verify: true, without invalidating the view.

The verification runs under the unchanged operation deadline and
CPU/input/handle budgets, reads and hashes every admitted file, and
compares membership and visibility with the published snapshot while
queries keep using it. If nothing differs it publishes nothing. The
first detected difference marks the view stale, closing readiness, and
the pass publishes a full repair. Deadline or cancellation leaves the
view ready but unverified until the next interval; other errors,
watcher uncertainty, explicit invalidation, concurrent events and stale
policy keep their fail-closed semantics.

Status adds last_verification and native verification policy fields,
and hello advertises serving-native-periodic-verification. Docs are
updated. Core tests cover unchanged availability, missed-change repair,
concurrent invalidation, read failures, cancellation and policy races.
CLI tests cover the interval boundary, mid-verification serving and
missed nested-directory repair with scan parity.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Cancellation, deadline and resource pressure keep a serving verification
ready only when it observed no difference. Add a managed regression for
both interleavings: a membership difference observed by discovery before
cancellation at a paused batch, and a content difference observed by the
full read before cancellation at publication. Both must leave the view
not ready with a full refresh required.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Managed v2 indexes can opt out of the binary-extension filename heuristic,
so text such as an ASCII RTF .doc is indexed and searched like ripgrep. NUL
classification, ignore, hidden, size and filename rules are unchanged.

- IndexingProfile gains an optional eligibility ("content-only"); the default
  is omitted, so default keys, storage names and hello.profile are unchanged.
- Worktree verification applies the extension rule only for the default.
- Daemons advertise content-eligibility-profile; v1 leases reject it.
- `--content-eligibility content` searches use only a matching managed view.
  The client and server refuse mismatches in either direction, and the client
  scans with the requested rule. Ordinary servers and local indexes are
  bypassed. index/serve reject the flag.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Invalidation schedules automatic reconciliation even with --no-watch, so
the explicit refresh may legitimately run a full pass after the hints are
consumed; assert the preserved content-only profile instead (hint-only
processing stays covered in tgrep-core). Housekeeping can remove a
released owner record before re-hold, which reports owner-retired; both
reason codes remain stale-identity, non-retryable and not-committed.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Capture the original failed operation and one best-effort view status within its existing wait budget. Report stop-request, observed acceptance, and post-accept exit timing without changing the shared shutdown deadline. Add deterministic diagnostic-output and loopback controls; no production changes or whole-test retries.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
ripgrep records each file's bytes_printed before writing its end message,
and the summary sums those per-file stats. tgrep added the end line to the
running file total after serializing it, so summary.bytes_printed exceeded
the sum of end records by every end line on scan, local-index, server and
managed v2 routes. Stop counting the end line and keep bytes_printed in the
JSON parity comparisons; only elapsed timing remains volatile.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Carry per-candidate work receipts from the server matching boundary, including candidates that emit no rows. Populate JSON summary searches/bytes_searched and each file's bytes without extra reads or scan-equivalent guesses. Validate receipts before output and charge them to existing shared response budgets. Keep elapsed conventions unchanged and document backend-work versus result counters.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
…ttach

The native watcher test assumed every initial views.attach succeeds on its
first operation. The managed contract documents a terminal failed result with
both commitment fields not-committed, category busy, reason
view-preparation-invalidated and retryable=true; the sealed 272c059 run hit it.

Factor the managed_faults exact-state recovery helper into managed_attach.rs
with an explicit per-call-site allowance. Catalog callers keep the unchanged
catalog-io allowance and messages. The watcher call site alone permits the
exact preparation-invalidation outcome: it inspects the old operation, replays
the old token unchanged, recovers the same root/profile/pending identity, uses
a fresh token only after the old terminal result is resolved, keeps the
original 30-second deadline shared across attempts and the existing 8-attempt
ceiling, and requires one lease bound to the first operation. Any other
outcome still fails with view diagnostics. No product code changes.

Scripted controls cover recovery, rewritten replays, extra leases, exhaustion,
deadline, rejected outcomes/identity/responses and the unchanged classifier.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Add a managed-test-hooks-only fault at the post-checkpoint preparation
boundary. Its bounded invalidation action advances and invalidates the real
view slot for each of three preparation attempts, producing the actual
retryable, not-committed view-preparation-invalidated operation receipt.
Production builds do not compile the action or its preparation handling.

Exercise the watcher recovery helper against a real managed daemon: verify the
failed receipt and three fault hits, then require token 2 to complete against
the same pending view and original lease, with native readiness, one lease,
indexed search, scan parity, and normal cleanup.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical stale-view and unverified-output defects, moderate search/verification handling issues, and scope/compatibility documentation discrepancies remain unresolved.

3 open issues
What changed in this PR

Prepares tgrep v1.2.3 with shared-index verification, query optimizations, lifecycle fixes, and protocol updates.

Changes:

  • Adds periodic native-view verification and content-eligibility profiles.
  • Batches sibling reads, compacts count replies, and updates JSON search statistics.
  • Preserves collection progress, frames owner-hold failures, and updates tests, documentation, and release versions.
File Description
tgrep-core/​tests/​managed_lifecycle.rs Tests batch pins and collection continuation.
tgrep-core/​src/​worktrees/​tests.rs Tests verification, batching, and eligibility profiles.
tgrep-core/​src/​worktrees.rs Implements serving verification and candidate batches.
tgrep-core/​src/​rooted/​tests.rs Tests batch bounds, lifetimes, and ancestor validation.
tgrep-core/​src/​rooted.rs Adds scoped sibling-read APIs.
tgrep-core/​src/​managed/​views.rs Integrates verification into managed reconciliation.
tgrep-core/​src/​managed/​maintenance.rs Preserves verification progress during busy idle probes.
tgrep-core/​src/​managed/​faults.rs Adds preparation-invalidation test hooks.
tgrep-core/​src/​managed/​collection.rs Adds reclamation and Linux lease regressions.
tgrep-core/​src/​generations/​mod.rs Adds content-eligibility profiles.
tgrep-cli/​tests/​shared_daemon/​managed_live.rs Tests periodic native verification.
tgrep-cli/​tests/​shared_daemon/​managed_faults.rs Reuses attach-retry helpers.
tgrep-cli/​tests/​shared_daemon/​managed_diagnostics.rs Adds bounded failure diagnostics.
tgrep-cli/​tests/​shared_daemon/​managed_clients.rs Tests owner-hold failure frames.
tgrep-cli/​tests/​shared_daemon.rs Expands batching, count, and response-limit coverage.
tgrep-cli/​tests/​ripgrep_parity.rs Tightens JSON byte-accounting comparisons.
tgrep-cli/​tests/​ripgrep_compat.rs Tests statistics and compact-count compatibility.
tgrep-cli/​src/​serve/​shared/​server.rs Batches reads and returns search-work statistics.
tgrep-cli/​src/​serve/​shared/​protocol.rs Supports eligibility-aware view discovery.
tgrep-cli/​src/​serve/​shared/​protocol_v2.rs Frames typed pre-handshake claim failures.
tgrep-cli/​src/​serve.rs Projects compact counts and search statistics.
tgrep-cli/​src/​search.rs Updates routing, batching, and response validation.
tgrep-cli/​src/​output.rs Corrects JSON byte accounting.
tgrep-cli/​src/​main.rs Adds eligibility options and verification help.
SHARED_WORKTREE_INDEXES.md Documents lifecycle and protocol changes.
SHARED_INDEX_BENCHMARKS.md Clarifies verification measurement boundaries.
README.md Documents search, verification, and watcher behavior.
fuzz/​Cargo.lock Updates the core release version.
CONTRIBUTING.md Updates release examples and watcher-test guidance.
Cargo.toml Bumps the workspace to 1.2.3.
Cargo.lock Updates first-party release versions.
AGENTS.md Updates operational contracts and examples.

Review effort: Max

Comment thread tgrep-cli/src/search.rs Resolved
Comment thread tgrep-core/src/worktrees.rs Resolved
Comment thread tgrep-cli/src/main.rs Resolved
Shengyu Fu (shengyfu) and others added 2 commits October 17, 2026 11:39
Co-authored-by: Copilot App <[email protected]>

Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Linux procfs can report ESRCH when a task exits after its stat file is opened. Treat that observation as task disappearance in the test-only assert_dead helper while preserving live-state deadlines and unrelated errors. Cover the real open/exit/read boundary and scripted live/error observations.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Shengyu Fu (shengyfu) and others added 4 commits October 17, 2026 15:29
open_generation takes the SQLite catalog writer lock with the fixed 250 ms
wait, so a concurrent writer can legally return retryable, uncommitted
busy/catalog-io (SHARED_WORKTREE_INDEXES.md). The legacy-reader test and the
guarded reader subprocess assumed first-attempt success with a bare unwrap.

Route both through the existing exact-class owner-claim retry helper, made
type-generic with its unchanged 10 s fixture bound and 20 ms spacing. Add a
real-boundary control that holds an owned BEGIN IMMEDIATE writer: it fails with
the old bare unwrap (same payload as CI run 39065427720), passes with the
helper, keeps an expired bound at one attempt, and stops on a non-Busy error.

No production changes. The historical lock holder in the CI sample remains
unknown.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Drive the real on-disk indexed CLI route with pipe backpressure so the
search is held inside the first sibling while the test replaces their
parent. The former batch loop printed the next sibling through the
replaced parent before failing ancestor verification; the streaming
route resolves it again and prints only the replacement.

Unix-only: Windows pins an open parent against replacement.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
Add a hooks-gated daemon integration test that pauses a real
collections.start operation at object-withdrawn, object-pending-deletion,
member-intent-saved, member-before-io and collection-before-complete,
services operations.cancel while the worker is parked, and then releases it.

The cancelled receipt must be terminal with no delete credit after the
cancel point, unchanged checkpoint members for pre-IO points, a discarded
verification context, namespace retained memory back at its pre-collection
baseline, and an idempotent replay. Fresh operations then resume from the
saved cursor and finish collection with scan parity.

Removing the cancellation recheck after MemberBeforeIo makes the test fail
with 1475 bytes credited after cancellation at member-intent-saved.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
A bounded collection pass may complete before an armed member/object
barrier: an escaped reader of the object skips it without error, or the
pass exhausts its elapsed budget and returns a resumable cursor. Windows CI
run 39092617708 hit this in the member-before-io iteration of
collection_crash_boundaries_preserve_live_views_and_resumable_progress
(hook armed with 0 hits, one completed pass, 0 errors, 0 verification
pages). The log cannot distinguish the two causes.

Fault tests now start continuation passes with fresh tokens only after a
classifier accepts the short pass (completed, uncancelled, errorless, no
omitted details, target detail limited to object-readers-active, or an
exceeded budget with a cursor). Pass completion is observed through the
in-memory maintenance counters so the poller never reads the catalog
while a pass may hold it at the credit barrier. Recovery assertions keep
their committed expectations, accepting an interrupted, uncommitted
continuation only at removal barriers after earlier passes deleted every
member. Adds a classifier unit test and a witness that drives both
legitimate paths deterministically. No production or budget changes.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: d2a0130e-af45-49cc-ac06-2c1da73d9d13
@shengyfu
Shengyu Fu (shengyfu) marked this pull request as ready for review October 18, 2026 05:33
Copilot AI max review requested due to automatic review settings October 18, 2026 05:33
@shengyfu
Shengyu Fu (shengyfu) merged commit 58629d2 into main Oct 18, 2026
16 checks passed
@shengyfu
Shengyu Fu (shengyfu) deleted the shengyfu-large-worktree-native-watching branch October 18, 2026 05:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-platform lifecycle changes retain unresolved readiness issues and open real-corpus qualification gates.

2 open issues
3 resolved since last review

Review effort: Max

Comment on lines +2266 to +2271
if matches!(
error.category,
crate::managed::ErrorCategory::Cancelled
| crate::managed::ErrorCategory::Deadline
| crate::managed::ErrorCategory::ResourcePressure
))

/// Operation budget exhaustion carries no evidence about checkout content.
fn is_budget_failure(error: &WorktreeError) -> bool {
matches!(error, WorktreeError::Index(crate::Error::Managed(error))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants