Commit graph

187 commits

Author SHA1 Message Date
Bryan Helmkamp
906868c30c
drop unused test-support feature from fabro-config
SettingsLayer::{test_default, ensure_test_auth_methods} are `pub(crate)`
and only called from fabro-config's own in-crate tests, but their impl
block was gated on `cfg(any(test, feature = "test-support"))`. No
external crate enabled the `test-support` feature, so under
`--all-features` the methods compiled in without reachable callers and
clippy flagged them as dead code. Narrow the gate to `cfg(test)` and
drop the vestigial feature entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 22:29:29 -04:00
Bryan Helmkamp
64dbdf2500
fix(ci): resolve workspace test and lint regressions 2026-04-23 20:49:30 -04:00
Bryan Helmkamp
d380c8f496
drop vestigial fabro-macros dep and DurationLayer aliases
After Unit 3.1 of the config boundary refactor, fabro-types no longer has
any #[derive(Combine)] sites — the fabro-macros dep is unused. Likewise
`Duration as DurationLayer` was an artifact from when layer and vocabulary
types lived side-by-side; the resolved Duration type has no Layer form now,
so the alias was misleading.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 20:06:19 -04:00
Bryan Helmkamp
f16becd2f7
clean up settings warning fallout 2026-04-23 19:53:40 -04:00
Bryan Helmkamp
6fc7251471
close config boundary audit and settings snapshot naming 2026-04-23 19:30:30 -04:00
Bryan Helmkamp
941c6e83f9
route fabro-config parsing through settings fromstr 2026-04-23 19:20:02 -04:00
Bryan Helmkamp
1bd7b7688f
lock down sparse settings exports in fabro-types 2026-04-23 19:10:45 -04:00
Bryan Helmkamp
73a47c1256
move fabro-config hidden settings tests in-crate 2026-04-23 19:04:57 -04:00
Bryan Helmkamp
9a898b12cd
move sparse settings layers into fabro-config 2026-04-23 18:10:12 -04:00
Bryan Helmkamp
b9fe542c5b
move serve runtime resolution behind config helper 2026-04-23 17:45:09 -04:00
Bryan Helmkamp
12ca64f5bf
route manifest assembly through builder source setters 2026-04-23 17:40:24 -04:00
Bryan Helmkamp
7d2600126a
drop raw settings merges from cli loaders 2026-04-23 17:37:22 -04:00
Bryan Helmkamp
2c55f10e62
store manifest defaults as run layers 2026-04-23 17:33:31 -04:00
Bryan Helmkamp
a5978b0b3c
split cli manifest overrides into run and cli layers 2026-04-23 17:28:45 -04:00
Bryan Helmkamp
2ec9e8bcdc
route project config discovery through file-based builders 2026-04-23 17:22:47 -04:00
Bryan Helmkamp
134d8c32d5
add dense run settings builder 2026-04-23 16:37:00 -04:00
Bryan Helmkamp
3cc094316b
add dense run goal and working dir helpers 2026-04-23 16:20:11 -04:00
Bryan Helmkamp
4c8f7fe164
use workflow builders in root and run fixtures 2026-04-23 15:20:42 -04:00
Bryan Helmkamp
662825ac65
use toml builders in config fixtures 2026-04-23 15:15:05 -04:00
Bryan Helmkamp
2a60b6c3dc
add workflow settings builder toml entrypoint 2026-04-23 15:12:48 -04:00
Bryan Helmkamp
68b9fc13a5
inline builtin defaults layer 2026-04-23 15:09:05 -04:00
Bryan Helmkamp
dc6a92e696
drop public settings load wrappers 2026-04-23 14:59:48 -04:00
Bryan Helmkamp
2ee9850abb
drop server resolve wrapper 2026-04-23 14:57:10 -04:00
Bryan Helmkamp
916b97c0ad
drop cli and features resolve wrappers 2026-04-23 14:43:07 -04:00
Bryan Helmkamp
43d32464a2
drop project run workflow resolve wrappers 2026-04-23 14:40:09 -04:00
Bryan Helmkamp
e20d8d9435
route project namespace resolution through workflow builders 2026-04-23 14:38:54 -04:00
Bryan Helmkamp
30986207cb
trim config wrapper and storage override helpers 2026-04-23 12:01:49 -04:00
Bryan Helmkamp
9220af6e80
migrate remaining run settings consumers to dense snapshots 2026-04-23 11:55:12 -04:00
Bryan Helmkamp
b2bcf0d5a8
refactor settings builders and dense run snapshots 2026-04-23 11:35:21 -04:00
Bryan Helmkamp
a770eb8e12
Merge remote-tracking branch 'origin/main' 2026-04-23 08:52:44 -04:00
Bryan Helmkamp
fc4e0381ac
simplify: dedupe splice helpers, trim dead map wrapper surface
- Collapse splice_model_fallbacks and splice_events into a single
  generic splice_combine guarded by a new SpliceMarker trait; the
  Combine impl for Vec<T: SpliceMarker> replaces the two per-enum impls.
