Commit graph

182 commits

Author SHA1 Message Date
Bryan Helmkamp
be084c1944
refactor(dev): decouple CLI reference generation
Expose the CLI reference renderer through a hidden fabro subcommand so fabro-dev can refresh docs without linking fabro-cli. Gate the fabro-dev binary behind the dev feature and update the cargo dev alias to opt into it explicitly.
2026-05-06 12:31:02 -04:00
Bryan Helmkamp
cebdf8dee5
Merge remote-tracking branch 'origin/main' into pr-176
# Conflicts:
#	lib/crates/fabro-cli/src/manifest_builder.rs
#	lib/crates/fabro-server/src/run_manifest.rs
2026-04-29 12:45:33 -04:00
Bryan Helmkamp
786e01c7a7
refactor(manifest): type bundle paths end-to-end
Introduce ManifestPath as the canonical in-memory key for run manifests so CLI-produced bundle keys and workflow/server consumers share the same normalization rules. Validate wire keys at the server boundary and add a CLI-to-server round-trip test for user-global @path references.
2026-04-29 12:26:39 -04:00
Bryan Helmkamp
f676fa779b
fix(ci): clean up clippy warnings and refresh CLI docs
Drop async from validate::run after the preflight refactor removed all
awaits, replace absolute paths and a one-liner helper in
manifest_validation, swap a redundant to_path_buf for clone in a test,
and regenerate cli.mdx so docs check stays green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 01:03:16 -04:00
Bryan Helmkamp
583fa1e9d1
refactor(config): share log destination resolution
Move FABRO_LOG_DESTINATION parsing into fabro-config so CLI and server worker startup use the same validation behavior. Worker startup now exports one canonical resolved destination instead of relying on a generic env allowlist path.
2026-04-26 17:47:22 -04:00
Bryan Helmkamp
e6ca9eba87
refactor(cli): rename ServerLogSink to LogSink
The Server prefix is redundant -- the type is used by both Server and
Worker variants of InternalLogSink, and the helper that builds it from a
runtime directory is renamed to log_sink to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:36:03 -04:00
Bryan Helmkamp
7abc11adc9
feat(server): route worker logs to the same destination as the parent
Workers are an internal implementation detail; operators should not need
to know about them. When the server runs in stdout mode (FABRO_LOG_DESTINATION=stdout,
e.g. inside containers), workers now also stream their tracing to stdout
so all server-level logs land on the same destination.

The parent propagates its resolved destination to each worker via
FABRO_LOG_DESTINATION and inherits the worker's stdout when the parent is
in stdout mode (so worker stdout flows through to docker logs). The
per-run log at <scratch>/runtime/server.log stays a file regardless --
it is read back by the run UI.

A CLI-side ServerLogSink::{File(PathBuf),Stdout} replaces Option<PathBuf>
so the file/stdout intent is explicit at the type level for both the
Server and Worker sinks. LogDestination gains strum::IntoStaticStr so
the parent can stringify it for the worker env without a hand-written map.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 17:16:03 -04:00
Bryan Helmkamp
3a6ef48e56
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	docs-internal/logging-strategy.md
#	lib/crates/fabro-cli/src/logging.rs
#	lib/crates/fabro-cli/src/main.rs
#	lib/crates/fabro-static/src/env_vars.rs
2026-04-26 16:29:54 -04:00
Bryan Helmkamp
126819a6c6
refactor(cli): collapse ServerLogDestination into LogDestination
The CLI-side ServerLogDestination enum duplicated the domain
LogDestination from fabro-types and only existed to bundle a PathBuf.
Replace InternalLogSink::Server { destination: ServerLogDestination }
with { log_path: Option<PathBuf> }, drop the server_log_destination
adapter, and let prepare_foreground_server_log derive the log path
from runtime_directory internally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:06:38 -04:00
Bryan Helmkamp
4b09b8f8fe
feat(server): add per-run worker logs
Mirror worker tracing into run-scoped runtime/server.log files, expose them through the run logs API, and include run.log in dump exports when available.
2026-04-26 14:53:03 -04:00
Bryan Helmkamp
d07596ca80
feat(server): support stdout log destination
Add configurable server log destinations with an environment override so containers can stream foreground server logs to stdout while local installs keep file logging by default. Validate configured log filters at load time and reject stdout logging for daemon mode.
2026-04-26 14:52:15 -04:00
Bryan Helmkamp
11be286fa1
refactor(dev): simplify generated docs tooling
Share the real CLI parser with reference generation, reuse option metadata flattening, and centralize dev command execution helpers.
2026-04-24 18:41:00 -04:00
Bryan Helmkamp
7e64bf8b69
feat(cli): render fatal errors with miette
Wrap root CLI errors at the main boundary so fatal diagnostics use miette's styled renderer while preserving existing telemetry, exit codes, and auth help hints.
2026-04-24 15:35:57 -04:00
Bryan Helmkamp
80de5ca616 refactor(static): centralize env var names
Add fabro-static::EnvVars as the shared registry for fixed environment variable names and migrate env reads, clap env bindings, and subprocess/test allowlists to use it.

