Commit graph

3228 commits

Author SHA1 Message Date
Bryan Helmkamp
f8e5192fb3
fix(pr): address review feedback on PR refactor
- Return the existing PullRequestRecord on 409 from POST /runs/{id}/pull_request
  so structured clients can recover the URL/number without a follow-up call.
  The response now includes both the error envelope and a pull_request field
  (same shape precedent as /install/finish's leftover_env_keys).
- Add server tests for merge/close error paths: 404 no_stored_record, 400
  unsupported_host, 503 integration_unavailable, 400 invalid_merge_method, 502
  github_not_found.
- Add a dedicated regression test proving the PR handlers use the
  github_api_base_url captured at AppState construction, not a request-time
  env read (SSRF defense invariant from the plan).
- Add an upgrade hint on unstructured 404s from the new PR client methods so
  a new CLI against an old server sees "Upgrade the fabro server" instead of
  an opaque failure.
- Refresh the stale CLI docs paragraph so it describes server-side GitHub
  credentials, matching the post-refactor reality.
- Regenerate the TypeScript API client (had fallen behind the prior OpenAPI
  schema additions) and add PullRequestRecord to ErrorResponse as an optional
  field for the 409 case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 20:34:18 -04:00
Bryan Helmkamp
0ffb4b0461
refactor(workflow): centralize run notices 2026-04-23 20:29:32 -04:00
Bryan Helmkamp
907b913894
refactor(auth): dedupe env bearer credentials 2026-04-23 20:29:32 -04:00
Bryan Helmkamp
7858a73146
fix(llm): require explicit model test client 2026-04-23 20:21:59 -04:00
Bryan Helmkamp
3e0345db1e
refactor(server): extract shared pull request GitHub context loader
The view, merge, and close handlers each repeated the same ~25-line
prologue: open the run reader, load state, unwrap the stored record,
parse owner/repo with the host check, and load GitHub creds. Move it
into `load_pull_request_github_context` so each handler keeps only the
work that's unique to it. Net -31 lines with no behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 20:18:33 -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
ec3d65928f
style(rustfmt): format remaining llm refactor files 2026-04-23 19:51:45 -04:00
Bryan Helmkamp
ba2eea3148
fix(llm): close remaining source resolution gaps 2026-04-23 19:40:57 -04:00
Bryan Helmkamp
c3ba84d8cc
fix(server): clear clippy warnings in server tests
Return `&'static str` from the mock provider's `name()` and drop
redundant `.to_string()` calls on `github.base_url()` (already owned).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 19:40:03 -04:00
Bryan Helmkamp
7536e64292
Merge remote-tracking branch 'origin/main' 2026-04-23 19:34:37 -04:00
Bryan Helmkamp
6fc7251471
close config boundary audit and settings snapshot naming 2026-04-23 19:30:30 -04:00
Bryan Helmkamp
ddd961ddcc
refactor(pr): move pull request commands server-side 2026-04-23 19:23:52 -04:00
Bryan Helmkamp
941c6e83f9
route fabro-config parsing through settings fromstr 2026-04-23 19:20:02 -04:00
Bryan Helmkamp
e17bd789dd
drop dead fabro-types settings layer module 2026-04-23 19:15:39 -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
c847a828de
Merge remote-tracking branch 'origin/main'
Some checks are pending
TypeScript / Build (push) Waiting to run
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
2026-04-23 19:03:29 -04:00
Bryan Helmkamp
904c8842f0
refactor(workflow): consolidate list_events walk and dedupe test helpers
FINALIZE loaded the run event log twice: once via build_conclusion_from_store
for stage durations, then again to count ArtifactCaptured events. Merged into
a single walk feeding both the conclusion and the artifact count.

Collapsed six near-identical pipeline::execute + emit_terminal + flush blocks
in test_support into one execute_and_emit_terminal helper. Also trimmed
narrative comments that described caller ordering, control flow, or the fix
commit rather than non-obvious invariants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 19:01:58 -04:00
Bryan Helmkamp
b0da8308d4
drop server raw settings test helpers 2026-04-23 18:54:31 -04:00
Bryan Helmkamp
cb14dc43d1
refactor(llm): use credential sources and split run services 2026-04-23 18:54:27 -04:00
Bryan Helmkamp
4f1c5f1f52
migrate server auth tests to dense runtime settings 2026-04-23 18:46:15 -04:00
Bryan Helmkamp
0e29d8edd1
Merge remote-tracking branch 'origin/main' into main
Integrates upstream fixes (docs Get Started button, manifest git
working_directory) with local workflow cleanup commits.
2026-04-23 18:44:47 -04:00
Bryan Helmkamp
e8a89ac393
fix(workflow): dedupe stages/billing and surface real errors in terminal event
Follow-ups to the FINALIZE terminal-event refactor, surfaced during
review:

- build_terminal_event: drop re-wrapping Err outcomes in Error::engine,
  which doubled the "Engine error: " prefix on display. Surface the
  original error directly.
- Unify loop billing: move billing aggregation into a shared
  billing_from_checkpoint helper iterating node_outcomes.values() once
  per unique node. Both Conclusion.billing and the emitted terminal
  event use it, so the persisted metadata snapshot and the run.completed
  event can't disagree.
- Dedupe conclusion.stages by node id while preserving execution order.
  completed_nodes has duplicates for looping workflows, but
  node_outcomes, node_retries, and stage_durations are all keyed by
  node_id with overwrite semantics, so duplicate StageSummary rows
  carried identical latest-visit values and inflated total_retries /
  the PR Fabro Details table.
- test_support: flush StoreProgressLogger before reading state.
  StoreProgressLogger forwards events via mpsc, so state() right after
  execute could miss StageCompleted entries and return stale billing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:44:41 -04:00
Bryan Helmkamp
8f4345b43f
migrate workflow operation tests off sparse settings layers 2026-04-23 18:42:01 -04:00
Bryan Helmkamp
6c6368e287
plan 2026-04-23 18:38:46 -04:00
Bryan Helmkamp
57b1539b96
refactor(dump): test the real server boundary, drop client-side storage fakes
`fabro dump` had a `DumpDataSource` trait with two impls: `ServerDumpSource`
(production, goes through the HTTP client) and a `#[cfg(test)] LocalDumpSource`
that constructed a `fabro_store::{Database, ArtifactStore}` in-process and
replayed hand-written events into it. The trait existed solely to let tests
bypass the server boundary, which meant the production path was never
exercised by unit tests and every storage-layer refactor leaked up into CLI
test fixtures.

Delete the trait, both impls, the `export_run(&RunDatabase, &ArtifactStore, …)`
test-only helper, and the 500-line inline event-replay test. The single
remaining path calls `Client::{list_run_events, read_run_blob,
list_run_artifacts, download_stage_artifact}` directly. End-to-end coverage
lives in `tests/it/cmd/dump.rs` (real server, real runs), and pure layout
logic is covered by `fabro_workflow::run_dump::tests` — both of which match
the project's testing-strategy.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:38:46 -04:00
Bryan Helmkamp
db132d11a7
migrate cli install tests off sparse settings layers 2026-04-23 18:37:37 -04:00
Bryan Helmkamp
8f47bc9317
migrate server tests off raw settings layers 2026-04-23 18:31:33 -04:00
Bryan Helmkamp
9a898b12cd
move sparse settings layers into fabro-config 2026-04-23 18:10:12 -04:00
Bryan Helmkamp
ab2060820d
plan 2026-04-23 17:54:02 -04:00
Bryan Helmkamp
b5684ead94
fix stale dense run fixtures in types and store tests 2026-04-23 17:51:20 -04:00
Bryan Helmkamp
4585f9874c
fix(test): wait for chrome process exit instead of polling for screenshot
The headless Chrome screenshot test polled for the screenshot file every
100 ms for 20 seconds, then panicked. Slow CI runners (Ubuntu 24.04 GHA)
sometimes took longer than the polling deadline, surfacing as a flake.

Chrome with `--screenshot` exits when the file is written, so waiting on
the process is the deterministic completion signal — no polling, no
arbitrary deadline that might be too short.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 17:49:04 -04:00
Bryan Helmkamp
41c47dbe12
fix(workflow): emit terminal run event from FINALIZE, not on_run_end
The `WorkflowRunCompleted` / `WorkflowRunFailed` event was emitted from
`EventLifecycle::on_run_end`, a callback the executor fires at the end of
the EXECUTE phase. But the run isn't done at that point — RETRO and
FINALIZE still need to run, and FINALIZE writes the meta branch's finalize
commit. Observers that treat the event as "done" (CLI attach, daemon SSE
consumers) could observe terminal state and act on it before the worker
flushed its remaining writes.

The recovery scenario test exposed this: it deletes the meta branch
right after `fabro run` returns, then asserts the branch is empty. On
loaded CI runners the worker's finalize commit landed after the delete,
recreating the branch and failing the assertion.

Move the terminal event emission to `pipeline::finalize::finalize`, after
`write_finalize_commit`. The lifecycle's `on_run_end` overrides for event
and git become empty (deleted — the trait already provides a no-op
default). Three pieces of cross-cutting state (`final_patch`,
`captured_artifact_count`, the dead `EventLifecycle` reads of
`last_git_sha`) only existed to ferry data from EXECUTE to the terminal
event; deleted those too. The aggregator collapses to a one-line
delegate to `hook.on_run_end`.

`write_finalize_commit` now takes the conclusion as a parameter and
injects it into the projection copy, since the terminal event hasn't run
through the run store yet when the meta branch is written.

`build_terminal_event` is `pub(crate)` so `test_support` helpers (which
stop at EXECUTE) can mirror the production payload.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 17:48:56 -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
5748dd3d30
move serve storage overrides behind dense server settings 2026-04-23 17:16:54 -04:00
Bryan Helmkamp
31dc4a78f7
route app state reload through dense server settings 2026-04-23 17:13:09 -04:00
Bryan Helmkamp
83fc1602ea
route cli settings loads through dense config 2026-04-23 17:09:21 -04:00
Bryan Helmkamp
c21498a55a
Merge pull request #170 from fabro-sh/fix/manifest-git-working-directory
fix(cli): use working_directory for manifest git detection
2026-04-23 17:00:58 -04:00
Bryan Helmkamp
96b904c24a
switch workflow operations to dense settings 2026-04-23 16:59:56 -04:00
Marcel Hild
8a6f83bb08
fix(cli): use working_directory for manifest git detection
build_manifest_git() was called with the CLI's cwd, which detects the
wrong repo/branch when fabro is invoked from a workspace directory that
differs from the target repo (e.g. via `[run] working_dir = "repos/foo"`
in .fabro/project.toml). Now resolve working_directory once in
build_run_manifest, share it with resolve_manifest_goal (dropping the
duplicate resolution), and pass it to build_manifest_git.

Also rename the build_manifest_git parameter from `cwd` to `repo_path`
to reflect that it now receives the resolved working directory.

Add a regression test that spins up a workspace git repo and a
separate target git repo beneath it, points `[run] working_dir` at the
target, and asserts the manifest's git branch and origin come from the
target repo.

Ports https://github.com/durandom/fabro/pull/2 to the post-v2-schema
code (Settings -> SettingsLayer).

Closes #159

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:53:55 -04:00
Bryan Helmkamp
8d472bb6ed
use run settings builder in manifest preflight 2026-04-23 16:51:09 -04:00
Bryan Helmkamp
eaca3daac4
cache dense workflow settings in workflow loader 2026-04-23 16:48:07 -04:00
Bryan Helmkamp
134d8c32d5
add dense run settings builder 2026-04-23 16:37:00 -04:00
Bryan Helmkamp
8eb92b5a74
dedupe dense settings resolution in create 2026-04-23 16:35:04 -04:00