Skip to content

test(cli): cover daemon and local-read contracts - #4394

Open
ScriptedAlchemy wants to merge 9 commits into
masterfrom
docs/4344-user-guide-and-daemon-contract-tests
Open

ScriptedAlchemy wants to merge 9 commits into
masterfrom
docs/4344-user-guide-and-daemon-contract-tests

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Part of #4344; #4348 covers README.md and SECURITY.md.

Root cause

The user guide still described persistent service installation as the normal daemon prerequisite and retained wording that could be read as query-triggered freshness work, even after the shipped contract made the running daemon mandatory and service installation optional. The production behavior also lacked focused journey tests proving the typed no-daemon refusal/no-write boundary and that bundled pricing/native usage reads stay network-free.

Change

  • Align docs/USER-GUIDE.md with the merged docs(security): clarify daemon authority and outbound operations #4348 contract: a running daemon is required, daemon install-service is optional, daemon run is the foreground alternative, and MCP/read paths do not perform an implicit refresh. The existing Privacy and Network section remains the authority for GitHub, semantic/configured-remote effects and local-only bundled pricing/native usage reads.
  • Add production-path CLI tests with isolated home/profile/project inputs for:
    • typed code_index_scheduler_unavailable refusal before any init/index write;
    • status and query refusing with the daemon-unreachable exit code without starting a daemon or creating storage;
    • cost, gain, and current-counter completing with zero connections to a controlled loopback HTTP proxy.

Existing versus added coverage

Existing init_accepts_relative_current_directory and init_wait_holds_until_first_generation_is_ready already initialize through the shared fixture that executes tracedecay daemon run; no duplicate foreground-daemon test was added. Existing status/tool tests covered individual no-daemon states, while the new combined read test adds the explicit no-start/no-store assertion. The no-daemon init/no-write and controlled-listener network assertions are new.

Review follow-up

  • Configure the controlled loopback proxy for the daemon, fixture init, and every listed CLI read before those processes start. The observer now owns a scoped listener thread, stops only after the CLI children and daemon are reaped, drains queued connections, and joins before asserting zero connections. A real loopback regression covers connection counting and listener cleanup when the observed action panics.
  • Pin no-daemon children to the same private endpoint as the daemon fixture, use canonical child ownership for the new journeys, and use short private Unix homes so remote sandbox path length cannot invalidate the socket fixture.
  • Exercise status/search first on a cold, unenrolled project and then on the existing enrolled-and-stopped fixture. Cold init and read checks run with the global database enabled and assert absence of the canonical Git identity marker, profile accounting database, project-shard namespace, daemon authority, and repo-local store. Each read also verifies that the pinned endpoint remains unavailable.
  • Correct the remaining README comment that called service installation required, and split foreground daemon startup from the project commands that run in another terminal.

Falsifiability evidence for the original implementation

Before commit, the prior owner temporarily broke each guarded production behavior in one local build, ran the compiled Bazel test artifact, then reverted the breaks:

  • forcing init admission available changed the observed error to daemon_connect_down; the typed-refusal test failed;
  • returning early from status produced exit 0 instead of daemon-unreachable 69; the status/query test failed;
  • adding a ureq pricing request produced 1 accepted proxy connection; the local-only test failed.

After reverting, each exact test reported 1 passed; 0 failed. These direct artifact runs are retained only as falsifiability evidence for the original implementation, not as final Bazel test evidence. They were not rerun for the revised observer, cold-read assertions, or cleanup regression in the review follow-up.

Original-head validation

Normal configuration, with no timeout increase:

scripts/require-exact-test.sh /opt/homebrew/bin/bazel test \
  //crates/tracedecay-cli:core_cli_suite \
  --repo_env=CC=/usr/bin/clang \
  --disk_cache=$HOME/.cache/tracedecay-bazel-disk \
  --test_output=all \
  --test_arg=cli_non_interactive_test::init_without_a_running_daemon_refuses_before_any_index_write \
  --test_arg=--exact

Blocked before test execution: crate-universe cargo-bazel splice timed out (exit 48, elapsed 722.961s; no libtest count). After the final rebase, a repeat again reached no test and the Bazel server terminated with Socket closed (exit 37).

/opt/homebrew/bin/bazel build --config=clippy \
  //crates/tracedecay-cli:core_cli_suite \
  --repo_env=CC=/usr/bin/clang \
  --disk_cache=$HOME/.cache/tracedecay-bazel-disk

Blocked before compilation by the same cached crate-universe splice timeout (exit 48). No budget was raised and no direct-binary run is claimed as final validation.

Validation of the review follow-up

Follow-up commit: 2c2bd60ce79300f20b1735529986ff9b2ad3c568.

The revised three-file change passes the pinned Rust formatter, git diff --check, and commitlint. The final source and test changes received independent review. No local native build, direct-binary test run, timeout increase, or budget increase was performed for this follow-up. Bazel CI on the published follow-up head must establish compilation and native behavioral results; the original implementation's direct-artifact evidence above does not validate the revised tests.

CI and shutdown follow-up

The follow-up commits address failures exposed by the PR test runs:

  • Reuse the canonical memory admission repair so index builds size and charge their reservation atomically against measured capacity; preserve truthful blocked progress and ready generations.
  • Await production harness shutdown in 24 MCP source-edit/changelog tests before their fixture directories are removed.
  • Retain the canonical project request lease through an accepted curator run, durable settlement, observation, and task-lock release. Global shutdown and exact-project retirement now reach the run's interruption control. Native enqueue refusal returns typed unavailability.
  • Keep preparation, replay, and recovery journal writes owned after forced authenticated-socket client cancellation. The existing blocking-work ownership scope carries the project lease until each filesystem operation returns.
  • cf2b6fe4 moves persisted scope lookup and CAS admission onto the existing asynchronous SQL reader. It preserves the foreground priority, actor seal, and five-second budget. The real cold-root storage journey now executes CAS, readback, and stale-CAS requests on native tasks and checks that the scope-store reader-wait counter does not increase.

The shutdown repairs are in bf193ab2, 7fa37f88, and 99810d70. Regressions cover exact-root retirement isolation, real MCP settlement during harness shutdown, and a real authenticated socket whose client is aborted and joined while its reservation writer is paused.

Validation: pinned Rust formatting, whitespace checks, commitlint, and independent source/API/lifetime review passed. Native regression execution is pending Bazel CI on the published head. No assertion, deadline, admission budget, or CI gate was weakened. The confirmed ownership defects do not by themselves establish the cause of every earlier suite timeout.


Devin Review

@changeset-bot

changeset-bot Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: b24ed62

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@devin-ai-integration devin-ai-integration Bot 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.

🔍 Devin Review: 2 flags

Not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Observe the daemon and CLI proxy lifetimes under scoped child ownership,
drain and join the listener, and cover listener cleanup during unwinding.
Assert no storage creation for cold init and reads with accounting enabled,
then verify stopped-daemon reads against the same private endpoint.
Clarify optional service installation and foreground startup terminals.

Refs #4344

@ScriptedAlchemy ScriptedAlchemy left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Pushed the reviewed follow-up in 2c2bd60 (refs #4344; builds on merged #4348).

The original proxy was installed after daemon startup, so daemon-side pricing requests could escape the network assertion. The observer now configures the daemon, init, and each CLI child before startup; owns a scoped listener; reaps children before stop; drains pending accepts; and joins before checking the count. A real loopback regression covers counting and cleanup on panic.

Cold init and read checks now pin the fixture endpoint, use canonical child ownership and short Unix homes, enable normal global accounting, and verify absence of the canonical identity marker, profile database, project shards, daemon authority, and repository-local store. The stopped-enrolled read case remains covered, with an endpoint probe after each command. README and user-guide instructions now consistently describe optional service installation and foreground startup in another terminal.

Validation: pinned rustfmt, git diff --check, and commitlint passed; independent source review completed. No local native run was claimed for these revised tests. Bazel CI on this commit must establish compilation and behavior. The PR body now explicitly distinguishes the original implementation's direct-artifact evidence from this follow-up.

ScriptedAlchemy and others added 6 commits October 21, 2026 04:58
Use the canonical asynchronous SQL reader for persisted scope lookup and
CAS admission while preserving the foreground priority and read budget.
Exercise real native-task CAS, readback, and stale-revision conflict
requests and assert that scope-set reads do not park native workers.

This branch has not been deployed

No deployments
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.

1 participant