Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
a1d04c2
plan: Define async Turso persistence migration scope
davidabram Oct 7, 2026
e67d85d
docs: resolve PR2 static async persistence architecture
davidabram Oct 7, 2026
a9f51c6
planning: Record async Turso persistence source inventory
davidabram Oct 7, 2026
5f118a5
docs: require static dispatch throughout PR2 propagation closure
davidabram Oct 7, 2026
7b51562
runtime: Await Turso persistence on the application runtime
davidabram Oct 7, 2026
2c6cfe5
tests: Remove disabled CLI tests and scaffolding
davidabram Oct 7, 2026
7ce2260
db: Make transaction setup synchronous and offload key lookup
davidabram Oct 7, 2026
a45b05b
runtime: Complete async Turso migration and isolate blocking lock waits
davidabram Oct 7, 2026
1935745
runtime: Move guarded-shell supervision to a blocking worker
davidabram Oct 7, 2026
298d2e4
runtime: Make Git snapshot and mutation scope resolution asynchronous
davidabram Oct 7, 2026
0346a83
runtime: Move mutation-scope state transactions off async workers
davidabram Oct 7, 2026
c60d23a
tests: Add golden coverage for patch reconstruction
davidabram Oct 7, 2026
47950a3
sync: Complete concurrent stream processing before reporting errors
davidabram Oct 7, 2026
72553ee
lifecycle: Restrict service trait visibility
davidabram Oct 7, 2026
c8bd23e
runtime: Keep worktree locks through cancellable ref mutations
davidabram Oct 8, 2026
b51bb21
runtime: Keep marker I/O within protected worktree ownership
davidabram Oct 8, 2026
282d065
runtime: Clean up temporary snapshot indexes asynchronously
davidabram Oct 8, 2026
b636feb
context: Clarify async persistence plan safety scope
davidabram Oct 8, 2026
31ccac1
db: Enforce exclusive transactional persistence
davidabram Oct 8, 2026
ff69adc
sync+auth: Protect credential rotation and stop sibling streams on te…
davidabram Oct 8, 2026
efdc007
runtime: Preserve mutation boundaries across cancellation and exec
davidabram Oct 8, 2026
a3a4627
context: Record T04 DB runtime blocking-scope audit
davidabram Oct 8, 2026
5355671
context: Record PR2 async persistence guarantees and cancellation pro…
davidabram Oct 8, 2026
fab5f64
runtime: Validate retry policies and identify database kinds
davidabram Oct 10, 2026
b7d2b69
context: Add async persistence cleanup plan
davidabram Oct 8, 2026
3be5b9a
plan: Record T01 dead-code baseline inventory
davidabram Oct 8, 2026
7fec253
runtime: Remove verified dead code and suppressions
davidabram Oct 8, 2026
989a04a
agent-trace: Add reconstruction fixtures and golden tests
davidabram Oct 8, 2026
0580f9e
runtime: Retain unwired reconciliation with scoped dead-code allowances
davidabram Oct 8, 2026
9bddf28
runtime: Remove redundant async wrappers and sync retry helper
davidabram Oct 8, 2026
3279139
async-runtime: Record PR3 blocking and future-size audit
davidabram Oct 8, 2026
a9cc418
context: Record PR3 cleanup audit and validation handoff
davidabram Oct 8, 2026
b374498
sync+tests: Preserve the diff-traces compatibility contract
davidabram Oct 8, 2026
93a93a6
runtime: Remove unused ensure import
davidabram Oct 10, 2026
3f9782e
context: Define observability log lock striping plan
davidabram Oct 8, 2026
19b3903
observability: Replace per-path lock registry with fixed lock striping
davidabram Oct 8, 2026
579f1e9
observability: Add regression coverage for striped log locking
davidabram Oct 8, 2026
94641c0
observability: Record striped log-lock contract
davidabram Oct 8, 2026
0736322
context: Define mutation-cursor reconciliation wiring plan
davidabram Oct 8, 2026
aad3183
context: Record reconciliation wiring audit findings
davidabram Oct 8, 2026
e3b5c98
runtime: Add ref maintenance entrypoints and state tracking
davidabram Oct 8, 2026
23e80fe
runtime: Harden ref maintenance persistence and DB opening
davidabram Oct 8, 2026
941623f
runtime+hooks: Trigger ref reconciliation advisories after completed …
davidabram Oct 8, 2026
a1f6c2d
hooks+runtime: Emit reconciliation advisory diagnostics
davidabram Oct 8, 2026
56606d5
doctor: Run snapshot ref reconciliation from --fix
davidabram Oct 8, 2026
5eea383
tests: Add mutation ref reconciliation regression coverage
davidabram Oct 9, 2026
0c20fa2
tests: Complete ref reconciliation production-path coverage
davidabram Oct 9, 2026
5cae78a
runtime: Remove stale ref-reconciliation exemptions
davidabram Oct 9, 2026
b62e878
tests: Verify doctor reconciliation recovery outcomes
davidabram Oct 9, 2026
d9cf0ff
runtime: Distinguish uncertain advisory-state writes
davidabram Oct 9, 2026
1635e39
tests+context: Verify missing maintenance DB opens without creation
davidabram Oct 9, 2026
bea4876
tests: Use platform state root in doctor reconciliation sandbox
davidabram Oct 9, 2026
e252112
tests: Consolidate ref reconciliation coverage
davidabram Oct 9, 2026
3d418e9
runtime: Bound database write retries by contention deadline
davidabram Oct 10, 2026
5dd1f6c
perf(nix): use test-profile Crane cache and avoid duplicate Quint MBT…
davidabram Oct 10, 2026
b617550
ci(quint): avoid rebuilding MBT in spec-only workflow
davidabram Oct 10, 2026
76f9abe
ci(nix): reuse macOS release build for CLI smoke test
davidabram Oct 10, 2026
9f31296
ci(nix): record phase timings in GitHub job summaries
davidabram Oct 10, 2026
fe2cee4
perf(nix): prepare test dependencies without redundant cargo build
davidabram Oct 10, 2026
3aefff2
perf(nix): omit Turso FFI crate types from test vendors
davidabram Oct 10, 2026
fce48dd
fix(nix): restore valid Turso vendoring and test dependency definition
davidabram Oct 10, 2026
24cbf45
perf(nix): disable test-profile debuginfo to shrink artifacts
davidabram Oct 10, 2026
460f87c
fix(build): avoid tracking generated OUT_DIR inputs
davidabram Oct 10, 2026
18af3ed
style(build): apply rustfmt to generated-input staging
davidabram Oct 10, 2026
5f39066
feat(setup): select multiple integration targets in interactive setup
davidabram Oct 11, 2026
7129f66
perf(nix): reuse musl dependency artifacts and skip redundant release…
davidabram Oct 11, 2026
3727b7a
sync: Add tests for first-terminal-error precedence across streams
davidabram Oct 11, 2026
f3c3525
agent_trace_sync: Bound ingestion batch requests with a timeout
davidabram Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions .github/workflows/pr-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,22 @@ jobs:

- name: Run flake checks
run: |
time nix flake check --fallback --print-build-logs
start="$SECONDS"
nix flake check --fallback --print-build-logs
elapsed="$((SECONDS - start))"
printf 'Nix flake check: %dm %02ds\n' "$((elapsed / 60))" "$((elapsed % 60))" | tee -a "$GITHUB_STEP_SUMMARY"

# On macOS release validation builds the same native CLI dependency
# closure, so run its smoke test there rather than building it twice.
- name: Build and smoke-test native CLI
if: matrix.os == 'ubuntu-latest'
run: |
time nix build .#sce --fallback --out-link result --print-build-logs
start="$SECONDS"
nix build .#sce --fallback --out-link result --print-build-logs
./result/bin/sce --help
./result/bin/sce version
elapsed="$((SECONDS - start))"
printf 'Native CLI build + smoke: %dm %02ds\n' "$((elapsed / 60))" "$((elapsed % 60))" | tee -a "$GITHUB_STEP_SUMMARY"

release-validation:
name: Release validation (${{ matrix.os }})
Expand Down Expand Up @@ -78,4 +87,19 @@ jobs:

- name: Build release package and audit portability
run: |
time nix build .#ci-checks --fallback --out-link result-ci-checks --print-build-logs
start="$SECONDS"
nix build .#ci-checks --fallback --out-link result-ci-checks --print-build-logs
elapsed="$((SECONDS - start))"
printf 'Release validation: %dm %02ds\n' "$((elapsed / 60))" "$((elapsed % 60))" | tee -a "$GITHUB_STEP_SUMMARY"

# On Darwin, .#sce-release is the native CLI with commit metadata.
# Smoke-test that exact binary, which is already built by .#ci-checks.
- name: Smoke-test macOS release CLI
if: matrix.os == 'macos-latest'
run: |
start="$SECONDS"
./result-ci-checks/sce-release/bin/sce --help
./result-ci-checks/sce-release/bin/sce version
elapsed="$((SECONDS - start))"
printf 'macOS release CLI smoke: %dm %02ds\n' "$((elapsed / 60))" "$((elapsed % 60))" | tee -a "$GITHUB_STEP_SUMMARY"

17 changes: 2 additions & 15 deletions .github/workflows/quint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ jobs:
needs: detect
if: needs.detect.outputs.quint == 'true'
runs-on: ubuntu-latest
# The Quint Connect Nix check compiles the CLI crate, so this needs more
# headroom than the pure-Quint steps alone required.
# The Rust/Quint Connect MBT suite already runs in the Nix CI cli-tests
# check on both Linux and macOS. Keep this workflow spec-only.
timeout-minutes: 30
steps:
- name: Harden the runner (Audit all outbound calls)
Expand All @@ -70,12 +70,6 @@ jobs:
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # v22

