Commit graph

1699 commits

Author SHA1 Message Date
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
Bryan Helmkamp
2ef87240e7
fix(dump): propagate serde errors from RunDump::from_projection
push_json_entry and push_json_entry_path silently dropped entries via if let Ok(...) on serde_json::to_value, hiding any future Serialize impl failure as missing files. They now return Result, RunDump::from_projection returns Result<Self>, and the three production callers (pipeline/finalize, lifecycle/git init + checkpoint) report failures via emit_metadata_snapshot_failed with MetadataSnapshotFailureKind::Write.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:32:48 -04:00
Bryan Helmkamp
b96647314c
docs(deployment): split into local vs self-hosted, drop Render/Fly/DO
Reframe the deployment docs around the actual product story: Fabro
runs as a server, and the only deployment question is where that
server runs (laptop vs self-hosted Docker). Drop the Render, Fly.io,
and DigitalOcean guides and their config files; keep Railway as the
managed shortcut.

- New: administration/deployment.mdx (overview, two-mode framing)
- New: administration/self-host-docker.mdx (compose-first how-to)
- Move: administration/deploy-server.mdx -> reference/server-operations.mdx
  (it was operational reference, not deploy guidance)
- Delete: deploy-render.mdx, deploy-fly-io.mdx, deploy-digital-ocean.mdx
- Delete: render.yaml, fly.toml, railway.toml, Dockerfile.deploy
- docker-compose.yaml: load .env if present so users can drive the
  stack from a single env file end-to-end
- Update internal links and the docs-test that pinned the old path
2026-05-01 09:26:35 -04:00
Bryan Helmkamp
a4cfc617aa
refactor: expose redacted_output_tail as a public free fn
Drops the synthetic ExecResult fabricated in sandbox_metadata::stdout_output_tail
just to reach private redaction logic. The redact + sanitize + tail pipeline
now lives behind fabro_sandbox::redacted_output_tail(stdout, stderr, max),
which ExecResult::redacted_output_tail also delegates to.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:21:59 -04:00
Bryan Helmkamp
5437257521
refactor: unify metadata snapshot failure helpers and drop floor_char_boundary copies
Groups the MetadataSnapshotFailed event payload into a MetadataSnapshotFailure
struct and replaces the two near-identical 11-arg emit_metadata_snapshot_failed
helpers in lifecycle/git.rs and pipeline/finalize.rs with one shared helper
in sandbox_metadata.rs. Both #[allow(too_many_arguments)] blocks are removed.

Also deletes two hand-written floor_char_boundary copies (fabro-agent and
fabro-sandbox) in favor of the stable str::floor_char_boundary, matching how
most existing call sites already use it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:17:47 -04:00
Bryan Helmkamp
78979e5f66
Merge remote-tracking branch 'origin/main' 2026-05-01 08:55:38 -04:00
Bryan Helmkamp
7f23038820
refactor(retro): drop redundant mkdir and dead run_dir plumbing
Sandbox::write_file already creates parent dirs in every backend (local, docker, daytona), so the per-file mkdir -p exec_command in upload_data_files was a wasted round-trip. Also remove the run_dir param/field that became unused after RunDump took over hydration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 08:49:02 -04:00
Bryan Helmkamp
96d7ba4aa0
refactor: dedup exec failure diagnostic plumbing
Collapses four duplicate tracing field blocks in event.rs behind
ExecOutputTail::trace_summary, drops the parallel MetadataPushError
struct in favor of reusing SandboxMetadataError::Operation, inlines
the single-use Error::exec_result accessor, and gates the test-only
ExecResult::from_process_output to cfg(test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 08:46:08 -04:00
Bryan Helmkamp
2f7aeba417
fix(workflow): preserve exec failure diagnostics
Add bounded redacted exec output tails to failure events while keeping tracing log-safe. Centralize tail projection on ExecResult and thread diagnostics through metadata, setup, devcontainer, and CLI install failures.
2026-05-01 08:45:50 -04:00
Bryan Helmkamp
9f2555e497
test(sandbox): move Docker streaming check out of unit tests
Keep daemon-dependent Docker lifecycle coverage as an ignored integration test so the default unit path remains runnable without Docker.
2026-05-01 08:31:31 -04:00
Bryan Helmkamp
542b56e51c
fix(sandbox): honor early Docker exec stop requests
Preserve timeout stop requests that arrive before the Docker exec wrapper has written its child pid, and cover that path with a fast unit regression test.
2026-05-01 08:31:31 -04:00
Bryan Helmkamp
165b38c3ed
refactor(workflow): write metadata snapshots with git2
Replace the sandbox-side fast-import metadata writer with an in-process git2 writer that builds metadata commits locally and pushes them with worker-side GitHub credentials. Keep sandbox git probing separate from metadata runtime state so checkpoint commits and metadata snapshots have independent lifecycles.
2026-05-01 00:22:01 -04:00
Bryan Helmkamp
93908de46c
refactor(retro): share run dump hydration
Move RunDump into fabro-dump so CLI export and retro uploads share the same hydrated run layout. Drop the legacy artifact file-ref parser, add best-effort run.log retrieval for retro, and update retro prompts/docs to use events.jsonl and checkpoints.
2026-04-30 23:31:12 -04:00
Bryan Helmkamp
7cb120b96c
refactor: drop type assertions and reuse generated enums
Some checks are pending
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
TypeScript / Build (push) Waiting to run
Replace local CommandTermination/CommandOutputStream literal unions with
the generated enums from fabro-api-client, drop `as` casts and the `id!`
non-null assertion in run-stages, flatten the 6-deep status ternary into
streamStatus(), and use fabro_util::time::elapsed_ms in handler/llm/cli.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 22:45:38 -04:00
Bryan Helmkamp
6da71be2fa
fix(sandbox): forward exec_command_streaming through WorktreeSandbox 2026-04-30 22:45:38 -04:00
Bryan Helmkamp
1383022678
refactor(daytona): wrap session lifecycle in RAII guard 2026-04-30 22:45:38 -04:00
Bryan Helmkamp
7ee58b2fcc
refactor(server): unify command-log response construction 2026-04-30 22:45:38 -04:00
Bryan Helmkamp
de64136a0e
refactor: tighten command-log streaming hot paths 2026-04-30 22:45:38 -04:00
Bryan Helmkamp
e590610dad
test(cli): read command logs via endpoint 2026-04-30 22:45:38 -04:00
Bryan Helmkamp
3827d3946e
fix(daytona): satisfy streaming smoke lints 2026-04-30 22:45:38 -04:00
Bryan Helmkamp
83919f3569
test(daytona): add live streaming smoke 2026-04-30 22:45:37 -04:00
Bryan Helmkamp
f5f6c76f16
fix(daytona): preserve streamed command semantics 2026-04-30 22:45:37 -04:00