Commit Graph

12134 Commits

Author SHA1 Message Date
gsxdsm
faeb491ea4 fix(dashboard): harden terminal paste contract and manual-start button per review
Review follow-up to 907e8d03e (ce-code-review, 8 personas):
- Ctrl/Cmd+V with no clipboard API (or after a denied read) now returns
  false WITHOUT preventDefault: xterm skips key handling and the browser's
  default paste fires xterm's helper-textarea listener once. Returning true
  made non-mac xterm inject \x16 and cancel the native paste (verified
  against xterm 5.5.0 _keyDown).
- A denied clipboard read sets a sticky ref so later pastes use the native
  path instead of being preventDefaulted into zero delivery.
- Custom-path delivery goes through terminal.paste() to restore bracketed
  paste and newline normalization.
- 'Start terminal' surfaces createTab failures in the error banner and
  disables while a create is in flight (no duplicate PTY sessions).
- normalizeActiveTab() extracted so storage-read and server-validation
  share one all-inactive tie-break; failure-path regression test added.
- Rewrote docs/solutions/ui-bugs/xterm-async-font-remeasure-paste-dedupe.md
  to the current paste contract (was prescribing the pre-#1902 behavior).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:46:02 -07:00
gsxdsm
ca4639bb67 feat(dashboard): allow multiple tasks from one plan via epoch-scoped claims
One planning session can now create multiple tasks. Task-creation claims
are epoch-scoped: proposalClaimId stays planning-session:{id} for epoch 0
and becomes planning-session:{id}#N after the plan is edited past a
created task (rotateTaskCreationEpochOnReopen archives createdTaskId into
createdTaskIds and resets claim state). Unedited Proceed replays stay
idempotent within an epoch; crash-after-insert dedup still reconciles via
the epoch-keyed task row. Complete sessions resume to an editable plan
review with a linked-task banner; the task-created handoff gains a
Continue planning action.

Hardening from the multi-agent code review (9 reviewers):
- Reopen + rotation run only AFTER turn admission, so a rejected request
  never burns a phantom rotation (P1, 3 reviewers).
- Claim-lifecycle CAS writes are surgical jsonb merges and reconcile takes
  an expected-epoch guard, so a concurrent rotation can never be reverted
  or an archived task re-linked to a new epoch.
- create-task 409s while the session is still generating (turn-completion
  persist could tear the fresh linkage).
- Durable-read fallback in create-task now logs before trusting the
  in-memory epoch.
- linkedTaskId no longer leaks across session switches; the banner
  resolves the just-created Task before the tasks prop refreshes and
  falls back to the newest archived task after rotation; Continue
  planning re-registers the active session.
- Shared applyCompletePlanningResume helper replaces triplicated resume
  view-transitions; stale one-task-per-session comment corrected.

Tests: post-rotation replay idempotency and epoch-keyed crash reconcile
(e2e), rewind rotation + rejected-rewind non-rotation + payload
normalization round-trip (unit), Continue planning + banner-leak (UI),
create-task 409 (routes), and a new PG integration suite pinning the
surgical CAS merge and reconcile epoch guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:37:49 -07:00
gsxdsm
907e8d03e6 fix(dashboard): terminal manual-start on Windows clients and single-delivery Ctrl/Cmd+V paste
GitHub #2121/#2307: Windows browser clients intentionally skip first-tab
auto-create, but TerminalModal showed an endless 'Starting terminal...'
spinner whose only escape was the tab-strip '+'. useTerminalSessions now
exposes autoCreateDisabled and the modal renders an explicit 'Start
terminal' action instead. All-inactive persisted tab payloads are also
normalized on restore so the spinner can't wedge on activeTab=null.

Paste: attachCustomKeyEventHandler returning false does not cancel the
browser's default paste, so Ctrl/Cmd+V delivered the payload twice (custom
clipboard read + xterm helper-textarea paste event). preventDefault() makes
the custom read the single path; when the async clipboard API is missing
(non-HTTPS remote access, older Firefox) the handler returns true so the
native paste path works instead of paste being dead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:30:45 -07:00
gsxdsm
0e6108a1a5 fix(dashboard): Stop cancels pending initial planning turns per-session
stopGeneration only aborted generations with an activeGenerations record.
A just-started session whose initial turn was still pending (registered
by start-streaming, not yet consumed by a stream connect) returned false
from Stop and the "stopped" generation sprang back to life on the next
stream connect. Stop now discards the pending turn too, and remains
strictly keyed to its session id so stopping one plan never affects other
concurrently generating sessions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:52:19 -07:00
gsxdsm
370a7a645d fix(dashboard): a validated plan stays readable, editable, and creatable
A finished plan must never land on a do-nothing screen:

