ForgeKitFORGEKIT

Build Log

Alloy Cross-Machine Runner Presence Fix

August 1, 2026

Found and fixed the root cause of a live 'Runner: Never seen' bug on Railway: presence/claim matching compared absolute filesystem paths between two different machines, which structurally can never match.

AlloyBug FixMulti-TenancyRailwayRunner
1
cross-machine architectural bug found and fixed
11/11
real-DB integration tests passing (2 files)
3/3
real-DB proof scripts passing

Timeline

Start
Continued from prior session's multi-tenancy remediation
Alloy live on Railway; testing runner registration for a second workspace
+20m
Runner worked on localhost, not on alloy.forgekits.build
Same machine, same runner process — Ignite page showed 'Runner: Unavailable — Never seen'
+35m
Temporary diagnostic logging added to the Ignite page
Railway's own runtime logs showed correct path resolution but presence result: null
+45m
Root cause confirmed: absolute-path prefix matching across disjoint filesystems
Server (Railway, Linux, /app/...) vs runner (local, Windows, C:\ForgeKit\...) can never share a path prefix
+1h
Scoped fix approved and implemented
workspaceKey now derives from product.folderPath (repo-relative); getRunnerPresence matches on (ownerId, workspaceId) only
+1.5h
All call sites, tests, and proof scripts updated and verified against real Neon DB
tsc clean, 452 unit tests, 2 integration test files (11 tests), 3 proof scripts all pass
+2h
Committed, merged to railway-proof, pushed, verified live
Zeb confirmed runner presence now shows available on both localhost and alloy.forgekits.build
Close
Committed uncommitted Corpus HCE v2 doc, retro, wrap
4a1e603 (fix), ab90de7 (railway-proof), 19f90c3 (corpus docs)

What shipped

Diagnosed a live 'Runner: Unavailable — Never seen' report on alloy.forgekits.build (Railway) despite the exact same runner process registering successfully against localhost

Added temporary diagnostic logging to app/w/[slug]/ignite/page.tsx to trace the real values Railway's server process was computing, since the bug was invisible to tsc and to every existing test

Root-caused via Railway's own live logs: the server (Linux container, cwd /app/products/alloy) and the runner (Windows, local machine) were both resolving correct paths independently, but getRunnerPresence's SQL prefix-match compared absolute paths between the two machines — a structural impossibility, not a bug in either side's path resolution

Confirmed this was the exact unsolved question docs/platform/railway-alloy-recommendation.md had already flagged: 'Runner's multi-user architecture is undecided... 1 deployment <-> 1 Runner <-> 1 owner <-> 1 local filesystem model'

Designed and implemented the scoped fix: createControlledExecution now takes an explicit productFolderPath (repo-relative, identical on every machine) and derives workspaceKey from it instead of the absolute cwd

Simplified getRunnerPresence to match on (ownerId, workspaceId) alone, dropping the cross-machine-broken cwd/path prefix check entirely — a runner serves its whole registered root, not one specific Product path

Simplified claimNextCommand's eligibility check by removing a second, now-redundant EXISTS clause that also compared workspace_key via prefix match

Updated every real call site: lib/actions.ts's 3 createControlledExecution calls (conductArc, runHarvest, startExecution), all getRunnerPresence callers, and the getActiveExecutionForTarget caller in lib/execution-context.ts

Updated all 4 test/script files tsc flagged as missing the new required field: harvest-execution.integration.test.ts, prove-arc-control-model.ts, prove-execution-authority.ts, prove-forge-conduct.ts

Found and fixed a real test bug while re-running the isolation suite: an earlier test's leftover Workspace-A runner row was now visible under the new (ownerId, workspaceId)-only matching, which the old cwd-scoped matching had accidentally masked — fixed by deleting and restoring an equivalent lease around the getRunnerPresence test

Removed the temporary diagnostic logging from the Ignite page once root-caused and fixed

Committed with fresh Access Control Gate evidence (real authority-check description, not a rubber-stamp), merged railway-proof into master's fix via master -> railway-proof merge, pushed, and confirmed the fix live on Railway with Zeb

Separately committed a pre-existing, complete Corpus (Historical Corpus Engine) v2 architecture doc and its Anvil/Strike/pattern-registry journal entries that were sitting uncommitted in the working tree from earlier in this session's history