Skip to content

fix(bin): keep Lavish server address local to each home - #5873

Open
roderik wants to merge 4 commits into
kunchenguid:mainfrom
roderik:fm/lavish-host-per-machine
Open

roderik wants to merge 4 commits into
kunchenguid:mainfrom
roderik:fm/lavish-host-per-machine

Conversation

@roderik

@roderik roderik commented Sep 27, 2026 •

Copy link
Copy Markdown

Intent

Rebase the Lavish per-machine configuration fix onto current upstream main, run the focused secondmate harness tests and validation, and update #5873 so it is ready to merge after the maintainer approves fork workflows. Do not merge.

What Changed

  • Took lavish-axi-host out of the default FM_INHERITABLE_CONFIG set in bin/fm-config-inherit-lib.sh. Config propagation and the bootstrap sweep no longer copy the primary's per-machine Lavish server address into secondmate homes, and they no longer overwrite or remove a secondmate's own value. fm-spawn.sh still exports each home's own config/lavish-axi-host into worker launches, and its comment now says so.
  • Updated docs/configuration.md and the operational-home-layout skill to say the file is per-home and not inherited. The docs also note that a home which already has a copy of the primary's address keeps it until an operator rewrites or removes that home's config/lavish-axi-host once.
  • Extended tests/fm-secondmate-harness.test.sh. The tests now check that propagation leaves a secondmate's own Lavish address untouched and never copies the primary's address into a home that has none. They also check that the address survives the bootstrap sweep's push, re-converge and mirror-absence steps.

🤖 Generated with Claude Code

Risk Assessment

✅ Low: The change removes one item from the inheritable config list, keeps every upstream entry, updates the docs and comments to match, and adds behavioral tests. Before this fix those tests would have failed, because the primary's lavish-axi-host was copied into and overwrote secondmate homes. The requested manual-cleanup note is present.

Testing

I ran the real fm-config-push.sh from a disposable lab primary home into a registered secondmate home. On the target commit, the secondmate's config/lavish-axi-host was never pushed and never mirror-deleted. It stayed absent when the secondmate had no value, and it kept the secondmate's own value when the primary changed or removed its address. crew-harness still propagated normally. The same run on base fa48367 pushed the primary's address, overwrote the secondmate's value and deleted it when the primary cleared its file, which reproduces the bug this change fixes. The reread-nudge send was refused because the secondmate fixture is not a lab home. The gate's lifecycle guard is what refused it, and it has no effect on the propagation results. The focused fm-secondmate-harness suite also ran (its log is attached), but that is a unit-level run rather than a live product scenario, so it is recorded as untested under the live contract. I removed the lab homes and the temporary base export; the worktree is clean.

  • Live validation: ✅ go - 3 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Config push leaves a secondmate home without its own Lavish address empty (the primary's address is not copied) ✅ pass live config-push-target.txt scenario A: lavish-axi-host missing from the item report, SM config/lavish-axi-host = <absent>, crew-harness pushed; the base run pushed primary-host.example:4387
Config push keeps a secondmate's own Lavish address when the primary changes its address ✅ pass live config-push-target.txt scenario B: SM keeps sm-host.example:4387 while crew-harness converges to claude; the base run overwrote it with primary-host-2.example:4387
Adversarial: primary removes its Lavish address; the absence mirror must not delete the secondmate's own value ✅ pass live config-push-target.txt scenario C: SM still sm-host.example:4387; the base run reported 'pushed - mirrored primary absence' and deleted it
Focused secondmate harness tests (propagate lib, B7 bootstrap sweep and the other inheritance tests) pass ⏸️ untested no The prior payload recorded this as a unit-test run (live=false), not a run against the live product, so it does not establish a live result. The suite log is attached as an artifact for reference.
Remote secondmate config push (fm-remote-inherit-push.sh) does not push the primary's Lavish address over SSH ⏸️ untested no Needs an SSH-reachable remote host with a seeded secondmate home. Provide a lab remote host with its remote_host set in a lab secondmate meta record to drive it.
PR #5873 updated and ready to merge after maintainer approval ⏸️ untested no The push and PR updates belong to later phases owned by the outer executor, not this test phase.
Evidence: Focused secondmate harness test log

Source: Focused secondmate harness test log

ok - A1 fm-harness.sh secondmate resolves the fallback chain; crew mode unchanged
ok - fm-harness detects only Cursor Agent CLI's exact invocation marker
ok - C1 fm-harness.sh secondmate-model/secondmate-effort resolve the optional tokens; bare harness stays empty (backward-compat)
ok - pi-signed identity: authoritative launch selection distinguishes shared wrapper ancestry
ok - harness identity: dash-leading ps command names are basename operands, not options
ok - B1 propagate_inheritable_config: copy, idempotence, convergence, absence-mirror, exclusion, no-op, skip diagnostics
ok - B2 spawn: secondmate runs the secondmate harness; its home inherits declared config
ok - B3 spawn: an absent secondmate-harness falls back to the crew harness (backward-compat)
ok - B4 spawn: no config at all -> own harness and no propagation side effects
ok - B5 spawn: an explicit per-spawn harness arg overrides config/secondmate-harness
ok - B6 spawn: an unverified resolved secondmate harness is refused (guard intact)
skip: cursor executable not resolvable in this environment, so the launch could not be built
ok - B5b spawn: FM_BACKEND wins over inherited config/backend
ok - B5c spawn: explicit --backend wins over FM_BACKEND and inherited config/backend
ok - C2 spawn: a bare harness-only secondmate-harness file launches with no model/effort flag (backward-compat)
ok - C3 spawn: config/secondmate-harness's model token threads --model into the launch and meta
ok - C4 spawn: config/secondmate-harness's model+effort tokens thread into the launch and meta
ok - C5 spawn: an explicit --model overrides config/secondmate-harness's model token; the file's effort token still applies
ok - C6 spawn: an explicit --effort overrides config/secondmate-harness's effort token; the file's model token still applies
ok - C7 spawn: an explicit --harness starts with clean model/effort defaults
ok - C8 spawn: an explicit --harness still honors explicit model/effort flags
ok - C9 spawn: secondmate launch pins supervision to its own harness
ok - C9 spawn: the harness fallback chain still resolves with no tokens; crew/scout launches are unaffected by this feature
ok - B7 bootstrap sweep pushes, re-converges, and mirrors absence; never inherits secondmate-harness
ok - B8 bootstrap sweep propagates config even when the home's tracked files are already current
ok - B9 bootstrap sweep defers new inherited config until the home ignores it
ok - B10 bootstrap sweep materializes and inherits the startup-memory default while fast-forwarding
ok - B12b backend inheritance: present values and primary absence converge exactly
ok - C2b spawn: config/claude-permission-mode=auto reaches a Claude secondmate launch
ok - claude secondmate launches cover the parent-home steering inbox in auto and bypass modes
ok - B12c claude-permission-mode inheritance: present values and primary absence converge exactly
ok - B12c presentation inheritance: the primary default converges on, and only an explicit opt-out propagates off
ok - B11 bootstrap sweep surfaces config propagation failures
ok - B11 bootstrap rereads completed config writes after partial propagation
ok - B12 config-push propagates via shared live discovery, reports items, rereads on change only, and does not fast-forward
ok - B13 config-push reports dirty, non-allowing, and invalid homes without failing warnings-only runs
ok - B14 config-push exits nonzero on real propagation errors
ok - B14 config-push rereads completed config writes after partial propagation
ok - B15 config reread is per-home, exact-byte, ordered, and pointer-only
ok - B16 config reread isolation, ABSENT, generation safety, send failure, and retry
ok - B20 config reread publication failures retain exact generations for retry
ok - B21 config reread instruction-write failures retain exact retry generations
ok - B21 config reread preserves exact bytes when temporary adoption also fails
ok - B21 config reread serializes concurrent propagation and delivery
ok - B22 full config reread retry queues drain before new publication
ok - B23 mixed config reread delivery failures still bound sent history
ok - B26 config reread delivery stops after the oldest failed generation
ok - B17 config reread skips unchanged homes and reads destination post-write bytes
ok - B18 bootstrap config reread path works; spawn flexibility remains defaults-only
ok - B19 bootstrap respawns before inherited-config reread
ok - B25 spawn quarantines stale rereads without blocking relaunch
ok - B24 bootstrap detect-only mode remains filesystem read-only
# all fm-secondmate-harness tests passed

real	5m39.117s
user	2m2.621s
sys	2m31.812s
Evidence: Live fm-config-push.sh transcript at target (Lavish address stays per-home)

Source: Live fm-config-push.sh transcript at target (Lavish address stays per-home)

== Scenario A: secondmate home has NO own lavish-axi-host; primary sets primary-host.example:4387
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  1 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the guarded operation WILL still run.
●  watcher supervision needs Stop-owned automatic recovery; inspect the hook registration and startup status before ending the turn.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
config-push: <LAB> -> live secondmate homes
secondmate sm1 (<SM>):
  crew-dispatch.json: unchanged
  dispatch-never-send: unchanged
  crew-harness: pushed
  backlog-backend: unchanged
  backend: unchanged
  herdr-presentation-spaces: unchanged
  startup-memory-budget: unchanged
  trace-context: unchanged - session-scoped
  launch-env-allowlist: unchanged
  claude-permission-mode: unchanged
  keep-ai-trailers: unchanged
  data/captain-shared.md: unchanged
CONFIG_REREAD: secondmate sm1: send failed: error: refusing fleet lifecycle from inside a no-mistakes gate worktree (~/.no-mistakes/repos/49bdd8e38f81.git)
--- after push A
  SM config/lavish-axi-host = <absent>
  SM config/crew-harness = codex
== Scenario B: secondmate sets its own per-machine address; primary changes its own
WARNING: watcher still down (same stale episode; last beat: never, grace 300s) - full banner already printed this episode.
config-push: <LAB> -> live secondmate homes
secondmate sm1 (<SM>):
  crew-dispatch.json: unchanged
  dispatch-never-send: unchanged
  crew-harness: pushed
  backlog-backend: unchanged
  backend: unchanged
  herdr-presentation-spaces: unchanged
  startup-memory-budget: unchanged
  trace-context: unchanged - session-scoped
  launch-env-allowlist: unchanged
  claude-permission-mode: unchanged
  keep-ai-trailers: unchanged
  data/captain-shared.md: unchanged
CONFIG_REREAD: secondmate sm1: send failed: error: refusing fleet lifecycle from inside a no-mistakes gate worktree (~/.no-mistakes/repos/49bdd8e38f81.git)
--- after push B
  SM config/lavish-axi-host = sm-host.example:4387
  SM config/crew-harness = claude
== Scenario C: primary removes its lavish-axi-host (absence mirror must not delete the secondmate's own)
WARNING: watcher still down (same stale episode; last beat: never, grace 300s) - full banner already printed this episode.
config-push: <LAB> -> live secondmate homes
secondmate sm1 (<SM>):
  crew-dispatch.json: unchanged
  dispatch-never-send: unchanged
  crew-harness: unchanged
  backlog-backend: unchanged
  backend: unchanged
  herdr-presentation-spaces: unchanged
  startup-memory-budget: unchanged
  trace-context: unchanged - session-scoped
  launch-env-allowlist: unchanged
  claude-permission-mode: unchanged
  keep-ai-trailers: unchanged
  data/captain-shared.md: unchanged
CONFIG_REREAD: secondmate sm1: send failed: error: refusing fleet lifecycle from inside a no-mistakes gate worktree (~/.no-mistakes/repos/49bdd8e38f81.git)
--- after push C
  SM config/lavish-axi-host = sm-host.example:4387
  SM config/crew-harness = claude
Evidence: Live fm-config-push.sh transcript at base fa48367 (bug reproduced)

Source: Live fm-config-push.sh transcript at base fa48367 (bug reproduced)

A: lavish-axi-host: pushed -> SM = primary-host.example:4387 B: lavish-axi-host: pushed -> SM = primary-host-2.example:4387 (secondmate value overwritten) C: lavish-axi-host: pushed - mirrored primary absence -> SM = <absent>

== Scenario A: secondmate home has NO own lavish-axi-host; primary sets primary-host.example:4387
  lavish-axi-host: pushed
--- after push A
  SM config/lavish-axi-host = primary-host.example:4387
  SM config/crew-harness = codex
== Scenario B: secondmate sets its own per-machine address; primary changes its own
  lavish-axi-host: pushed
--- after push B
  SM config/lavish-axi-host = primary-host-2.example:4387
  SM config/crew-harness = claude
== Scenario C: primary removes its lavish-axi-host (absence mirror must not delete the secondmate's own)
  lavish-axi-host: pushed - mirrored primary absence
--- after push C
  SM config/lavish-axi-host = <absent>
  SM config/crew-harness = claude

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • ⚠️ bin/fm-config-inherit-lib.sh:80 - Existing homes keep the primary's Lavish address. Since c443d8c (fix(bin): unify Lavish host and disconnect handling #5060, 2026-09-20), lavish-axi-host has been in FM_INHERITABLE_CONFIG, so the primary's address has been copied into local and remote secondmate homes (remote homes through fm-remote-inherit-push.sh). This change removes the item from the list. The absence mirror only reaches listed items, so no later sweep, spawn or config push will touch a copy that is already there. A remote secondmate on another machine that received the primary's address will keep sending its workers to the wrong machine's Lavish server until someone deletes config/lavish-axi-host by hand. That is the failure this fix targets. Nothing records which copies were inherited and which were set by the user, so the code cannot remove old inherited copies safely. The smallest options are (a) an upgrade note in docs/configuration.md telling operators to check or delete the file in remote secondmate homes, or (b) new cleanup machinery that tracks where each copy came from. Option (b) extends the change, so the remedy needs the author's decision.

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 3 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Config push leaves a secondmate home without its own Lavish address empty (the primary's address is not copied) ✅ pass live config-push-target.txt scenario A: lavish-axi-host missing from the item report, SM config/lavish-axi-host = <absent>, crew-harness pushed; the base run pushed primary-host.example:4387
Config push keeps a secondmate's own Lavish address when the primary changes its address ✅ pass live config-push-target.txt scenario B: SM keeps sm-host.example:4387 while crew-harness converges to claude; the base run overwrote it with primary-host-2.example:4387
Adversarial: primary removes its Lavish address; the absence mirror must not delete the secondmate's own value ✅ pass live config-push-target.txt scenario C: SM still sm-host.example:4387; the base run reported 'pushed - mirrored primary absence' and deleted it
Focused secondmate harness tests (propagate lib, B7 bootstrap sweep and the other inheritance tests) pass ⏸️ untested no The prior payload recorded this as a unit-test run (live=false), not a run against the live product, so it does not establish a live result. The suite log is attached as an artifact for reference.
Remote secondmate config push (fm-remote-inherit-push.sh) does not push the primary's Lavish address over SSH ⏸️ untested no Needs an SSH-reachable remote host with a seeded secondmate home. Provide a lab remote host with its remote_host set in a lab secondmate meta record to drive it.
PR #5873 updated and ready to merge after maintainer approval ⏸️ untested no The push and PR updates belong to later phases owned by the outer executor, not this test phase.
  • bash tests/fm-secondmate-harness.test.sh (focused secondmate harness suite, including the updated propagate-lib and B7 bootstrap-sweep Lavish assertions)
  • Live FM_HOME=&lt;lab&gt; bin/fm-config-push.sh against a disposable fm-lab-home primary with a registered local secondmate home (state/sm1.meta), at target 2832a4e, in three steps: (A) the secondmate has no address, (B) the secondmate has its own address and the primary changes its value, (C) the primary removes its value
  • The same live fm-config-push.sh run against a git archive fa48367 export of the base commit, to reproduce the old inheritance behavior for contrast
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate:

Verdict: Whole thread + tip vs main 3b689975 reviewed. No linked closing issue. First look; first-time fork CI/NM approved after diff review (config inherit list + docs/tests only; no security risk).

Tip vs main: Removes lavish-axi-host from FM_INHERITABLE_CONFIG so each home keeps its own per-machine Lavish address; docs/AGENTS updated; tests assert secondmate address is preserved across propagate/bootstrap. Main still lists lavish-axi-host as inheritable while calling it per-machine — inheritance overwrites secondmate locals.

contract-class: restore — concrete existing per-machine Lavish address contract was broken by primary→secondmate inheritance; tip restores machine-local values.

VISION.md (each rule)

  • One captain, one interface / peace of mind: aligns — secondmate boards stay on the right machine without captain surgery.
  • Authority is explicit and never inferred: aligns — no new autonomy.
  • Scripts own the mechanics, agents own the judgment: aligns — inherit list is scripted.
  • A restart is a non-event: aligns — local config survives convergence.
  • Delegation with a spine: aligns — no task-contract change.
  • The fleet outlives any vendor: aligns — home-local config, not vendor lock-in.
  • Scope: aligns — configuration inheritance surface.

Attestation: MISSING (no no-mistakes pipeline attestation in body). Blocker for author: raise/update via git push no-mistakes so NM can pass, then wait for green CI. CI/NM: approved this pass (36298178615 CI, 36298178616 NM) — NM expected to fail until attestation lands. mergeable: MERGEABLE/UNSTABLE. No auto-merge while attestation missing. Firstmate flag: no (waiting-author). Security tip: none.

@roderik
roderik force-pushed the fm/lavish-host-per-machine branch from 3d01ad2 to fcf977c Compare September 27, 2026 08:01
@roderik roderik changed the title Keep Lavish server addresses local to each home fix: keep Lavish server address local to each home Sep 27, 2026
@roderik
roderik force-pushed the fm/lavish-host-per-machine branch from fcf977c to e81f998 Compare September 28, 2026 09:54
@greptile-apps

greptile-apps Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Changes how Lavish server configuration is inherited between homes.

The PR appears safe to merge; no outstanding finding or new actionable issue was identified.

Reviews (2) · Last reviewed commit: "no-mistakes(review): Document manual cle..."

@roderik roderik changed the title fix: keep Lavish server address local to each home fix(bin): keep Lavish server address local to each home Sep 28, 2026

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate: whole thread re-read. Prior stamp was waiting-author (attestation MISSING on 3d01ad28). Tip moved to 2832a4eb; Pipeline attestation now present.

HEAD 2832a4ebbcbd36fb8645ea26f1b835d7bb4be7a4. MERGEABLE/UNSTABLE vs main fa483673. Author roderik not blocked. Attestation MATCH (body head_sha = tip; ## Pipeline raised). Fork workflows on this HEAD were action_required; approved this pass after diff review (no security risk): CI 36407996467, NM 36407996719/36408027633. NM now SUCCESS; tip CI in_progress.

Closes: body has no Fixes/Closes issue link — closes=none (mentions #5060 as the earlier inheritance that introduced the bug). Not a closes-ready-for-pr claim.

Contract-class: restore (own tip-vs-main; FM-LEARN-CLAIMS). lavish-axi-host is per-machine/per-home; tip removes it from default FM_INHERITABLE_CONFIG so config-push/bootstrap no longer copy or absence-mirror the primary's address over secondmate homes; docs + skill note existing inherited copies need one-time operator cleanup; tests cover leave-untouched / never-copy / survive-sweep. Restores the intended local-only contract — not a new default-on surface.

VISION.md (each rule)

  1. One captain, one interface — aligns (secondmates keep correct local Lavish without captain surgery).
  2. Authority explicit — aligns (no new autonomy).
  3. Scripts own mechanics — aligns (inherit list is scripted).
  4. Restart non-event — aligns (local config survives convergence).
  5. Delegation with a spine — aligns (no task-contract change).
  6. Fleet outlives vendor — aligns (home-local config, not vendor lock-in).
  7. Scope — aligns (configuration inheritance surface).

Outcome: waiting-ci. No auto-merge until tip CI green. Firstmate flag: no (CI unfinished). Security tip: none.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants