diff --git a/cli/src/services/config/resolver.rs b/cli/src/services/config/resolver.rs index 0d07e793..dc8db4e7 100644 --- a/cli/src/services/config/resolver.rs +++ b/cli/src/services/config/resolver.rs @@ -187,13 +187,6 @@ where resolve_global_config_path, )?; - if !runtime.validation_errors.is_empty() { - bail!( - "Agent Trace storage config resolution failed because a discovered config file is invalid: {}", - runtime.validation_errors.join(" | ") - ); - } - Ok(ResolvedAgentTraceStorageRuntimeConfig { repository_id: runtime.agent_trace_repository_id.value, repository_remote: runtime.agent_trace_repository_remote.value, @@ -564,7 +557,7 @@ where source: ValueSource::ConfigFile(value.source), }, None => ResolvedValue { - value: true, + value: false, source: ValueSource::Default, }, }; @@ -907,10 +900,10 @@ mod tests { } #[test] - fn agent_trace_auto_sync_defaults_to_true() { + fn agent_trace_auto_sync_defaults_to_false_when_missing() { let runtime = resolve_runtime_with_config(None).unwrap(); - assert!(runtime.agent_trace_auto_sync.value); + assert!(!runtime.agent_trace_auto_sync.value); assert_eq!(runtime.agent_trace_auto_sync.source, ValueSource::Default); } diff --git a/cli/src/services/setup/command.rs b/cli/src/services/setup/command.rs index 8fe6a616..668c2323 100644 --- a/cli/src/services/setup/command.rs +++ b/cli/src/services/setup/command.rs @@ -23,7 +23,6 @@ impl SetupCommand { // The repository root is resolved before any prompt so the interactive // optional-workflow prompt can pre-check the persisted selection. let repository_root = resolve_setup_repository(&setup_start_path)?; - setup::validate_existing_repo_local_config(&repository_root).map_err(CliError::runtime)?; let setup_dispatch = if self.request.context_only { None diff --git a/cli/src/services/setup/mod.rs b/cli/src/services/setup/mod.rs index 66d58f71..f21bd79a 100644 --- a/cli/src/services/setup/mod.rs +++ b/cli/src/services/setup/mod.rs @@ -56,10 +56,11 @@ pub(crate) fn is_missing_git_remote_error(error: &anyhow::Error) -> bool { } /// Canonical JSON payload for a newly bootstrapped repo-local `.sce/config.json`. -/// Contains only the `$schema` declaration pointing to the SCE config JSON Schema. +/// Declares the SCE config JSON Schema and explicitly opts new repositories into +/// Agent Trace post-commit synchronization. fn repo_local_config_bootstrap_payload() -> String { format!( - "{{\n \"$schema\": \"{}\"\n}}\n", + "{{\n \"$schema\": \"{}\",\n \"agent_trace\": {{\n \"auto_sync\": true\n }}\n}}\n", crate::services::agent_trace::sce_config_schema_url() ) } @@ -485,27 +486,11 @@ pub fn ensure_git_remote(repository_root: &Path, remote_name: &str) -> Result<() })) } -/// Validates an existing repo-local `.sce/config.json` before setup performs -/// any other repository or lifecycle work. An absent config remains eligible -/// for the normal bootstrap path. -pub fn validate_existing_repo_local_config(repository_root: &Path) -> Result<()> { - let config_file = RepoPaths::new(repository_root).sce_config_file(); - if !config_file.exists() { - return Ok(()); - } - - crate::services::config::validate_config_file(&config_file).with_context(|| { - format!( - "Setup preflight rejected invalid repo-local config file '{}'", - config_file.display() - ) - }) -} - /// Bootstraps the repo-local `.sce/config.json` file if it does not already exist. /// /// Creates the `.sce/` parent directory as needed, then writes the canonical -/// schema-only JSON payload. If the file already exists, it is left untouched. +/// schema and Agent Trace bootstrap JSON payload. If the file already exists, it +/// is left untouched. pub fn bootstrap_repo_local_config(repository_root: &Path) -> Result<()> { let repo_paths = RepoPaths::new(repository_root); let config_file = repo_paths.sce_config_file(); @@ -845,6 +830,15 @@ pub fn persist_integration_targets( let repo_paths = RepoPaths::new(repository_root); let config_file = repo_paths.sce_config_file(); + // Default-discovered invalid config is intentionally degradable during + // setup. Do not rewrite it while recording the installed target: the + // startup resolver already reported the invalid layer and setup must leave + // the user's file byte-for-byte unchanged. + if config_file.exists() && crate::services::config::validate_config_file(&config_file).is_err() + { + return Ok(()); + } + // Read existing config or start with bootstrap payload. let raw = if config_file.exists() { fs::read_to_string(&config_file) @@ -1956,7 +1950,7 @@ mod tests { assert_eq!( payload, format!( - "{{\n \"$schema\": \"https://sce.crocoder.dev/v{}/config.json\"\n}}\n", + "{{\n \"$schema\": \"https://sce.crocoder.dev/v{}/config.json\",\n \"agent_trace\": {{\n \"auto_sync\": true\n }}\n}}\n", env!("CARGO_PKG_VERSION") ) ); diff --git a/context/architecture.md b/context/architecture.md index 81d50b21..db5d2a10 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -115,12 +115,12 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/cli_schema.rs` is now the canonical owner for top-level command metadata for the real clap-backed command set (`auth`, `config`, `setup`, `doctor`, `hooks`, `policy`, `sync`, `version`, `completion`), including the slim top-level help purpose text and per-command visibility on `sce`, `sce help`, and `sce --help`; `cli/src/command_surface.rs` remains the custom top-level help renderer and known-command classifier, adding the synthetic `help` row plus the ASCII banner while consuming that shared metadata instead of maintaining a parallel command catalog. - `cli/src/services/default_paths.rs` is the canonical production path catalog for the CLI: it resolves config/state/cache roots with platform-aware XDG or `dirs` fallbacks through an internal `roots` seam, exposes named default paths for current persisted artifacts and database/log files (global config, auth tokens, auth DB, local DB, default observability log directory, and the sole Agent Trace DB path helper `agent_trace_db_path_for_repository` under `repos//agent-trace.db`; the former global-sentinel and per-checkout Agent Trace path helpers were removed by the `retire-legacy-agent-trace-db` plan), and owns canonical repo-relative, embedded-asset, install, hook, and context-path accessors so non-test production path definitions have one shared owner. Compile-time generated payload paths are owned by `build.rs` under `OUT_DIR`, not by the default-path catalog. Current production consumers such as config discovery, observability config resolution, doctor reporting, setup/install flows, database adapters, checkout identity, Agent Trace storage resolution, and local hook runtime path resolution consume this shared catalog rather than defining owned path literals in their own modules. - `cli/src/services/agent_trace.rs` is the Rust CLI owner for the SCE web base URL (`SCE_WEB_BASE_URL`) and exposes helpers for SCE-owned URL construction: Agent Trace conversation lookup URLs, persisted Agent Trace trace URLs, Agent Trace session URLs, and setup-created config schema URLs. Production Rust code should consume those helpers instead of repeating `sce.crocoder.dev` literals. The config resolver separately owns the `control_plane_base_url` runtime seam, whose baked `sce sync` default is `https://sce.crocoderlab.dev`; this control-plane host is not a web URL or schema owner. -- `cli/src/services/config/mod.rs` is the config service facade and `sce config` orchestration surface (`show`, `validate`, `--help`), with bare `sce config` routed by `cli/src/app.rs` to the same help payload as `sce config --help`. Focused submodules own the implementation slices: `types.rs` owns shared config/runtime primitives, `schema.rs` owns generated schema embedding plus typed file parsing, `policy.rs` owns bash-policy semantic validation plus policy-specific formatting and runtime preset-catalog access for the Rust evaluator, `resolver.rs` owns deterministic config-file discovery, file-layer merging, explicit value precedence (`flags > env > config file > defaults` where flag-backed), shared auth-key resolution, observability-runtime resolution, attribution-hooks runtime gate and `agent_trace.auto_sync` resolution, database-retry config resolution and `DATABASE_RETRY_CONFIG` `OnceLock` initialization, default-discovered invalid-file degradation, strict invalid-discovered-layer errors for Agent Trace storage, and explicit-path fatal errors for `--config` / `SCE_CONFIG_FILE`, and private `render.rs` owns `sce config show` / `sce config validate` text and JSON output construction plus rendering-specific display-value helpers. The facade preserves existing `services::config` imports for startup/auth/hooks callers while delegating command execution to resolution plus rendering submodules. +- `cli/src/services/config/mod.rs` is the config service facade and `sce config` orchestration surface (`show`, `validate`, `--help`), with bare `sce config` routed by `cli/src/app.rs` to the same help payload as `sce config --help`. Focused submodules own the implementation slices: `types.rs` owns shared config/runtime primitives, `schema.rs` owns generated schema embedding plus typed file parsing, `policy.rs` owns bash-policy semantic validation plus policy-specific formatting and runtime preset-catalog access for the Rust evaluator, `resolver.rs` owns deterministic config-file discovery, file-layer merging, explicit value precedence (`flags > env > config file > defaults` where flag-backed), shared auth-key resolution, observability-runtime resolution, attribution-hooks runtime gate and `agent_trace.auto_sync` resolution (omitted values fall back to `false`; setup bootstrap supplies an explicit `true`), database-retry config resolution and `DATABASE_RETRY_CONFIG` `OnceLock` initialization, default-discovered invalid-file degradation consumed by startup, setup, and Agent Trace storage, and explicit-path fatal errors for `--config` / `SCE_CONFIG_FILE`, and private `render.rs` owns `sce config show` / `sce config validate` text and JSON output construction plus rendering-specific display-value helpers. The facade preserves existing `services::config` imports for startup/auth/hooks callers while delegating command execution to resolution plus rendering submodules. - `cli/src/services/output_format.rs` defines the canonical shared CLI output-format contract (`OutputFormat`) for supporting commands, with deterministic `text|json` parsing and command-scoped actionable invalid-value guidance. - `cli/src/services/config/types.rs` is the canonical owner for the shared runtime/config primitive seam used by the CLI: `LogLevel`, `LogFormat`, `SCE_LOG_LEVEL`, `SCE_LOG_FORMAT`, `SCE_LOG_DIR`, `DEFAULT_LOG_FILE_RETENTION_LIMIT`, and the shared bool parsing helpers used by both config resolution and observability bootstrap; `cli/src/services/config/mod.rs` re-exports those primitives through the facade. - `cli/src/services/capabilities.rs` defines the current broad CLI capability traits consumed by the borrowed, compile-time-typed `AppContext`: `FsOps` with `StdFsOps` for filesystem operations and `GitOps` with `ProcessGitOps` for git command execution plus repository-root/hooks-directory resolution. Existing service internals do not consume these traits directly yet; command execution uses narrow accessors and repo-root-scoped context derivation. - `cli/src/services/lifecycle.rs` defines the current compile-safe lifecycle seam. `ServiceLifecycle` has default no-op generic `diagnose`, `fix`, and `setup` methods over `C: HasRepoRoot`, with lifecycle-owned health, fix, and setup result types so the trait contract is not publicly anchored to doctor/setup module types or the full `AppContext` shape. The same module owns the static `LifecycleProvider` enum and shared `lifecycle_providers(include_hooks)` catalog/factory, returning providers in deterministic order (config → local_db → auth_db → agent_trace_db → hooks when requested); enum dispatch calls each concrete provider through generic context methods without boxed lifecycle-provider allocation or repo-root trait-object context erasure. Hooks exposes a `HooksLifecycle` provider in `cli/src/services/hooks/lifecycle.rs` for hook rollout diagnosis/fix/setup using lifecycle-owned health records plus the canonical required-hook installer. Config exposes a `ConfigLifecycle` provider in `cli/src/services/config/lifecycle.rs` for global/repo-local config validation and repo-local `.sce/config.json` bootstrap. local_db exposes a `LocalDbLifecycle` provider in `cli/src/services/local_db/lifecycle.rs` for canonical local DB path health, parent-directory readiness/bootstrap, and `LocalDb::new()` setup. auth_db exposes an `AuthDbLifecycle` provider in `cli/src/services/auth_db/lifecycle.rs` for canonical auth DB path health, parent-directory readiness/bootstrap, and `AuthDb::new()` setup. agent_trace_db exposes an `AgentTraceDbLifecycle` provider in `cli/src/services/agent_trace_db/lifecycle.rs` for setup-time repository-scoped Agent Trace storage initialization when a repo root is available and repository Agent Trace DB path health/fix from resolved repository identity, returning an actionable "requires a Git repository" diagnostic outside repository context (no global/checkout fallback path; the former fallback was removed by the `retire-legacy-agent-trace-db` plan). Doctor runtime aggregates the full provider catalog for `diagnose` and `fix` and adapts lifecycle records into doctor report/fix records at the orchestration boundary; setup command aggregates the shared catalog for `setup` with hooks included only when requested and adapts hook setup outcomes before rendering setup-owned messages. -- Agent Trace lifecycle setup resolves `agent_trace.repository_id` / `agent_trace.repository_remote`, creates/reuses checkout identity for diagnostics, and creates or migrates the repository-scoped DB through `agent_trace_storage::resolve_agent_trace_storage(...)`; hook runtime uses the same storage identity/path resolution and no-migration open path, with missing or stale schema failing open through the existing `Run 'sce setup'.` guidance. +- Agent Trace lifecycle setup resolves `agent_trace.repository_id` / `agent_trace.repository_remote`, creates/reuses checkout identity for diagnostics, and creates or migrates the repository-scoped DB through `agent_trace_storage::resolve_agent_trace_storage(...)`; setup and hook runtime consume the shared degraded result for invalid default-discovered config, while explicit config failures remain fatal. Hook runtime uses the same storage identity/path resolution and no-migration open path, with missing or stale schema failing open through the existing `Run 'sce setup'.` guidance. - `cli/src/services/auth_command/mod.rs` defines the implemented auth command surface for `sce auth login|logout|whoami`, including device-flow login, stored-credential validation/renewal through login with device-flow fallback, logout, and Control Plane `/me`-backed whoami rendering in text/JSON formats; text mode uses flat `Email`, `First Name`, `Last Name`, `Role`, `Permissions`, and `Organization Name` labels, with optional names and missing role/permissions/workspace values handled deterministically. Logged-out text returns exact login guidance and renewal reports retain the `login` operation label. `cli/src/services/auth_command/command.rs` owns the `AuthCommand` payload used by the static `RuntimeCommand` enum. There is no public renewal or status subcommand. - `cli/src/services/db/mod.rs` provides the shared generic Turso infrastructure seam: `DbSpec` supplies a service-specific name, path, ordered embedded migrations, and config-file lookup key (`db_config_key()`), while `TursoDb` owns parent-directory creation, `Builder::new_local(...)` initialization (with `experimental_multiprocess_wal(true)` for safe concurrent access), Turso connection setup, tokio current-thread runtime bridging, retry-backed blocking `execute`/`query`/`query_values`/`query_map` wrappers, and generic migration execution with per-database `__sce_migrations` metadata. `TursoDb::new()` and `EncryptedTursoDb::new()` wrap only their local open/connect block in `run_with_retry_sync` using a config-driven connection-open policy resolved from the `DATABASE_RETRY_CONFIG` `OnceLock` with fallback to hardcoded defaults, while operation methods use a config-driven operation policy from the same source. `query_values()` returns fully fetched column names plus raw `turso::Value` rows for deterministic operator-facing rendering; `query_map()` retries the initial query and row-fetch loop, then applies caller row mapping after retry completion. Migration execution is not retried and uses batch execution so one migration file may contain multiple SQL statements while still recording one migration ID. The same module also provides `EncryptedTursoDb`, a structurally parallel encrypted adapter that resolves the encryption key through `encryption_key::get_or_create_encryption_key()`, enables Turso local encryption with strict `aegis256` cipher selection, and exposes retry-backed synchronous wrappers plus migration execution. `cli/src/services/db/encryption_key.rs` first derives a Turso-compatible 64-character hex key from non-empty `SCE_AUTH_DB_ENCRYPTION_KEY` env-secret text when present, otherwise falls back to keyring-backed credential-store get-or-create behavior; no plaintext auth DB fallback exists. - `cli/src/services/local_db/mod.rs` provides the concrete local DB spec and `LocalDb` type alias over the shared generic `TursoDb` adapter. `LocalDbSpec` resolves the deterministic persistent runtime DB target through the shared default-path seam and declares no local migrations; `TursoDb` supplies retry-backed blocking `execute`/`query`, parent-directory creation, Turso connection setup, tokio current-thread runtime bridging, and generic migration execution. @@ -132,7 +132,7 @@ The repository includes a new placeholder Rust binary crate at `cli/`. - `cli/src/services/doctor/mod.rs` owns the current doctor request/report surface while focused submodules (`doctor/inspect.rs`, `doctor/render.rs`, `doctor/fixes.rs`, `doctor/types.rs`) split report fact collection, rendering, manual fix reporting, and doctor-owned domain types into smaller seams; `cli/src/services/doctor/command.rs` owns the `DoctorCommand` payload used by the static `RuntimeCommand` enum and executes against any context implementing repo-root scoping. Runtime doctor execution resolves a repository root, derives a scoped context, requests the shared static lifecycle provider catalog with hooks included for service-owned `diagnose` and `fix` behavior, adapts lifecycle-owned health/fix records into doctor-owned problem/fix records, and then renders stable text/JSON problem records with category/severity/fixability/remediation fields plus deterministic fix-result reporting in fix mode. Agent Trace database inspection is no longer a doctor-adjacent command surface; doctor owns repository-scoped DB health and checkout identity facts, while `sce sync` owns control-plane synchronization. Report fact collection preserves environment/repository/hook/integration display data and adds a non-launching `post_commit_auto_sync` fact based on canonical post-commit managed-block currency plus resolved `agent_trace.auto_sync` source/value; this fact does not launch `sce sync`, and existing hook problem/remediation/readiness semantics remain authoritative. Service-owned lifecycle providers own config validation, local DB and repository-scoped Agent Trace DB readiness/bootstrap, and hook rollout diagnosis/repair. Integration inspection in `doctor/inspect.rs` is scoped twice over: `resolve_doctor_integration_targets` picks which targets to inspect, and `persisted_optional_workflows` (reused from setup) resolves which optional workflows the repository selected, which the OpenCode/Claude/Pi/Codex child collectors apply through `iter_embedded_assets_for_setup_target_with_selection`. An unselected optional workflow therefore contributes no expected children at all, so no row and no missing/mismatch problem can be produced for it, while a selected one keeps the unchanged presence and content-hash checks. Codex's collector (`collect_codex_integration_groups`) is the one exception to the single-target-directory shape the other three share: since `CODEX_EMBEDDED_ASSETS` relative paths already carry their own `.agents/`/`.codex/` prefix, it resolves its integration root through `InstallTargetPaths::codex_target_dir()` (the repository root itself) rather than a `RepoPaths` per-target subdirectory, and splits assets into `Skills` (`.agents/skills/` prefix) and `Hooks` (`.codex/` prefix) groups instead of Pi's `Extensions`/`Prompts`/`Skills` split. Its `.codex/hooks.json` reporting is per-registration rather than one whole-file child: `codex_hook_config::diagnose_document` classifies each of the four required registrations as `PresentAndCurrent`/`Missing`/`Stale` (or the whole document as `Malformed` when it cannot be structurally validated) without writing anything, so unrelated user handlers never create a false whole-document mismatch. For a structurally current registration, `codex_hook_trust` separately reads (never writes) Codex's own durable `$CODEX_HOME/config.toml` hook-trust state — reproducing upstream's `hook_hash`/`hook_key`/`hook_trust_status` exactly — and reports `Trusted`/`Untrusted`/`Modified`/`Disabled`/`Unknown`; only `Trusted` renders healthy. `sce doctor --fix` repairs a structurally unhealthy `.codex/hooks.json` through the existing merge-install path, but a registration that is current yet not-yet-trusted is never "fixed", since SCE cannot grant Codex hook trust. - `cli/src/services/version/mod.rs` defines the version command parser/rendering contract (`parse_version_request`, `render_version`) with deterministic text output and stable JSON runtime-identification fields; `cli/src/services/version/command.rs` owns the `VersionCommand` payload used by the static `RuntimeCommand` enum. - `cli/src/services/completion/mod.rs` defines completion parser/rendering contract (`parse_completion_request`, `render_completion`) with deterministic Bash/Zsh/Fish script output aligned to current parser-valid command/flag surfaces; `cli/src/services/completion/command.rs` owns the `CompletionCommand` payload used by the static `RuntimeCommand` enum. -- `cli/src/services/hooks/mod.rs` defines the current local hook runtime parsing/dispatch (`HookSubcommand`, `run_hooks_subcommand`), including the silent `claude-model-state` lifecycle intake delegated to `cli/src/services/hooks/claude_model_state.rs`, plus a commit-msg co-author policy seam (`apply_commit_msg_coauthor_policy`) that injects one canonical SCE trailer only when the enabled-by-default attribution-hooks config/env control is not opted out, `SCE_DISABLED` is false, and the staged-diff AI-overlap preflight confirms AI/editor evidence (`StagedDiffAiOverlapResult::Overlap`); the preflight is wired into `run_commit_msg_subcommand_in_repo` and logs `sce.hooks.commit_msg.ai_overlap_error` on error paths; `cli/src/services/hooks/command.rs` owns the `HooksCommand` payload used by the static `RuntimeCommand` enum. In the current attribution-only baseline, `pre-commit` and `post-rewrite` are deterministic no-op surfaces; `post-commit` requires validated `--remote-url`, threads that URL through the Agent Trace flow, prints it to stderr, and remains an active intersection + Agent Trace persistence entrypoint (captures current commit patch, queries recent repository-level `diff_traces` from the bounded past-7-days window, combines valid patches via `patch::combine_patches`, intersects with post-commit patch via `patch::intersect_patches`, persists result to `post_commit_patch_intersections`, then persists built Agent Trace payloads with range-level `content_hash` values to `agent_traces` in the repository-scoped Agent Trace DB without post-commit file artifacts); after successful validation and persistence, the default-enabled config-file-only `agent_trace.auto_sync` gate launches one detached sync-owned `sync --format json` child unless explicitly disabled in config, with launcher failures ignored and no high-frequency hook trigger; `diff-trace` performs STDIN JSON intake, validates required non-empty `sessionID`/`diff`/`tool_name`, optional `model_id` (absent/`null` → `None`), required nullable/non-empty `tool_version` plus required `u64` `time` (Unix epoch milliseconds), rejects values that cannot fit signed `time_ms` storage, prefixes the stored `diff_traces.session_id` before insert construction (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi, same-tool idempotent), and inserts the parsed payload fields into `RepositoryAgentTraceDb` without creating a parsed-payload `context/tmp` artifact; Claude structured `PostToolUse` diff-trace intake resolves model attribution with `direct > exact transcript > exact session/agent state > NULL`: direct top-level or nested metadata wins, otherwise the event's `transcript_path` is scanned for the assistant envelope whose `tool_use.id` matches `tool_use_id`, then persistence performs one exact local `claude_model_state` lookup using canonical session and ephemeral agent scope; model values normalize once through `claude/`, subagents do not inherit main-session state, and unresolved values remain nullable. `session-model` is no longer a supported hook route. +- `cli/src/services/hooks/mod.rs` defines the current local hook runtime parsing/dispatch (`HookSubcommand`, `run_hooks_subcommand`), including the silent `claude-model-state` lifecycle intake delegated to `cli/src/services/hooks/claude_model_state.rs`, plus a commit-msg co-author policy seam (`apply_commit_msg_coauthor_policy`) that injects one canonical SCE trailer only when the enabled-by-default attribution-hooks config/env control is not opted out, `SCE_DISABLED` is false, and the staged-diff AI-overlap preflight confirms AI/editor evidence (`StagedDiffAiOverlapResult::Overlap`); the preflight is wired into `run_commit_msg_subcommand_in_repo` and logs `sce.hooks.commit_msg.ai_overlap_error` on error paths; `cli/src/services/hooks/command.rs` owns the `HooksCommand` payload used by the static `RuntimeCommand` enum. In the current attribution-only baseline, `pre-commit` and `post-rewrite` are deterministic no-op surfaces; `post-commit` requires validated `--remote-url`, threads that URL through the Agent Trace flow, prints it to stderr, and remains an active intersection + Agent Trace persistence entrypoint (captures current commit patch, queries recent repository-level `diff_traces` from the bounded past-7-days window, combines valid patches via `patch::combine_patches`, intersects with post-commit patch via `patch::intersect_patches`, persists result to `post_commit_patch_intersections`, then persists built Agent Trace payloads with range-level `content_hash` values to `agent_traces` in the repository-scoped Agent Trace DB without post-commit file artifacts); after successful validation and persistence, the setup-enabled config-file-only `agent_trace.auto_sync` gate launches one detached sync-owned `sync --format json` child when its resolved value is true (a newly created setup config supplies the explicit `true`; omitted configuration resolves to `false`), with launcher failures ignored and no high-frequency hook trigger; `diff-trace` performs STDIN JSON intake, validates required non-empty `sessionID`/`diff`/`tool_name`, optional `model_id` (absent/`null` → `None`), required nullable/non-empty `tool_version` plus required `u64` `time` (Unix epoch milliseconds), rejects values that cannot fit signed `time_ms` storage, prefixes the stored `diff_traces.session_id` before insert construction (`oc_` for OpenCode, `cc_` for Claude, `pi_` for Pi, same-tool idempotent), and inserts the parsed payload fields into `RepositoryAgentTraceDb` without creating a parsed-payload `context/tmp` artifact; Claude structured `PostToolUse` diff-trace intake resolves model attribution with `direct > exact transcript > exact session/agent state > NULL`: direct top-level or nested metadata wins, otherwise the event's `transcript_path` is scanned for the assistant envelope whose `tool_use.id` matches `tool_use_id`, then persistence performs one exact local `claude_model_state` lookup using canonical session and ephemeral agent scope; model values normalize once through `claude/`, subagents do not inherit main-session state, and unresolved values remain nullable. `session-model` is no longer a supported hook route. - Generated Claude settings register `SessionStart` and `PostModelSwitch` only for the local model-state hook; `sce hooks session-model` is no longer a supported hook command. Claude Code 2.1.250 and 2.1.251 compatibility smoke passed with the unknown `PostModelSwitch` registration, so SCE installs it unconditionally without a raised minimum or capability gate. The `session_models` table/API and generic session-level fallback lookup were removed in T02 of the `remove-session-models-direct-claude-model-id` plan; the separate `sce hooks claude-model-state` command writes Claude lifecycle observations into the non-exported exact-scope register through the no-migration hook-runtime DB path, without restoring that generic abstraction. `diff-trace` uses direct-first/event-transcript-second Claude `model_id` resolution and consults the exact local lifecycle state only as its final fallback, with direct `tool_version` values. - `cli/src/services/resilience.rs` defines bounded retry/timeout/backoff execution policy (`RetryPolicy`, `run_with_retry`) for transient operation hardening with deterministic failure messaging and retry observability. - `context/cli/agent-trace-auto-sync.md` documents the sync-owned, one-shot post-commit launcher boundary: it reuses `sce sync`, has no daemon or local retry machinery, and fails open when child startup cannot be completed; doctor reports this capability without invoking the launcher. diff --git a/context/cli/agent-trace-auto-sync.md b/context/cli/agent-trace-auto-sync.md index be66f21b..d7651765 100644 --- a/context/cli/agent-trace-auto-sync.md +++ b/context/cli/agent-trace-auto-sync.md @@ -2,16 +2,18 @@ ## Purpose -Automatic synchronization is a default-enabled convenience layered on the existing +Automatic synchronization is a setup-enabled convenience layered on the existing `sce sync` command. It does not replace explicit synchronization or introduce a -second synchronization engine. +second synchronization engine. A newly created repo-local config opts in +explicitly; a config layer that omits the setting remains disabled at runtime. ## Configuration `agent_trace.auto_sync` is a config-file-only boolean resolved through the normal -global-then-local config merge. It defaults to `true`, and `sce config show` -reports the resolved value and its source. Set it explicitly to `false` to opt -out. There is no environment variable or CLI flag for this setting. +global-then-local config merge. The runtime fallback is `false`, while `sce setup` +writes an explicit `true` when it creates a missing repo-local `.sce/config.json`. +`sce config show` reports the resolved value and its source. Set it explicitly to +`false` to opt out. There is no environment variable or CLI flag for this setting. ## Trigger boundary diff --git a/context/cli/agent-trace-storage.md b/context/cli/agent-trace-storage.md index 1b55f589..d64f39c5 100644 --- a/context/cli/agent-trace-storage.md +++ b/context/cli/agent-trace-storage.md @@ -13,7 +13,7 @@ Module at `cli/src/services/agent_trace_storage/` (T04 of the `repository-scoped ## Resolution flow -1. Agent Trace storage runtime config is resolved through the config service; any invalid discovered config layer is an error at this boundary rather than a skipped layer with fallback values. For valid input, repository identity uses `repository_identity::resolve` precedence (explicit config ID → configured remote URL, default `origin`); resolution errors carry `.sce/config.json` guidance and never echo URLs. A failed config or identity resolution creates no state directories. +1. Agent Trace storage runtime config is resolved through the config service; invalid default-discovered config layers are skipped with the shared resolver's remaining values and validation diagnostics, while explicit `--config` / `SCE_CONFIG_FILE` failures remain fatal. Repository identity then uses `repository_identity::resolve` precedence (explicit config ID → configured remote URL, default `origin`); resolution errors carry `.sce/config.json` guidance and never echo URLs. A failed config or identity resolution creates no state directories. 2. Checkout identity reuse via `checkout::resolve_git_dir` + `get_or_create_checkout_id` (`/sce/checkout-id`). 3. DB path from `default_paths::agent_trace_db_path_for_repository{,_at}`, which rejects empty or path-unsafe repository IDs (separators, `.`, `..`). 4. DB open splits by caller through `agent_trace_db::repository::RepositoryAgentTraceDb`, sharing steps 1–3 through an internal `open_storage_with` helper parameterized by the DB-opener: @@ -28,4 +28,4 @@ The resolver never selects, creates, or touches pre-migration checkout-scoped `< Registered in `cli/src/services/mod.rs` and consumed by hook runtime, Agent Trace lifecycle setup, and `sce sync`. T05 changed the resolved DB handle to the repository-scoped adapter and validates the stored `repository_metadata.repository_id` before returning storage; T08 wired hooks/lifecycle to pass resolved config values into this context; the former trace UX was later removed by the `retire-legacy-agent-trace-db` plan. The `agent-trace-source-instance-id` plan's T03 split hook-runtime resolution into its own no-migration entrypoint, switching `open_agent_trace_db_for_hook_runtime` in `cli/src/services/hooks/mod.rs` off the setup/lifecycle resolver so hook runtime never runs migration `002` (or any migration). Covered by in-module tests: repository separation, SSH/HTTPS clone consolidation, linked-worktree consolidation, explicit-ID override, idempotent re-resolution, missing-identity guidance, path-segment validation, pre-migration checkout DB byte preservation/non-selection, empty fresh repository DB state, repository-level row sharing across equivalent clone checkouts, credential-safe remote canonicalization, concurrent first-open convergence, and hook-runtime resolution (fails before setup on a missing DB, fails before setup on a baseline-only pre-`002` schema without recording migration `002`, and matches setup's `RepositoryMetadata` once setup has run) (`nix build .#checks..cli-tests`). -See also: [repository-identity.md](repository-identity.md), [checkout-identity.md](checkout-identity.md), [default-path-catalog.md](default-path-catalog.md), [../sce/agent-trace-db.md](../sce/agent-trace-db.md), and [the fail-closed boundary decision](../decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md). +See also: [repository-identity.md](repository-identity.md), [checkout-identity.md](checkout-identity.md), [default-path-catalog.md](default-path-catalog.md), [../sce/agent-trace-db.md](../sce/agent-trace-db.md), [the degraded discovered-config boundary decision](../decisions/2026-09-04-setup-storage-degrade-invalid-discovered-config.md), and the superseded [fail-closed boundary decision](../decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md). diff --git a/context/cli/config-precedence-contract.md b/context/cli/config-precedence-contract.md index 4c209647..1109c5b6 100644 --- a/context/cli/config-precedence-contract.md +++ b/context/cli/config-precedence-contract.md @@ -4,7 +4,7 @@ This contract documents the implemented `sce config` command behavior, runtime resolver, renderer, and canonical Pkl-authored `sce/config.json` schema. The schema is emitted to payload-relative `config/schema/sce-config.schema.json` under Cargo `OUT_DIR` or packaging fallbacks and embedded by `cli/src/services/config/schema.rs` as `SCE_CONFIG_SCHEMA_JSON`; no generated schema is committed. -The current implementation resolves flat logging keys and Agent Trace runtime keys with deterministic precedence and source metadata, exposes resolved-value inspection through `sce config show`, and keeps `sce config validate` focused on validation status plus errors/warnings. File logging is explicitly controlled by the config-file/default `log_to_file` boolean, which defaults to `true`; `log_to_file` and `log_dir` resolve independently, with omitted `log_dir` falling back to the default location. Threshold, format, directory, and `log_file_retention_limit` values are consumed by runtime logging; the concrete logger uses the retention value for primary and v2 creation-triggered cleanup. The default-enabled `agent_trace.auto_sync` value is consumed by the post-commit trigger boundary and by doctor readiness reporting, and can be disabled explicitly. +The current implementation resolves flat logging keys and Agent Trace runtime keys with deterministic precedence and source metadata, exposes resolved-value inspection through `sce config show`, and keeps `sce config validate` focused on validation status plus errors/warnings. File logging is explicitly controlled by the config-file/default `log_to_file` boolean, which defaults to `true`; `log_to_file` and `log_dir` resolve independently, with omitted `log_dir` falling back to the default location. Threshold, format, directory, and `log_file_retention_limit` values are consumed by runtime logging; the concrete logger uses the retention value for primary and v2 creation-triggered cleanup. The config-file-only `agent_trace.auto_sync` value is consumed by the post-commit trigger boundary and by doctor readiness reporting: omitted values resolve to `false`, while `sce setup` writes an explicit `true` for a newly created repo-local config and explicit `false` remains the opt-out. ## Command surface @@ -29,7 +29,7 @@ Agent Trace repository identity keys are also config-file only with per-key `glo - `agent_trace.repository_id` — optional explicit repository identity; resolves as an optional value with no default. - `agent_trace.repository_remote` — Git remote name used to derive repository identity; defaults to `origin` (`DEFAULT_AGENT_TRACE_REPOSITORY_REMOTE` in `cli/src/services/config/resolver.rs`) when no config file sets it. -- `agent_trace.auto_sync` — boolean for the post-commit Agent Trace synchronization trigger; config-file only, with no flag or environment layer, and defaults to `true` (set `false` to opt out). +- `agent_trace.auto_sync` — boolean for the post-commit Agent Trace synchronization trigger; config-file only, with no flag or environment layer. Omitted values resolve to `false`; a newly created repo-local config from `sce setup` explicitly writes `true`, and `false` remains the opt-out. Resolved observability values that currently have no CLI flag layer follow the same lower-precedence chain without a flag step: @@ -69,7 +69,7 @@ Config file selection follows this deterministic order: When both discovered defaults exist, they are merged in memory in deterministic order `global -> local`, and local values override global values per key. -When a default-discovered global or repo-local config file exists but fails JSON parsing, top-level-object validation, or schema validation, runtime resolution now skips that file, collects the failure text in `validation_errors`, and continues with remaining discovered layers plus defaults. Explicit `--config ` and `SCE_CONFIG_FILE` selections remain fatal on those errors. This means normal command startup still reaches dispatch for commands such as `sce version`, `sce doctor`, and `sce hooks commit-msg` even when discovered config is invalid. Setup and Agent Trace storage are deliberate stricter consumers: setup validates an existing repo-local file after Git-root resolution and before prompts, context bootstrap, lifecycle work, or asset installation, while storage resolution errors on any invalid discovered layer instead of using fallback identity values. See [the fail-closed boundary decision](../decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md). +When a default-discovered global or repo-local config file exists but fails JSON parsing, top-level-object validation, or schema validation, runtime resolution now skips that file, collects the failure text in `validation_errors`, and continues with remaining discovered layers plus defaults. Explicit `--config ` and `SCE_CONFIG_FILE` selections remain fatal on those errors. This means normal command startup still reaches dispatch for commands such as `sce version`, `sce doctor`, and `sce hooks commit-msg` even when discovered config is invalid. Setup and Agent Trace storage consume the same degraded result: setup continues after Git-root and remote preflight, preserves an invalid local file, and skips local target/optional-workflow persistence for that run, while storage uses remaining identity values or the default remote. See [the degraded discovered-config boundary decision](../decisions/2026-09-04-setup-storage-degrade-invalid-discovered-config.md). ## Validation contract @@ -79,7 +79,7 @@ When a default-discovered global or repo-local config file exists but fails JSON - Each reported schema-validation error is prefixed with the failing value's JSON-pointer location when it has one (for example `/integrations/optional_workflows/0: "nonesuch" is not one of "brownfield"`), so a rejected value names the key it came from; root-level errors keep their unprefixed text. Errors remain sorted and joined with ` | `. - After schema validation, `cli/src/services/config/schema.rs` deserializes top-level and nested config structure (`policies`, `policies.bash`, `policies.attribution_hooks`) into typed serde DTOs and applies focused Rust-owned mapping helpers for enum conversion and source attribution; policy-specific semantic checks are owned by `cli/src/services/config/policy.rs`. - The canonical top-level schema declaration `"$schema": "https://sce.crocoder.dev/v/config.json"` (where `` is the CLI release version) is a supported config key for both explicit and discovered `sce/config.json` files, including command-startup paths like `sce version` and other config-loading commands that parse config before normal command dispatch. -- Startup/runtime config resolution now degrades gracefully only for default-discovered files: invalid discovered files are skipped and reported via collected `validation_errors`, while explicit `--config` / `SCE_CONFIG_FILE` targets still fail immediately on the same parse or validation errors. +- Startup/runtime config resolution degrades gracefully for default-discovered files across ordinary startup, setup, and Agent Trace storage: invalid discovered files are skipped and reported via collected `validation_errors`, while explicit `--config` / `SCE_CONFIG_FILE` targets still fail immediately on the same parse or validation errors. - Config file content must be valid JSON with a top-level object. - Allowed keys: `$schema`, `log_level`, `log_format`, `log_to_file`, `log_dir`, `log_file_retention_limit`, `workos_client_id`, `control_plane_base_url`, `agent_trace`, `policies`, `integrations`. @@ -95,7 +95,7 @@ When a default-discovered global or repo-local config file exists but fails JSON - `agent_trace` must be an object when present and currently allows `repository_id`, `repository_remote`, and `auto_sync`. - `agent_trace.repository_id` must be a non-empty string when present. - `agent_trace.repository_remote` must be a non-empty string when present; omitted values resolve to `origin`. -- `agent_trace.auto_sync` must be a boolean when present; omitted values resolve to `true`. +- `agent_trace.auto_sync` must be a boolean when present; omitted values resolve to `false`. A newly created repo-local config from `sce setup` contains an explicit `true` value. - `integrations` must be an object when present and currently allows `target` and `optional_workflows`; either key alone yields a parsed `IntegrationsConfig` with the other defaulting to empty. - `integrations.target` must be an array of unique canonical target IDs when present. diff --git a/context/context-map.md b/context/context-map.md index 253f11ac..c0973dd0 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -12,15 +12,15 @@ Feature/domain context: - `context/cli/cli-command-surface.md` (CLI command surface including top-level help with ASCII art banner and gradient rendering, setup install flow with the repeatable `sce setup --workflow ` optional-workflow selection and its interactive post-target multi-select, WorkOS device authorization flow + token storage behavior including stored-credential renewal through `sce auth login`, attribution-only hook routing with validated post-commit `--remote-url` plumbing plus DB-backed `diff-trace` dual persistence and post-commit Agent Trace payload persistence including range `content_hash`, setup-owned local DB + repository-scoped Agent Trace DB bootstrap plus doctor DB health coverage with credential-safe repository identity diagnostics, centralized Rust SCE web URL helpers in `services::agent_trace`, nested flake release package/app installability, Cargo local install + crates.io readiness policy, hidden `sce policy bash` command adapter for bash-policy hook callers, and top-level `sce sync` command wiring for current-repository Agent Trace synchronization; static `RuntimeCommand` enum dispatch lives in `services/command_registry.rs`, command payload structs for help/version/completion/auth/config/setup/doctor/hooks/policy/sync are owned by their respective `services/{name}/command.rs` files, and clap-to-runtime conversion lives in `services/parse/command_runtime.rs`) - `context/cli/default-path-catalog.md` (canonical production CLI path-ownership contract centered on `cli/src/services/default_paths.rs`, including persisted auth/config files, named DB paths for auth/local/repository-scoped Agent Trace databases, the default observability log-dir accessor consumed by config resolution with Linux `${XDG_STATE_HOME:-~/.local/state}/sce/logs` fallback semantics, repo-relative, embedded-asset, install, hook, and context-path families plus the regression guard that keeps production path ownership centralized) - `context/cli/repository-identity.md` (repository identity module in `cli/src/services/repository_identity/`: pure scheme-neutral `host[:port]/path` canonicalization for SCP/`ssh://`/HTTPS/`git://` remote URLs with credential stripping, hostname lowercasing, default-port removal, and query/fragment/trailing-`.git` cleanup, trim-only explicit-identity handling, `sha256("sce-repository-id-v1\0" + canonical_identity)` repository IDs, credential-safe fieldless errors, plus the `resolve` runtime submodule applying explicit-config-then-configured-remote precedence with `git config --get remote..url` lookup, `RepositoryIdentitySource` provenance, and `.sce/config.json`-guidance resolution errors that never echo URLs; consumed by the T04 `agent_trace_storage` resolver) -- `context/cli/agent-trace-storage.md` (repository-scoped Agent Trace storage resolver in `cli/src/services/agent_trace_storage/`: `AgentTraceStorageContext` inputs mirroring the `agent_trace.*` config keys, strict rejection of invalid discovered config before identity fallback, `ResolvedAgentTraceStorage` carrying repository identity + checkout ID + `/sce/repos//agent-trace.db` path + open `RepositoryAgentTraceDb` + typed `RepositoryMetadata`, `resolve_agent_trace_storage{,_at_state_root}` setup/lifecycle entrypoints with idempotent concurrent-safe first open via bounded fast-path-then-migrate retry plus narrow one-file schema migration-metadata repair and repository metadata validation, a separate no-migration `resolve_agent_trace_storage_for_hook_runtime{,_at_state_root}` pair that high-frequency hook callers use exclusively and that never runs migration `002` or any migration, path-unsafe repository ID rejection in `default_paths::agent_trace_db_path_for_repository{,_at}`, strict never-touch boundary for any pre-migration checkout-scoped/global DB files, and active hook/runtime plus Agent Trace lifecycle setup call-site consumption after T08) +- `context/cli/agent-trace-storage.md` (repository-scoped Agent Trace storage resolver in `cli/src/services/agent_trace_storage/`: `AgentTraceStorageContext` inputs mirroring the `agent_trace.*` config keys, shared degradation of invalid default-discovered config before identity fallback while explicit selections remain fatal, `ResolvedAgentTraceStorage` carrying repository identity + checkout ID + `/sce/repos//agent-trace.db` path + open `RepositoryAgentTraceDb` + typed `RepositoryMetadata`, `resolve_agent_trace_storage{,_at_state_root}` setup/lifecycle entrypoints with idempotent concurrent-safe first open via bounded fast-path-then-migrate retry plus narrow one-file schema migration-metadata repair and repository metadata validation, a separate no-migration `resolve_agent_trace_storage_for_hook_runtime{,_at_state_root}` pair that high-frequency hook callers use exclusively and that never runs migration `002` or any migration, path-unsafe repository ID rejection in `default_paths::agent_trace_db_path_for_repository{,_at}`, strict never-touch boundary for any pre-migration checkout-scoped/global DB files, and active hook/runtime plus Agent Trace lifecycle setup call-site consumption after T08) - `context/cli/checkout-identity.md` (current checkout identity infrastructure in `cli/src/services/checkout/`, including `/sce/checkout-id` UUIDv7 storage, setup/hook integration that creates/reuses checkout identity as repository-scoped Agent Trace diagnostic metadata, the removed per-checkout DB opener/path helper, `sce doctor` checkout identity display, and the never-touch on-disk handling of pre-migration checkout-scoped DB files that are no longer inspectable via the CLI) - `context/cli/patch-service.md` (standalone patch domain model, parser, JSON load helpers, and set operations in `cli/src/services/patch.rs` for in-memory parsed unified-diff representation, capturing only touched lines plus minimal per-file/per-hunk metadata, supporting both `Index:` SVN-style and `diff --git` git-style formats, with `ParseError` for actionable malformed-input diagnostics, `PatchLoadError`/`load_patch_from_json`/`load_patch_from_json_bytes` for storage-agnostic JSON reconstruction, `intersect_patches` for target-shaped overlap with exact-match-first and historical `kind`+`content` fallback semantics plus matched-constructed-line `session_id` and matched-constructed-hunk `model_id` provenance inheritance, and `combine_patches` for ordered patch combination with later-wins conflict resolution plus winning-hunk `model_id` provenance inheritance; repository structured-row reconstruction supplies persisted hunk-model and canonical touched-line-session provenance before these operations; `parse_patch`, `intersect_patches`, and `combine_patches` are consumed by the active post-commit hook runtime) - `context/cli/structured-patch-service.md` (Claude structured editor-hook derivation in `cli/src/services/structured_patch.rs`, including `Write` structured-update hunks, `Write` `tool_input.content` create fallback, `Edit` structured patches, deterministic skip reasons, `ParsedPatch` output semantics, Rust golden fixture coverage, and repository read-time enrichment that assigns persisted row `model_id` to each hunk and canonical row `session_id` to each touched line) - `context/cli/styling-service.md` (CLI text-mode output styling with `owo-colors`, TTY/`NO_COLOR` policy, shared helper API for human-facing surfaces including sync completion markers, and per-column right-to-left RGB gradient banner rendering) -- `context/cli/agent-trace-auto-sync.md` (default-enabled post-commit Agent Trace synchronization with explicit-false opt-out plus doctor readiness reporting: the existing `sce sync` command launched once through the current executable after local persistence, detached null-standard-stream behavior, fail-open startup, canonical managed-block proof of hook readiness, stable text/JSON enabled/disabled/not-ready/not-applicable states, no daemon/queue/high-frequency trigger, and retryability through manual sync and control-plane cursor authority) +- `context/cli/agent-trace-auto-sync.md` (setup-enabled post-commit Agent Trace synchronization with explicit-false opt-out plus doctor readiness reporting: a newly created repo-local config supplies the explicit `true` opt-in while omitted runtime values resolve to `false`; the existing `sce sync` command is launched once through the current executable after local persistence, with detached null-standard-stream behavior, fail-open startup, canonical managed-block proof of hook readiness, stable text/JSON enabled/disabled/not-ready/not-applicable states, no daemon/queue/high-frequency trigger, and retryability through manual sync and control-plane cursor authority) - `context/cli/sync-command.md` (the top-level `sce sync` command: repository-scoped Agent Trace storage resolution, WorkOS-authenticated four-stream control-plane synchronization through the sync-owned consumer-typed `services::sync::progress` reporter contract with sync-owned events, its generic/no-op contract and `indicatif` presentation adapter for aligned stderr progress with independent stream completion, explicit successful finalization, JSON stdout silence, and rejection of the removed `sce trace` command group) - `context/cli/agent-trace-sync-command.md` (composed local-to-control-plane `sce sync` architecture: the `hooks/plugins → repository Agent Trace DB → AgentTraceExportReader → sce sync → HTTPS + WorkOS Bearer → control plane` data flow, the `sce auth login` / `cd ` / `sce sync` user flow, the no-local-cursor/no-`agent-trace-sync.db`/no-Turso-Sync/no-`BridgeLock`/no-local-DWH invariants, and `401`/`409`/ambiguous-batch-failure recovery semantics) -- `context/cli/config-precedence-contract.md` (implemented `sce config` show/validate command contract, deterministic `flags > env > config file > defaults` resolution order, focused `config/resolver.rs` ownership for config discovery/merge/runtime precedence plus default-discovered invalid-file degradation, focused `config/render.rs` ownership for `show`/`validate` text+JSON output construction, canonical `$schema` acceptance for startup-loaded `sce/config.json` files, shared auth-key env/config/optional baked-default support starting with `workos_client_id`, shared runtime resolution for flat logging observability keys including config-file/default `log_to_file`, `log_dir` / `SCE_LOG_DIR` with `/sce/logs` defaulting plus config-file/default-only positive `log_file_retention_limit`, config-file-only `agent_trace.repository_id`/`agent_trace.repository_remote` repository-identity keys with default remote `origin`, default-enabled `agent_trace.auto_sync` boolean resolution with explicit-false opt-out for the post-commit trigger boundary, the catalog-derived `integrations.optional_workflows` optional-workflow selection key, JSON-pointer-prefixed schema-validation errors, canonical Pkl-generated `sce/config.json` schema ownership plus CLI embedding/reuse contract including `policies.attribution_hooks.enabled` default-true/explicit-false opt-out metadata, config-file selection order, `show` provenance output, and trimmed `validate` output contract) +- `context/cli/config-precedence-contract.md` (implemented `sce config` show/validate command contract, deterministic `flags > env > config file > defaults` resolution order, focused `config/resolver.rs` ownership for config discovery/merge/runtime precedence plus default-discovered invalid-file degradation, focused `config/render.rs` ownership for `show`/`validate` text+JSON output construction, canonical `$schema` acceptance for startup-loaded `sce/config.json` files, shared auth-key env/config/optional baked-default support starting with `workos_client_id`, shared runtime resolution for flat logging observability keys including config-file/default `log_to_file`, `log_dir` / `SCE_LOG_DIR` with `/sce/logs` defaulting plus config-file/default-only positive `log_file_retention_limit`, config-file-only `agent_trace.repository_id`/`agent_trace.repository_remote` repository-identity keys with default remote `origin`, `agent_trace.auto_sync` resolution with omitted-value fallback `false`, explicit-false opt-out, and setup-written explicit `true` bootstrap behavior for the post-commit trigger boundary, the catalog-derived `integrations.optional_workflows` optional-workflow selection key, JSON-pointer-prefixed schema-validation errors, canonical Pkl-generated `sce/config.json` schema ownership plus CLI embedding/reuse contract including `policies.attribution_hooks.enabled` default-true/explicit-false opt-out metadata, config-file selection order, `show` provenance output, and trimmed `validate` output contract) - `context/cli/capability-traits.md` (current broad CLI capability seam in `cli/src/services/capabilities.rs`, including `FsOps`/`StdFsOps`, `GitOps`/`ProcessGitOps`, git root/hooks resolution behavior, compile-time-typed borrowed AppContext wiring with associated-type narrow capability accessors plus `ContextWithRepoRoot` repo-root-scoped context derivation, generic command execution bounds, and test-only unimplemented stubs; current service internals do not consume fs/git traits until later lifecycle migration tasks) - `context/cli/service-lifecycle.md` (current compile-safe lifecycle seam in `cli/src/services/lifecycle.rs`, including default no-op `ServiceLifecycle` diagnose/fix/setup methods against narrow `HasRepoRoot`, lifecycle-owned health/fix/setup result types with generic setup messages, doctor/setup adapter boundaries, the static `LifecycleProvider` enum catalog/dispatcher, hook/config/local_db/auth_db/agent_trace_db lifecycle providers including setup-time repository-scoped Agent Trace DB initialization plus checkout identity diagnostics, implemented doctor aggregation over diagnose/fix providers, and implemented setup aggregation over `setup` providers in order config → local_db → auth_db → agent_trace_db → hooks when requested) - `context/sce/cli-exit-code-contract.md` (stable class-based `sce` process exit-code contract in `cli/src/app.rs`, so automation can branch on failure category without parsing error text) @@ -56,7 +56,7 @@ Feature/domain context: - `context/sce/setup-githooks-hook-asset-packaging.md` (compile-time `sce setup --hooks` required-hook template packaging contract, including all-hook non-blocking missing-`sce` install guidance, available-CLI argument forwarding, post-commit-only origin remote lookup plus remote-URL forwarding/fallback behavior, setup-service accessor surface, and current validation posture) - `context/sce/setup-githooks-install-flow.md` (setup-service required-hook install orchestration with git-truth hooks-path resolution, managed-block merge content computation that preserves foreign hook content, per-hook installed/updated/skipped outcomes decided against the merged content, the unreachable-block advisory, and atomic-swap replacement with recovery guidance) - `context/sce/setup-githooks-cli-ux.md` (T04 composable `sce setup` target+`--hooks` / `--repo` command-surface contract, option compatibility validation, and deterministic setup/hook output semantics) -- `context/sce/setup-repo-local-config-bootstrap.md` (setup local bootstrap behavior: Git-root-gated validation of existing repo-local config before prompts, context, lifecycle, hooks, or assets, additive durable-context baseline via `sce setup --bootstrap-context` and every normal setup path, repo-local `.sce/config.json` create-if-missing via config lifecycle, additive `integrations.target` persistence after successful target installs, `integrations.optional_workflows` selection persistence with prompt-over-flag-over-persisted precedence, plus lifecycle-owned local DB initialization before hooks/config asset dispatch) +- `context/sce/setup-repo-local-config-bootstrap.md` (setup local bootstrap behavior: Git-root and named-remote preflights before prompts/context/lifecycle/hooks/assets, shared degraded handling for invalid default-discovered repo-local config with byte-preserving skip of integration persistence, explicit-config fatality, additive durable-context baseline via `sce setup --bootstrap-context` and every normal setup path, repo-local `.sce/config.json` create-if-missing via config lifecycle, additive `integrations.target` persistence after successful target installs, `integrations.optional_workflows` selection persistence with prompt-over-flag-over-persisted precedence, plus lifecycle-owned local DB initialization before hooks/config asset dispatch) - `context/sce/cli-security-hardening-contract.md` (T06 CLI redaction contract, setup `--repo` canonicalization/validation, and setup write-permission probe behavior) - `context/sce/agent-trace-post-rewrite-local-remap-ingestion.md` (current post-rewrite no-op baseline plus historical remap-ingestion reference) - `context/sce/agent-trace-rewrite-trace-transformation.md` (current post-rewrite no-op baseline plus historical rewrite-transformation reference) @@ -98,6 +98,7 @@ Supporting repo docs: Recent decision records: +- `context/decisions/2026-09-07-split-auto-sync-defaults.md` (newly bootstrapped repo-local config explicitly opts into Agent Trace auto-sync while omitted runtime values remain disabled) - `context/decisions/2026-09-01-remove-top-level-config-timeout.md` (removes the unused top-level config timeout key, environment override, and config-command flags without introducing a replacement global timeout; nested retry and unrelated runtime timeout paths remain active) - `context/decisions/2026-08-23-codex-canonical-worktree-path-resolution.md` (accepts upstream-compatible Codex apply_patch parent/absolute paths only when canonical resolution remains inside the Git worktree, validates nearest existing prefixes for missing targets, and rejects symlink escapes) - `context/decisions/2026-08-23-codex-nondestructive-hook-ownership.md` (uses one shared structural ownership predicate and merge service for setup/doctor: Codex SCE handlers require the generated helper path plus the `sce hooks codex` contract, while unrelated hook configuration survives) @@ -107,6 +108,7 @@ Recent decision records: - `context/decisions/2026-09-01-claude-model-attribution-state.md` (accepts a Claude-specific local latest-model-state register as a bounded exception to the prior no-session-level-cache attribution constraint, with best-effort local observation-time ordering and no export/sync scope) - `context/decisions/2026-09-01-claude-post-model-switch-compatibility.md` (accepts unconditional installation of the Claude `PostModelSwitch` registration after Claude Code 2.1.250/2.1.251 compatibility smoke showed unknown-event tolerance and settings preservation) - `context/decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md` (keeps general startup degradation for invalid discovered config while making setup and Agent Trace storage fail closed before side effects or fallback identity selection) +- `context/decisions/2026-09-04-setup-storage-degrade-invalid-discovered-config.md` (supersedes the prior fail-closed boundary: setup and Agent Trace storage now consume shared degradation for invalid default-discovered config while explicit selections remain fatal) - `context/decisions/2026-08-14-compact-task-record-supersedes-handoff.md` (the completed task record — `Completed`/`Files changed`/`Result`/`Verify`/`Context impact`/`Context synchronization`, identified only by plan path and task ID — is the sole durable input for immediate and cross-session task synchronization, with no separate persisted `Context synchronization handoff` structure; supersedes only the handoff-shape portion of `2026-08-12-persist-workflow-sync-lifecycle-in-plans.md`, whose `pending`/`synced`/`blocked` lifecycle-state invariant remains in force) - `context/decisions/2026-08-12-decision-gate-semantics.md` (nonqualifying/skipped decision gates are non-blocking; ADRs are immutable, active-only reuse is allowed, changed decisions create new dated records, and `Deprecated`/`Superseded` are creation-time-only statuses) - `context/decisions/2026-08-12-observational-final-validation.md` diff --git a/context/decisions/2026-09-04-setup-storage-degrade-invalid-discovered-config.md b/context/decisions/2026-09-04-setup-storage-degrade-invalid-discovered-config.md new file mode 100644 index 00000000..d226ad34 --- /dev/null +++ b/context/decisions/2026-09-04-setup-storage-degrade-invalid-discovered-config.md @@ -0,0 +1,93 @@ +# Decision: Degrade Invalid Default-Discovered Config at Setup and Storage Boundaries + +Date: 2026-09-04 +Status: Accepted +Plan: `context/plans/setup-degraded-invalid-config-agent-trace.md` +Task: `T01` +Supersedes: `context/decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md` + +## Context + +Ordinary startup already skips invalid default-discovered global or repo-local +configuration layers, preserves the existing `sce.config.invalid_config` +warning, and continues with remaining layers or defaults. Setup and Agent Trace +storage had retained a stricter boundary: setup rejected an invalid local file +before its normal flow, while storage rejected any invalid discovered layer +before repository identity resolution. This divergence prevented setup and +repository-scoped hook tracing from using the same degraded configuration +behavior. Focused resolver, setup, and hook-runtime tests establish that the +invalid local file can remain untouched while valid remaining configuration or +the default remote continues to provide the required values. + +## Decision + +` sce setup` and Agent Trace hook storage shall skip invalid default-discovered +configuration layers and continue with the shared resolver's remaining-layer or +default values; explicit `--config` and `SCE_CONFIG_FILE` selections remain +fatal. + +## Rationale + +Using the shared resolver result keeps startup, setup, and hook-runtime +configuration behavior aligned without weakening explicit operator intent. +Setup can complete its Git/remote preflight, lifecycle, and asset flow without +repairing a user's invalid file, and repository-scoped tracing can continue to +the same identity and database path selected by valid remaining configuration +or the default `origin` remote. + +## Alternatives considered + +- **Keep setup and storage fail-closed** — preserves the previous safety boundary + but needlessly blocks normal setup and hook tracing when a lower-priority + discovered layer is invalid. +- **Make explicit configuration degradable too** — would discard an explicit + operator selection and weaken the fatal configuration contract. +- **Repair invalid local configuration during setup** — would mutate user-owned + bytes as a side effect and could destroy information needed for manual repair. + +## Compatibility and risks + +- Ordinary and setup consumers may proceed using a remaining layer or default + after a discovered configuration failure; the existing warning and validation + error reporting remain in place. +- Invalid local configuration is intentionally not rewritten, so target and + optional-workflow persistence may be omitted for that run. +- Genuine Agent Trace database, identity, Git, and remote failures retain their + existing diagnostics and fail-open behavior. + +## Guardrails + +- Only default-discovered global and repo-local layers are degradable. +- Explicit `--config` and `SCE_CONFIG_FILE` parse or validation failures remain + fatal. +- The generated schema, precedence rules, repository identity canonicalization, + database schema, and no-migration hook opening contract do not change. +- Setup never repairs, deletes, or rewrites an invalid discovered config file. + +## Consequences + +- `sce setup` can reach its normal Git/remote preflight, bootstrap, lifecycle, + and requested asset-install flow despite invalid discovered configuration. +- Agent Trace hook-runtime DB opening uses the same degraded repository identity + inputs as the shared runtime resolver and can persist representative hook data. +- Operators still receive the established invalid-config warning and must repair + the file separately when they want its settings or setup persistence restored. + +## Follow-up + +- `/validate` must verify the plan's setup, resolver, Agent Trace storage, hook, + and explicit-config acceptance criteria and repository-wide checks. + +## References + +- Plan: [`setup-degraded-invalid-config-agent-trace`](../plans/setup-degraded-invalid-config-agent-trace.md) +- Task: `T01` +- Current-state context: [`CLI config precedence contract`](../cli/config-precedence-contract.md) +- Current-state context: [`SCE setup local bootstrap`](../sce/setup-repo-local-config-bootstrap.md) +- Current-state context: [`Repository-scoped Agent Trace storage resolver`](../cli/agent-trace-storage.md) +- Current-state context: [`Agent Trace hooks command routing`](../sce/agent-trace-hooks-command-routing.md) +- Evidence: [`config resolver`](../../cli/src/services/config/resolver.rs) +- Evidence: [`setup command`](../../cli/src/services/setup/command.rs) +- Evidence: [`setup service`](../../cli/src/services/setup/mod.rs) +- Evidence: [`hooks service`](../../cli/src/services/hooks/mod.rs) +- Related decision: [`Fail Closed at Setup and Agent Trace Storage Boundaries for Invalid Discovered Config`](2026-08-26-setup-storage-fail-closed-on-invalid-config.md) diff --git a/context/decisions/2026-09-07-split-auto-sync-defaults.md b/context/decisions/2026-09-07-split-auto-sync-defaults.md new file mode 100644 index 00000000..a92e4dd5 --- /dev/null +++ b/context/decisions/2026-09-07-split-auto-sync-defaults.md @@ -0,0 +1,71 @@ +# Decision: Split setup and runtime auto-sync defaults + +Date: 2026-09-07 +Status: Accepted +Plan: `context/plans/update-auto-sync-default-behavior.md` +Task: `T01` + +## Context + +The repo-local config created by `sce setup` and the runtime resolver previously +shared an implicit `agent_trace.auto_sync` default. The desired rollout needs +newly bootstrapped repositories to opt into post-commit synchronization while +repositories and config layers that omit the key remain conservative. The +existing boolean schema, explicit values, and global-before-local merge are +already established and must remain compatible. + +## Decision + +`sce setup` writes an explicit `agent_trace.auto_sync: true` in a newly created +repo-local `.sce/config.json`, while the runtime resolver resolves an omitted +`agent_trace.auto_sync` value to `false` with default provenance. + +## Rationale + +The generated setup file provides an intentional, visible opt-in for new +repositories without changing the behavior of existing repositories that have +no such setting. Explicit configuration remains the sole higher-precedence +input, so global/local precedence and opt-out behavior remain stable. + +## Alternatives considered + +- **Keep one implicit `true` default everywhere** — Existing repositories would + continue opting into automatic synchronization without an explicit config + declaration. +- **Use `false` for setup bootstrap and runtime fallback** — New repositories + would not receive the requested setup opt-in. + +## Compatibility and risks + +- Existing config files are left untouched and explicit `true`/`false` values + retain their current meaning; only omitted runtime values change to `false`. +- The setup payload now contains an additional schema-supported field, and its + explicit value is covered by setup bootstrap tests. + +## Guardrails + +- Do not change the schema shape, config precedence, post-commit launcher, or + synchronization protocol. +- Only a newly created repo-local setup config receives the explicit `true`; + existing files are never rewritten by bootstrap. + +## Consequences + +- New repositories created through setup are explicitly opted into automatic + post-commit synchronization. +- Omitted values in global/local config layers resolve to a disabled runtime + gate, making the setup-generated declaration the visible opt-in boundary. + +## Follow-up + +- Update current durable setup and Agent Trace configuration context to state + the split defaults. + +## References + +- Plan: [`update-auto-sync-default-behavior`](../plans/update-auto-sync-default-behavior.md) +- Task: `T01` +- Current-state context: [`CLI config precedence contract`](../cli/config-precedence-contract.md) +- Current-state context: [`Automatic Agent Trace synchronization`](../cli/agent-trace-auto-sync.md) +- Evidence: [`setup bootstrap implementation`](../../cli/src/services/setup/mod.rs) +- Evidence: [`runtime resolver implementation`](../../cli/src/services/config/resolver.rs) diff --git a/context/glossary.md b/context/glossary.md index e0827df9..ec35f20a 100644 --- a/context/glossary.md +++ b/context/glossary.md @@ -3,7 +3,7 @@ - `repo-level verification preference`: Current repository guidance that contributor-facing validation/check flows should prefer `nix flake check`; direct Cargo verification commands are secondary and used only when explicitly requested or for narrow targeted debugging, while `cargo fmt` remains the explicit autofix path. - lightweight post-task verification baseline: Required quick checks after each completed task in this repo: `nix run .#pkl-check-generated` and `nix flake check`. - disposable plan lifecycle: Policy where `context/plans/` holds active execution artifacts only; completed plans are disposable and durable outcomes must be reflected in current-state context files and/or `context/decisions/`. -- important change (context sync): A completed task change that affects cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology; these changes require root context edits in `context/overview.md`, `context/architecture.md`, and/or `context/glossary.md` instead of verify-only handling. `setup config preflight` is the Git-root-gated check that validates an existing repo-local `.sce/config.json` before prompts, context bootstrap, lifecycle initialization, hooks, or target asset installation; invalid config fails setup closed, absent config remains eligible for create-if-missing bootstrap, Agent Trace storage has the parallel strict rule for invalid discovered config layers, and ordinary startup consumers retain degraded-default behavior. See [the fail-closed boundary decision](decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md). +- important change (context sync): A completed task change that affects cross-cutting behavior, repository-wide policy/contracts, architecture boundaries, or canonical terminology; these changes require root context edits in `context/overview.md`, `context/architecture.md`, and/or `context/glossary.md` instead of verify-only handling. `setup config handling` is the Git-root-gated setup path that keeps an invalid default-discovered repo-local `.sce/config.json` untouched while allowing normal preflight, bootstrap, lifecycle, hooks, and target installation to continue; absent config remains eligible for create-if-missing bootstrap, Agent Trace storage consumes the same degraded result for invalid discovered layers, explicit `--config` and `SCE_CONFIG_FILE` failures remain fatal, and ordinary startup consumers retain degraded-default behavior. See [the degraded discovered-config boundary decision](decisions/2026-09-04-setup-storage-degrade-invalid-discovered-config.md). - verify-only root context pass: Context-sync mode for localized tasks where root-level behavior, architecture, and terminology are unchanged; root shared files are checked against code truth but are not edited by default. - ephemeral generated payload: Files materialized by `config/pkl/generate.pkl` using payload-relative `config/.opencode/**`, `config/.claude/**`, `config/.pi/**`, `config/.agents/**`, `config/.codex/**`, and `config/schema/sce-config.schema.json` paths beneath Cargo `OUT_DIR`, temporary previews, or packaging fallbacks. These layouts are installed by `sce setup` but are never committed as repository target trees; `config/automated/.opencode/**` remains a forbidden generator surface. - `Codex root-aware hook invocation`: Generated `.codex/hooks.json` command contract that resolves the Git repository root at hook runtime, invokes the installed helper through quoted path expansion from root or nested event cwd, preserves JSON STDIN, and exits silently successfully when Git-root resolution fails. The existing helper remains responsible for missing-`sce` stderr guidance; the contract forbids install-time absolute paths and `eval`. @@ -111,7 +111,7 @@ - `setup required-hook install orchestration`: Setup-service flow in `cli/src/services/setup/mod.rs` (`install_required_git_hooks`, backed by the rename-injectable `install_required_git_hooks_with_rename`) that resolves repository root + effective hooks directory via git truth, then for each hook computes the bytes to stage with the `setup hook-merge seam` (`hook_merge::merge_or_create_hook`) instead of writing the canonical asset verbatim, reports deterministic per-hook outcomes (`Installed`, `Updated`, `Skipped`) against that merged content plus the executable bit, enforces executable permissions, sets `RequiredHookInstallResult.unreachable_block_advisory` (rendered as a named advisory line) when an appended block would be unreachable, and uses the `setup atomic-swap` policy (see `setup atomic-swap`) — staged content is renamed directly over an existing hook without unlinking it first — with deterministic recovery guidance on swap failure. - `setup hooks CLI mode`: `sce setup` behavior activated by `--hooks` (with optional `--repo `), supporting both hooks-only runs and composable target+hooks runs in one invocation; implemented through `cli/src/services/setup/command.rs` + `cli/src/services/setup/mod.rs`, enforces deterministic compatibility validation (`--repo` requires `--hooks`; target flags remain mutually exclusive), and emits stable setup/hook status output. - `setup repo gate`: Preflight check in `cli/src/services/setup/command.rs` that calls `cli/src/services/setup/mod.rs` (`ensure_git_repository`) before any setup writes begin; enforces that all `sce setup` modes (config-only, hooks-only, combined, and interactive) require the current directory to be inside a git repository, failing with actionable guidance to run `git init` and rerun `sce setup` when the precondition is not met. -- `setup local bootstrap`: Pre-install setup bootstrap behavior now owned by lifecycle providers: `ConfigLifecycle::setup` creates missing `.sce/config.json` with the canonical versioned schema-only payload (`{"$schema": "https://sce.crocoder.dev/v/config.json"}`, using the CLI release version), `LocalDbLifecycle::setup` initializes the canonical local DB via `LocalDb::new()`, and `AgentTraceDbLifecycle::setup` creates/reuses checkout identity, resolves repository identity, initializes the repository-scoped Agent Trace DB via `agent_trace_storage`, and records repository ID, checkout ID, and `database_path`; the setup command aggregates these calls before config/hooks dispatch across all normal setup modes after context baseline bootstrap. +- `setup local bootstrap`: Pre-install setup bootstrap behavior now owned by lifecycle providers: `ConfigLifecycle::setup` creates missing `.sce/config.json` with the canonical versioned schema declaration plus explicit `agent_trace.auto_sync: true` bootstrap opt-in, `LocalDbLifecycle::setup` initializes the canonical local DB via `LocalDb::new()`, and `AgentTraceDbLifecycle::setup` creates/reuses checkout identity, resolves repository identity, initializes the repository-scoped Agent Trace DB via `agent_trace_storage`, and records repository ID, checkout ID, and `database_path`; the setup command aggregates these calls before config/hooks dispatch across all normal setup modes after context baseline bootstrap. - `setup context baseline bootstrap`: Additive durable-context tree bootstrap in `cli/src/services/setup/mod.rs` (`bootstrap_context_baseline`) that create-if-missing writes neutral baseline Markdown files, working directories, and `context/tmp/.gitignore` via `RepoPaths` accessors. `sce setup --bootstrap-context` is the dedicated context-only mode and must be used alone; every normal successful setup path also ensures the same baseline after the Git gate and before lifecycle/config install work without overwriting existing content. - `CLI redaction-safe diagnostics contract`: baseline security behavior implemented via `cli/src/services/security.rs` (`redact_sensitive_text`) and applied to app-level errors, setup git-diagnostic surfacing, and observability output sinks so common secret-bearing token forms are masked before emission. - `setup directory write-permission probe`: deterministic pre-write guard implemented in `cli/src/services/security.rs` (`ensure_directory_is_writable`) and used by setup install/hook flows to fail fast with actionable remediation when target directories are not writable. @@ -247,4 +247,4 @@ - `parts table (Agent Trace DB)`: Agent Trace DB table created by migration `009_create_parts.sql`; stores append-only message parts with columns `type` (typed by Rust as `text`/`reasoning`/`patch`/`question` and stored as unconstrained `TEXT NOT NULL`), `text`, `message_id`, `session_id`, `generated_at_unix_ms`, `created_at`, `updated_at`. Uses only the internal `id` for row identity (no upsert/dedup). Multiple parts can exist for the same `(session_id, message_id)`. A compound index on `(session_id, message_id, generated_at_unix_ms, id)` enables ordered joins. No foreign keys to `messages` or any other table, so parts may be inserted before their parent message exists. - `AgentTraceExportReader`: Read-only incremental export reader in `cli/src/services/agent_trace_export/mod.rs` over one `RepositoryAgentTraceDb`, exposing `read_messages_after`/`read_parts_after`/`read_diff_traces_after`/`read_agent_traces_after`, each `(cursor: i64, limit: usize) -> Result>` over `WHERE id > cursor ORDER BY id ASC LIMIT {limit}`. Holds no local cursor, performs no mutation, makes no network calls, and returns owned camelCase `serde::Serialize` export-row DTOs matching the shipped control-plane ingestion contract. See `context/sce/agent-trace-export-readers.md`. - `context synchronization lifecycle`: Durable task-level state for synchronization after successful `/next-task` execution. The task record is `pending`, `synced`, or `blocked`; blocked records carry a blocker, required action, and retry condition. Missing lifecycle state on a completed task is unresolved debt, not evidence of synchronization. `/validate` does not persist a plan-level synchronization lifecycle. See `context/sce/shared-context-code-workflow.md`. -- `agent_trace.auto_sync`: Config-file-only boolean resolved by the shared config layers for the post-commit Agent Trace synchronization boundary; omitted values are `true` and explicit `false` opts out, and `sce config show` reports its winning source. After validation and repository-DB persistence, enabled post-commit runs launch the existing sync-owned `sync --format json` command once through the current executable with detached null-standard-stream child semantics and repository-root working directory; the hook never waits, has no daemon or high-frequency trigger, and treats launcher failures as fail-open. See [Agent Trace hook routing](sce/agent-trace-hooks-command-routing.md). +- `agent_trace.auto_sync`: Config-file-only boolean resolved by the shared config layers for the post-commit Agent Trace synchronization boundary; omitted values are `false`, while setup writes an explicit `true` into a newly created repo-local config, and explicit `false` opts out. `sce config show` reports the winning source. After validation and repository-DB persistence, enabled post-commit runs launch the existing sync-owned `sync --format json` command once through the current executable with detached null-standard-stream child semantics and repository-root working directory; the hook never waits, has no daemon or high-frequency trigger, and treats launcher failures as fail-open. See [Agent Trace hook routing](sce/agent-trace-hooks-command-routing.md). diff --git a/context/overview.md b/context/overview.md index f7ba0b26..37e8bcce 100644 --- a/context/overview.md +++ b/context/overview.md @@ -12,7 +12,7 @@ The generated `/next-task` workflow persists task-level context-synchronization - **Stderr diagnostics:** stable `SCE-ERR-{PARSE,VALIDATION,RUNTIME,DEPENDENCY}` codes with class-default `Try:` remediation (see `context/sce/cli-error-code-taxonomy.md`). - **Stdout/stderr:** command payloads on stdout only; redacted diagnostics and text-mode `sce sync` progress on stderr, while JSON sync remains silent (see `context/sce/cli-stdout-stderr-contract.md`). - **Observability:** config-resolved logging with tracing, explicit config-file/default `log_to_file` control, error-specific stderr suppression when file logging is enabled, and optional dated/session-partitioned `log_dir` / `SCE_LOG_DIR` files with retention (see `context/sce/cli-observability-contract.md`). -- **Config precedence:** `flags > env > config file > defaults` (see `context/cli/config-precedence-contract.md`); invalid default-discovered config remains degradable for ordinary startup, while setup and Agent Trace storage fail closed before side effects or fallback identity selection. The config-file-only `agent_trace.auto_sync` setting defaults to `true` and is resolved with source metadata for the post-commit trigger and doctor readiness boundaries. Its asynchronous post-commit behavior and doctor capability reporting are documented in `context/cli/agent-trace-auto-sync.md`. +- **Config precedence:** `flags > env > config file > defaults` (see `context/cli/config-precedence-contract.md`); invalid default-discovered config remains degradable for ordinary startup, setup, and Agent Trace storage, while explicit `--config` and `SCE_CONFIG_FILE` failures remain fatal. Setup preserves invalid repo-local files and may omit target/optional-workflow persistence for that run. The config-file-only `agent_trace.auto_sync` setting resolves omitted values to `false`, while setup explicitly writes `true` into a newly created repo-local config; source metadata feeds the post-commit trigger and doctor readiness boundaries. Its asynchronous post-commit behavior and doctor capability reporting are documented in `context/cli/agent-trace-auto-sync.md`. - **Attribution hooks:** enabled by default, gated by staged-diff AI-overlap preflight; `SCE_ATTRIBUTION_HOOKS_DISABLED` opt-out (see `context/sce/agent-trace-commit-msg-coauthor-policy.md`). - **Install channels:** repo-flake Nix, Cargo, npm, and source-built Flatpak (`dev.crocoder.sce`); Homebrew deferred (see `context/sce/cli-first-install-channels-contract.md`). diff --git a/context/patterns.md b/context/patterns.md index 998e6190..37cf1eca 100644 --- a/context/patterns.md +++ b/context/patterns.md @@ -127,11 +127,11 @@ - For observability log-directory configuration, resolve `log_dir` through `SCE_LOG_DIR` > config-file `log_dir` > `default_paths::observability_log_dir()` (`/sce/logs`; Linux `${XDG_STATE_HOME:-~/.local/state}/sce/logs`); select log files per emission from the machine-local date and optional logger session context, append rendered records to the selected file, run retention only after successfully creating a selected file, and keep session IDs out of rendered log schemas unless a caller explicitly passes them as normal fields. - Keep `log_file_retention_limit` flat and config-file/default only: validate it as an integer with minimum `1`, merge global before local, default it to `10`, expose resolved source metadata without adding an environment variable or CLI flag, and pass the resolved value unchanged to primary and v2 creation-triggered logger cleanup. -- For runtime CLI configuration, keep precedence deterministic and explicit (`flags > env > config file > defaults`) and expose inspect/validate command entrypoints with stable text/JSON outputs. Config-file-only Agent Trace runtime switches such as `agent_trace.auto_sync` should document their default and explicit opt-out, resolve global before local, and expose winning source metadata without adding an environment variable or CLI flag unless the contract explicitly requires one. -- For default-enabled automatic Agent Trace synchronization, keep the post-commit launcher as a one-shot reuse of `sce sync`: start the current executable after local Agent Trace persistence, use the repository root and null child streams, do not wait, and fail open on launcher errors. Keep manual sync and the control-plane cursor authority as the retry path; do not add daemons, watchers, polling, queues, or high-frequency hook triggers. +- For runtime CLI configuration, keep precedence deterministic and explicit (`flags > env > config file > defaults`) and expose inspect/validate command entrypoints with stable text/JSON outputs. Config-file-only Agent Trace runtime switches such as `agent_trace.auto_sync` should document the resolver fallback and explicit opt-out, distinguish setup-written bootstrap values, resolve global before local, and expose winning source metadata without adding an environment variable or CLI flag unless the contract explicitly requires one. +- For setup-enabled automatic Agent Trace synchronization, keep the post-commit launcher as a one-shot reuse of `sce sync`: start the current executable after local Agent Trace persistence when the resolved setting is true, use the repository root and null child streams, do not wait, and fail open on launcher errors. Keep manual sync and the control-plane cursor authority as the retry path; do not add daemons, watchers, polling, queues, or high-frequency hook triggers. - For commands that support text/JSON dual output, centralize `--format ` parsing in one shared contract and pass command-specific `--help` guidance into invalid-value errors instead of duplicating parser logic per command. - For setup-style command contracts, keep interactive mode as the zero-flag default and enforce mutually-exclusive explicit target flags for non-interactive automation. -- For setup config safety, validate an existing repo-local config immediately after resolving the Git root and before prompts, context bootstrap, lifecycle providers, hooks, or target assets; preserve create-if-missing behavior for absent config and keep general startup degradation scoped away from setup and Agent Trace storage identity resolution. +- For setup config safety, resolve invalid default-discovered config through the shared degraded layer behavior, preserve the invalid repo-local file byte-for-byte, and allow Git/remote preflight, context bootstrap, lifecycle providers, hooks, and target assets to continue; preserve create-if-missing behavior for absent config, skip target/optional-workflow persistence when the local file is invalid, and keep explicit `--config` / `SCE_CONFIG_FILE` failures fatal. - For durable-context bootstrap, keep create-if-missing additive semantics: ensure baseline paths on every successful setup path, offer a dedicated standalone `--bootstrap-context` mode, and never overwrite existing context content. - For security-sensitive CLI UX, redact common secret-bearing token/value forms before emitting diagnostics/log lines, including app-level errors, setup git stderr diagnostics, and observability sink output. - For user-supplied setup repository paths (`sce setup --hooks --repo `), canonicalize/validate the path as an existing directory before git command execution, and run deterministic write-permission probes on setup write targets before staging/swap operations. diff --git a/context/plans/setup-degraded-invalid-config-agent-trace.md b/context/plans/setup-degraded-invalid-config-agent-trace.md new file mode 100644 index 00000000..31f9cfea --- /dev/null +++ b/context/plans/setup-degraded-invalid-config-agent-trace.md @@ -0,0 +1,153 @@ +# Plan: setup-degraded-invalid-config-agent-trace + +## Change summary + +Align `sce setup` and Agent Trace hook-runtime storage with ordinary startup +configuration behavior. When a default-discovered global or repo-local +`.sce/config.json` is invalid, the shared resolver should skip that layer, +retain the existing `sce.config.invalid_config` warning, and continue with any +valid remaining layer or degraded defaults. An outdated `$schema` URL must not +abort setup. + +The same degraded values must reach +`open_agent_trace_db_for_hook_runtime()` so invalid discovered configuration does +not block conversation tracing, diff tracing, commit attribution, post-commit +processing, Claude model-state intake, or other Agent Trace DB-backed hook work. +Explicit `--config` and `SCE_CONFIG_FILE` selections remain fatal, and invalid +repo-local configuration is not repaired or rewritten as a side effect of +continuing setup. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [x] AC1: `sce setup` completes its normal Git/remote preflight, bootstrap, + lifecycle, and requested asset-install flow when a default-discovered global + or repo-local config file is invalid, including an outdated `$schema` URL; + valid remaining layers and defaults continue to determine setup values, and + the invalid repo-local file remains byte-for-byte unchanged. + - Validate: Focused setup tests plus an integration-style setup case with + invalid global/local discovered config assert successful continuation, + unchanged invalid-file content, and the existing startup warning event. +- [x] AC2: `resolve_agent_trace_storage_runtime_config()` and + `open_agent_trace_db_for_hook_runtime()` continue past invalid + default-discovered config, use the remaining valid layer or default remote, + and expose an open repository-scoped DB to DB-backed hook flows. + - Validate: Focused resolver, Agent Trace storage, and hooks tests cover + invalid global/local layers, default/remaining-layer identity selection, + successful hook-runtime DB opening, and representative conversation/diff + persistence paths. +- [x] AC3: Invalid explicit `--config` and `SCE_CONFIG_FILE` selections remain + fatal, while the existing config schema, repository identity canonicalization, + remote precedence, hook no-migration behavior, and genuine DB fail-open + diagnostics remain unchanged. + - Validate: Focused resolver/setup/hooks tests assert explicit-config failure, + identity and migration invariants, and unchanged hook diagnostics. + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `nix run .#pkl-check-generated` +- `nix flake check` + +### Context sync + +- `context/overview.md` +- `context/architecture.md` +- `context/glossary.md` +- `context/cli/config-precedence-contract.md` +- `context/sce/setup-repo-local-config-bootstrap.md` +- `context/cli/agent-trace-storage.md` +- `context/sce/agent-trace-hooks-command-routing.md` +- A new dated decision record superseding `context/decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md` + +## Task context synchronization lifecycle + +Persist this field in every plan; this is durable plan state, not chat state: + +- **Task context synchronization:** every task carries `pending | synced | blocked`. + A completed task must be `synced` before another task can start or the plan can + finish. +- For `blocked`, record **Blocker**, **Required action**, and **Retry condition** + beside the status. Never infer `synced` from conversation history; write every + lifecycle transition to the plan file. + +## Constraints and non-goals + +- **In scope:** The default-discovered invalid-layer boundary in the shared + runtime resolver, setup preflight and integration-persistence behavior, + `open_agent_trace_db_for_hook_runtime()` and its hook callers, focused Rust + regression tests, and the listed durable context. +- **Out of scope:** Changes to the JSON Schema, startup warning identifier, + explicit-config strictness, repository identity canonicalization or remote + precedence, Agent Trace DB schema/migrations, generated integrations, or + unrelated setup behavior. +- **Constraints:** Reuse the existing resolver and schema seams; preserve + credential-safe deterministic diagnostics, startup warning behavior, setup Git + and remote preflights, no-migration hook opening, existing hook fail-open + handling for genuine DB failures, and Nix-based verification. Add no + dependencies. +- **Non-goal:** Do not make invalid configuration silently valid, delete or + repair user files, introduce a new storage fallback database, or make explicit + config selections degradable. + +## Assumptions + +- “Follow startup behavior” means only default-discovered invalid layers are + skipped; explicit `--config` and `SCE_CONFIG_FILE` inputs remain fatal. +- Continuing setup with an invalid repo-local file must not rewrite that file; + setup may omit integration-target/optional-workflow persistence for that run + rather than mutating invalid user configuration. +- The existing repository-scoped identity fallback (`agent_trace.repository_id`, + configured remote, then default `origin`) and no-migration hook DB path are + sufficient; no new identity or database fallback is needed. + +## Task stack + +- [x] T01: `Align setup and Agent Trace hook storage with degraded discovered config` (status:done) + - Task ID: T01 + - Scope: In — remove setup's default-discovered invalid-config hard-fail, make Agent Trace storage runtime configuration use the shared skipped-layer result, keep invalid repo-local config untouched when setup continues, and add focused resolver/setup/storage/hooks regressions for `open_agent_trace_db_for_hook_runtime()` and representative DB-backed hook writes. Preserve explicit-config failures, startup warning emission, Git/remote preflight order, repository identity precedence, no-migration opening, and genuine DB failure diagnostics. Out — schema changes, config repair or migration, new storage fallbacks, repository identity canonicalization, generated assets, and unrelated setup/hook behavior. + - Dependencies: none + - Done when: Invalid default-discovered global or local config no longer aborts setup or blocks repository-scoped Agent Trace hook DB opening; setup completes without rewriting the invalid local file; remaining-layer/default precedence and explicit-config failure behavior are covered by passing focused tests. + - Verify: `nix develop -c sh -c './scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::config::resolver && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::setup && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::agent_trace_storage && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::hooks'`. + - Completed: 2026-09-04 + - Files changed: `cli/src/services/config/resolver.rs`; `cli/src/services/setup/command.rs`; `cli/src/services/setup/mod.rs`; `cli/src/services/hooks/mod.rs` + - Result: Agent Trace storage now consumes the shared degraded resolver result instead of failing on invalid default-discovered layers. Setup no longer rejects invalid repo-local config during preflight, and target persistence skips invalid local files without rewriting them. Added resolver precedence regressions, byte-preserving setup persistence coverage, and hook-runtime DB opening/conversation-write coverage with invalid discovered local config. Explicit configuration failures and existing DB/hook behavior remain unchanged. + - Verify: `nix develop -c sh -c './scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::config::resolver && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::setup && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::agent_trace_storage && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::hooks'` — passed (20 resolver, 67 setup, 14 Agent Trace storage, and 181 hooks tests). + - Context impact: Material cross-cutting behavior change to shared config resolution, setup persistence, and Agent Trace hook storage; durable context synchronization is required for the listed config/setup/Agent Trace contracts and a superseding decision record. + - Context synchronization: synced + +## Open questions + +None. The requested boundary is explicit, the repository already owns the +degraded resolver and hook-runtime opener, and the non-destructive persistence +choice follows the existing setup asset/config safety rules. + +## Validation Report + +**Status:** validated +**Date:** 2026-09-04 + +### Commands run + +- `nix run .#pkl-check-generated` -> exit 0 (ephemeral Pkl generation passed: 141 files; inventory parity matched) +- `nix flake check` -> exit 0 (all flake checks passed) +- `nix develop -c sh -c './scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::config::resolver && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::setup && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::agent_trace_storage && ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml services::hooks'` -> exit 0 (20 resolver, 67 setup, 14 Agent Trace storage, and 181 hooks tests passed) + +### Success-criteria verification + +- [x] AC1: `sce setup` completes its normal Git/remote preflight, bootstrap, lifecycle, and requested asset-install flow when a default-discovered global or repo-local config file is invalid, including an outdated `$schema` URL; valid remaining layers and defaults continue to determine setup values, and the invalid repo-local file remains byte-for-byte unchanged. -> Resolver and setup regression tests passed, including invalid discovered-layer continuation and byte-preserving invalid repo-local persistence. +- [x] AC2: `resolve_agent_trace_storage_runtime_config()` and `open_agent_trace_db_for_hook_runtime()` continue past invalid default-discovered config, use the remaining valid layer or default remote, and expose an open repository-scoped DB to DB-backed hook flows. -> Resolver, Agent Trace storage, and hooks suites passed, including invalid-layer precedence, hook-runtime DB opening, conversation writes, diff persistence, and post-commit flows. +- [x] AC3: Invalid explicit `--config` and `SCE_CONFIG_FILE` selections remain fatal, while the existing config schema, repository identity canonicalization, remote precedence, hook no-migration behavior, and genuine DB fail-open diagnostics remain unchanged. -> Focused resolver, setup, Agent Trace storage, and hooks suites passed, including explicit-config, identity, remote, migration, and fail-open regression coverage. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- None identified. diff --git a/context/plans/update-auto-sync-default-behavior.md b/context/plans/update-auto-sync-default-behavior.md new file mode 100644 index 00000000..42b663fb --- /dev/null +++ b/context/plans/update-auto-sync-default-behavior.md @@ -0,0 +1,136 @@ +# Plan: update-auto-sync-default-behavior + +## Change summary + +Separate the two `agent_trace.auto_sync` defaults that currently share one +configuration concept. When `sce setup` creates a missing repo-local +`.sce/config.json`, the generated file will explicitly contain +`"auto_sync": true`, opting the new repository into post-commit synchronization. +The runtime config resolver will remain conservative: an omitted value resolves +to `false`, while explicit config values continue to control behavior. + +The existing schema and post-commit trigger remain unchanged apart from these +default boundaries. Focused setup and resolver tests will make the distinction +regression-safe, and durable context will be corrected where it currently treats +the setup payload and resolver fallback as the same default. + +## Acceptance criteria + +How this plan is proven complete. Each criterion is observable and names the +check that proves it. `/validate` runs these checks; no task in the stack +performs final validation. + +- [x] AC1: A newly generated repo-local `.sce/config.json` explicitly contains `"agent_trace": { "auto_sync": true }` alongside its schema declaration. + - Validate: setup bootstrap tests assert the generated payload/file contains the explicit `agent_trace.auto_sync` value. +- [x] AC2: When `agent_trace.auto_sync` is absent from all config layers, the resolver returns `false` with default provenance; explicit `true` and `false` values and existing global/local precedence remain unchanged. + - Validate: focused config resolver tests cover the missing-value fallback, explicit values, and local-over-global resolution. +- [x] AC3: Durable SCE configuration and setup documentation distinguishes setup's explicit `true` bootstrap value from the resolver's `false` fallback without changing the documented post-commit opt-out semantics. + - Validate: manual review of the affected durable context files against the implemented setup payload and resolver branch. + +### Full validation + +Repository-wide checks `/validate` runs after the last task, regardless of +which criterion they map to. + +- `nix flake check` +- `nix run .#pkl-check-generated` + +### Context sync + +- `context/overview.md` +- `context/architecture.md` +- `context/patterns.md` +- `context/glossary.md` +- `context/context-map.md` +- `context/cli/config-precedence-contract.md` +- `context/cli/agent-trace-auto-sync.md` +- `context/sce/setup-repo-local-config-bootstrap.md` +- `context/sce/agent-trace-hooks-command-routing.md` + +## Task context synchronization lifecycle + +Persist this field in every plan; this is durable plan state, not chat state: + +- **Task context synchronization:** every task carries `pending | synced | blocked`. + A completed task must be `synced` before another task can start or the plan can + finish. +- For `blocked`, record **Blocker**, **Required action**, and **Retry condition** + beside the status. Never infer `synced` from conversation history; write every + lifecycle transition to the plan file. + +## Constraints and non-goals + +- **In scope:** repo-local setup config bootstrap payload and tests; config resolver omitted-value fallback and tests; the durable context files listed under Context sync. +- **Out of scope:** changes to the JSON schema's accepted shape, explicit config precedence, post-commit launcher behavior, synchronization protocol, generated target trees, and unrelated setup persistence. +- **Constraints:** preserve existing files when `.sce/config.json` already exists; preserve explicit `agent_trace.auto_sync` values and global-before-local merge behavior; use repository test and validation commands through Nix; do not edit generated artifacts. +- **Non-goal:** making every resolver default or every existing repository opt into auto-sync; only a newly created setup config receives the explicit `true` value. + +## Assumptions + +- The existing optional `agent_trace.auto_sync` schema field and config inspection surfaces already support the required boolean; this change only separates setup serialization from missing-value resolution. +- The current completed `automatic-agent-trace-sync` plan remains historical context and is not amended; this request is tracked as a new plan as requested. + +## Task stack + +- [x] T01: `Separate setup bootstrap and resolver auto_sync defaults` (status:complete) + - Task ID: T01 + - Scope: In — `cli/src/services/setup/mod.rs` bootstrap serialization/tests and `cli/src/services/config/resolver.rs` missing-value fallback/tests. Out — schema changes, hook/launcher behavior, and durable context edits. + - Dependencies: none + - Done when: newly created setup config payloads explicitly serialize `agent_trace.auto_sync` as `true`; missing resolver values remain `false` with default provenance; explicit values and global/local precedence still pass their focused tests. + - Verify: `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup`; `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml config::`. + - Completed: 2026-09-07 + - Files changed: + - `cli/src/services/setup/mod.rs` + - `cli/src/services/config/resolver.rs` + - Result: Setup bootstrap payloads now explicitly write `agent_trace.auto_sync: true`; omitted runtime values resolve to `false` with default provenance; explicit values and local-over-global precedence remain covered by focused tests. + - Verify: + - `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup` — passed (69 tests). + - `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml config::` — passed (59 tests). + - Context impact: `application_behavior` — setup bootstrap serialization and runtime config resolution changed; durable context remains pending for T02. + - Context synchronization: synced + +- [x] T02: `Document the intentionally split auto_sync defaults` (status:complete) + - Task ID: T02 + - Scope: In — the durable context files listed under Context sync, updating setup-generation and resolver-fallback statements to match T01. Out — application code, tests, generated outputs, and historical plan/decision records. + - Dependencies: T01 + - Done when: current context consistently says setup writes explicit `true` for a newly generated config, resolver fallback is `false` when missing, and explicit opt-out/trigger behavior is unchanged. + - Verify: manual review of the affected context files against `cli/src/services/setup/mod.rs` and `cli/src/services/config/resolver.rs`. + - Completed: 2026-09-07 + - Files changed: + - `context/architecture.md` + - `context/context-map.md` + - Result: Durable context now distinguishes the explicit `true` setup bootstrap opt-in from the resolver's `false` omitted-value fallback while preserving explicit configuration, precedence, trigger, and fail-open behavior. + - Verify: + - Manual review of the affected context files against `cli/src/services/setup/mod.rs` and `cli/src/services/config/resolver.rs` — passed; all listed setup/config/auto-sync statements align with the implementation, and stale current-state default wording was corrected. + - Context impact: documentation — current setup, config, and Agent Trace auto-sync context is synchronized with T01; the mandatory context synchronization pass remains required. + - Context synchronization: synced + +## Open questions + +None. The requested setup value, resolver fallback, separation boundary, and test coverage are explicit; remaining choices follow existing config and setup conventions. + +## Validation Report + +**Status:** validated +**Date:** 2026-09-07 + +### Commands run + +- `nix flake check` -> exit 0 (flake evaluation and checks passed) +- `nix run .#pkl-check-generated` -> exit 0 (ephemeral Pkl generation passed with 141 files) +- `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml setup` -> exit 0 (69 setup tests passed) +- `nix develop -c ./scripts/run-cli-cargo.sh test --manifest-path cli/Cargo.toml config::` -> exit 0 (59 config tests passed) + +### Success-criteria verification + +- [x] AC1: A newly generated repo-local `.sce/config.json` explicitly contains `"agent_trace": { "auto_sync": true }` alongside its schema declaration. -> setup test suite passed, including `repo_local_config_bootstrap_payload_uses_versioned_schema_url` and generated-payload/file bootstrap coverage. +- [x] AC2: When `agent_trace.auto_sync` is absent from all config layers, the resolver returns `false` with default provenance; explicit `true` and `false` values and existing global/local precedence remain unchanged. -> config resolver suite passed, including missing default, explicit true/false, and local-over-global tests. +- [x] AC3: Durable SCE configuration and setup documentation distinguishes setup's explicit `true` bootstrap value from the resolver's `false` fallback without changing the documented post-commit opt-out semantics. -> manually reviewed `context/overview.md`, `context/architecture.md`, `context/patterns.md`, `context/glossary.md`, `context/context-map.md`, `context/cli/config-precedence-contract.md`, `context/cli/agent-trace-auto-sync.md`, `context/sce/setup-repo-local-config-bootstrap.md`, and `context/sce/agent-trace-hooks-command-routing.md` against `cli/src/services/setup/mod.rs` and `cli/src/services/config/resolver.rs`; statements align. + +### Failed checks and follow-ups + +- None. + +### Residual risks + +- None identified. diff --git a/context/sce/agent-trace-hooks-command-routing.md b/context/sce/agent-trace-hooks-command-routing.md index 13e33cf3..41103000 100644 --- a/context/sce/agent-trace-hooks-command-routing.md +++ b/context/sce/agent-trace-hooks-command-routing.md @@ -32,6 +32,7 @@ - config `policies.attribution_hooks.enabled` - precedence: env over config file - default: enabled +- Hook-runtime Agent Trace DB opening resolves repository identity through the shared config resolver. Invalid default-discovered global or repo-local config layers are skipped in favor of the remaining valid layer or the default `origin` remote; explicit `--config` / `SCE_CONFIG_FILE` failures remain fatal. This degradation does not change no-migration schema readiness, repository identity canonicalization, or genuine DB fail-open diagnostics. - `commit-msg` is the only active attribution path. - Reads the message file as UTF-8. - Applies exactly one canonical trailer: `Co-authored-by: SCE `. @@ -64,7 +65,7 @@ - Post-commit Agent Trace success requires both schema validation and Agent Trace DB `agent_traces` persistence to succeed. - Current command-surface success output is: `post-commit hook processed intersection: commit=, intersection_files=`. - After Agent Trace validation and `agent_traces` persistence succeed, post-commit runs exactly one passive WAL checkpoint through `RepositoryAgentTraceDb::passive_checkpoint()` (see [shared-turso-db.md](shared-turso-db.md)) before resolving auto-sync. This is routine maintenance, not a durability boundary: a checkpoint failure is logged as a warning via `Logger::warn` with event `sce.agent_trace_db.passive_checkpoint_failed` and does not fail the hook or affect already-persisted Agent Trace data. `diff-trace` and `conversation-trace` do not checkpoint per write; only this one post-commit call site does. -- After Agent Trace validation and `agent_traces` persistence succeed, post-commit resolves the config-file-only `agent_trace.auto_sync` gate. When it is `true`, the hook invokes the sync-owned one-shot launcher exactly once with the repository root; the launcher starts the current `sce` executable as detached `sync --format json` work and is not awaited. Explicit `false` configuration does not launch; omitted configuration launches, and validation or persistence failure reaches the existing error path before the gate. Launcher/current-executable/spawn failures are fail-open and do not change the successful post-commit result. No `pre-commit`, `diff-trace`, or `conversation-trace` path invokes automatic synchronization. +- After Agent Trace validation and `agent_traces` persistence succeed, post-commit resolves the config-file-only `agent_trace.auto_sync` gate. When it is `true`, the hook invokes the sync-owned one-shot launcher exactly once with the repository root; the launcher starts the current `sce` executable as detached `sync --format json` work and is not awaited. Explicit `false` configuration and omitted configuration do not launch; a newly created setup config launches because it contains an explicit `true`. Validation or persistence failure reaches the existing error path before the gate. Launcher/current-executable/spawn failures are fail-open and do not change the successful post-commit result. No `pre-commit`, `diff-trace`, or `conversation-trace` path invokes automatic synchronization. - `post-rewrite` is a deterministic no-op entrypoint. - `diff-trace` reads STDIN JSON and classifies the payload: - **Claude structured payloads** (detected by presence of top-level `hook_event_name`): the STDIN JSON is validated through `derive_claude_structured_patch`. Supported `PostToolUse` `Write` create and `Edit` structured-patch events produce a `DiffTracePayload` with `payload_type="structured"` and the raw event JSON stored as the `diff` column without conversion to unified-diff text. Model attribution is resolved with `direct > exact transcript > exact Claude state > NULL`: top-level `model`, `model_id`, or `modelId`, or nested `model.id`, `model.model`, or `model.name`, wins when present. Otherwise, when the event provides both `transcript_path` and `tool_use_id`, Rust scans that Claude JSONL transcript for the assistant-message envelope whose `tool_use.id` matches, skipping malformed unrelated records. Either source is normalized once with the `claude/` prefix. For these raw structured Claude payloads only, if both event-local sources are unavailable, persistence performs one exact `(cc_, agent_id)` lookup in the local `claude_model_state` register after opening the repository DB; normalized payloads with `tool_name="claude"` do not qualify, and absent state remains nullable. Ephemeral `agent_id` is trimmed for exact lookup, with missing/null main-session context mapped to `""`; subagents never inherit main-session state. Missing/unreadable transcripts, unmatched tool calls, missing models, or absent lookup fields leave the parser's `model_id` nullable without rejecting the hook. No polling, waiting, or stored-raw-event reparsing participates. Unsupported Claude events (non-`PostToolUse`, unsupported tools, invalid payloads) produce a deterministic `NoOp` success result. diff --git a/context/sce/doctor-human-text-contract.md b/context/sce/doctor-human-text-contract.md index c47874ad..61b24bd4 100644 --- a/context/sce/doctor-human-text-contract.md +++ b/context/sce/doctor-human-text-contract.md @@ -57,13 +57,14 @@ JSON exposes the same fact as `post_commit_auto_sync` with stable `state`, remediation, and overall readiness semantics remain the source of blocking diagnostics. -The resolved `enabled` value defaults to `true` when `agent_trace.auto_sync` is -omitted and is `false` only for the explicit config opt-out. `source` reports -`default` or `config_file` for resolved values, or `unresolved` when config -resolution fails; `config_source` identifies the discovered global or local -config layer when applicable and is otherwise `null`. Doctor only reports -this fact: it never launches `sce sync` or a background process. The post-commit -runtime still launches one detached `sync --format json` child only after +The resolved `enabled` value defaults to `false` when `agent_trace.auto_sync` is +omitted; a newly created setup config contains an explicit `true`, and an +explicit `false` remains disabled. `source` reports `default` or `config_file` +for resolved values, or `unresolved` when config resolution fails; +`config_source` identifies the discovered global or local config layer when +applicable and is otherwise `null`. Doctor only reports this fact: it never +launches `sce sync` or a background process. The post-commit runtime still +launches one detached `sync --format json` child only after successful Agent Trace persistence when enabled, and launcher failures remain fail-open. diff --git a/context/sce/setup-repo-local-config-bootstrap.md b/context/sce/setup-repo-local-config-bootstrap.md index 10f38ffd..ee0325c3 100644 --- a/context/sce/setup-repo-local-config-bootstrap.md +++ b/context/sce/setup-repo-local-config-bootstrap.md @@ -7,18 +7,18 @@ Task `setup-repo-gate-and-local-config-bootstrap` T02, `turso-local-db-sync` T04 ## Behavior - Any successful `sce setup` run in a git-backed repository creates `.sce/config.json` when the file is absent. -- The bootstrap writes the canonical schema-only JSON payload: `{"$schema": "https://sce.crocoder.dev/v/config.json"}` (where `` is the CLI release version, with a trailing newline). +- The bootstrap writes the canonical JSON payload with the versioned schema declaration and explicit Agent Trace opt-in: `{"$schema": "https://sce.crocoder.dev/v/config.json", "agent_trace": {"auto_sync": true}}` (where `` is the CLI release version, with a trailing newline). - If `.sce/config.json` already exists, the bootstrap step returns `Ok(())` immediately and leaves the file untouched — no merge, no reformat, no overwrite. - The parent `.sce/` directory is created via `fs::create_dir_all` if missing. - The setup flow also bootstraps the canonical local DB through `LocalDbLifecycle::setup` and the Agent Trace DB through `AgentTraceDbLifecycle::setup`; both use the shared `TursoDb` adapter. -- After both repository preflights (`ensure_git_repository` and the effective named-remote URL check), setup validates an existing repo-local `.sce/config.json` before prompts, context baseline bootstrap, lifecycle providers, hooks, or target assets. Invalid config stops the run without those side effects; an absent config continues through the normal bootstrap path. -- Config/DB bootstrap runs after those preflights and config validation, and after context baseline bootstrap, before config/hooks dispatch, so it applies to all normal setup modes: config-only, hooks-only, combined, and interactive. +- After both repository preflights (`ensure_git_repository` and the effective named-remote URL check), setup consumes the shared resolver's degraded result for an invalid default-discovered repo-local `.sce/config.json`; the file remains untouched and the run continues through prompts, context baseline bootstrap, lifecycle providers, hooks, and target assets. An absent config continues through the normal bootstrap path, while explicit config selections remain fatal. +- Config/DB bootstrap runs after those preflights and after context baseline bootstrap, before config/hooks dispatch, so it applies to all normal setup modes: config-only, hooks-only, combined, and interactive. If the repo-local config is invalid, target and optional-workflow persistence is skipped rather than rewriting it. ## Context baseline bootstrap - `sce setup --bootstrap-context` is a non-interactive context-only mode and must be used alone (no target, hooks, non-interactive, or `--repo` flags). -- Context-only setup ensures both repository preflights, validates an existing repo-local config, then creates the baseline durable-context tree and exits without lifecycle providers, integration installs, or prompts. -- Every normal successful setup path also calls the same additive context bootstrap after both repository preflights and config validation, before lifecycle/config install work. +- Context-only setup ensures both repository preflights, then creates the baseline durable-context tree and exits without lifecycle providers, integration installs, or prompts; invalid default-discovered repo-local config remains untouched. +- Every normal successful setup path also calls the same additive context bootstrap after both repository preflights, before lifecycle/config install work. - Baseline paths: `context/overview.md`, `context/architecture.md`, `context/patterns.md`, `context/glossary.md`, `context/context-map.md`, `context/plans/`, `context/handovers/`, `context/decisions/`, `context/tmp/`, and `context/tmp/.gitignore`. - Create-if-missing only: existing files and directory contents are left untouched; missing individual paths are restored even when `context/` already exists. - New Markdown files use neutral headings/placeholders; `context-map.md` links baseline entry points without inventing repository details; `context/tmp/.gitignore` ignores scratch content while retaining itself (`*\n!.gitignore\n`). @@ -54,14 +54,14 @@ The same write also records the run's resolved optional-workflow selection under - `cli/src/services/agent_trace_db/lifecycle.rs` implements `AgentTraceDbLifecycle::setup()` for Agent Trace DB initialization. - Repo-local config bootstrap uses `RepoPaths::sce_config_file()` and `RepoPaths::sce_dir()`; context baseline bootstrap uses the shared context accessors including `RepoPaths::context_tmp_gitignore_file()`. - The canonical payload constant is `REPO_LOCAL_CONFIG_BOOTSTRAP_PAYLOAD`. -- `cli/src/services/setup/command.rs` resolves the effective `agent_trace.repository_remote`, runs both repository preflights, and validates an existing repo-local config before `bootstrap_context_baseline`. Context-only requests return after the baseline. Normal modes then derive a repo-root-scoped `AppContext` and aggregate lifecycle providers in config → local_db → auth_db → agent_trace_db → hooks order; `ConfigLifecycle::setup()` calls `bootstrap_repo_local_config(...)`, `LocalDbLifecycle::setup()` initializes the local DB, `AuthDbLifecycle::setup()` initializes the auth DB, and `AgentTraceDbLifecycle::setup()` initializes the Agent Trace DB. +- `cli/src/services/setup/command.rs` resolves the effective `agent_trace.repository_remote` and runs both repository preflights before `bootstrap_context_baseline`; default-discovered invalid config is handled by the shared resolver and is not rewritten. Context-only requests return after the baseline. Normal modes then derive a repo-root-scoped `AppContext` and aggregate lifecycle providers in config → local_db → auth_db → agent_trace_db → hooks order; `ConfigLifecycle::setup()` calls `bootstrap_repo_local_config(...)`, `LocalDbLifecycle::setup()` initializes the local DB, `AuthDbLifecycle::setup()` initializes the auth DB, and `AgentTraceDbLifecycle::setup()` initializes the Agent Trace DB. ## Relationship to other setup contracts -- The Git-repo gate (`ensure_git_repository`), effective named-remote URL preflight, and existing-config validation remain the preconditions for every setup write path, including context-only bootstrap. The gate classifies only an explicit Git `not a git repository` result and an actually missing/empty named-remote URL as typed user errors; Git/process/configuration and remote-lookup execution failures remain runtime errors with technical sources preserved. -- The repo-local config preflight is fail-closed only for an existing invalid config, while absent config remains create-if-missing. +- The Git-repo gate (`ensure_git_repository`) and effective named-remote URL preflight remain the preconditions for every setup write path, including context-only bootstrap. The gate classifies only an explicit Git `not a git repository` result and an actually missing/empty named-remote URL as typed user errors; Git/process/configuration and remote-lookup execution failures remain runtime errors with technical sources preserved. +- Default-discovered invalid repo-local config is degradable and never rewritten; explicit `--config` / `SCE_CONFIG_FILE` selections remain fatal, while absent local config remains create-if-missing. - Context baseline bootstrap is independent of config/DB/hooks install and runs before those steps on normal setup paths. - Local bootstrap (repo config + local DB init) is independent of config install and hook install; it runs before both after context baseline bootstrap. -- The bootstrap payload matches the `$schema` declaration accepted by startup config loading and the Pkl-authored JSON Schema embedded from Cargo `OUT_DIR`. +- The bootstrap payload matches the `$schema` declaration accepted by startup config loading and the Pkl-authored JSON Schema embedded from Cargo `OUT_DIR`; its explicit `agent_trace.auto_sync: true` is distinct from the runtime resolver's `false` fallback for omitted values. -See also [the fail-closed boundary decision](../decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md). +See also [the degraded discovered-config boundary decision](../decisions/2026-09-04-setup-storage-degrade-invalid-discovered-config.md) and the superseded [fail-closed boundary decision](../decisions/2026-08-26-setup-storage-fail-closed-on-invalid-config.md).