Commit graph

1149 commits

Author SHA1 Message Date
Bryan Helmkamp
7dd058cc40
refactor: unify run vocabulary and metadata snapshot layout
Implements the plan at
docs/plans/2026-04-20-003-refactor-unify-run-vocabulary-metadata-plan.md.

- Rename RunRecord to RunSpec and RunProjection.run to .spec everywhere
  in Rust source, tests, helpers, test names, and error messages.
- Introduce SerializableProjection wrapper that trims bulky node text
  fields (prompt, response, diff, stdout, stderr) for run.json snapshots.
- Collapse metadata-branch and CLI export to one RunDump::from_projection
  builder emitting run.json + graph.fabro + stages/{stage_id}/... and
  drop legacy top-level start/status/checkpoint/sandbox/retro/conclusion
  split files.
- Replace MetadataStore::write_checkpoint with write_snapshot returning
  the commit SHA; add read_run_projection/read_run_spec; demote
  read_checkpoint/read_start_record to projection-field extractors.
- Switch fork, rewind, rebuild_meta, CLI rewind recovery, and retro
  upload to read the unified projection layout.
- Add additive query methods on RunSpec and RunProjection.

Serde-level `alias = "spec"` shim dropped; `rename = "run"` retained to
keep the server API wire format stable per the plan's scope boundary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:17:23 -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
90b911c927
docs(plan): clarify unknown-event handling in client extraction
Document that unknown Fabro run events already fall back through
EventBody::Unknown, and that the refactor only needs to preserve
that behavior during the EventEnvelope move.
2026-04-20 18:26:46 -04:00
Bryan Helmkamp
381a186557
docs(plan): add fabro-client extraction plan
Capture the technical plan for extracting a new fabro-client crate from
fabro-cli, lifting domain DTOs (RunSummary, EventEnvelope, RunProjection,
ArtifactUpload) to fabro-types, and applying a set of OOP-style naming
cleanups along the way. Ran through ce-plan deepening and document-review
with feedback integrated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 17:37:31 -04:00
Bryan Helmkamp
acd89fb235
refactor: remove CLI client mTLS
Delete the CliTargetTls settings, ClientTlsSettings struct, rustls-pemfile
dep, and the fabro-http wrapper methods (use_rustls_tls/identity/
add_root_certificate) that only the CLI client-auth path used. The server
no longer terminates TLS in-process and the CliAuthStrategy::Mtls variant
had no construction or match sites.

Also simplify ServerTarget::HttpUrl to a tuple variant (HttpUrl(String))
now that tls is gone, removing the struct-variant ceremony across 22
construction and destructure sites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 17:37:24 -04:00
Bryan Helmkamp
41135dd9d1
fix(cli): remove explicit remote same-host auth fallbacks 2026-04-20 14:17:01 -04:00
Bryan Helmkamp
4c35c4b69f
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-server/src/jwt_auth.rs
#	lib/crates/fabro-server/src/serve.rs
#	lib/crates/fabro-server/src/server.rs
#	lib/crates/fabro-server/src/web_auth.rs
2026-04-20 09:47:47 -04:00
Bryan Helmkamp
2b0e3a743d
Merge remote-tracking branch 'origin/main' 2026-04-20 08:45:24 -04:00
Bryan Helmkamp
8259b7445e
feat(web): add run lifecycle actions
Expose cancel, archive, and unarchive from the run detail view,
surface blocked-question context, and route run-detail and run-files
notifications through a single shared toast provider.

This also refreshes the embedded SPA bundle and marks the lifecycle
actions plan complete.
2026-04-20 08:43:30 -04:00
Bryan Helmkamp
92ec483b60
Merge remote-tracking branch 'origin/main' 2026-04-20 08:39:29 -04:00
Bryan Helmkamp
9b1f08f0d4
docs(plan): ratify SHA-256 for user_agent_fingerprint
SHA-256 is already a workspace dep and is what the implementation uses at
server_client.rs:792-795. Avoids adding blake3 as a new dep for a use where
the algorithms are equivalent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 08:26:13 -04:00
Bryan Helmkamp
be74f91b7a
plans 2026-04-20 08:14:53 -04:00
Bryan Helmkamp
0686b82bce
fix(api): correct GitHub webhook OpenAPI contract
Model the GitHub webhook request body as JSON so the generated TypeScript
client exposes a coherent request shape, and add explicit conformance
coverage for the secret-gated webhook route.
2026-04-20 07:13:49 -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
c8cc9f20b0
feat(server): add explicit GitHub webhook strategies
Move GitHub webhook intake onto the main API router, add explicit
server_url and tailscale_funnel strategies, and validate strategy
requirements at config resolution. This also updates the API contract,
generated client, and operator docs to match the new webhook model.
2026-04-19 22:53:22 -04:00
Bryan Helmkamp
f31007f988
feat(server): move batch run selector resolution to the server
Resolve rm/archive/unarchive selectors through the server-owned
runs/resolve endpoint instead of CLI-side summary matching, and move
active-run delete force semantics into DELETE /runs/{id}.
2026-04-19 20:12:23 -04:00
Bryan Helmkamp
cd9ff8fafe
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-server/src/server.rs
2026-04-19 19:54:30 -04:00
Bryan Helmkamp
a62d06da4c
docs(plan): revert invented multi-node constraint; fabro-server is single-node
Reverts the `single_node_ack` acknowledgment flag and all the cross-node /
multi-node qualifier text introduced in the previous two commits. fabro-server
is single-node by design; there is no multi-node deployment model to design
against. The in-process per-hash and per-code mutexes in Units 9 and 10
provide the full atomicity guarantees R3 requires. R12 restored to the
original web-enabled + SESSION_SECRET-length check. No ack flag, no
config-surface EULA, no cross-node tests, no multi-node risks-table row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 19:51:19 -04:00
Bryan Helmkamp
83d712db24
docs(plan): enforce v1 single-node constraint via required acknowledgment flag
Adds `server.auth.github.single_node_ack: bool` (default `false`) as a new
config field required by startup validation when `github` is in
`auth.methods`. Without the flag, the server refuses to boot. This turns the
previously documentation-only single-node constraint into a fail-closed
startup check — an operator can still misdeploy to multi-node after setting
the flag, but they must affirmatively acknowledge the tradeoff first.

Alternative (auto-detect via SlateDB boot-heartbeat) deferred as future
work; explicit acknowledgment is lower-complexity and avoids rolling-deploy
false positives. Enforcement lives in Unit 5 startup validation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 19:51:19 -04:00
Bryan Helmkamp
e08e0163f8
docs(plan): add CLI auth login (GitHub OAuth + JWT) implementation plan
Adds a 22-unit implementation plan for `fabro auth login`/`logout`/`status`
with GitHub OAuth + PKCE, HS256 JWT access tokens, rotating opaque refresh
tokens, and a typed `IdpIdentity` flowing across fabro-types / fabro-store /
fabro-server. v1 is scoped to single-node deployments with `github` in
`auth.methods` (distributed refresh-token rotation coordination is deferred).

Origin spec: docs/superpowers/specs/2026-04-19-cli-auth-login-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 19:51:19 -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
1f6eb5b336
Merge origin/main into Run Files Changed feature branch
Integrates 39 commits from origin/main (archive/unarchive feature, UI
unification, theme/light-mode polish, Settings nav promotion, server
and CLI hardening).

Conflict resolutions:

- apps/fabro-web/app/routes/run-detail.tsx: origin removed the
  `broken` field from the tab config; local added the Files Changed
  tab. Kept the Files Changed tab, dropped the broken field per
  origin's shape.
- lib/crates/fabro-store/src/run_state.rs: both sides added tests
  in the same region. Kept local's two final_patch tests and all
  four of origin's archive/unarchive tests.
- lib/crates/fabro-spa/assets/: embedded SPA bundle rebuilt from
  the merged web source.
- lib/crates/fabro-workflow/src/operations/archive.rs: origin's new
  archive tests construct Event::WorkflowRunFailed{..}; added the
  final_patch: None field that local's lifecycle change introduced.

Workspace verification after merge: 4247 Rust tests + 95 web tests
all pass; clippy clean; fmt clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 19:30:36 -04:00
Bryan Helmkamp
4959778ea6
Merge origin/main into archived-run-status feature branch
Origin brought 21 commits of UI/install/test-helpers work that lived in
parallel with the archive feature. Only the SPA build outputs conflicted
(old bundle hashes on both sides). Resolution: accept origin's
resolution on the deleted files, then re-run scripts/refresh-fabro-spa.sh
from the merged source so the embedded bundle reflects both sides —
origin's Settings-nav/theme/stage-sidebar work plus this branch's
archived-status TypeScript changes in apps/fabro-web/app/data/runs.ts.

Verification:
- cargo build --workspace: clean
- cargo nextest run --workspace: 4198 passed, 182 skipped
- cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings: clean
- cargo +nightly-2026-04-14 fmt --check --all: clean
- apps/fabro-web bun run typecheck: clean
- apps/fabro-web bun test app/data/runs.test.ts: 8 pass

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 18:57:07 -04:00
Bryan Helmkamp
948d59062a
Merge origin/main into UI cleanup branch
Brings in the CLI storage/logging refactor (858e8e127), bootstrap
helper collapse (a256c14a7), and shared server-lifecycle test helpers
(f8c560a9a). No overlap with the web UI work on this branch.
2026-04-19 17:30:22 -04:00
Bryan Helmkamp
46813e3b05
docs(plan): mark Run Files tab plan completed
All 13 units shipped. Follow-ups noted inline: globset-based denylist
extraction and Virtualizer wrapping for very large runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:13:40 -04:00
Bryan Helmkamp
b589b581ff
docs(plan): mark Run Files tab plan partially completed
Captures what landed in this session (Units 1-10, 13) vs what's
deferred (Units 11-12) so follow-up work can pick up from a clean
baseline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 17:06:44 -04:00
Bryan Helmkamp
bdf645a774
docs: changelog entry and plan status=completed for archived runs 2026-04-19 16:59:46 -04:00
Bryan Helmkamp
03fc375cdd
feat(server): add archive/unarchive endpoints and include_archived listing
Extends the OpenAPI spec with POST /api/v1/runs/{id}/archive and /unarchive
operations, adds `archived` to the RunStatus enum, and adds an
`include_archived` query param to listRuns. Regenerates the progenitor-built
Rust types and the typescript-axios client. Implements `archive_run` and
`unarchive_run` handlers via `operations::archive/unarchive`, and extends
`list_runs` to filter archived runs unless opted in. Archived runs continue
to map through `api_status_from_workflow` and bypass the board column.
2026-04-19 16:53: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
54ddaa2cee
feat(install): redesign web wizard and scope dev token to PAT installs
Redesign the install wizard for clarity:
- swap the sidebar layout for a centered column and a horizontal stepper
- make completed/current stepper entries clickable links
- reorder steps so Server URL precedes LLMs
- use env-var placeholders (ANTHROPIC_API_KEY, etc.) with
  per-provider "Where do I get this?" disclosures
- replace the readonly "Validated username" input with a success pill
- drop the GitHub App name field (GitHub confirms the name anyway)
- re-label the GitHub App option and split review rows by strategy
- add a copy action to the Server URL on the review screen

Scope the dev token to PAT installs:
- only generate the dev token, write its files, and set FABRO_DEV_TOKEN
  inside the GithubInstallState::Token arm
- mark dev_token optional on InstallFinishResponse in the OpenAPI spec
- hide the Development token card on /install/finishing when absent
- add app_install_finish_omits_dev_token_and_does_not_write_it test

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:11:02 -04:00
Bryan Helmkamp
f65c7c3fd8
feat(api): add GET /runs/{id}/files spec + RunFilesMeta schema
Reintroduces the endpoint deleted in the April 5 server-only cleanup,
this time targeted at the web UI (not the CLI). Route registered with
not_implemented; real handler lands in Unit 5.

- FileDiff gains optional change_kind, truncated, truncation_reason,
  binary, sensitive fields (all additive, back-compat)
- New RunFilesMeta replaces PaginationMeta on PaginatedRunFileList
  (truncated, total_changed, to_sha, to_sha_committed_at, degraded,
  degraded_reason, patch, files_omitted_by_budget)
- from_sha / to_sha query params reserved for future use (non-default
  values 400 in v1)

Generated TS client picks up the new model; typecheck + openapi
conformance tests pass. No existing consumers of
PaginatedRunFileList['meta'] found in the monorepo.

Refs plan docs/plans/2026-04-19-002-feat-run-files-changed-tab-plan.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 15:33:24 -04:00
Bryan Helmkamp
b849738a5b
plans 2026-04-19 15:18:25 -04:00
Bryan Helmkamp
5958470a11
plan 2026-04-19 15:18:22 -04:00
Bryan Helmkamp
a1c816724b
plans 2026-04-19 15:18:21 -04:00
Bryan Helmkamp
2505cb6d46
Merge remote-tracking branch 'origin/main' into feat/web-install-wizard
# Conflicts:
#	lib/crates/fabro-spa/assets/assets/entry-ez8gc920.js
#	lib/crates/fabro-spa/assets/index.html
#	lib/packages/fabro-api-client/src/.openapi-generator/FILES
#	lib/packages/fabro-api-client/src/models/index.ts
2026-04-19 15:06:12 -04:00
Bryan Helmkamp
b8af65a9c6
refactor(runs): blocked status canonicalization cleanup (#165)
## Summary

Stacked cleanup of the `canonicalize blocked run status` work (local
commit `d13cdf374`) plus reconciliation with origin's `canonicalize
paginated run list responses` (origin commit `8ab689da7`). Both efforts
ran in parallel and diverged on the column name (`blocked` vs `waiting`)
and on how the board response is shaped — this PR converges them,
keeping `blocked` as the canonical column id while adopting origin's
`column` field on `RunListItem` and `StoreRunSummary` shape.

Also fixes a production-worker regression introduced by the
canonicalization: the worker's start-precondition only accepted
`Submitted | Starting`, so once runs started transitioning through
`Queued` on the way to `Starting`, every subprocess-worker run failed
with `Precondition failed: cannot start run: status is Queued`. That
cascaded into ~90 failing CLI/server integration tests locally.

## Commits

1. `f65843168` refactor(runs): simplify blocked status follow-ups
2. `1492d956c` chore: resolve clippy warnings
3. `676fd9f44` first merge of origin/main
4. `23fc92a2f` **fix(runs): allow Queued status in start precondition**
← the cascade-fix
5. `36b507a83` refactor: simplify pause/unpause + dedupe web status
tables
6. `8d8d27748` refactor(workflow): encapsulate BlockedStateTracker
inside HumanHandler
7. `1c17fda35` second merge of origin/main — resolves waiting vs blocked
8. `4cd3ef7b1` refactor(workflow): Mutex<usize> → AtomicUsize
9. `2e5a58e8a` fix(demo): align run-4 lifecycle status with Blocked
board column

## Test plan

- [x] fmt, clippy, build, doctests all clean
- [x] `cargo nextest run --workspace` — **4092/4092 pass**
- [x] `bun test` — **26/26 pass**, typecheck + production build clean
- [x] Manual CLI repro of the Queued-precondition fix
- [x] Browser smoke test: all 5 columns render with correct
labels/colors, demo run-4 appears in Blocked lane with question text
intact

## Known follow-up (not blocking)

A "paused-while-blocked" run (status `Paused` + `blocked_reason: Some`)
lands in the `running` column because the visible status chooses
`Paused` over `Blocked`. The pending question is not prominent on the
board. Addressing it would require `board_column()` to branch on
`(status, blocked_reason)` rather than just `status` — worth a separate
ticket.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:53:46 -04:00
Bryan Helmkamp
acb6b3f9d6
refactor(install): tag GithubAppOwner with discriminated object shape
The install GitHub App manifest shape encoded owner as `"personal"` or
`"org:<slug>"` - a magic string parsed in install-app.tsx, built by
install-api.ts, and reparsed server-side. Replace with a tagged object
`{ kind: "personal" } | { kind: "org", slug }` in the OpenAPI spec, the
progenitor-generated Rust types, and the frontend.

Server-side, the internal `GitHubAppOwner` enum keeps its semantic
shape but gains a `TryFrom<GithubAppOwnerInput>` conversion and emits
the tagged JSON via `as_session_value`.

Frontend drops `buildGithubOwnerValue` in favor of
`buildInstallGithubAppOwner`, and the ready-screen renders the owner
through a small helper instead of string concatenation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:48:31 -04:00
Bryan Helmkamp
dd4e467bfc
Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/crates/fabro-server/tests/it/api/mod.rs
2026-04-19 13:36:54 -04:00
Bryan Helmkamp
e8d0f75be9
Merge remote-tracking branch 'origin/main' 2026-04-19 12:46:19 -04:00
Bryan Helmkamp
9dd792c8b8
fix(install): exclude openai-compatible from v1 setup
Restrict the browser install flow to Anthropic, OpenAI, and Gemini,
remove the unused install-time base URL surface, and reject
openai_compatible with a stable 422 response.

Also fix the finishing health poller so it only redirects after the
server comes back healthy outside install mode instead of jumping early
on transient restart failures.
2026-04-19 11:43:38 -04:00
Bryan Helmkamp
ecdfdd82d8
feat(install): add browser-based setup flow
Implement the web-first install experience across the server, CLI, API spec,
web app, and packaged SPA assets.

This also removes test-side process env mutation by pushing env-dependent
decision points behind explicit helpers and test wiring.
2026-04-19 11:20:58 -04:00
Bryan Helmkamp
6226858648
fix(runs): finish canonical run summary rollout
Complete the /runs and /boards/runs canonicalization work by fixing the
run-detail response shape, preserving lifecycle status separately from board
columns, loading all board pages in the web client, and aligning the shared
status_reason typing.
2026-04-19 11:12:58 -04:00
Bryan Helmkamp
21240e2d09
fix(server): address TLS removal review follow-ups 2026-04-19 10:48:42 -04:00
Bryan Helmkamp
914778c8a8
refactor(server): remove inbound TLS termination
Remove server-side TLS listener support so Fabro only binds plain TCP
or Unix sockets, and update docs/tests around proxy-terminated HTTPS.
This also drops the removed [server.listen.tls] config shape and the
inbound TLS-specific diagnostics, fixtures, and integration coverage.
2026-04-19 10:43:57 -04:00
Bryan Helmkamp
8ab689da78
feat(runs): canonicalize paginated run list responses
Unify /api/v1/runs and /api/v1/boards/runs around a shared
paginated summary contract with additive convenience fields.

Update the server, demo data, generated clients, CLI pagination,
and web consumers so board views become a thin projection over the
canonical run summary surface.
2026-04-19 10:37:31 -04:00
Bryan Helmkamp
224673bdf6
docs(install): address sixth review pass on web-install spec
Two fixes:

P0 — Container packaging blocks install mode. The published Dockerfile
bakes /etc/fabro/settings.toml and sets FABRO_CONFIG, which under the
explicit-config carveout means containers would never enter install
mode. v1 must change the Dockerfile: drop the baked settings file,
drop FABRO_CONFIG, set FABRO_STORAGE_DIR=/storage, and persist
~/.fabro across container restarts (recommendation: move FABRO_HOME
into a subdirectory of the /storage volume so one mount covers both
config and data). Spelled out as load-bearing v1 implementation work
under Orchestration config updates. New decision-log row #24.

P2 — Force-foreground decision was not carried through to all sections.
Two leftover references to a `__serve` daemon child contradicted the
"install mode never daemonizes" decision — one in the local-lifecycle
prose, one in the manual smoke test. Updated both to describe the
foreground process exiting cleanly. Decision-log row for #21 also
updated to reflect that the install process IS the operator's `fabro
server start` invocation under foreground mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
d34f338e33
docs(install): address fifth review pass on web-install spec
Two fixes:

P1 — Install token surfacing in local daemon mode. Today's
`fabro server start` daemonizes by default; the daemon parent prints
its own summary but the child's stderr (where the install token would
print) is redirected to server.log. Operator wouldn't see the token
without tail-ing the log file. Decision: install mode forces foreground
regardless of how `fabro server start` was invoked; the token then
lands on the operator's terminal directly. Documented as "--foreground
is implicit during install." Daemon path is bypassed entirely for
install mode; restored on the supervisor restart.

P2 — `--no-web` contract hole. The flag is accepted by `server start`
and `server restart` but the spec didn't say what install mode does
with it. Decision: ignore during install with an explicit stderr
warning ("will be respected on next start"); respected after the
supervisor restart. Rejecting would force supervised-deployment
operators to either drop the flag or `docker exec` to run the CLI
wizard, defeating the point. Warning makes the override visible.

Added integration tests for both behaviors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
d21d9fa62f
docs(install): address fourth review pass on web-install spec
Three more fixes (all P2):

P2 — Goal wording said "using the same persistence helpers" but the
body explicitly carves out a separate install-mode vault path. Reword
to "same on-disk state, sharing the TOML/env primitives" so the
implementer isn't misled about how much of the CLI path is reused.

P2 — Summary said only `fabro server start` enters install mode but
the process model says start and restart. Reconcile: name both
commands explicitly in the summary.

P2 — Test plan covered the GitHub App `state` rejection path but not
the happy-path roundtrip (POST /install/github/app/manifest → GET
/install/github/app/redirect with stubbed conversion). Add an
integration test that covers the riskiest new path: code-exchange
wiring, session population, redirect-with-token handling, and that
the canonical-URL ordering decision actually flows through to the
manifest.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:50:44 -04:00
Bryan Helmkamp
0a576a5f74
docs(install): address third review pass on web-install spec
Three more fixes:

P0 — Local restart UX. Today's `fabro server start` does not stay
around to supervise the `__serve` child it spawns (`start.rs:318`), so
no auto-restart happens locally after `/install/finish` exits. Spec the
two cases honestly: supervised deployments rely on the supervisor;
local laptops show the operator a "run `fabro server start` to launch
your configured server" message after a 30s polling timeout. A built-in
local supervisor is named as a follow-up. Updated the manual-test
section to cover both cases and the orchestration-docs section to
detect supervised vs. local at boot time.

P1 — Auto-start callers must not enter install mode. `connect_server`
→ `connect_api_client_bundle` → `start::ensure_server_running_for_storage`
is used by `run attach`, `server runs`, etc. Add an explicit *Auto-start
callers* subsection and a new decision: only the explicit `fabro server
start` (or `restart`) command enters install mode. Auto-start callers
fail with a clear "configure first" message pointing the operator at
either `fabro server start` or `fabro install`.

P2 — Process-model rationale corrected. The previous draft claimed the
existing dispatch path "would error on missing settings.toml" but that
is false: `user.rs:77` returns defaults, `serve.rs:820-824` falls back
to a Unix socket, and `tests/it/cmd/server_start.rs:111` is a passing
test of `fabro server start` with no config. Reworded to say what is
actually true — without the fork, `fabro server start` cheerfully boots
a non-functional default server, and install mode displaces that
default. Summary line now mentions the explicit-config caveat too.

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