- name: Enable Magic Nix Cache
uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # v14
with:
use-flakehub: false
use-gha-cache: true

- name: Typecheck Quint spec
run: nix run .#quint -- typecheck spec/mutation_cursor.qnt

Expand All @@ -95,13 +89,6 @@ jobs:
--max-samples=5000
--max-steps=20

- name: Quint Connect model-based tests (Nix-pinned Rust + Quint)
# The entire MBT invocation goes through this Nix check rather than
# `cargo test` on the runner's own Cargo, so both the Rust toolchain
# and the Quint binary come from the repository's pinned flake
# inputs, never a second, unpinned Rust installation.
run: nix build .#checks.x86_64-linux.mutation-trace-quint-connect --print-build-logs

gate:
name: Quint gate
if: always()
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.direnv/
node_modules/
cli/target/
cli/target*/
cli/package-fallback/
integrations/**/target/
result*
Expand Down
2 changes: 1 addition & 1 deletion .sce/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"integrations": {
"optional_workflows": [],
"target": [
"claude",
"opencode",
"claude",
"pi",
"codex"
]
Expand Down
3 changes: 1 addition & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ Run from repo root through Nix (do not call bare `bun` on the host). Working dir

## Testing notes

- Rust tests live inline in source files and in module test files such as `cli/src/services/setup/tests.rs`.
- Rust tests live inline in source files and in module test files such as `cli/src/services/mutation_trace/mbt/tests.rs`.
- Repository Cargo builds must use `scripts/run-cli-cargo.sh`; it generates a fresh temporary Pkl payload, passes `SCE_CLI_GENERATED_INPUT_DIR` to Cargo, and cleans up the payload afterward.
- Rust/Cargo commands should be executed through `nix develop`, even for one-off builds, tests, fmt, and clippy runs.
- Prefer `nix flake check` for routine verification and avoid bare `cargo test` / `cargo check` / `cargo fmt --check` unless the user explicitly asks.
Expand Down Expand Up @@ -258,7 +258,6 @@ Run from repo root through Nix (do not call bare `bun` on the host). Working dir
- `context/overview.md`
- `cli/Cargo.toml`
- `cli/src/app.rs`
- `cli/src/services/setup/tests.rs`
- `config/lib/bash-policy-plugin/package.json`
- `config/lib/bash-policy-plugin/bash-policy-runtime.test.ts`
- `config/lib/bash-policy-plugin/opencode-bash-policy-plugin.ts`
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ reqwest = { version = "0.13", default-features = false, features = ["json", "for
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sha2 = "0.11"
tokio = { version = "1", default-features = false, features = ["rt", "io-util", "sync", "time", "macros", "rt-multi-thread"] }
tokio = { version = "1", default-features = false, features = ["rt", "io-util", "sync", "time", "macros", "rt-multi-thread", "process", "fs"] }
toml = "0.9"
tracing = "0.1"

Expand Down
27 changes: 20 additions & 7 deletions cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,11 @@ fn stage_generated_input(

let output_root = out_dir.join(PKL_OUTPUT_DIR);
remove_path_if_exists(&output_root)?;
copy_tree(&generated_input_root.join(PKL_OUTPUT_DIR), &output_root)?;
copy_tree(
&generated_input_root.join(PKL_OUTPUT_DIR),
&output_root,
true,
)?;

Ok(())
}
Expand Down Expand Up @@ -257,7 +261,7 @@ fn stage_packaged_fallback(manifest_dir: &Path, out_dir: &Path) -> io::Result<()
let source = fallback_root.join(directory);
let destination = out_dir.join(directory);
remove_path_if_exists(&destination)?;
copy_tree(&source, &destination)?;
copy_tree(&source, &destination, true)?;
}

Ok(())
Expand Down Expand Up @@ -342,14 +346,17 @@ fn stage_static_inputs(
copy_tree(
&manifest_dir.join("assets/hooks"),
&static_root.join("hooks"),
true,
)?;
copy_tree(
&manifest_dir.join(MIGRATIONS_ROOT),
&static_root.join(MIGRATIONS_ROOT),
true,
)?;
copy_file(
&repository_root.join("config/schema/agent-trace.schema.json"),
&static_root.join("schema/agent-trace.schema.json"),
true,
)
}

Expand All @@ -366,33 +373,39 @@ fn stage_codex_target(out_dir: &Path) -> io::Result<()> {
copy_tree(
&pkl_output_root.join(CODEX_AGENTS_SOURCE_DIR),
&destination_root.join(".agents"),
false,
)?;
copy_tree(
&pkl_output_root.join(CODEX_HOOKS_SOURCE_DIR),
&destination_root.join(".codex"),
false,
)
}

fn copy_tree(source_root: &Path, destination_root: &Path) -> io::Result<()> {
println!("cargo:rerun-if-changed={}", source_root.display());
fn copy_tree(source_root: &Path, destination_root: &Path, track_sources: bool) -> io::Result<()> {
if track_sources {
println!("cargo:rerun-if-changed={}", source_root.display());
}

let mut files = Vec::new();
collect_files(source_root, source_root, &mut files)?;
files.sort_unstable_by(|left, right| left.relative_path.cmp(&right.relative_path));

for file in files {
println!("cargo:rerun-if-changed={}", file.absolute_path.display());
copy_file(
&file.absolute_path,
&destination_root.join(&file.relative_path),
track_sources,
)?;
}

Ok(())
}

fn copy_file(source: &Path, destination: &Path) -> io::Result<()> {
println!("cargo:rerun-if-changed={}", source.display());
fn copy_file(source: &Path, destination: &Path, track_source: bool) -> io::Result<()> {
if track_source {
println!("cargo:rerun-if-changed={}", source.display());
}
let parent = destination
.parent()
.ok_or_else(|| invalid_data(&"staged file must have a parent directory"))?;
Expand Down
40 changes: 7 additions & 33 deletions cli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,16 @@ pub(crate) trait HasLogger {
fn logger(&self) -> &Self::Logger;
}

#[allow(dead_code)]
pub(crate) trait HasTelemetry {
type Telemetry: TelemetryTrait;

fn telemetry(&self) -> &Self::Telemetry;
}

#[allow(dead_code)]
pub(crate) trait HasFs {
type Fs: services::capabilities::FsOps;

fn fs(&self) -> &Self::Fs;
}

#[allow(dead_code)]
pub(crate) trait HasGit {
type Git: services::capabilities::GitOps;

Expand Down Expand Up @@ -113,23 +108,12 @@ where
HasLogger::logger(self)
}

#[allow(dead_code)]
pub(crate) fn fs(&self) -> &F {
HasFs::fs(self)
}

#[allow(dead_code)]
pub(crate) fn git(&self) -> &G {
HasGit::git(self)
}

fn telemetry(&self) -> &T {
HasTelemetry::telemetry(self)
}

/// Returns a context for a command-scoped repository root while preserving
/// the runtime logger, telemetry, and capability dependencies.
#[allow(dead_code)]
pub(crate) fn with_repo_root(&self, repo_root: impl Into<PathBuf>) -> Self {
Self {
logger: self.logger,
Expand All @@ -139,15 +123,6 @@ where
repo_root: Some(repo_root.into()),
}
}

/// Returns the resolved repository root path when available.
///
/// Lifecycle providers use this during setup to avoid re-resolving
/// the repository root independently.
#[allow(dead_code)]
pub fn repo_root(&self) -> Option<&Path> {
HasRepoRoot::repo_root(self)
}
}

impl<L, T, F, G> HasLogger for AppContext<'_, L, T, F, G>
Expand Down Expand Up @@ -186,10 +161,6 @@ where
G: services::capabilities::GitOps,
{
type Fs = F;

fn fs(&self) -> &Self::Fs {
self.fs
}
}

impl<L, T, F, G> HasGit for AppContext<'_, L, T, F, G>
Expand Down Expand Up @@ -415,6 +386,9 @@ where
Ok(command)
}

#[cfg(test)]
mod doctor_reconciliation_cli_tests;

#[cfg(test)]
mod tests {
use std::future::{poll_fn, Future};
Expand Down Expand Up @@ -590,12 +564,12 @@ mod tests {
let fs = services::capabilities::StdFsOps;
let git = services::capabilities::ProcessGitOps;
let context = AppContext::new(&logger, &telemetry, &fs, &git, None);
let result = run_command_lifecycle_with_context(
let result = Box::pin(run_command_lifecycle_with_context(
args.into_iter().map(String::from),
&services::command_registry::CommandRegistry::default(),
&context,
&mut Vec::new(),
)
))
.await;
if let Some(class) = expected_error {
let error = result.unwrap_err();
Expand Down Expand Up @@ -695,7 +669,7 @@ mod tests {
stdout.clear();
stderr.clear();
let missing_config = std::env::current_dir().unwrap().join("missing-config.json");
let code = run_with_dependency_check_and_streams(
let code = Box::pin(run_with_dependency_check_and_streams(
[
"sce",
"config",
Expand All @@ -707,7 +681,7 @@ mod tests {
|| Ok(()),
&mut stdout,
&mut stderr,
)
))
.await;
assert_eq!(code, ExitCode::from(4));
assert_eq!(stdout, b"");
Expand Down
Loading
Loading