Commit graph

1720 commits

Author SHA1 Message Date
Bryan Helmkamp
a614183378
chore(catalog): add GPT-5.5 and GPT-5.5 Pro, set 5.5 as OpenAI default
GPT-5.5 (released 2026-04-23) replaces 5.4 as the default OpenAI model.
Live integration tests confirm both new IDs respond on the OpenAI API;
they require default temperature like other reasoning models.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:12:40 -04:00
Bryan Helmkamp
b5bde88614
fix(preflight): finish LLM probe regression 2026-05-04 11:12:40 -04:00
Bryan Helmkamp
1994f938d7
chore: fix flaky test 2026-05-04 11:12:40 -04:00
Bryan Helmkamp
253af11508
refactor(billing): simplify run-billing post-review cleanups
Use BilledTokenCounts::default() for the non-LLM branch, hoist the
by-model stage count and hasLlmStages predicate out of JSX, and drop
the in-test for-loop in favor of iterator-based assertions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 23:01:04 -04:00
Bryan Helmkamp
95eb13750a
fix(billing): render non-LLM run stages
Include completed stages without LLM usage in run billing responses so command-only runs still show runtime rows. Keep token and model aggregates scoped to billed LLM usage, and render placeholder values in the web billing table.
2026-05-03 22:49:33 -04:00
Bryan Helmkamp
6780dff63f
fix(workflow): retain exec output tails on failures
Keep sandbox exec failures structured until event emission so git push, checkpoint, notice, and retro failures can expose redacted output tails without expanding their terse error strings.

Also add log rendering that appends sanitized tail content for exec-backed errors while preserving the existing safe Display behavior.
2026-05-03 21:30:34 -04:00
Bryan Helmkamp
446c7cc065
fix(sandbox): surface snapshot lifecycle progress
Emit snapshot slow-path events only when Docker or Daytona actually performs image or snapshot work, replace retired completion markers with snapshot.ready, and render the lifecycle in attach/log output.
2026-05-03 20:44:16 -04:00
Bryan Helmkamp
fe342a4bd7
fix(redact): skip name fields to preserve sandbox identifiers
ULID-derived sandbox names like fabro-01KQR3V9D4VPFFWMNTVH09J48G tripped
the entropy detector and rendered as REDACTED in CLI run output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 19:57:55 -04:00
Bryan Helmkamp
a425724719
refactor(server): reuse canonical_origin in run_web_url
Delegate to the existing AppState::canonical_origin helper instead of
re-resolving server.web.url and re-checking emptiness inline. The helper
already validates the URL via validate_public_url, so a misconfigured
non-http(s) origin no longer leaks through into run_web_url's output.

Also pass web_url into create_run_input directly rather than constructing
with None and immediately patching the field at the call site.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:27:34 -04:00
Bryan Helmkamp
649b57c185
feat(api): expose web_url on run responses and run.created event
So that CLI and other API consumers can surface a clickable link to the
run's web UI page instead of guessing route shapes or probing settings.
The server populates `web_url` from `server.web.enabled` and
`server.web.url`, returns it on `RunStatusResponse` (create plus all
lifecycle transitions), and persists it on the `run.created` event so
attach replays the same link without re-deriving it.

CLI: prints `Web UI: <url>` as a run-header info line, driven off the
replayed event so fresh runs and `attach` share one code path. Absent
when the UI is disabled.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:18:19 -04:00
Bryan Helmkamp
2d7c79de1e
feat(server): validate Daytona API key scopes
Probe the Daytona API at install, `fabro secret set DAYTONA_API_KEY`,
and `fabro doctor` time to confirm the configured key carries the
snapshot/sandbox scopes Fabro needs. Operators now see a precise scope
error against the control plane instead of a generic sandbox-create
failure at first run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 17:09:01 -04:00
Bryan Helmkamp
bfb6bdb25c
fix(cli): bound server readiness probes
Use HTTP health checks with short deadlines for managed server readiness and add finite control-plane request timeouts for CLI/server clients. Keep stream bodies uncapped so SSE attach flows can remain long-lived.
2026-05-02 20:13:18 -04:00
Bryan Helmkamp
66f06950ba
refactor: simplify Rust review cleanup
Centralize shared test setup and graph vocabularies, remove stringly event checks, and make server handler dependencies explicit.
2026-05-02 15:41:17 -04:00
Bryan Helmkamp
a479db981f
chore(validate): remove stale rule section dividers
Leftover from when rules.rs was a single 3500-line file. Numbering
was stale (Rule 23 and Rule 24 each appeared twice after the split)
and duplicated info already in the filename.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:19:06 -04:00
Bryan Helmkamp
ae5ccb5ce2
refactor(workflow): split event module by responsibility
Keep fabro_workflow::event as the public facade while moving event conversion, names, redaction, sink, emitter, stored-field helpers, and StageScope into focused modules. Co-locate the existing event tests with the moved code and update the events strategy docs for the new module layout.
2026-05-02 14:52:10 -04:00
Bryan Helmkamp
b1d560faf7
refactor(validate): split lint rules into modules 2026-05-02 13:44:55 -04:00
Bryan Helmkamp
10555a292d
refactor(server): split HTTP handlers into modules 2026-05-02 13:32:49 -04:00
Bryan Helmkamp
0723ca068c
refactor(server): move server tests out of main module 2026-05-02 13:10:31 -04:00
Bryan Helmkamp
886173f5ad
refactor(server): gate test app state helpers
Move test-only app state constructors into the gated test_support module
so release builds do not expose or link fixture helpers and secrets.
2026-05-02 13:02:41 -04:00
Bryan Helmkamp
f219987f2a
fix(test): align worker token fixtures with auth routing
Share CLI integration worker-token issuance through the auth test helper so test tokens carry the same worker kid header as production-issued tokens.
2026-05-02 12:08:00 -04:00
Bryan Helmkamp
d10e0f5c56
refactor: simplify auth and actor handling
Tighten auth state to remove impossible identity branches and stringly error codes.
Route worker JWTs by header metadata, avoid unnecessary auth context cloning, and reuse shared helpers across tests and Slack payload handling.
Carry typed timeout actor metadata through failures instead of deriving it from display text.
2026-05-02 11:44:17 -04:00
Bryan Helmkamp
2c595d5939
refactor: dedupe auth helpers and tidy principal tests
Replace hand-built RequestAuthContext literals in github_webhook with the
existing ::invalid()/::authenticated() constructors, collapse the duplicate
demo/real principal layers into a single cloneable layer, and forward the
_with_anyhow error constructors to their _with_source twins to drop the
duplicated cause-collection bodies. refresh_credential_from_headers now
reuses jwt_auth::bearer_token_from_headers for Authorization parsing.
test_support shares one TEST_DEV_TOKEN-derived bearer header instead of a
hand-pasted literal. Replace for-loops in principal/cli_flow tests with
per-variant cases to honor the no-loops-in-tests rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 11:14:59 -04:00
Bryan Helmkamp
b499a17796
fix(error): preserve remaining error context
Carry structured error sources through workflow, server, tracker, and CLI paths instead of flattening them into strings before the render boundary.
2026-05-02 10:51:15 -04:00
Bryan Helmkamp
43f03087e6
Merge remote-tracking branch 'origin/main' 2026-05-02 10:06:25 -04:00
Bryan Helmkamp
f6b8d1acdb
Fix principal auth gap regressions 2026-05-02 10:02:12 -04:00
Bryan Helmkamp
29c45498b0
Fix run principal attribution gaps 2026-05-02 09:14:02 -04:00
Bryan Helmkamp
8f4c12580c
refactor: dedupe artifact entry adapters, retry URL helper, query-param check
Extract run_artifact_entry_from / artifact_entry_from in fabro-server so
the two list-artifact handlers share a single conversion site. Push the
?retry=... query append into stage_artifacts_url in fabro-client so
upload callers don't repeat it. Replace required_filename and
required_retry with one generic required_query_param<T> helper.