- submitResponse/rewindSession REOPEN a validated session (clear the
  terminal marker; the turn's persistSession durably writes it) instead
  of rejecting with "already been validated". validateSession remains the
  only terminalizer.
- A complete session with no created task resumes into the full plan
  review workspace (read plan, Refine/comments, Proceed) instead of the
  create-only retry card; task-linked sessions still resume to the task
  handoff, preserving the never-rotated one-task-per-session claim.
- The live create-failure screen gains a Back to plan action.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:52:19 -07:00
gsxdsm
ddea2876c4 fix(dashboard): let the planning workspace loader scroll on short viewports
Code-review follow-up to e2ee8ba27: the loader overlay now hosts the
streamed-thinking pane, and on short viewports (landscape phones are in
the mobile breakpoint) the centered column could exceed the overlay and
clip the Stop button and thinking output. The overlay scrolls instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:52:19 -07:00
gsxdsm
e2ee8ba276 fix(dashboard): stream AI thinking on every Planning Mode generation step
The workspace loader that covers all follow-up turns (next question,
refine, contextual comments, question regeneration) showed only a spinner
and elapsed time — streamed thinking/output was visible only on the first
pre-summary turn. Reuse the initial loading view's thinking container and
toggle there, and mirror the generation-activity label instead of a
hardcoded "Generating plan…".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:39:10 -07:00
gsxdsm
7cb87e7687 fix(dashboard): regenerate interview questions in mission/milestone/onboarding too
Extends the Planning Mode no-active-question fix to the other three
interview lanes: a LIVE session (no summary yet) that receives a
submission with no active question now reprompts the agent to continue
the interview and ask a fresh question — carrying the submitted input as
context — instead of throwing "No active question in session". Completed
interviews (summary present) still reject late submissions, preserving
the existing contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:39:10 -07:00
gsxdsm
64b20c8be3 fix(dashboard): regenerate a planning question instead of "No active question in session"
Refining a plan (or submitting any input) while the session had no active
question — e.g. after a failed retry cleared summary/currentQuestion —
threw InvalidSessionStateError("No active question in session") at the
operator. Now the interview continues instead:

- The refine and contextual-comment branches no longer require
  session.summary; they fall back to a running summary rebuilt from
  persisted history.
- A submission with no active question reprompts the agent via
  formatQuestionRegenerationForAgent to produce a fresh option-driven
  question, carrying the submitted operator input along as context.
- The Planning modal forwards no-question submissions to the server
  (loading view + SSE) instead of dead-ending with a local error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:29:59 -07:00
gsxdsm
b462978e92 fix(dashboard): emit planning terminal error exactly once on stream reconnect
Code-review follow-up to 716e69862: the terminal-error reconcile ran after
the Last-Event-ID replay, so a reconnecting client received a buffered
error event from the replay AND again from the reconcile block (double
onError, duplicate auto-retry triggers). The reconcile now runs before the
replay and skips it for terminal sessions, writing the newest buffered
error event (or a fresh broadcast when the bounded buffer evicted it)
exactly once, gated on lastEventId.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:18:04 -07:00
gsxdsm
2bebed18b2 fix(dashboard): pin mobile comment composer to visualViewport above keyboard
Phone fixed bottom:overlap left the panel under the soft keyboard (layout vs
visual viewport). While open on mobile, remeasure visualViewport and pin with
top/max-height so the entry box stays visible when the keyboard opens.
2026-07-23 18:16:28 -07:00
gsxdsm
b67dca4178 fix(dashboard): stop Chat Latest button jumping under the cursor
Center the jump-to-latest chip with margin-inline auto instead of
transform:translateX(-50%) so global .btn transform transitions and
:active scale cannot shift it sideways in Quick Chat and full Chat.
2026-07-23 18:15:03 -07:00
gsxdsm
716e698628 fix(dashboard): stop Planning Mode hanging on provider errors mid-generation
Provider errors thrown between persistSession("generating") and the turn's
own error handling (agent rebuild in ensureSessionAgent, history replay,
legacy sync createSession first turn) escaped to the route and left the
session row "generating" forever with no error, no SSE event, and no
watchdog — the modal hung on "Thinking/Generating plan" because its SSE
reconnect loop and 8s poll both treat a persisted "generating" row as
healthy.

- submitResponse/retrySession/createSession now convert any non-abort
  escape after entering "generating" into the standard persisted retryable
  error + SSE error broadcast before rethrowing.
- The SSE stream route reconciles settled/stranded sessions on connect
  (reconcileStalePlanningGeneration): a terminal error is replayed and the
  stream closed; a "generating" session with no live/pending turn past the
  watchdog window is converted to a retryable interrupted error.
- Provider failures on the JSON reformat retry now surface as themselves
  instead of a misleading "no valid JSON" parse error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:14:29 -07:00
gsxdsm
dcbf923e07 fix(dashboard): keep planning comment editor open after selection collapse
Snapshot the selected quote on Add-comment pointerdown and freeze it for the
composer so mobile selectionchange can no longer clear the quote and unmount
the entry box as soon as it opens.
2026-07-23 18:12:52 -07:00
gsxdsm
34a9216509 fix(dashboard): prevent comment-composer keyboard blur without early commit
Add/Submit no longer run on pointerdown (that closed the box immediately).
Match Start Planning: preventDefault keeps focus for the click, then click
commits the action once.
2026-07-23 18:09:13 -07:00
gsxdsm
b6a930eff0 fix(dashboard): commit planning comments on pointerdown before keyboard blur
On phone/tablet the first tap of Add/Submit blurred the composer, closed the
keyboard, and shifted the fixed panel so the click was lost. Commit the action
on pointerdown (same pattern as Refine Apply) so one tap is enough.
2026-07-23 18:03:21 -07:00
gsxdsm
45da5f71d3 fix(dashboard): keep planning comment composer above the keyboard
Pin the selection comment editor as a fixed panel on tablet and phone, and
lift it with visualViewport keyboard metrics so the first focus no longer
hides the form under the OS keyboard (or off-screen on tablet).
2026-07-23 17:56:05 -07:00
gsxdsm
f8e6fd5e2b fix(dashboard): stack tablet Add comment above actions with mobile icon
Tablet plan-actions no longer use flex nowrap (which put Add comment beside
Refine/Proceed). Keep the two-column grid so the selection control is a
full-width first row, and pin MessageSquarePlus to the same 16px/token size
as mobile.
2026-07-23 17:49:53 -07:00
gsxdsm
b15fd2b498 fix(dashboard): stack mobile Add comment above Refine/Proceed
Phone no longer pins Add comment under the action rail as a fixed bar. It
uses the same full-width in-flow footer row as tablet, above Refine and
Proceed. The composer stays fixed when open.
2026-07-23 17:43:27 -07:00
gsxdsm
73a57d9487 fix(dashboard): recover finished planning sessions instead of retry dead-ends
Reopening a complete plan no longer shows "still being prepared" when the
validated payload marker is missing. Generation Retry that hits
"already been validated" refreshes into create-retry or plan review.
2026-07-23 17:39:33 -07:00
gsxdsm
28e2cd587c fix(dashboard): put plan-review Add comment above actions on tablet
Tablet (≤1024px) now uses the action-rail Add-comment control as a full-width
row above Refine/Proceed instead of the document-end trigger. Phone keeps the
fixed bar above the mobile nav; desktop keeps the in-document control.
2026-07-23 17:36:10 -07:00
gsxdsm
c1d37cb137 test(FN-8544): assert mission autopilot system actor on status updates
Align MissionAutopilot expectations with autonomy-audit attribution: updateMission
carries the system actor options, and autopilot_disabled is recorded on the
mutation instead of a separate logMissionEvent mirror.
2026-07-23 17:28:56 -07:00
gsxdsm
0307476f35 fix(tests): restore listTasks hot-path contract and PG harness fs isolation
- usage-limit-detector + provider-health-monitor: make three bare listTasks()
  callers explicit with { slim: true }, restoring the architecture-hot-paths
  contract (they only read scalar pause/column/model-provider fields).
- pg-test-harness beforeEach: wipe <rootDir>/.fusion/tasks after TRUNCATE ...
  RESTART IDENTITY so filesystem isolation matches the id reset; stale task
  dirs from prior tests no longer collide with reused IDs (fixes
  store-reservation-atomicity rollback assertions).
2026-07-23 17:27:59 -07:00
gsxdsm
62c52972fc fix(dashboard): keep mobile plan-review selection comments on-screen
Plan review Add-comment controls now track document-level selectionchange so
they appear as soon as text is selected and dismiss when the selection ends.
On mobile the trigger and composer are fixed above the nav (with width auto)
so operators no longer need to scroll to reach them.
2026-07-23 17:19:26 -07:00
gsxdsm
dfb9ca6630 FN-8543: enforce bounded generated-fix remediation
Keep generated fix chains within their root retry budget and preserve intervention stops.

- Track retry counts and stop reasons on the canonical root feature.
- Persist project-isolated lineage stops across generated-fix removal and archive paths.
- Serialize stop recording with generated-fix admission and expose conflict-safe mission resume behavior.

Files changed:
 .changeset/fn-8543-bounded-fix-lineage.md          |   7 +
 docs/missions.md                                   |   6 +-
 .../__tests__/postgres/mission-store.pg.test.ts    |  72 +++++++
 packages/core/src/async-mission-store-queries.ts   |  91 ++++++++-
 packages/core/src/async-mission-store.ts           | 206 ++++++++++++++++++---
 packages/core/src/index.ts                         |   2 +-
 packages/core/src/mission-store.ts                 |  10 +
 packages/core/src/mission-types.ts                 |   7 +
 .../0035_fn_8543_mission_lineage_stop.sql          |  31 ++++
 packages/core/src/postgres/schema-applier.ts       |  18 +-
 packages/core/src/postgres/schema/project.ts       |  21 +++
 .../core/src/task-store/archive-lifecycle-2.ts     |  15 +-
 .../core/src/task-store/async-archive-lineage.ts   |  10 +-
 packages/dashboard/src/mission-routes.ts           |  14 +-
 packages/engine/src/mission-execution-loop.ts      |  30 ++-
 15 files changed, 495 insertions(+), 45 deletions(-)

Fusion-Task-Id: FN-8543

Fusion-Task-Lineage: 24c03d63-5914-4072-aa17-16862432fc78

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 16:12:44 -07:00
Victor Canô
0c085bf444 fix(engine): pushAfterMerge no longer strands approved merges when the remote diverges (#2407)
## Problem

With `pushAfterMerge` enabled (and `mergeStrategy` other than
`pull-request`), if `origin/<integration-branch>` advances externally
between the local squash-merge and the push, the divergence path opens a
clean-room `git pull --rebase` and an AI agent resolves and stages the
conflicts — but the flow could end there: no `git rebase --continue`, no
push, and no surfaced error.

Because finalize runs *before* the push, the task is already `done`, so
a reviewed, approved merge is silently left container-only, and every
subsequent merge on the project stalls the same way. Separately, an
abort mid-push (`MergeAbortedError`) was swallowed with only a
process-log warning — no task-log entry, no run-audit event.

## Change

- **Deterministic regression coverage** for the conflicting-divergence
path (real-git fixture) proving the rebase runs to completion and the
push lands (refs converge), plus abort/termination scenarios.
- **Recovery-branch safety net:** before the clean-room rebase starts,
the pre-rebase local squash is force-pushed to a per-task remote branch
`fusion/<task-id>-stranded`, so approved content is never container-only
— even across process death or abort. Deleted after a successful target
push; retained on failure/abort as the recovery source.
- **Never-silent outcomes:** every non-pushed outcome (failure or abort)
writes a durable task-log entry and a `push:origin` run-audit event. The
audit contract now documents `push:origin` as polymorphic (dashboard
Smart Push vs. automated post-merge push) and enumerates the automated
path's outcomes, including the new `"aborted"` shutdown case.
- **Cleanup hardening:** `isRebaseInProgress` now probes Git's
worktree-specific `rebase-merge`/`rebase-apply` state directories
(async, timeout-guarded) so a completed rebase can't receive a spurious
second `--continue`; unfinished rebases are cleaned up.

Out of scope by design: withholding the "merge confirmed" state until
the push succeeds — the `FNXC:MergePush` invariant ("a push problem can
never park or roll back a landed merge") is deliberate; the recovery
branch + surfacing satisfy the data-preservation intent without breaking
it.

## Files
`packages/engine/src/merger-ai.ts`, `packages/engine/src/merger.ts`,
`packages/engine/src/run-audit.ts`, new/updated tests under
`packages/engine/src/__tests__/`, `docs/settings-reference.md`,
`docs/dashboard-guide.md`, `AGENTS.md`, and a labeled changeset.

## Validation
`tsc --noEmit` clean; engine divergence + merger suites pass (41 tests);
rebased onto current `main` with no conflicts.

---

_Developed with Claude Code, under human supervision and review._


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Prevented approved post-merge pushes from becoming stranded when the
remote diverges by using a recovery-branch workflow and safer cleanup.
* Improved behavior and reporting when pushes are aborted or fail after
merge, including clearer non-fatal status and audit outcomes.
* **Documentation**
* Expanded push-after-merge and dashboard Smart Push documentation with
recovery-branch and `push:origin`/`push:recovery-branch` outcome
semantics.
* **Tests**
* Added end-to-end regression tests for divergent/conflicting AI
push-after-merge flows, including abort and worktree cleanup
verification.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Victor Cano <victortroz@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-23 15:55:03 -07:00
Phil Larson
9f79b22d51 fix(i18n): restore secondary locale key parity (#2430)
## Summary
- synchronize all five secondary app locale catalogs with the authored
English key structure
- restore fallback entries for heartbeat controls, release-channel
settings, report targeting, and task provenance labels
- add a patch changeset for the catalog parity fix

## Test Plan
- `pnpm i18n:status`
- `pnpm --filter @fusion/i18n test` (29 tests)
- `pnpm --filter @fusion/dashboard exec vitest run
app/components/__tests__/AgentsView.test.tsx --silent=passed-only
--reporter=dot` (138 tests)
- `pnpm check:changesets`
- `pnpm build`


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Improved localization consistency for heartbeat controls, capability
settings, release-channel configuration, reporting guidance, and task
provenance details.
- Added missing translation entries across Spanish, French, Korean,
Simplified Chinese, and Traditional Chinese locales.
- Untranslated values now fall back cleanly to the authored English text
structure, preventing missing or inconsistent labels in supported
interfaces.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-23 15:54:41 -07:00
Umut
2b9131ba7c Fix broken anchor in README Workflow Steps link (#2431)
The Workflow Steps bullet in README.md links to
`./docs/workflow-steps.md#workflow-declared-optional-steps`, but the
target heading is `#### Workflow-declared optional steps
(`optional-group` nodes)`, which GitHub slugifies (including the
parenthesized text) to
`#workflow-declared-optional-steps-optional-group-nodes`. As a result
the link lands at the top of the page instead of the intended section.

The correct anchor is already used by a self-link elsewhere in the same
file (docs/workflow-steps.md, the "Optional groups and default-on gates"
row), confirming the expected slug.

This is a one-line fix: append `-optional-group-nodes` to the anchor in
README.md.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Updated the Workflow Steps documentation link to direct readers to the
more specific “optional group nodes” section.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-23 15:54:16 -07:00
gsxdsm
11fab37379 feat(ci): incremental caching for the PR merge-gate jobs (Gate, Build, Typecheck) (#2421)
## Summary

Every PR's blocking checks were dominated by redundant full rebuilds,
not by tests. Measured on recent runs: the Gate job spent ~6 of its ~7.5
min on a cold `pnpm build` (the exact-key dist cache missed on virtually
every PR) for ~45s of actual boot smoke + gate tests; Build ran ~8 min
and Typecheck ~4 min, both fully cold every time. Expected end state
once the warm job has run on main: all four blocking checks in roughly
2–4 min wall-clock.

### Gate job
- New `gate-dist-*` cache namespace with `restore-keys`, additionally
caching `.fusion/cache/plugin-build-cache.json` (build-workspace's
per-package content-hash skip cache) and `packages/cli/dist`. The
always-run `pnpm build` reconciles a near-match restore by content hash
and rebuilds only the packages the PR touched. This is safe *because*
the gate builds after restoring — the shard jobs' "no restore-keys" rule
(FN-4232/FN-4605 stale-dist incidents) still stands there, since they
consume dist without building.
- `FUSION_CLI_FULL_PACKAGE=0` on the gate build: skips the multi-minute
CLI desktop/plugins/DTS packaging tail nothing in the gate consumes
(same shape `pnpm verify:fast` proves locally). Full CLI packaging
coverage stays blocking in the Build job.

### Build job
- Restore-only tap (`actions/cache/restore`) of the same warmed cache.
Restore-only because this job runs FULL CLI packaging (`CI=true`) and
saving that shape would swap the cache's canonical fast-CLI contents out
from under the Gate job. Its distinctive coverage is preserved:
`ensureFullPackageCliPlanned` force-plans the CLI in full mode
regardless of cache state.

### Typecheck job
- Caches per-package tsc incremental buildinfo — self-validating (tsc
hashes every input against it and re-checks whatever changed), so
`restore-keys` is correctness-neutral by construction.
- **Fixes a real incrementality bug:** `tsconfig.json` and
`tsconfig.app.json` in the dashboard both inherited
`${configDir}/dist/.tsbuildinfo` from `tsconfig.base.json`, so the two
typecheck programs clobbered each other's buildinfo and re-checked the
full program every run — incremental typechecking never worked for the
dashboard, in CI or locally. `tsconfig.app.json` now writes
`dist/.tsbuildinfo-app`. Measured: dashboard typecheck 44s cold → 5.6s
warm.

### Warm job (full-suite.yml, push to main)
- New `warm-gate-build-cache` job saves both caches from main on every
push. Caches saved on a PR merge ref are invisible to other PRs, so
without this every PR's *first* run would still build/check cold.

## Guardrails

`ci-workflow.test.ts` pins the coupled invariants so they can't drift
apart silently:
- restore-keys requires the reconciling `pnpm build` after restore,
before boot smoke
- the mtime-defeating seed step stays exact-hit-only
- byte-identical cache path lists between the Gate/Build/warm blocks
(actions/cache versions caches by path list — a drifted list makes
caches mutually invisible)
- Build stays restore-only and must NOT opt out of full CLI packaging
- Typecheck cache shape + the distinct dashboard app buildinfo path

## Notes

- First PR runs after this lands still build cold until the warm job has
run once on main.
- No changeset: CI config + test-only per AGENTS.md.

## Verification

- `ci-workflow.test.ts` + `package-config.test.ts`: 106 tests pass
- Dashboard typecheck run twice locally: 44s cold → 5.6s warm, both
`.tsbuildinfo` and `.tsbuildinfo-app` written, exit 0
- Cache block path/key parity verified programmatically across both
workflow files

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Performance**
* Improved CI build and type-check performance through incremental
caching.
* Added cache warming from the main branch to speed up pull request
checks.
* Enabled faster CLI packaging during gate validation while retaining
full packaging coverage elsewhere.

* **Bug Fixes**
* Prevented dashboard TypeScript build information from being
overwritten, preserving incremental type-checking reliability.

* **Tests**
* Added coverage to verify CI cache behavior, build ordering, cache
paths, and packaging modes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:53:31 -07:00
gsxdsm
94644ef849 fix(planning): mark session complete after Proceed-with-plan task creation
Proceed with plan called /api/planning/create-task without the legacy
/validate step, so the persisted AI session stayed awaiting_input and the
session list/needs-input banner kept advertising a finished session. The
create-task route now terminalizes the session via validateSession on every
path that ends with a created task, including alreadyCreated reconciliation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:45:39 -07:00
gsxdsm
d3f15f92bf docs: rewrite 0.73.0 beta changelog sections to per-beta deltas
The root CHANGELOG's beta sections (and the matching GitHub prerelease bodies, now edited in place) carried full-cycle aggregates because every beta distilled all preserved pre-mode changesets. Rebuilt each section from packages/cli/CHANGELOG.md's incremental per-beta entries so each beta lists only its own changes; future releases are handled by the channel-scoped selection in release.mjs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:41:09 -07:00
gsxdsm
e5caea542a FN-8544: gate mission remediation behind autopilot
Keep mission validation report-only until an operator explicitly enables autopilot.

- Gate validator-created remediation features and task dispatch behind mission autopilot.
- Audit attributed status and autopilot transitions atomically across mission stores.
- Expose mission autonomy controls and document the opt-in lifecycle.

Files changed:
 .changeset/fn-8544-mission-autonomy-audit.md       |   7 ++
 docs/missions.md                                   |  10 +-
 packages/cli/src/extension.ts                      |  26 ++++-
 .../__tests__/postgres/mission-store.pg.test.ts    |  27 +++++
 packages/core/src/async-mission-store.ts           |  70 +++++++++++--
 packages/core/src/index.gate.ts                    |   3 +
 packages/core/src/index.ts                         |   3 +
 packages/core/src/mission-store.ts                 | 113 +++++++++++++--------
 packages/core/src/mission-types.ts                 |  22 ++++
 .../dashboard/app/components/MissionManager.tsx    |   1 +
 packages/dashboard/src/mission-routes.ts           |  25 +++--
 .../src/__tests__/agent-mission-tools.test.ts      |  17 +++-
 .../src/__tests__/mission-execution-loop.test.ts   |  21 ++++
 packages/engine/src/agent-heartbeat.ts             |   4 +-
 packages/engine/src/agent-tools.ts                 |  30 +++++-
 packages/engine/src/executor.ts                    |   5 +-
 packages/engine/src/mission-autopilot.ts           |  51 +++++-----
 packages/engine/src/mission-execution-loop.ts      |  49 ++++++---
 packages/engine/src/triage.ts                      |   5 +-
 19 files changed, 377 insertions(+), 112 deletions(-)

Fusion-Task-Id: FN-8544

Fusion-Task-Lineage: 23a69923-5a19-407e-9fe2-8973c166ee9a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 15:25:09 -07:00
gsxdsm
e7c9b2ac80 FN-8542: separate milestone acceptance from feature validation
Keep feature validation scoped to linked feature assertions while evaluating milestone acceptance at rollup.

- Add assertion scope and origin provenance with database migration support
- Synchronize milestone acceptance prose to a canonical milestone assertion
- Prevent milestone assertions from affecting feature verdicts and document the completion contract
- Cover scoped validation and milestone rollup behavior with core and engine tests

Files changed:
 .changeset/fn-8542-feature-validation-scope.md     |   7 +
 docs/missions-completion-contract.md               |  25 +-
 docs/missions.md                                   |   6 +-
 .../mission-store.sync-loop-transition.test.ts     |  53 +++++
 packages/core/src/async-mission-store-queries.ts   |  17 +-
 packages/core/src/async-mission-store.ts           |  58 ++++-
 packages/core/src/mission-store.ts                 | 118 +++++++++-
 packages/core/src/mission-types.ts                 |  25 ++
 .../core/src/postgres/migrations/0000_initial.sql  |   2 +
 .../0034_milestone_assertion_provenance.sql        |  30 +++
 packages/core/src/postgres/schema-applier.ts       |  24 +-
 packages/core/src/postgres/schema/project.ts       |   1 +
 .../src/__tests__/mission-execution-loop.test.ts   | 161 ++++++++++++-
 packages/engine/src/mission-execution-loop.ts      | 262 ++++++++++++++++-----
 14 files changed, 700 insertions(+), 89 deletions(-)

Fusion-Task-Id: FN-8542

Fusion-Task-Lineage: cf112d31-376a-456e-be08-225eab5de393

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 14:39:44 -07:00
gsxdsm
2978ec4973 FN-8551: add accessible agent heartbeat controls
Add per-agent and project-wide heartbeat enablement controls.

- Add preserved runtime configuration helpers and heartbeat controls across agent list, board, and org-chart views.
- Add bulk enable/disable actions, accessible labels, localized copy, documentation, and release metadata.
- Cover heartbeat mutations through dashboard, route, scheduler, and layout smoke tests.

Files changed:
 .changeset/fn-8551-agent-heartbeat-controls.md     |   7 +
 docs/dashboard-guide.md                            |   2 +
 packages/dashboard/app/api/agents.ts               |  12 ++
 packages/dashboard/app/api/legacy.ts               |   2 +
 .../dashboard/app/components/AgentDetailView.tsx   |  14 +-
 packages/dashboard/app/components/AgentsView.css   |  11 ++
 packages/dashboard/app/components/AgentsView.tsx   | 186 ++++++++++++++++-----
 .../AgentDetailView.advanced-settings.test.tsx     |  29 ++++
 .../__tests__/AgentDetailView.test-helpers.ts      |   2 +
 .../app/components/__tests__/AgentsView.test.tsx   |  68 ++++++++
 .../dashboard/scripts/browser-layout-smoke.mjs     |  54 ++++++
 .../src/routes/__tests__/agent-core-routes.test.ts |  69 ++++++++
 .../src/__tests__/heartbeat-scheduler.test.ts      |  21 +++
 packages/i18n/locales/en/app.json                  |  19 ++-
 packages/i18n/locales/es/app.json                  |  19 ++-
 packages/i18n/locales/fr/app.json                  |  19 ++-
 16 files changed, 484 insertions(+), 50 deletions(-)

Fusion-Task-Id: FN-8551

Fusion-Task-Lineage: 2d4c8a15-a444-47b6-b57c-f41fc4163155

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 14:32:58 -07:00
gsxdsm
3d0ce2ed3a FN-8545: enforce mission lineage task admission
Protect feature bootstrap task creation with mission-lineage admission rules.

- Restrict supervised agents to linked autonomous mission features
- Atomically claim defined feature tasks and preserve duplicate ownership
- Lock defined feature claims to prevent concurrent bootstrap inserts
- Document admission behavior and add PostgreSQL and delegation coverage

Files changed:
 .changeset/fn-8545-mission-admission.md            |   7 +
 docs/agents.md                                     |   6 +
 docs/missions.md                                   |  12 +-
 .../__tests__/postgres/mission-store.pg.test.ts    | 119 ++++++++++++
 packages/core/src/async-mission-store.ts           | 203 +++++++++++++++++++--
 packages/core/src/duplicate-guard.ts               |  14 +-
 packages/core/src/mission-store.ts                 |  15 ++
 packages/core/src/task-store/task-creation.ts      | 152 ++++++++++-----
 .../src/__tests__/agent-tools-delegation.test.ts   | 152 ++++++++++++++-
 packages/engine/src/agent-tools.ts                 | 151 ++++++++++++++-
 10 files changed, 753 insertions(+), 78 deletions(-)

Fusion-Task-Id: FN-8545

Fusion-Task-Lineage: c6e1b46d-f434-4b07-93bc-27e1f6b491b1

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 14:21:29 -07:00
gsxdsm
ffbda3fb52 FN-8550: theme agent Settings controls
Apply token-driven styling and responsive behavior across Agent Settings controls.

- Theme configuration inputs, runtime tabs, avatar actions, policy editor, model combobox, and skill multiselect states
- Add coverage for Settings styling contracts, runtime/avatar semantics, and skill selection states
- Correct the model-filter clear control sizing with a valid themed font token

Files changed:
 .../agent-detail-settings-theme-styling.test.ts    | 103 ++++++++++++
 .../dashboard/app/components/AgentDetailView.css   | 113 +++++++++++++
 .../dashboard/app/components/AgentDetailView.tsx   |   8 +-
 .../app/components/AgentPermissionPolicyEditor.css |  44 +++++-
 .../app/components/CustomModelDropdown.css         |  84 +++++-----
 .../dashboard/app/components/SkillMultiselect.css  | 174 ++++++++++++++-------
 .../dashboard/app/components/SkillMultiselect.tsx  |   4 +
 .../AgentDetailView.advanced-settings.test.tsx     |  36 +++++
 .../components/__tests__/SkillMultiselect.test.tsx |  57 +++++++
 9 files changed, 518 insertions(+), 105 deletions(-)

Fusion-Task-Id: FN-8550

Fusion-Task-Lineage: 5a55ded8-2cd7-4364-855a-3763d5d8af95

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 13:38:41 -07:00
gsxdsm
15b5441afc FN-8548: keep GitHub import actions on one mobile row
Keep all selected GitHub issue actions touch-safe and visible on a single mobile row.

- Group detail action controls separately from the comment composer and make their mobile tracks shrinkable.
- Add responsive browser-smoke coverage at 320px, 390px, and 412px plus modal structure tests.
- Document the mobile behavior and add a patch changeset.

Files changed:
 .changeset/fn-8548-mobile-github-import-actions.md |   7 +
 docs/dashboard-guide.md                            |   8 +-
 .../dashboard/app/components/GitHubImportModal.css |  42 +++++-
 .../dashboard/app/components/GitHubImportModal.tsx |  80 ++++++------
 .../__tests__/GitHubImportModal.test.tsx           |  50 ++++++++
 packages/dashboard/app/styles.css                  |  11 +-
 .../dashboard/scripts/browser-layout-smoke.mjs     | 142 ++++++++++++++++++++-
 7 files changed, 290 insertions(+), 50 deletions(-)

Fusion-Task-Id: FN-8548

Fusion-Task-Lineage: 8fab6a1d-0ca9-4246-9707-e1fc84ca58e5

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 13:28:19 -07:00
gsxdsm
e734ed8a48 FN-8541: expose actionable validator diagnostics
Surface normalized, secret-safe validator evidence and assertion verdicts across mission events and remediation work.

- Normalize, redact, bound, and render per-assertion validation diagnostics in shared core APIs.
- Attach verdict-driven diagnostics to failure events and generated fixes while suppressing duplicate triage noise.
- Display validator evidence in Mission activity and document the operator workflow.
- Add core and engine coverage for evidence, mixed blocked verdicts, and triage behavior.

Files changed:
 .changeset/fn-8541-validator-diagnostics.md        |   7 ++
 docs/missions.md                                   |  17 +++
 .../mission-store.validation-diagnostics.test.ts   |  65 ++++++++++
 packages/core/src/async-mission-store.ts           |   8 +-
 packages/core/src/index.gate.ts                    |  10 ++
 packages/core/src/index.ts                         |  10 ++
 packages/core/src/mission-store.ts                 |  10 +-
 packages/core/src/mission-types.ts                 | 136 +++++++++++++++++++++
 .../dashboard/app/components/MissionManager.css    |  21 ++++
 .../dashboard/app/components/MissionManager.tsx    |  56 +++++++++
 packages/dashboard/app/components/mission-types.ts |   3 +
 .../src/__tests__/mission-execution-loop.test.ts   |  44 +++++++
 .../mission-validator-behavioral-posture.test.ts   |  37 +++++-
 packages/engine/src/mission-execution-loop.ts      | 117 +++++++++++++-----
 14 files changed, 501 insertions(+), 40 deletions(-)

Fusion-Task-Id: FN-8541

Fusion-Task-Lineage: b226fc34-f35c-4ce5-bcb5-e418529caaa7

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 13:21:10 -07:00
gsxdsm
47d2d176ef FN-8552: add disabled heartbeat scheduling option
Allow agent heartbeat scheduling to be paused and resumed without losing its configured cadence.

- Add a Disabled heartbeat interval dropdown option that persists runtime enablement.
- Re-enable scheduling when preset or custom intervals are selected.
- Cover disabled, legacy, desktop/mobile, and configuration-preservation flows.
- Document the heartbeat control and add a patch changeset.

Files changed:
 .changeset/fn-8552-heartbeat-disabled-option.md    |   7 ++
 README.md                                          |   2 +-
 packages/dashboard/app/components/AgentsView.tsx   |  41 +++++++-
 .../app/components/__tests__/AgentsView.test.tsx   | 115 +++++++++++++++++++++
 4 files changed, 162 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-8552

Fusion-Task-Lineage: 07f78005-4ac0-4210-9dd3-6c5b06ab7bc5

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 13:04:17 -07:00
gsxdsm
2021d5679b FN-8540: render mission hierarchies in agent lookup
Render complete mission hierarchy details from the fn_mission_show agent tool.

- Format mission, linked-goal, milestone, slice, and feature metadata with IDs and statuses
- Link features to their tasks and bound verbose acceptance and verification text
- Cover populated and empty hierarchy responses with regression tests
- Add a patch changeset for the agent lookup fix

Files changed:
 .changeset/fn-8540-mission-show-hierarchy.md       |  7 ++
 .../src/__tests__/agent-mission-tools.test.ts      | 68 +++++++++++++++++++
 packages/engine/src/agent-tools.ts                 | 77 +++++++++++++++++++++-
 3 files changed, 150 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-8540

Fusion-Task-Lineage: f2282226-3f4e-4d9f-bd8e-d18ad9639c03

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 12:46:09 -07:00
gsxdsm
a69e66b54b FN-8553: prevent agent card badge overlap
Keep agent identities and status badges readable across card widths.

- Wrap desktop and split-sidebar card headers without permitting text overflow.
- Stack identity and badge regions on narrow mobile cards.
- Cover long identities and populated badge layouts with regression tests.

Files changed:
 packages/dashboard/app/components/AgentsView.css   | 38 +++++++++++++++++++++
 .../app/components/__tests__/AgentsView.test.tsx   | 39 ++++++++++++++++++++++
 .../__tests__/agents-view-mobile.test.tsx          | 12 +++++++
 3 files changed, 89 insertions(+)

Fusion-Task-Id: FN-8553

Fusion-Task-Lineage: b0015f41-44e6-4cc9-8ec9-d9c0c61f7f18

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 12:40:10 -07:00
gsxdsm
0d355f371c FN-8547: add local OpenAI-compatible provider onboarding
Add guided onboarding for OpenAI-compatible local model providers.

- Add custom/local provider prompts and atomic models registry updates.
- Preserve registry fields, validate endpoint configuration, and support Qwen thinking compatibility.
- Document setup and cover registry persistence with onboarding tests.

Files changed:
 .changeset/fn-8547-local-provider-onboarding.md    |   7 +
 docs/cli-reference.md                              |  13 ++
 docs/settings-reference.md                         |  35 ++++-
 packages/cli/src/commands/__tests__/onboard.test.ts |  55 ++++++-
 packages/cli/src/commands/onboard.ts               | 161 ++++++++++++++++++++-
 5 files changed, 261 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-8547

Fusion-Task-Lineage: 740221de-fce8-43ae-a095-13b8abf1904a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 12:31:55 -07:00
gsxdsm
84d7306bd3 FN-8546: fix ideation candidate discovery
Expose persisted ideation candidate identities so agents can select a candidate for convergence.

- Render candidate IDs, provenance, source references, and content in show and diverge responses.
- Cover discover-to-converge behavior, duplicate content, empty sessions, and missing sessions.
- Document the direct candidate-ID convergence workflow and add a patch changeset.

Files changed:
 .changeset/fn-8546-ideation-candidate-ids.md       |  7 ++
 docs/agent-tool-surface-full-loop.md               |  4 +-
 docs/ideation/persisted-diverge-converge.md        |  6 +-
 .../src/__tests__/agent-ideation-tools.test.ts     | 93 +++++++++++++++++++---
 packages/engine/src/agent-tools.ts                 | 23 +++++-
 5 files changed, 116 insertions(+), 17 deletions(-)

Fusion-Task-Id: FN-8546

Fusion-Task-Lineage: 7232701f-5c6b-40fc-8d46-d65b97af9c0a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 12:26:02 -07:00
gsxdsm
ff165ecb5a fix: scope beta release notes to that beta's changesets; stable keeps full-cycle rollup
Pre-mode preserves consumed changeset .md files, so every beta's distilled notes and GitHub prerelease body aggregated the entire cycle since the last stable (v0.73.0-beta.4 shipped the full 0.72.0→0.73.0 aggregate). Betas now distill only changesets not yet recorded in pre.json's consumed ledger, and fail loudly when a beta would ship nothing new. Stable promotion still feeds the full preserved set, keeping its notes an explicit rollup of every beta in the cycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 12:18:24 -07:00
gsxdsm
c4292b25ef FN-8539: make Planning Mode selection-driven
Make Planning Mode refine repository-grounded plans through successive operator choices.

- Offer concrete directions and Other for vague planning openers
- Rebuild running plans around selected options, multi-selections, and Other responses
- Add selection-loop coverage and operator documentation

Files changed:
 .changeset/fn-8539-option-driven-planning.md       |   7 ++
 docs/dashboard-guide.md                            |   2 +-
 .../__tests__/planning-infinite-interview.test.ts  | 131 ++++++++++++++++++++-
 .../planning-interview-formatters.test.ts          |  37 ++++--
 packages/dashboard/src/planning.ts                 |  34 +++---
 5 files changed, 185 insertions(+), 26 deletions(-)

Fusion-Task-Id: FN-8539

Fusion-Task-Lineage: 585bae1e-6d9e-4733-b787-77b70a7d1259

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 12:08:58 -07:00
gsxdsm
3f976e3dca FN-8538: give Planning Mode a dedicated collaborative prompt
Planning Mode now uses a standalone collaborative prompt rather than inherited task-triage instructions.

- Resolve the Planning Mode default independently of workflows and triage assignments.
- Preserve explicit full-system prompt overrides and update prompt-setting documentation.
- Cover dedicated prompt behavior and add the published-package changeset.

Files changed:
 .changeset/fn-8538-planning-prompt.md              |  7 +++
 docs/dashboard-guide.md                            |  3 +-
 .../core/src/__tests__/prompt-overrides.test.ts    |  7 +++
 packages/core/src/prompt-overrides.ts              |  8 ++-
 packages/dashboard/app/utils/builtinPrompts.ts     |  8 ++-
 .../__tests__/planning-infinite-interview.test.ts  | 60 +++++++++++++++++++++-
 .../__tests__/planning-prompt-resolution.test.ts   | 47 ++++++++++-------
 packages/dashboard/src/planning.ts                 | 46 +++++------------
 8 files changed, 130 insertions(+), 56 deletions(-)

Fusion-Task-Id: FN-8538

Fusion-Task-Lineage: 36e0665d-7995-4bc5-9c73-948f7f4e9131

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 11:41:15 -07:00
gsxdsm
d6d8a5e919 FN-8537: keep planning actions visible on mobile
Keep Planning Refine and Proceed controls visible across mobile plan-review hosts.

- Make the plan document pane the responsive scroll owner while preserving its action rail.
- Cover portrait and short-landscape embedded and modal layouts with CSS and browser tests.
- Add a patch changeset for the mobile planning action fix.

Files changed:
 .changeset/fn-8537-mobile-planning-actions.md      |  7 ++++++
 .../dashboard/app/components/PlanningModeModal.css | 25 ++++++++++++++++++++++
 .../__tests__/PlanningModeModal.css.test.ts        | 17 +++++++++++++++
 .../src/__tests__/planning-browser-e2e.test.ts     | 20 +++++++++++++++--
 4 files changed, 67 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-8537

Fusion-Task-Lineage: 7a53aa74-859d-4c76-bf26-ab6ea72873dd

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 11:03:33 -07:00
gsxdsm
2499803c73 fix: guard CE sessions against concurrent-turn displacement and harden JSON-protocol parsing
Port the planning turn-admission invariant (FNXC:PlanningTurnAdmission,
2026-07-22) into the Compound Engineering orchestrator: at most one turn
(opening/answer/resume-rehydration) is admitted per CE session, reserved
synchronously and held until the turn settles — a re-entered mobile view
re-submitting a turn now gets CeTurnInProgressError (HTTP 409) instead of
displacing the in-flight turn's live agent, which surfaced as "Failed to
parse agent response: AI returned no valid JSON". cancel()/discard()
force-clear the reservation; releases are token-scoped so a stale release
can't drop a newer turn's slot.

In the engine interactive-ai-session seam: bump the reformat retry from
one to two attempts (non-Anthropic default models comply less reliably
with the JSON-only protocol), and log every failed parse with a bounded
raw-response snippet plus resolved provider/model — including a distinct
empty-assistant-message marker — so support can diagnose these reports
without a repro.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 10:31:22 -07:00
gsxdsm
492d375e8f FN-8536: fix planning retry ownership after failure
Release a settled retry token so a later planning error can start the next bounded attempt.

- Clear only the matching retry owner before scheduling its successor.
- Cover distinct stream errors after retry settlement.
- Add a patch changeset for the recovery fix.

Files changed:
 .changeset/fn-8536-planning-retry.md                           |  7 +++++++
 packages/dashboard/app/components/PlanningModeModal.tsx        | 10 ++++++++++
 .../__tests__/PlanningModeModal.planning-flow.test.tsx         |  5 +++++
 3 files changed, 22 insertions(+)

Fusion-Task-Id: FN-8536

Fusion-Task-Lineage: cccb0793-390e-4bdb-b459-939760e644bb

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 10:25:16 -07:00
gsxdsm
2df0c7e90b fix(#2411): recover from a stale postmaster.pid instead of joining a dead port
After a hard host crash (SIGKILL, power loss), postmaster.pid survives with no
postmaster behind it. The optimistic join handed every subsequent boot a URL to
the dead port, so the dashboard could never start again without a manual pid
delete. Probe the recorded pid with signal 0: provably dead (ESRCH) rebuts the
live-lock presumption and the boot takes an owned start — PostgreSQL itself
re-validates and reclaims the stale lock file, so a recycled live pid keeps the
old join-then-fail behavior and a genuinely live postmaster still surfaces the
lock collision we already join on. EPERM counts as alive (fail-closed).

Verified end to end: real cluster started, postmaster SIGKILLed leaving the pid
file + interrupted WAL, fresh lifecycle detected the stale lock, ran an owned
start, and crash recovery preserved the marker row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 10:00:09 -07:00