Skip to content

proxy-supervise: main() never runs when invoked via a symlinked path (~/code -> ~/git/code) — supervisor timer silently no-ops since 2026-10-27 #2083

Closed

Description

@dezren39

Bug

bin/proxy-supervise.mjs ends with:

if (import.meta.url === `file://${process.argv[1]}`) {
  main();
}

Node resolves import.meta.url to the realpath of the entry module, but process.argv[1] keeps the path as invoked. On the laptop, ~/code is a symlink to ~/git/code (created 2026-10-27 13:39), and the home-manager proxy-supervisor unit invokes $HOME/code/bin/proxy-supervise.mjs — so the guard is never true, main() never runs, and the process exits 0 with no output.

Impact

Every timer-driven reconcile since the symlink appeared has been a silent no-op (systemd shows Starting/Finished in <1s, status SUCCESS). Consequences observed 2026-10-28:

  • Converted fleet proxies sat on alternate ports (19742-19748) for hours while stale home-manager fallback units held the canonical ports; the supervisor never completed a roll.
  • Canonical :18748 (commandcode) had no working listener while consumers pointed at it.
  • The supervisor only did work when an agent invoked it via a fully resolved path (e.g. from a worktree).

Repro

node ~/code/bin/proxy-supervise.mjs --config ~/.config/proxy-supervisor/config.json --only clef-proxy --status   # prints nothing, rc 0
node ~/git/code/bin/proxy-supervise.mjs --config ~/.config/proxy-supervisor/config.json --only clef-proxy --status # prints the status line

Fix

Compare against the realpath, e.g. import.meta.url === pathToFileURL(fs.realpathSync(process.argv[1])).href (guard the realpath call so module import in tests still works). Add a regression test that invokes the guard logic through a symlinked path.

Related: #916 (unit churn), #883 (stale bin/ tree in home-layer eval — separate cause of stale canonical-port code).

Acceptance criteria

  • Invoking bin/proxy-supervise.mjs through a symlinked path (e.g. ~/code -> ~/git/code) runs main() instead of exiting 0 silently
  • Direct invocation via the real path still works, and a regression test covers the symlinked-invocation case
  • The fix compares canonicalised paths (or an equivalent robust entry check) rather than special-casing one laptop path

Activity

  1. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  2. added
    effort/sSmall: expected under 2 hours of work
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    priority/highImportant and time-sensitive
    source/humanFiled directly by a human
    on Oct 29, 2026
  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Intake review

    Clear, reproduced bug: the entry guard compares import.meta.url (realpath-resolved) against the as-invoked process.argv[1], so the laptop's home-manager unit has silently no-opped since the ~/code symlink appeared on 2026-10-27. No merged PR or commit on main resolves this (checked at intake; the issue is hours old and still carries no queue/work labels). Suggested approach: canonicalise process.argv[1] (fs.realpathSync) before the comparison, or compare against the module's own resolved path; add a test that spawns the script through a symlink. Risk: low — entry-guard only; watch for Windows/relative-path edge cases in the canonicalisation. Related: the proxy-supervisor unit's silent failure means past reconciles since 2026-10-27 should be treated as not-run.

    — repo-fleet-monitor intake enrichment (protocol §5): acceptance criteria appended to the body where missing, labels normalized, meta/enriched applied.

  4. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Update from the proxy service-model redesign tracked in #2104 (design decision 2026-10-28 23:05 CDT): the redesign retires the proxy-supervisor's process-management role entirely — the fleet proxies become automatic flake-declared user services and the supervisor timer/oneshot + config are removed in the same change so it cannot respawn fps-* units.

    If that lands, PR #2085's entry-point guard fix becomes moot: there will be no supervisor invocation left for the symlink guard to break. #2085 should therefore not be merged on its own ahead of the redesign; its disposition follows #2104.

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

Metadata

Metadata

Assignees

Labels

effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/highImportant and time-sensitivesource/humanFiled directly by a humanstatus:done

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions