From 3443b880ea100b673613bc5f05190b5b49141b1e Mon Sep 17 00:00:00 2001 From: stefanskoricdev Date: Tue, 1 Sep 2026 15:38:27 +0200 Subject: [PATCH 1/2] config: Add descriptions and defaults to schema Add descriptive metadata and explicit defaults to the generated configuration schema, while documenting runtime default resolution separately. Co-authored-by: SCE --- config/pkl/base/sce-config-schema.pkl | 38 +++++++++++++++++++---- context/cli/config-precedence-contract.md | 4 +-- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/config/pkl/base/sce-config-schema.pkl b/config/pkl/base/sce-config-schema.pkl index 49d99fec..f486e531 100644 --- a/config/pkl/base/sce-config-schema.pkl +++ b/config/pkl/base/sce-config-schema.pkl @@ -27,23 +27,28 @@ local mutuallyExclusiveConstraints = bash_policy_presets.mutually_exclusive.toLi local retryPolicyFieldsSchema = new JsonSchema { type = "object" + description = "Retry timing and attempt limits for one database operation." additionalProperties = false required = new { "max_attempts"; "timeout_ms"; "initial_backoff_ms"; "max_backoff_ms" } properties { ["max_attempts"] = new JsonSchema { type = "integer" + description = "Maximum number of attempts for the operation." minimum = 1 } ["timeout_ms"] = new JsonSchema { type = "integer" + description = "Timeout in milliseconds for each attempt." minimum = 1 } ["initial_backoff_ms"] = new JsonSchema { type = "integer" + description = "Initial retry backoff in milliseconds." minimum = 0 } ["max_backoff_ms"] = new JsonSchema { type = "integer" + description = "Maximum retry backoff in milliseconds." minimum = 0 } } @@ -51,6 +56,7 @@ local retryPolicyFieldsSchema = new JsonSchema { local perDbRetrySchema = new JsonSchema { type = "object" + description = "Retry policy overrides for a database's connection and query operations." additionalProperties = false properties { ["connection_open"] = retryPolicyFieldsSchema @@ -72,36 +78,45 @@ local sceConfigSchema = new JsonSchema { } ["log_level"] = new JsonSchema { type = "string" + description = "Minimum severity of log records." enum = new { "error"; "warn"; "info"; "debug" } + default = "error" } ["log_format"] = new JsonSchema { type = "string" + description = "Format used for log records." enum = new { "text"; "json" } + default = "text" } ["log_to_file"] = new JsonSchema { type = "boolean" - description = "Write log records to the configured log directory. Defaults to true." + description = "Write log records to the configured log directory." default = true } ["log_dir"] = new JsonSchema { type = "string" + description = "Directory for log files when file logging is enabled." minLength = 1 + default = "/sce/logs" } ["log_file_retention_limit"] = new JsonSchema { type = "integer" + description = "Maximum number of log files retained." minimum = 1 default = 10 } ["timeout_ms"] = new JsonSchema { type = "integer" + description = "Timeout value in milliseconds for config operations." minimum = 0 } ["workos_client_id"] = new JsonSchema { type = "string" + description = "WorkOS client ID used for authentication." } ["control_plane_base_url"] = new JsonSchema { type = "string" - description = "Base URL of the control-plane Agent Trace ingestion API used by `sce trace sync`. Defaults to the canonical SCE control plane." + description = "Base URL of the control-plane Agent Trace ingestion API used by `sce trace sync`." minLength = 1 } ["agent_trace"] = new JsonSchema { @@ -116,35 +131,37 @@ local sceConfigSchema = new JsonSchema { } ["repository_remote"] = new JsonSchema { type = "string" - description = "Git remote name used to derive repository identity. Defaults to origin when omitted." + description = "Git remote name used to derive repository identity." minLength = 1 default = "origin" } ["auto_sync"] = new JsonSchema { type = "boolean" - description = "Launch a detached, best-effort `sce sync` after successful post-commit Agent Trace persistence. Defaults to true." + description = "Launch a detached, best-effort `sce sync` after successful post-commit Agent Trace persistence." default = true } } } ["policies"] = new JsonSchema { type = "object" + description = "Policy configuration for SCE runtime and bash-tool enforcement." additionalProperties = false properties { ["attribution_hooks"] = new JsonSchema { type = "object" - description = "Attribution hook policy. Commit-msg attribution is enabled by default and can be suppressed with SCE_ATTRIBUTION_HOOKS_DISABLED=1 or by setting enabled to false." + description = "Policy for commit-msg attribution hooks." additionalProperties = false properties { ["enabled"] = new JsonSchema { type = "boolean" - description = "Enable SCE attribution hooks. Defaults to true when omitted; set false as an explicit opt-out. Environment opt-out: SCE_ATTRIBUTION_HOOKS_DISABLED." + description = "Enable SCE attribution hooks." default = true } } } ["database_retry"] = new JsonSchema { type = "object" + description = "Per-database retry policy overrides for local, Agent Trace, and auth databases." additionalProperties = false properties { ["local_db"] = perDbRetrySchema @@ -154,10 +171,12 @@ local sceConfigSchema = new JsonSchema { } ["bash"] = new JsonSchema { type = "object" + description = "Bash-tool command blocking policy configuration." additionalProperties = false properties { ["presets"] = new JsonSchema { type = "array" + description = "Built-in bash-tool policy preset IDs to enable." uniqueItems = true items = new JsonSchema { type = "string" @@ -167,6 +186,7 @@ local sceConfigSchema = new JsonSchema { } ["custom"] = new JsonSchema { type = "array" + description = "Repository-defined bash-tool policies with custom matching and messages." items = new JsonSchema { type = "object" additionalProperties = false @@ -174,6 +194,7 @@ local sceConfigSchema = new JsonSchema { properties { ["id"] = new JsonSchema { type = "string" + description = "Unique identifier for the custom bash policy." minLength = 1 not = new JsonSchema { enum = presetIds @@ -181,11 +202,13 @@ local sceConfigSchema = new JsonSchema { } ["match"] = new JsonSchema { type = "object" + description = "Command matching rule for the custom bash policy." additionalProperties = false required = new { "argv_prefix" } properties { ["argv_prefix"] = new JsonSchema { type = "array" + description = "Leading command arguments that activate the policy." minItems = 1 items = new JsonSchema { type = "string" @@ -208,6 +231,7 @@ local sceConfigSchema = new JsonSchema { } ["message"] = new JsonSchema { type = "string" + description = "User-facing message shown when the policy blocks a command." minLength = 1 } } @@ -219,10 +243,12 @@ local sceConfigSchema = new JsonSchema { } ["integrations"] = new JsonSchema { type = "object" + description = "Integration targets and optional workflows selected for SCE setup." additionalProperties = false properties { ["target"] = new JsonSchema { type = "array" + description = "Integration targets into which SCE assets are installed." uniqueItems = true items = new JsonSchema { type = "string" diff --git a/context/cli/config-precedence-contract.md b/context/cli/config-precedence-contract.md index f498e205..e4f71711 100644 --- a/context/cli/config-precedence-contract.md +++ b/context/cli/config-precedence-contract.md @@ -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; the generated schema documents default `origin`. +- `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`. - `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. @@ -107,7 +107,7 @@ When a default-discovered global or repo-local config file exists but fails JSON - `sce setup` writes this key: it records the selection resolved for the run and reads the stored value back when `--workflow` is absent, which is the only consumer of the key today. See [setup local bootstrap](../sce/setup-repo-local-config-bootstrap.md). - `policies` must be an object when present and currently allows `attribution_hooks`, `database_retry`, and `bash`. -- `policies.attribution_hooks` must be an object when present and currently allows `enabled`; the generated schema documents default `true`, and explicit `enabled: false` remains a valid opt-out alongside the runtime `SCE_ATTRIBUTION_HOOKS_DISABLED` environment opt-out. +- `policies.attribution_hooks` must be an object when present and currently allows `enabled`; explicit `enabled: false` remains a valid opt-out alongside the runtime `SCE_ATTRIBUTION_HOOKS_DISABLED` environment opt-out. - `policies.bash` must be an object when present and currently allows only `presets` and `custom`. - `policies.bash.presets` must be an array of unique built-in preset IDs: `forbid-git-all`, `forbid-git-commit`, `use-pnpm-over-npm`, `use-bun-over-npm`, `use-nix-flake-over-cargo`. - `use-pnpm-over-npm` and `use-bun-over-npm` are mutually exclusive and fail validation when both are present. From dfd5df42289e9240c1ef7053d663bbe3ce55612b Mon Sep 17 00:00:00 2001 From: stefanskoricdev Date: Tue, 1 Sep 2026 16:00:29 +0200 Subject: [PATCH 2/2] config: Remove unused top-level timeout configuration Remove the unconsumed timeout_ms setting, SCE_TIMEOUT_MS environment override, and config command flags so the CLI only exposes operational configuration. Align schema validation, resolution, output, and documentation with the reduced surface while preserving nested retry timeout behavior. Co-authored-by: SCE --- cli/src/cli_schema.rs | 6 -- cli/src/services/command_registry.rs | 1 - cli/src/services/config/render.rs | 10 --- cli/src/services/config/resolver.rs | 41 ------------ cli/src/services/config/schema.rs | 9 +-- cli/src/services/config/types.rs | 1 - cli/src/services/parse/command_runtime.rs | 4 -- config/pkl/base/sce-config-schema.pkl | 5 -- context/cli/config-precedence-contract.md | 16 ++--- context/context-map.md | 1 + ...6-09-01-remove-top-level-config-timeout.md | 65 +++++++++++++++++++ context/overview.md | 2 +- 12 files changed, 76 insertions(+), 85 deletions(-) create mode 100644 context/decisions/2026-09-01-remove-top-level-config-timeout.md diff --git a/cli/src/cli_schema.rs b/cli/src/cli_schema.rs index a7dc33bc..6ecc1ffe 100644 --- a/cli/src/cli_schema.rs +++ b/cli/src/cli_schema.rs @@ -274,9 +274,6 @@ pub enum ConfigSubcommand { #[arg(long, value_enum)] log_level: Option, - - #[arg(long)] - timeout_ms: Option, }, #[command(about = "Validate config files and report pass/fail with errors or warnings")] @@ -289,9 +286,6 @@ pub enum ConfigSubcommand { #[arg(long, value_enum)] log_level: Option, - - #[arg(long)] - timeout_ms: Option, }, } diff --git a/cli/src/services/command_registry.rs b/cli/src/services/command_registry.rs index b38f903e..07f26190 100644 --- a/cli/src/services/command_registry.rs +++ b/cli/src/services/command_registry.rs @@ -137,7 +137,6 @@ pub fn default_runtime_command(name: &str) -> Option { report_format: services::config::ReportFormat::Text, config_path: None, log_level: None, - timeout_ms: None, }, ), }, diff --git a/cli/src/services/config/render.rs b/cli/src/services/config/render.rs index c8d764a7..571a7db8 100644 --- a/cli/src/services/config/render.rs +++ b/cli/src/services/config/render.rs @@ -27,11 +27,6 @@ pub(super) fn format_show_output(runtime: &RuntimeConfig, report_format: ReportF style::value(PRECEDENCE_DESCRIPTION) ), format_config_paths_text(runtime), - format_resolved_value_text( - "timeout_ms", - &runtime.timeout_ms.value.to_string(), - runtime.timeout_ms.source, - ), format_optional_auth_resolved_value_text( WORKOS_CLIENT_ID_KEY, &runtime.workos_client_id, @@ -86,11 +81,6 @@ pub(super) fn format_show_output(runtime: &RuntimeConfig, report_format: ReportF runtime.log_file_retention_limit.value, runtime.log_file_retention_limit.source, ), - "timeout_ms": { - "value": runtime.timeout_ms.value, - "source": runtime.timeout_ms.source.as_str(), - "config_source": runtime.timeout_ms.source.config_source().map(ConfigPathSource::as_str), - }, "workos_client_id": format_optional_auth_resolved_value_json(WORKOS_CLIENT_ID_KEY, &runtime.workos_client_id), "control_plane_base_url": format_optional_auth_resolved_value_json(CONTROL_PLANE_BASE_URL_KEY, &runtime.control_plane_base_url), "agent_trace": { diff --git a/cli/src/services/config/resolver.rs b/cli/src/services/config/resolver.rs index 38b28e77..0d07e793 100644 --- a/cli/src/services/config/resolver.rs +++ b/cli/src/services/config/resolver.rs @@ -22,7 +22,6 @@ use super::types::{ ENV_ATTRIBUTION_HOOKS_DISABLED, ENV_LOG_DIR, ENV_LOG_FORMAT, ENV_LOG_LEVEL, }; -const DEFAULT_TIMEOUT_MS: u64 = 30000; pub(crate) const DEFAULT_AGENT_TRACE_REPOSITORY_REMOTE: &str = "origin"; pub(crate) const PRECEDENCE_DESCRIPTION: &str = "flags > env > config file > defaults"; const WORKOS_CLIENT_ID_ENV: &str = "WORKOS_CLIENT_ID"; @@ -73,7 +72,6 @@ pub(super) struct RuntimeConfig { pub(super) log_to_file: ResolvedValue, pub(super) log_dir: ResolvedOptionalValue, pub(super) log_file_retention_limit: ResolvedValue, - pub(super) timeout_ms: ResolvedValue, pub(super) attribution_hooks_enabled: ResolvedValue, pub(super) workos_client_id: ResolvedOptionalValue, pub(super) control_plane_base_url: ResolvedOptionalValue, @@ -135,7 +133,6 @@ pub(crate) fn resolve_agent_trace_auto_sync_runtime_config( report_format: ReportFormat::Text, config_path: None, log_level: None, - timeout_ms: None, }, cwd, |key| std::env::var(key).ok(), @@ -182,7 +179,6 @@ where report_format: ReportFormat::Text, config_path: None, log_level: None, - timeout_ms: None, }, cwd, env_lookup, @@ -210,7 +206,6 @@ pub(crate) fn resolve_bash_policy_runtime_config(cwd: &Path) -> Result() - .map_err(|_| anyhow!("Invalid timeout '{raw}' from SCE_TIMEOUT_MS."))?; - resolved_timeout_ms = ResolvedValue { - value, - source: ValueSource::Env, - }; - } - if let Some(value) = request.timeout_ms { - resolved_timeout_ms = ResolvedValue { - value, - source: ValueSource::Flag, - }; - } - let mut resolved_attribution_hooks_enabled = ResolvedValue { value: true, source: ValueSource::Default, @@ -623,7 +585,6 @@ where log_to_file: resolved_log_to_file, log_dir: resolved_log_dir, log_file_retention_limit: resolved_log_file_retention_limit, - timeout_ms: resolved_timeout_ms, attribution_hooks_enabled: resolved_attribution_hooks_enabled, workos_client_id: resolved_workos_client_id, control_plane_base_url: resolved_control_plane_base_url, @@ -786,7 +747,6 @@ pub(crate) fn init_database_retry_config_from_environment(cwd: &Path) { report_format: ReportFormat::Text, config_path: None, log_level: None, - timeout_ms: None, }, cwd, ) { @@ -815,7 +775,6 @@ mod tests { report_format: ReportFormat::Text, config_path: None, log_level: None, - timeout_ms: None, } } diff --git a/cli/src/services/config/schema.rs b/cli/src/services/config/schema.rs index 846eab52..c3723f0f 100644 --- a/cli/src/services/config/schema.rs +++ b/cli/src/services/config/schema.rs @@ -37,7 +37,6 @@ pub(crate) const TOP_LEVEL_CONFIG_KEYS: &[&str] = &[ "log_to_file", "log_dir", "log_file_retention_limit", - "timeout_ms", super::resolver::WORKOS_CLIENT_ID_KEY.config_key, super::resolver::CONTROL_PLANE_BASE_URL_KEY.config_key, "agent_trace", @@ -46,7 +45,7 @@ pub(crate) const TOP_LEVEL_CONFIG_KEYS: &[&str] = &[ ]; pub(crate) const TOP_LEVEL_CONFIG_KEYS_DESCRIPTION: &str = - "$schema, log_level, log_format, log_to_file, timeout_ms, workos_client_id, control_plane_base_url, agent_trace, policies, integrations, log_dir, log_file_retention_limit"; + "$schema, log_level, log_format, log_to_file, workos_client_id, control_plane_base_url, agent_trace, policies, integrations, log_dir, log_file_retention_limit"; static CONFIG_SCHEMA_VALIDATOR: OnceLock = OnceLock::new(); @@ -75,7 +74,6 @@ pub(crate) struct ParsedFileConfigDocument { pub(crate) log_to_file: Option, pub(crate) log_dir: Option, pub(crate) log_file_retention_limit: Option, - pub(crate) timeout_ms: Option, pub(crate) workos_client_id: Option, pub(crate) control_plane_base_url: Option, pub(crate) agent_trace: Option, @@ -163,7 +161,6 @@ pub(crate) struct FileConfig { pub(crate) log_to_file: Option>, pub(crate) log_dir: Option>, pub(crate) log_file_retention_limit: Option>, - pub(crate) timeout_ms: Option>, pub(crate) attribution_hooks_enabled: Option>, pub(crate) workos_client_id: Option>, pub(crate) control_plane_base_url: Option>, @@ -312,9 +309,6 @@ pub(crate) fn parse_file_config( let log_file_retention_limit = typed .log_file_retention_limit .map(|value| FileConfigValue { value, source }); - let timeout_ms = typed - .timeout_ms - .map(|value| FileConfigValue { value, source }); let workos_client_id = typed .workos_client_id .map(|value| FileConfigValue { value, source }); @@ -333,7 +327,6 @@ pub(crate) fn parse_file_config( log_to_file, log_dir, log_file_retention_limit, - timeout_ms, attribution_hooks_enabled, workos_client_id, control_plane_base_url, diff --git a/cli/src/services/config/types.rs b/cli/src/services/config/types.rs index cc86c5b9..3ee843c3 100644 --- a/cli/src/services/config/types.rs +++ b/cli/src/services/config/types.rs @@ -167,7 +167,6 @@ pub struct ConfigRequest { pub report_format: ReportFormat, pub config_path: Option, pub log_level: Option, - pub timeout_ms: Option, } #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/cli/src/services/parse/command_runtime.rs b/cli/src/services/parse/command_runtime.rs index 31d56473..2f06a471 100644 --- a/cli/src/services/parse/command_runtime.rs +++ b/cli/src/services/parse/command_runtime.rs @@ -352,7 +352,6 @@ fn convert_config_subcommand( format, config, log_level, - timeout_ms, } => Ok(RuntimeCommand::Config( services::config::command::ConfigCommand { subcommand: services::config::ConfigSubcommand::Show( @@ -360,7 +359,6 @@ fn convert_config_subcommand( report_format: format, config_path: config, log_level, - timeout_ms, }, ), }, @@ -369,7 +367,6 @@ fn convert_config_subcommand( format, config, log_level, - timeout_ms, } => Ok(RuntimeCommand::Config( services::config::command::ConfigCommand { subcommand: services::config::ConfigSubcommand::Validate( @@ -377,7 +374,6 @@ fn convert_config_subcommand( report_format: format, config_path: config, log_level, - timeout_ms, }, ), }, diff --git a/config/pkl/base/sce-config-schema.pkl b/config/pkl/base/sce-config-schema.pkl index f486e531..2c7d2191 100644 --- a/config/pkl/base/sce-config-schema.pkl +++ b/config/pkl/base/sce-config-schema.pkl @@ -105,11 +105,6 @@ local sceConfigSchema = new JsonSchema { minimum = 1 default = 10 } - ["timeout_ms"] = new JsonSchema { - type = "integer" - description = "Timeout value in milliseconds for config operations." - minimum = 0 - } ["workos_client_id"] = new JsonSchema { type = "string" description = "WorkOS client ID used for authentication." diff --git a/context/cli/config-precedence-contract.md b/context/cli/config-precedence-contract.md index e4f71711..4c209647 100644 --- a/context/cli/config-precedence-contract.md +++ b/context/cli/config-precedence-contract.md @@ -8,8 +8,8 @@ The current implementation resolves flat logging keys and Agent Trace runtime ke ## Command surface -- `sce config show [--config ] [--log-level ] [--timeout-ms ] [--format ]` -- `sce config validate [--config ] [--log-level ] [--timeout-ms ] [--format ]` +- `sce config show [--config ] [--log-level ] [--format ]` +- `sce config validate [--config ] [--log-level ] [--format ]` - bare `sce config` returns the same help payload as `sce config --help` - `sce config --help` - Help text for `sce config`, `sce config show`, and `sce config validate` frames the command family as the operator entrypoint for config inspection and validation; `show` covers resolved runtime values with provenance, `validate` covers pass/fail plus validation issues and warnings, and bare `sce config` is help-first rather than defaulting to `show`. @@ -18,10 +18,10 @@ The current implementation resolves flat logging keys and Agent Trace runtime ke Resolved runtime values follow this deterministic order: -1. flag values (`--log-level`, `--timeout-ms`) -2. environment values (`SCE_LOG_LEVEL`, `SCE_TIMEOUT_MS`) -3. config file values (`log_level`, `timeout_ms`) -4. defaults (`log_level=error`, `timeout_ms=30000`) +1. flag values (`--log-level`) +2. environment values (`SCE_LOG_LEVEL`) +3. config file values (`log_level`) +4. defaults (`log_level=error`) Repo-configured bash-tool policy values are config-file only in this task slice: they load from `policies.bash` in the selected config files, merge `global -> local` alongside the rest of the config object, and currently have no flag or environment override layer. @@ -82,14 +82,13 @@ When a default-discovered global or repo-local config file exists but fails JSON - 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. - 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`, `timeout_ms`, `workos_client_id`, `control_plane_base_url`, `agent_trace`, `policies`, `integrations`. +- 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`. - Unknown keys fail validation. - `log_to_file` must be a boolean when present and defaults to `true`; it is independent of `log_dir`. - `log_level` must be one of `error|warn|info|debug`. - `log_format` must be `text` or `json` when present. - `log_dir` must be a non-empty string when present. - `log_file_retention_limit` must be an integer with minimum `1`; zero, negative, fractional, string, and object values fail schema validation. -- `timeout_ms` must be an unsigned integer. - `workos_client_id` must be a string when present. - `control_plane_base_url` must be a non-empty string when present. @@ -162,3 +161,4 @@ When a default-discovered global or repo-local config file exists but fails JSON - `cli/src/services/config/schema.rs` - `cli/src/services/config/policy.rs` - `context/cli/agent-trace-auto-sync.md` +- [Decision: Remove the unused top-level config timeout surface](../decisions/2026-09-01-remove-top-level-config-timeout.md) diff --git a/context/context-map.md b/context/context-map.md index b1985622..12e075ee 100644 --- a/context/context-map.md +++ b/context/context-map.md @@ -98,6 +98,7 @@ Supporting repo docs: Recent decision records: +- `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) - `context/decisions/2026-08-23-codex-event-scoped-apply-patch-evidence-identities.md` (uses bounded, deterministic `tool_use_id`-derived synthetic line identities for Codex apply_patch evidence; positions are evidence identities rather than source line numbers, with existing patch combination/intersection semantics unchanged) diff --git a/context/decisions/2026-09-01-remove-top-level-config-timeout.md b/context/decisions/2026-09-01-remove-top-level-config-timeout.md new file mode 100644 index 00000000..76e38996 --- /dev/null +++ b/context/decisions/2026-09-01-remove-top-level-config-timeout.md @@ -0,0 +1,65 @@ +# Decision: Remove the unused top-level config timeout surface + +Date: 2026-09-01 +Status: Accepted +Plan: `context/plans/remove-top-level-config-timeout.md` +Task: `T01` + +## Context + +The CLI exposed a top-level `timeout_ms` config key, `SCE_TIMEOUT_MS`, and +`--timeout-ms` options for `sce config show` and `sce config validate`, but no +operational runtime path consumed the resolved value. The canonical schema, +Rust config resolver, output contract, and active documentation nevertheless +advertised it. Database retry timeouts and unrelated runtime timeout constants +are independently used and must remain available. + +## Decision + +Remove the unused top-level timeout configuration surface without introducing a +replacement global timeout setting. + +## Rationale + +Removing dead configuration prevents users from relying on a setting that has +no operational effect and keeps the schema, CLI, resolver, output, and +documentation contracts aligned. Retaining nested database retry timeout +fields preserves the timeout controls that are actually consumed. + +## Alternatives considered + +- **Keep the setting for compatibility** — It would continue advertising a + configuration value with no runtime effect. +- **Replace it with a global operational timeout** — That expands scope into a + timeout redesign not established by the task. + +## Compatibility and risks + +- Existing configs using top-level `timeout_ms` and invocations using + `--timeout-ms` are rejected after this change; the schema and CLI now make + that removal explicit, while nested retry configuration remains compatible. + +## Guardrails + +- Do not remove `policies.database_retry.*.timeout_ms` or unrelated auth, + control-plane, database, and resilience timeout behavior. +- Keep generated schema artifacts ephemeral and document only the active + configuration contract. + +## Consequences + +- The supported top-level config key set and `sce config` command surface are + smaller and no longer imply a configurable global timeout. +- The remaining timeout fields have clearer ownership in retry or operational + runtime paths. + +## Follow-up + +- None. + +## References + +- Plan: [`remove-top-level-config-timeout`](../plans/remove-top-level-config-timeout.md) +- Task: `T01` +- Current-state context: [`CLI Config Precedence Contract`](../cli/config-precedence-contract.md) +- Evidence: [`sce-config-schema.pkl`](../../config/pkl/base/sce-config-schema.pkl) diff --git a/context/overview.md b/context/overview.md index 80959703..9aac2819 100644 --- a/context/overview.md +++ b/context/overview.md @@ -30,7 +30,7 @@ The `setup` command includes an `inquire`-backed target-selection flow: default For repository generation consumers, `config/pkl/generator-inputs.txt` declares the canonical Pkl/plugin input set and `scripts/produce-cli-generated-input.sh` owns its discovery, two-pass `config/pkl/generate.pkl` evaluation, determinism comparison, payload/input inventories, in-flight input-mutation rejection, atomic handoff publication, and staging cleanup. `scripts/run-cli-cargo.sh` creates a fresh temporary destination, delegates generation to that producer, invokes the requested Cargo workflow with `SCE_CLI_GENERATED_INPUT_DIR`, and removes the handoff after Cargo success, failure, or handled signals. `config/pkl/check-generated.sh` delegates the same production mechanics while retaining contract and path assertions. The root flake also runs `codex-hook-command`, which generates the Codex assets and verifies root, nested-cwd, spaced-path, stdin-forwarding, and fail-open invocation behavior against a stub `sce`. `scripts/prepare-cli-generated-assets.sh` moves the producer-validated Pkl payload and checksums into the unchanged package fallback, adds hooks, migrations, and the Agent Trace schema, and appends only those static checksums to the combined inventory. The root flake's pre-Cargo `cliGeneratedInput` derivation invokes the same producer from a declarative source containing the producer plus its declared inputs. `cli/build.rs` rejects missing, incomplete, modified, or stale repository handoffs, copies the validated payload into Cargo `OUT_DIR/pkl-generated`, stages static inputs under `OUT_DIR/static`, and writes setup-asset, optional-workflow-catalog, and migration Rust manifests into `OUT_DIR`; it never invokes Pkl. Published crates carry the ignored packaging-only fallback, and unpacked downstream builds validate and copy it into their own `OUT_DIR` without requiring Pkl or parent repository paths. The setup service also provides repository-root install orchestration: it resolves the repository root, ensures the additive durable-context baseline, then for normal modes derives a repo-root-scoped `AppContext` from the runtime command context, aggregates `ServiceLifecycle::setup` calls across lifecycle providers (config → local_db → auth_db → agent_trace_db → hooks when requested), handles interactive or flag-based target selection for config asset installation, and reports deterministic completion details (selected target(s) and installed file counts). Setup installs config assets (`.opencode`/`.claude`/`.pi`) per file: each embedded asset is staged and swapped into its own destination path, creating parent directories as needed, without removing or recreating the target directory as a whole, so files a repository owns inside an SCE-managed target directory survive a setup run untouched. Two assets are merge targets rather than verbatim writes: Claude's `.claude/settings.json` and OpenCode's `.opencode/opencode.json`. For each, setup JSON-merges the generated document into the user's existing file rather than overwriting it, and fails deterministically without writing if the existing file is not valid JSON; a missing file is still created from the generated document verbatim. Claude's merge replaces only SCE-owned hook entries (identified by a command containing `run-sce-or-show-install-guidance.sh`) and the `$schema` key while preserving every other key and hook entry untouched. OpenCode's merge replaces the `$schema` key and merges the `plugin` array as a set: any entry shaped like an SCE plugin path (`./plugins/sce-*`) is dropped, structurally, so a path an older or renamed catalog once installed is still recognized and pruned, and the generated document's canonical plugin entries are appended after the surviving user entries. Required-hook install uses the same per-file stage/atomic-swap choreography as config-asset install — the staging file is renamed directly over an existing hook without unlinking it first, so a rename failure leaves the prior hook untouched. Both flows return deterministic recovery guidance (recover from version control) on swap failure, without creating backup artifacts. After installing, config install prunes stale SCE-owned assets: it deletes every path the full embedded catalog for the target claims but the current selection did not install (a deselected optional workflow, or an asset a newer catalog renamed or dropped), then removes any parent directory left empty by that deletion, leaving a directory intact if a user file still lives inside it. The setup command gates all modes on an existing git repository before any writes. Internally, `cli/src/services/setup/mod.rs`now separates install-flow logic from interactive prompt logic through focused support seams. The CLI now also applies baseline security hardening for reliability-driven automation: diagnostics/logging paths use deterministic secret redaction,`sce setup --hooks --repo ` canonicalizes and validates repository paths before execution, and setup write flows run explicit directory write-permission probes before staging/swap operations. -The config service now provides deterministic runtime config resolution with explicit precedence (`flags > env > config file > defaults`), strict config-file validation (`$schema`, `log_level`, `log_format`, `log_to_file`, `log_dir`, `timeout_ms`, `workos_client_id`, and nested `policies.bash`, `policies.attribution_hooks.enabled`, plus `policies.database_retry` with per-DB `connection_open`/`query` retry policy specs), deterministic default discovery/merge of global+local config files (`${config*root}/sce/config.json`then`.sce/config.json`with local override, where`config_root` comes from the shared default-path seam with XDG/`dirs::config_dir()` config-root resolution), defaults for the resolved observability value set (`log_level=error`, `log_format=text`, `log_dir=/sce/logs`), shared auth-key resolution with optional baked defaults starting at `workos_client_id`, first-class bash-policy preset/custom parsing with deterministic conflict and duplicate-prefix validation, custom-policy `satisfied_by`wrapper exemption (a policy does not fire when the matched command was unwrapped from a declared wrapper such as`nix shell nixpkgs#ripgrep`), and a canonical Pkl-authored `sce/config.json`JSON Schema generated beneath Cargo`OUT_DIR`and embedded by`cli/src/services/config/mod.rs`for both`sce config validate`and doctor-time config checks. Runtime startup config loading keeps parity with that schema by accepting its`$schema`declaration in repo-local and global config files, so startup commands such as`sce version`no longer fail before dispatch on that field; the canonical declaration is versioned as`"https://sce.crocoder.dev/v/config.json"` using the CLI release version; this schema URL is separate from the `https://sce.crocoderlab.dev` baked default used by `sce sync` for control-plane ingestion. App-runtime observability now consumes flat logging keys through the shared resolver, so env values still override config-file values while config files provide deterministic fallback for `log_dir`; positive-integer `log_file_retention_limit` uses config-file/default precedence, defaults to `10`, and controls creation-triggered cleanup for primary and v2 log files; `sce config show` reports resolved observability/auth/policy values with provenance, while `sce config validate` is now a trimmed validation surface that reports only pass/fail plus validation errors or warnings in text and JSON modes. The canonical preset catalog and matching contract live in `config/pkl/base/bash-policy-presets.pkl` and `context/sce/bash-tool-policy-enforcement-contract.md`. +The config service now provides deterministic runtime config resolution with explicit precedence (`flags > env > config file > defaults`), strict config-file validation (`$schema`, `log_level`, `log_format`, `log_to_file`, `log_dir`, `workos_client_id`, and nested `policies.bash`, `policies.attribution_hooks.enabled`, plus `policies.database_retry` with per-DB `connection_open`/`query` retry policy specs), deterministic default discovery/merge of global+local config files (`${config*root}/sce/config.json`then`.sce/config.json`with local override, where`config_root` comes from the shared default-path seam with XDG/`dirs::config_dir()` config-root resolution), defaults for the resolved observability value set (`log_level=error`, `log_format=text`, `log_dir=/sce/logs`), shared auth-key resolution with optional baked defaults starting at `workos_client_id`, first-class bash-policy preset/custom parsing with deterministic conflict and duplicate-prefix validation, custom-policy `satisfied_by`wrapper exemption (a policy does not fire when the matched command was unwrapped from a declared wrapper such as`nix shell nixpkgs#ripgrep`), and a canonical Pkl-authored `sce/config.json`JSON Schema generated beneath Cargo`OUT_DIR`and embedded by`cli/src/services/config/mod.rs`for both`sce config validate`and doctor-time config checks. Runtime startup config loading keeps parity with that schema by accepting its`$schema`declaration in repo-local and global config files, so startup commands such as`sce version`no longer fail before dispatch on that field; the canonical declaration is versioned as`"https://sce.crocoder.dev/v/config.json"` using the CLI release version; this schema URL is separate from the `https://sce.crocoderlab.dev` baked default used by `sce sync` for control-plane ingestion. App-runtime observability now consumes flat logging keys through the shared resolver, so env values still override config-file values while config files provide deterministic fallback for `log_dir`; positive-integer `log_file_retention_limit` uses config-file/default precedence, defaults to `10`, and controls creation-triggered cleanup for primary and v2 log files; `sce config show` reports resolved observability/auth/policy values with provenance, while `sce config validate` is now a trimmed validation surface that reports only pass/fail plus validation errors or warnings in text and JSON modes. The canonical preset catalog and matching contract live in `config/pkl/base/bash-policy-presets.pkl` and `context/sce/bash-tool-policy-enforcement-contract.md`. Invalid default-discovered config files now also degrade gracefully at startup: `sce` keeps running with degraded observability defaults, logs `sce.config.invalid_config` warnings, and reserves hard failures for explicit `--config` / `SCE_CONFIG_FILE` targets or other truly invalid runtime observability inputs. `cli/src/services/config/mod.rs` is now a module facade that declares focused config submodules (`types`, `schema`, `policy`, `resolver`, private `render`, `command`, and `lifecycle`), re-exporting `pub use types::*`and`pub(crate) use schema::validate_config_file`. Shared config primitive ownership is delegated to `cli/src/services/config/types.rs`; schema loading and file parsing to `cli/src/services/config/schema.rs`; bash-policy semantic validation and policy-specific formatting to `cli/src/services/config/policy.rs`; runtime discovery/precedence to `cli/src/services/config/resolver.rs`; and `sce config show`/`sce config validate`text+JSON output construction to`cli/src/services/config/render.rs`. Downstream modules continue importing through `services::config`unchanged. The CLI now has a generic borrowed`AppContext`dependency view in`cli/src/app.rs`; `AppRuntime`owns concrete production logger/telemetry/fs/git dependencies, and command execution receives context views that borrow those dependencies plus an optional`repo_root: Option`. `AppContext::with_repo_root(...)`/`ContextWithRepoRoot`derives repo-root-scoped views while preserving the borrowed runtime dependencies, and command execution is generic over associated-type narrow accessor traits where practical. The broad capability seam lives in`cli/src/services/capabilities.rs`, where `FsOps`/`StdFsOps`wrap filesystem operations and`GitOps`/`ProcessGitOps`wrap git process execution plus repository-root/hooks-directory resolution. The shared default path service in`cli/src/services/default_paths.rs`is now the canonical owner for production CLI path definitions. It resolves per-user config/state/cache roots through a dedicated internal`roots`seam, exposes the current persisted-artifact inventory (global config and auth tokens), and also defines named DB paths (auth DB, local DB, Agent Trace DB) plus the repo-relative, install, hook, and context-path accessors consumed across current CLI production code. Non-test production modules should consume this shared catalog instead of hardcoding owned path literals. No default cache-backed persisted artifact currently exists, so cache-root resolution remains available without speculative cache-path features and no legacy default-path fallback is supported.