(From impls were the cleaner shape but the orphan rule blocks them:
NodeArtifact lives in fabro-store, RunArtifactEntry in fabro-api,
neither is in fabro-server. Free fns achieve the same dedup without
adding a fabro-store -> fabro-api coupling.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 01:16:10 -04:00
Bryan Helmkamp
f628b91c04
Merge origin/main
Reconcile parallel refactors that converged on stage vocabulary from
opposite directions. Origin's vocabulary wins everywhere it conflicts:
StageProjection (struct), StageState (status enum, kept), StageCompletion
(record). Local's artifact-retries feature, OpenAPI typing of JSON-blob
fields, parallel awaits in build_conclusion_from_store, and shared
RETRY_SEGMENT_PREFIX constant carry forward on top.

Origin's stage_at_visit reducer helpers (8 arms) supersede the local
stage_entry_with_current_visit (5 arms); same intent, broader coverage.
Origin's iter_stages_mut and first_event_seq helper unification are
preserved unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 22:05:41 -04:00
Bryan Helmkamp
8d7b9a804a
Unify run event principals 2026-05-01 21:56:47 -04:00
Bryan Helmkamp
5393b12beb
refactor: skip linear scans and serial awaits in run state and finalize
Defer current_visit_for to the fallback branch in stage_entry_with_current_visit
so events that already carry stage_id avoid an O(N stages) scan per event.
Run state() and list_events() concurrently in build_conclusion_from_store, and
share a single retry- segment prefix between encode and decode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 21:33:39 -04:00
Bryan Helmkamp
cc81f538f4
refactor(api): type StageState JSON-blob fields so the TS client stops emitting any
provider_used, script_invocation, and script_timing become object | null;
parallel_results becomes Array<object> | null. The Rust StageState type is
unaffected because fabro-api/build.rs replaces it with fabro_types::StageState.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 21:16:56 -04:00
Bryan Helmkamp
576c43d216
refactor(dump): bind rank width to a single source and drop dead retry validation
Extract STAGE_RANK_WIDTH and a derived MAX_STAGES_IN_DUMP in fabro-dump so
the path-prefix format and the stage-count cap can't drift, and replace the
two `{rank:03}-...` literals with a shared stage_dir_name helper.

Replace the cli/dump.rs `u32::try_from(artifact.retry)` with the symmetric
inverse of the server's `cast_signed()` emit. The OpenAPI schema declares
`minimum: 0`, so the negative branch is unreachable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 21:13:21 -04:00
Bryan Helmkamp
b01a666cd9
refactor: simplify retry-related helpers and orphan dump scan
Remove unused RunProjection::stage_mut, share decode_retry_and_filename
between artifact_store decoders, reuse stage_visit() in the artifact
lifecycle, and cache the dump.log entry index so RunDump::add_orphan_notice
no longer rescans entries on every call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:55:56 -04:00
Bryan Helmkamp
56a2257d8a
refactor(run-projection): extract stage_at_visit helpers in reducer
Some checks are pending
TypeScript / Build (push) Waiting to run
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Generated Docs (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
Eight reducer arms repeated the same node_id-presence check followed by a
visit-derivation step (either explicit from props, or
`current_visit_for(...).unwrap_or(1)`) and a `stage_entry` call. Pull
those into `stage_at_visit` and `stage_at_current_visit` so each arm just
binds the projection entry and writes its fields. The visit-derivation
strategy is now legible from the helper name instead of buried in a
free-floating `let visit = ...` line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:47:40 -04:00
Bryan Helmkamp
840dc42d3c
refactor(run-projection): dedupe first_event_seq helper and tighten dump
Expose `fabro_types::first_event_seq` next to `StageProjection`, replacing
six identical `nonzero` test helpers and the private one in `run_state`.
Add `RunProjection::iter_stages_mut` so `SerializableProjection` can
clear bulky fields without the collect-then-lookup dance, and let the
`fabro-dump` loop iterate `(&StageId, &StageProjection)` borrows directly
to drop the per-stage `StageId::clone()` and redundant HashMap lookup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:41:57 -04:00
Bryan Helmkamp
95dae5afac
feat(run): separate stage state and artifact retries 2026-05-01 20:10:47 -04:00
Bryan Helmkamp
cea1fa739d
refactor(run-projection): use stage vocabulary 2026-05-01 19:56:22 -04:00
Bryan Helmkamp
3a7e9c49ff
refactor(error): drop String error shims and DisplayContains test traits
Follow-up to the workspace-wide error chain preservation: removes the
`From<String>` impl on `PullRequestApiError`, the unused `SharedError::as_anyhow`,
and the test-only `DisplayContains`/`DisplayStringExt` traits that papered over
String errors. Call sites now build `anyhow!` errors directly and tests stringify
errors explicitly via `.to_string()`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 19:35:22 -04:00
Bryan Helmkamp
3f9a861f87
fix(error): preserve source chains across workspace
Keep typed transport and provider errors intact through API, GitHub, OAuth, install, diagnostics, and artifact paths. Add regression coverage for cloned shared errors and communication error chains.
2026-05-01 17:30:20 -04:00
Bryan Helmkamp
aa90f97224
test(cli): tighten env-dev-token-ignore tests
Restore snapshot form for auth status JSON test so re-introducing an
env_dev_token field would fail the snapshot, and rename the ps test to
reflect that it proves FABRO_DEV_TOKEN is ignored rather than that auth
is generally required.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 16:25:13 -04:00
Bryan Helmkamp
1b30a2803a
fix(cli): remove dev-token env auth override 2026-05-01 15:04:01 -04:00
Bryan Helmkamp
79e0783838
fix(sandbox): stabilize Docker exec stop test 2026-05-01 14:06:20 -04:00
Bryan Helmkamp
49fc9e6db7
fix(sandbox): skip Docker exec command after early stop
Short-circuit the controlled shell wrapper when the stop file already exists so a cancelled Docker exec does not launch user code before the pid watcher can terminate it.
2026-05-01 13:54:23 -04:00
Bryan Helmkamp
ab4d299fde
refactor(workflow): compute snapshot stats inside the blocking task
write_snapshot_blocking now derives entry_count and bytes from the
entries slice instead of taking them as parameters. The arity drops
from five to three, and the cheap O(n) work moves off the async
runtime into spawn_blocking where the rest of the snapshot already
runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 10:21:38 -04:00
Bryan Helmkamp
964c31837e
refactor(workflow): reuse GitHubCredentials::resolve_bearer_token
Make GitHubCredentials::resolve_bearer_token public and call it from
run_metadata::mint_token instead of re-implementing the JWT-sign +
installation-token branch. Eliminates the unreachable!() that arose from
matching the same enum twice.

Also drop the metadata_ field-name prefix on RunMetadataRuntime fields
(degraded, warning_emitted) — the prefix is redundant inside a struct
already named RunMetadataRuntime. Method names unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 10:12:31 -04:00
Bryan Helmkamp
84ab48d534
Merge origin/main into git2-metadata-writer branch
Origin advanced 11 commits in parallel, including refactors that
restructured the now-deleted sandbox_metadata fast-import writer
(structured ExecFailure for push errors, redacted_output_tail helper,
RunDump moved to fabro-dump crate, RunDump::from_projection now returns
Result, MetadataSnapshotFailureKind::Write, MetadataSnapshotFailed event
gains exec_output_tail, RunStoreBackend gains read_run_log).

Resolution: take ours for the four metadata-writer files (sandbox_metadata
deleted, lifecycle/git.rs, pipeline/finalize.rs, sandbox_git.rs) since the
git2 writer supersedes that module. Fold origin's API changes into the
ours-side: switch to fabro_dump::RunDump, handle from_projection's Result,
populate exec_output_tail: None in MetadataSnapshotFailed (git2 push
failures have no exec stdout/stderr), implement read_run_log on test
mocks. Drop unused from_raw_entries from fabro-dump.

A follow-up will port the structured push-failure pattern to run_metadata
without widening ExecFailure to non-exec ops.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 10:00:27 -04:00
Bryan Helmkamp
155d0a5a28
Merge remote-tracking branch 'origin/main' 2026-05-01 09:43:39 -04:00
Bryan Helmkamp
84a6ee941a
fix(workflow): adopt MetadataSnapshotFailure in dump-error branches
Adapt the from_projection error branches in lifecycle/git.rs (init + checkpoint phases) and pipeline/finalize.rs to the new free-function emit_metadata_snapshot_failed and MetadataSnapshotFailure struct introduced in 543725752. The merge auto-resolved cleanly but left the dump-error sites on the deprecated method/positional-args signature.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:42:16 -04:00
Bryan Helmkamp
8a1828cc95
refactor(workflow): reuse fabro-checkpoint Store and dedupe helpers
Replace the hand-rolled tree builder in run_metadata with
fabro-checkpoint's Store::write_blob/write_tree/write_commit/update_ref,
deleting BuildTreeError, TreeNode, build_tree, insert_tree_node, and
write_tree_node. Also fold three smaller duplications: the identical
metadata_writer_for_repo test helpers in lifecycle/git.rs and
pipeline/finalize.rs become RunMetadataWriterHandle::new_for_test_repo,
sandbox_git_runtime reuses sandbox_git::exec_err, and METADATA_PERMISSIONS
is a LazyLock instead of being rebuilt per snapshot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:39:18 -04:00
Bryan Helmkamp
5ef4b87878
Merge remote-tracking branch 'origin/main' 2026-05-01 09:34:44 -04:00