- Drop inherent iter/iter_mut (redundant with Deref/DerefMut),
  AsRef/AsMut, and IntoIterator for &_/&mut _ on ReplaceMap/StickyMap/
  MergeMap — they had zero external callers. DerefMut and IntoIterator
  for Self stay because labels.extend(...) relies on both.
- Drop unused _api parameter on resolve_web.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:52:41 -04:00
Bryan Helmkamp
da9453cbd1
refactor(config): move settings combine into types 2026-04-23 08:42:19 -04:00
Bryan Helmkamp
37cd8ff45f
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-server/src/lib.rs
#	lib/crates/fabro-server/src/serve.rs
#	lib/crates/fabro-server/src/server.rs
2026-04-23 08:34:44 -04:00
Bryan Helmkamp
f5758d99d0
refactor(config): collapse settings resolver 2026-04-23 08:00:56 -04:00
Bryan Helmkamp
e6e091fe8e
refactor(server): lock down server secrets 2026-04-23 07:15:27 -04:00
Bryan Helmkamp
ec18c1864b
simplify: rename Resolver::from_file → from_layer and trim docs
The fresh `Resolver` API takes a `&SettingsLayer`, not a file path, so
its constructor should match the existing `ServerSettings::from_layer`
and `UserSettings::from_layer` naming. The `*_from_file` suffix on the
older free helpers is a legacy choice (their input was historically
loaded from a file); leave those names alone since they're a stable
public API used across many call sites.

Also drop two doc-comment references to specific call sites (the simplify
guidelines treat those as rot bait — call sites move, the doc lies).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:21:43 -04:00
Bryan Helmkamp
52d24531df
simplify: introduce Resolver to apply settings defaults once
Previously, each per-namespace `resolve_*_from_file` helper, together with
`resolve_storage_root` and the `*Settings::from_layer` constructors, called
`apply_builtin_defaults(file.clone())` independently. That meant every
batch resolve cloned the entire `SettingsLayer` (including hooks, MCPs,
sandbox config, etc.) and merged the static defaults layer once per call.
The worst offender, `fabro_workflow::operations::create::resolve_settings_tree`,
ran that pipeline four times back-to-back per `create_run` request.

Add `fabro_config::Resolver`, which applies builtin defaults exactly once
on construction and exposes per-namespace methods (`server`, `cli`,
`features`, `project`, `run`, `workflow`, `storage_root`) plus low-level
`*_into(&mut errors)` variants for callers that want to merge errors
across multiple namespaces. The standalone `resolve_*_from_file` helpers
and `resolve_storage_root` remain on the public API, but each is now a
one-liner that delegates to `Resolver::from_file(...)` so single-namespace
callers see no behavior change.

Migrate the multi-namespace consumers:
- `ServerSettings::from_layer` and `UserSettings::from_layer` build one
  `Resolver` and call the `*_into` pair, preserving the original
  "surface all errors from both namespaces" semantics.
- `resolve_settings_tree` builds one `Resolver` and pulls all four
  namespaces from it, dropping three redundant defaulting+clone passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:18:20 -04:00
Bryan Helmkamp
2dfefe36e9
simplify: dedupe render_resolve_errors across crates
Three byte-identical copies of `render_resolve_errors` had drifted into
`fabro-server/src/run_manifest.rs`, `fabro-workflow/src/operations/start.rs`,
and `fabro-workflow/src/operations/create.rs`. Each one folded a
`&[ResolveError]` into a semicolon-separated string for surfacing through
`anyhow!` / `Error::Precondition` envelopes.

Promote the helper to `fabro_config::render_resolve_errors` (it lives next
to `ResolveError`, the type it acts on) and rewrite the four call sites
in workflow ops plus the one in run_manifest to call the shared version.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:54:05 -04:00
Bryan Helmkamp
a6e755c200
simplify: dedupe storage-root override + cache demo settings
- Promote `apply_storage_dir_override` to `fabro_config::user` so the
  serve startup path stops carrying its own copy of the storage-root
  mutation that already lived in `fabro-cli/user_config.rs`.
- Inline the `load_settings` and `router_web_enabled` one-liner wrappers
  in `fabro-server/src/serve.rs` and drop the dead
  `let _ = CliLayer::default()` marker.
- Cache the demo `server_settings()` JSON in a `OnceLock` so the demo
  mode stops re-parsing TOML, re-resolving, and re-serializing the same
  static fixture on every `GET /api/v1/settings` request.
- Standardize the four `state.settings.read().unwrap()` callsites in
  `fabro-server/src/server.rs` on `.expect("settings lock poisoned")`
  to match the existing convention.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:47:00 -04:00
Bryan Helmkamp
28a9f036d8
fix: server-side settings authority + unit tests that never hit live S3
Two related correctness bugs surfaced by the failing test suite:

1. Server-owned settings didn't flow into run settings, and the few
   server-only fields that did leak in made run snapshots bulky and let
   callers re-resolve server state from the run layer.

   - effective_settings::materialize_settings_layer now treats the
     server's run/features stanzas as base defaults (client layers
     still win where set), and enforce_server_authority keeps the
     original cherry-pick of storage/scheduler/artifacts/web/api but
     no longer lets the rest of the server namespace propagate. auth,
     listen, ip_allowlist, slatedb, logging, and integrations stay on
     the server, where AppState::server_settings() already has them.

   - run_preflight, the scheduler start-path, and operations::start
     now read GitHub integrations from state.server_settings() (or
     StartServices::github_permissions, which the server populates)
     instead of re-resolving the server namespace from the run's
     settings layer.

   - create_app_state{_with_options,_with_env_lookup,_with_options_and_registry_factory}
     and create_app_state_with_store_and_env_lookup all route through
     ensure_test_auth_methods so the strict resolver accepts
     SettingsLayer::default() in tests.

   - Fixed the start_run_persists_full_settings_snapshot assertion
     that expected server.integrations.github.app_id in the run's
     persisted settings — the new design deliberately omits it.

2. Unit and integration tests were hitting live AWS S3.

   - Added a NoProxyReqwestConnector (behind a dedicated reqwest 0.12
     dep aliased as object_store_reqwest) and wired it through
     AmazonS3Builder::with_http_connector. macOS SystemConfiguration
     proxy discovery in the default reqwest client was blowing past
     nextest's 20s kill timeout on serve.rs's S3 builder unit tests;
     the no-proxy connector brings them under 15ms.

   - InstallAppState::for_test_with_paths now sets
     FABRO_TEST_IN_MEMORY_STORE=1 so /install/finish's artifact-metadata
     sentinel write short-circuits to the in-memory object store and
     never contacts AWS. The install integration tests verify
     persistence/redaction, not S3 reachability.

`cargo nextest run --workspace`: 4495/4495 passing.
`cargo +nightly-2026-04-14 fmt --check --all`: clean.
`cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings`: clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:15:56 -04:00
Bryan Helmkamp
2ddbe49cb8
lint: fix clippy absolute_paths & disallowed_methods after merge
- Import serde:🇩🇪:Error trait so the `custom` fn pointer uses `D::Error`
  instead of the absolute `serde:🇩🇪:Error::custom` path.
- Import `fabro_api::types::ServerSettings` / `fabro_config::UserSettings`
  directly rather than through absolute paths.
- Gate sync `std::fs::write` fixture setup in new config resolver tests
  with a file-level `#![expect(clippy::disallowed_methods, …)]`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:48:20 -04:00
Bryan Helmkamp
fa62da5d9d
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-api/build.rs
#	lib/crates/fabro-server/src/install.rs
#	lib/crates/fabro-server/src/serve.rs
#	lib/packages/fabro-api-client/src/.openapi-generator/FILES
#	lib/packages/fabro-api-client/src/models/index.ts
2026-04-22 21:18:50 -04:00
Bryan Helmkamp
93b6577cd3
simplify: drop duplicate settings plumbing from cli/server refactor
- Remove CommandContext::cli_settings and cascade through 11 functions
  whose only use of `cli: &CliNamespace` was constructing it; dispatchers
  now forward only cli_layer.
- Drop `ServerSettings as CurrentServerSettings` /
  `ServerNamespace as ResolvedServerSettings` rename aliases; use the
  canonical type names in fabro-server.
- Inline `local_server::server_settings` and `user_config::{resolve_user_settings,
  resolve_cli_settings}` wrappers; callers use `ServerSettings::from_layer`
  / `UserSettings::from_layer` directly (anyhow converts via `?`).
- Trim narrative module doc in fabro-config/src/lib.rs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:02:37 -04:00
Bryan Helmkamp
732e6f96f3
lint(install): fix clippy warnings missed in feat commit
Some checks are pending
Rust / Boundary (push) Waiting to run
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
Clean up clippy -D warnings violations that slipped through in 4bf0c4031:

- envfile.rs: extend the existing module-level #![expect] to also cover clippy::disallowed_types so the intentional std::io::Write usage stops tripping the workspace lint.
- install.rs: import ServerSecrets and EnvFileUpdate at the top and drop the fully-qualified call sites (unused_qualifications); collapse the nested if-let around the post-finish manual-credentials cleanup (collapsible_match); gate the test's std::fs::write with #[expect(clippy::disallowed_methods, reason="...")].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 20:49:14 -04:00
Bryan Helmkamp
4bf0c40319
feat(install): add object-store step to web install 2026-04-22 19:31:09 -04:00
Bryan Helmkamp
ebb8bf7add
refactor settings API entrypoints 2026-04-22 18:58:47 -04:00
Bryan Helmkamp
911f957200
refactor(config): move Bind and ServerDaemon into fabro-config
`Bind` and `ServerDaemon` are serde-serialized descriptions of on-disk
server state (the `server.json` record). They belong with
`RuntimeDirectory` in fabro-config rather than in fabro-server's web
layer.

The practical payoff: fabro-test was hand-parsing `server.json` via
`serde_json::Value["pid"]` because fabro-server already depends on
fabro-test (cycle blocked the reverse edge). Moving these types into
fabro-config lets fabro-test call `ServerDaemon::{load_running, read,
remove}` directly, dropping ~20 lines of duplicated record parsing.

fabro-config gains `fabro-proc` and `tempfile` as deps to cover
`ServerDaemon::{is_running, write}`. All 16 `fabro_server::{bind,
daemon}` import sites in fabro-server and fabro-cli are rewritten to
`fabro_config::{bind, daemon}`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:44:59 -04:00
Bryan Helmkamp
7a58ab4e2b
refactor(server): unify daemon runtime metadata 2026-04-22 16:07:52 -04:00
Bryan Helmkamp
2cb6235617
refactor(types): centralize test SettingsLayer fixture builder
Add SettingsLayer::test_default() and SettingsLayer::ensure_test_auth_methods()
to fabro-types behind a "test-support" feature, then collapse the five
near-identical ensure_fixture_auth_methods/default_settings/test_default_settings
helpers that the dev-token gating cleanup spread across fabro-config,
fabro-server, and fabro-workflow.

Why: the next required SettingsLayer field would otherwise need updating in
five places. With the canonical helper in fabro-types, adding a required field
becomes a one-line change.

The cfg(any(test, feature = "test-support")) gate keeps the helpers out of
production builds. Consumer crates enable the feature via dev-dependencies.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:56:42 -04:00
Bryan Helmkamp
041aca3ea3
chore: fix pre-existing clippy lints and missing-auth-methods test failures
After removing the implicit [server.auth] dev-token default, several unit
tests still passed empty SettingsLayer values into paths that resolve
server settings, so they panicked with "server.auth.methods: field is
required". Restore them by injecting dev-token methods in test fixtures
(consistent with the existing fabro-config resolve_server test pattern),
and rescue create_test_app_state_with_session_key, which bypassed the
existing ensure_test_auth_methods helper.

Clippy clean-ups unblock `cargo clippy --workspace -- -D warnings`:
- fabro-config: bring SettingsLayer into scope, flatten single-arm match
- fabro-cli: gate storage_dir unit tests with allow(deprecated), drop
  unnecessary borrow, scope effective_settings imports, drop needless
  raw-string hashes
- fabro-server: replace Option<Option<String>> test helper with an
  EnvOverride enum, widen test unwrap → expect

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:17:56 -04:00