Add clippy bans for raw std::env lookup APIs so future dynamic env facades must be documented explicitly.
2026-04-24 12:29:51 -04:00
Bryan Helmkamp
099dd881a8
merge origin/main into local main
Integrates origin's worker-JWT-auth work (commits 8a6f83bb0..c847a828d)
with the config-boundary refactor that landed locally. Conflicts
resolved:

- commands/dump.rs: take origin's removal of the 500-line in-process
  test block (replaced by real-server integration coverage).
- commands/run/runner.rs: keep local's dense WorkflowSettings import,
  drop dead SettingsLayer import, pull in origin's ActorRef.
- manifest_builder.rs: adopt origin's lifted working_directory
  resolution (fixes #159 - manifest git detection in nested repos),
  but via local's resolve_working_directory_from_run API that takes
  the dense RunNamespace. Update the regression test's
  ManifestBuildInput literal to local's run_overrides/cli_overrides
  field shape.
- server.rs: keep origin's jwt_auth_mode/jwt_auth_state/
  test_user_subject/issue_test_user_jwt/issue_test_worker_token/
  create_run_with_bearer/bearer_request test helpers, adapt
  jwt_auth_state to local's create_test_app_state_with_session_key
  signature (ServerSettings + RunLayer), keep local's dense
  canonical_origin_settings that returns ServerSettings via
  server_settings_from_toml. Rewrite
  build_app_state_requires_session_secret_for_worker_tokens against
  the dense AppStateConfig (resolved_settings +
  resolved_runtime_settings_for_tests).

Post-merge verification: workspace builds clean, cargo +nightly
fmt --check all clean, cargo +nightly clippy --workspace
--all-targets -- -D warnings clean, cargo nextest run --workspace
4560 tests passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 21:13:28 -04:00
Bryan Helmkamp
84b79f9d69
derive local server cli config from lifecycle settings 2026-04-23 15:49:58 -04:00
Bryan Helmkamp
077469d0c6
refactor(auth): scrub FABRO_WORKER_TOKEN from worker env at startup
The worker subprocess is spawned with env_clear+allowlist by the server, so
the only sensitive value in its env is FABRO_WORKER_TOKEN itself. Read the
token and remove_var it from the process env in main() before Tokio starts
worker threads, then thread it explicitly through runner::execute(&str).

Every descendant (hooks, local sandbox, devcontainer initializeCommand,
MCP stdio, etc.) now inherits a worker env with no bearer in it, so an
unscrubbed spawn site cannot leak the token. This makes the prior denylist
scrub in fabro-hooks and fabro-sandbox redundant — delete it and the shared
WORKER_SECRET_ENV_DENYLIST constant. The sandbox keeps its _api_key/_secret/
_token/_password/_credential suffix heuristic for user-supplied env_vars
hygiene.

Extend the server-dispatched-worker env-leak integration test to also
assert a Bash stage running in the worker does not observe FABRO_WORKER_TOKEN.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 15:10:58 -04:00
Bryan Helmkamp
519f46038d
refactor(auth): use per-run worker JWTs for subprocesses 2026-04-23 11:04:45 -04:00
Bryan Helmkamp
4ad4d8fd36
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-cli/src/commands/dump.rs
#	lib/crates/fabro-cli/src/commands/store/mod.rs
#	lib/crates/fabro-cli/src/main.rs
2026-04-23 08:42:16 -04:00
Bryan Helmkamp
c52e89438b
simplify: fold ResolvedBaseContext into CommandContext
`ResolvedBaseContext` was a staging struct that held pre-context
settings so main.rs could read `user_settings.cli` before committing
to a full `CommandContext`. Now that install no longer needs the
indirection, the staging step doesn't earn its weight.

Give `CommandContext` a direct `from_disk(cli_layer, process_local_json)`
constructor that does the load + printer derivation + struct build in
one shot. main.rs builds one `base_ctx` before the dispatch match and
every arm borrows it — the `build_base_ctx` closure and ~20 duplicate
`let base_ctx = build_base_ctx()?;` lines disappear.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:17:27 -04:00
Bryan Helmkamp
967b1efe76
simplify: migrate install to CommandContext and delete cli_settings local
Public entry points (`execute`, `run_install`, `run_install_github_command`,
`run_install_inner`, `run_install_github_inner`) now take `&CommandContext`
instead of a 4-tuple of `(cli, cli_layer, process_local_json, printer)`.
Extract cli/printer/json from the context once at the top of each.

The nested doctor invocation inside run_install_inner previously built a
fresh `ResolvedBaseContext::from_disk(...).to_context()` with
`process_local_json = false`. Doctor only reads the resolved output
format (`base_ctx.json_output()`), not the invocation flag, so passing
the parent ctx through is behaviorally equivalent and avoids a second
disk load.

main.rs drops the `cli_settings` local entirely — no remaining command
needs it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:12:21 -04:00
Bryan Helmkamp
d51c6dfb76
simplify: migrate exec/parse/workflow/upgrade/uninstall to CommandContext
These top-level commands still took `&CliNamespace` + `Printer`
separately. Thread `&CommandContext` through the public entry points
and pull what's needed (`user_settings().cli`, `printer()`,
`json_output()`) from the context:

- parse: both args were unused — drop entirely.
- workflow list/create: use `ctx.json_output()` / `ctx.printer()`.
- exec: bind `cli = &ctx.user_settings().cli` at the top; drop unused
  printer param.
- upgrade: extract cli/printer inside run_upgrade; leave the private
  run_upgrade_brew helper with its existing signature (unit tests use
  `CliNamespace::default()` directly).
- uninstall: use `ctx.json_output()` / `ctx.printer()`.

Install remains on the old signature — its nested callback structure
makes a larger refactor than this simplification pass warrants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:06:46 -04:00
Bryan Helmkamp
a8623fb996
simplify: flatten commands/store/ after dump rename
The `fabro store dump` -> `fabro dump` rename left `commands/store/` as a
vestigial directory with a stale one-line `StoreRunExport` alias. Move
`dump.rs` and `rebuild.rs` up to `commands/`, import `RunDump` directly,
rename `dump::dump_command` -> `dump::run`, and clean up stale docs and
a noise test that only asserted clap's default error output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:58:26 -04:00
Bryan Helmkamp
2e07cf10a1
simplify: borrow cli_settings from ResolvedBaseContext instead of cloning
The `cli_settings` local was a standalone clone of `user_settings.cli`.
Drop the clone and rebind it as `&resolved_base.user_settings().cli`
inside the async block — all callers already borrowed it anyway.
Pre-async uses inline `resolved_base.user_settings().cli.<field>`
directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:52:06 -04:00
Bryan Helmkamp
cb9b762119
feat(cli): rename store dump to dump 2026-04-23 07:48:03 -04:00
Bryan Helmkamp
4fa5896d78
refactor(cli): narrow base context construction 2026-04-23 07:33:21 -04:00
Bryan Helmkamp
2b933597b2
refactor(cli): finish command context cleanup 2026-04-23 07:14:32 -04:00
Bryan Helmkamp
fbe0bdfbc1
refactor: align cli command boundaries on CommandContext 2026-04-23 01:08:14 -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
ebb8bf7add
refactor settings API entrypoints 2026-04-22 18:58:47 -04:00
Bryan Helmkamp
9c25a8f461
refactor(cli): dedupe daemon scaffolding, thread RuntimeDirectory
Collapses the identical scopeguard + serve_command block in
`start.rs::execute_foreground` into a single `foreground::serve_with_daemon_record`
helper shared with `server::dispatch`.

Changes `prepare_foreground_server_log`, `acquire_lock`, and
`load_or_create_local_session_secret` to take `&RuntimeDirectory` instead
of `&Path storage_dir`, since each only consumed the path to immediately
rebuild a `RuntimeDirectory`. Callers that still need the raw storage
path for child processes keep it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:38:07 -04:00
Bryan Helmkamp
7a58ab4e2b
refactor(server): unify daemon runtime metadata 2026-04-22 16:07:52 -04:00
Bryan Helmkamp
92a09adb20
feat(cli): suggest fabro auth login on auth-required errors
Unauthenticated commands surfaced only `error: Authentication required.`
with no remediation. Add a cyan-bold `hint:` line pointing at
`fabro auth login` in the top-level error printer, keyed off
`ExitClass::AuthRequired` so it covers every command that hits the
server (run, exec, ps, system info, etc.). Suppressed when `--json` is
set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 10:49:22 -04:00
Bryan Helmkamp
0781e3a2c1
test(cli): suppress browser launch under spawned fabro test subprocesses
Add FABRO_SUPPRESS_OPEN_BROWSER env knob via fabro_util::browser::try_open.
apply_test_isolation now sets it, so install-mode and auth-login tests that
spawn a real fabro binary no longer pop real browser windows. All six
open::that call sites route through the helper; consolidates the direct
open crate dep into fabro-util.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 07:50:34 -04:00
Bryan Helmkamp
112f9c176a
Merge remote-tracking branch 'origin/main' 2026-04-22 00:17:08 -04:00
Bryan Helmkamp
6e07f688ab
refactor(cli): collapse duplicate server-settings resolvers through local_server
Route install/uninstall through local_server::storage_dir instead of hand-
rolled copies, drop dead connect_api_client and run_dir plumbing, eliminate
double-resolve in prepare_server_bootstrap, and tighten the boundary
allowlist now that uninstall no longer needs the exemption.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:16:49 -04:00
Bryan Helmkamp
5b1c40764d
refactor(cli): enforce CLI/server settings boundary
Move server-only settings reads out of user-facing CLI commands into a
dedicated local_server module, the install/uninstall exceptions, and the
worker subcommand. Adds bin/dev/check-boundary.sh to prevent regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:37:15 -04:00
Bryan Helmkamp
105559bc8a
feat(cli): exit with code 4 on authentication-required failures
Returns exit code 4 whenever the CLI fails because the user needs to run
fabro auth login, so scripts and the install wizard can distinguish
re-auth from generic failures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:34:21 -04:00
Bryan Helmkamp
f0f04abf44
refactor(client): extract fabro-client crate
Lift shared client DTOs into fabro-types, move auth/target/error/session
logic into fabro-client, and reduce fabro-cli to orchestration around the
builder-based client path.

This also lands the remaining plan cleanup for ApiError, ServerTarget
canonicalization, and the RunEventStream rename at the CLI boundary.
2026-04-20 20:42:20 -04:00
Bryan Helmkamp
9c68c57bcc
feat(auth): add CLI GitHub login and logout flow
Add the server-side CLI OAuth endpoints and token persistence needed to
mint JWT access tokens and rotating refresh tokens from the existing
GitHub web auth flow.

Add CLI auth storage plus `fabro auth login`, `logout`, and `status`, and
prefer stored OAuth access tokens when building target clients.
2026-04-20 07:12:52 -04:00
Bryan Helmkamp
e0b2d71668
refactor(unwrap): clear non-test workspace warnings 2026-04-19 20:56:38 -04:00
Bryan Helmkamp
72924ba611
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-agent/src/cli.rs
#	lib/crates/fabro-cli/src/commands/run/run_progress/mod.rs
#	lib/crates/fabro-cli/tests/it/cmd/exec.rs
#	lib/crates/fabro-cli/tests/it/scenario/lifecycle.rs
#	lib/crates/fabro-telemetry/src/spawn.rs
#	lib/crates/fabro-workflow/tests/it/attractor_compat.rs
#	lib/crates/fabro-workflow/tests/it/cp_integration.rs
2026-04-19 20:32:02 -04:00
Bryan Helmkamp
ad0d532691
chore(clippy): require reasons on allow attributes
Enable clippy::allow_attributes_without_reason at the workspace level.
Add concise, callsite-specific reasons to existing allow attributes, including generated code paths.
2026-04-19 20:24:24 -04:00
Bryan Helmkamp
64cf35cc7d
fix(lint): restore clippy cleanliness after async ripple from std::fs work
Two follow-ups the workspace lint now catches:

- fabro-server tests/it/api/install.rs: a newer install-router integration
  test was missing the `.await` after `build_install_router(...)` -- the
  fn became async when the devcontainer/install-mode resolver was
  converted to tokio::fs in commit 19939c5f0.
- fabro-cli main.rs: add #[expect(clippy::disallowed_methods)] to the
  #[cfg(test)] module whose write_test_settings helper uses sync
  std::fs::write to stage CLI settings fixtures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 19:41:47 -04:00
Bryan Helmkamp
a2b77b1a30
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-cli/src/commands/run/rewind.rs
#	lib/crates/fabro-cli/src/logging.rs
2026-04-19 19:33:40 -04:00
Bryan Helmkamp
26db764e6c
feat(server): resolve run selectors on the server
Add a server-native run selector endpoint and migrate CLI single-run flows to
use it instead of local workflow-store heuristics. This also moves store dump
export assembly into the CLI, removes the production CLI dependency on
fabro_workflow run lookup and dump helpers, and records the remaining
cli-to-workflow coupling in an audit document.
2026-04-19 19:31:13 -04:00
Bryan Helmkamp
5c248fc885
fix(clippy): clean up nightly-clippy findings on merged CLI work
Nothing behavioral — each change is what clippy asked for:

- fabro-test: wrap the three polling-helper thread::sleep calls in a
  single poll_sleep() with an #[expect(clippy::disallowed_methods,
  reason = …)] since the helpers are deliberately blocking
- fabro-test: server_log_files now uses Path::extension() with
  eq_ignore_ascii_case("log") instead of a case-sensitive ends_with
- fabro-workflow: import default_storage_dir rather than calling it
  through its full module path
- fabro-cli/server/record: same absolute_paths fix
- fabro-cli/main tests: use a `use tokio::runtime::Runtime` to stop
  referencing `tokio::runtime::Runtime` by full path
- fabro-cli/tests: replace three `as u32` casts on as_u64() results
  with u32::try_from(...).expect(…)
- fabro-cli/tests: six `format!("...", var)` assertions switched to
  the inline `{var}` form clippy prefers

Full verification passes: fmt, clippy, cargo nextest (4141 tests),
bun typecheck, bun test (40 tests), bun build, SPA embed diff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:39:06 -04:00
Bryan Helmkamp
a256c14a77
refactor(cli): collapse duplicated bootstrap and settings helpers
- Merge prepare_foreground_server_bootstrap and prepare_server_sink_bootstrap
  into one prepare_server_bootstrap(config, storage, foreground).
- Drop three one-line settings_layer_* passthroughs from user_config; callers
  now use load_settings_with_{storage_dir,config_and_storage_dir} directly.
- Swap underscore-prefixed lock field for #[expect(dead_code, reason=…)] to
  document RAII intent explicitly.
- Remove two narrate-what-it-does comments.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:40:33 -04:00
Bryan Helmkamp
858e8e1270
fix(cli): unify server state and logging under storage
Route server-owned logs to <storage>/logs/server.log from the start of
tracing, remove legacy home/config ownership paths, and fail fast when
a running legacy daemon is detected instead of silently proceeding.

This also adds the missing sink-resolution, truncate/append,
concurrency, legacy-config, and uninstall regression coverage for the
home/storage cleanup plan.
2026-04-19 16:34:27 -04:00
Bryan Helmkamp
95b101a26f
lint(clippy): disallow blocking std::io and std::net on Tokio paths
Extends the workspace clippy.toml — which already bans std:🧵:sleep,
std:🧵:spawn, and std::process::Command::new on Tokio paths — with:

- disallowed-types: std::io::{Read, Write, BufRead, BufReader, BufWriter}
  and std::net::{TcpStream, TcpListener, UdpSocket}
- disallowed-methods: std::io::{stdin, stdout, stderr}

Non-blocking std::io items (Error, ErrorKind, Result, IsTerminal, Cursor)
remain allowed. std::fs is intentionally deferred.

Annotates ~24 pre-existing sync call sites with #[expect(..., reason = "...")]
matching the established pattern. All annotations describe why blocking I/O
is intentional in that context (sync CLI command, test helper, pre-fork
flush, etc.), so a future conversion to async will surface as an unfulfilled
lint expectation instead of silently drifting.

Fixes one real Tokio-path issue surfaced by the new lint:
fabro-cli's server-start daemon-health poller (try_connect) was a sync fn
called from async execute_daemon; std::net::TcpStream::connect_timeout
blocked a Tokio worker for up to 100ms per poll iteration. Converted to
tokio::net::{TcpStream, UnixStream} with tokio::time::timeout.

One follow-up flagged in-code: fabro-agent/src/cli.rs's JSON event writer
uses std::io::stdout() inside tokio::spawn. Annotated with a FOLLOW-UP
reason pointing at tokio::io::stdout; left unchanged since volume is low
and scope exceeded this pass.

Verified: clippy clean, cargo +nightly fmt --check clean, full nextest
workspace run (4131 passed, 182 skipped).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:06:02 -04:00