Skip to content

hyp init leaves joined upgrades in base-URL mode because attach skips precede proxy CA readiness #842

Description

@bgmcmullen

Problem

On a fleet-enrolled machine upgrading from a version whose Claude attachment is
base_url to a proxy-capable version, hyp init can complete successfully
without migrating Claude to proxy mode.

The wizard conflates two states:

  • a successful join lane with a fresh enrollment that installed the current daemon;
  • any existing HypAware attach marker with an attachment in the desired mode.

As a result, the joined finale can skip both daemon installation and Claude
attach, restart the current daemon only at the end, and create the proxy CA
after the opportunity to reattach has passed. A manual hyp attach claude
afterward sees the CA and completes the migration.

Reproduction

  1. Install a version that attaches Claude by base URL, such as 1.22.0.
  2. Run hyp init and enroll the machine with a team server.
  3. Confirm ~/.claude/settings.json contains _hypaware.mode: "base_url".
  4. Upgrade HypAware to a proxy-capable version, such as 1.23.0, while the old daemon is still running.
  5. Run hyp init through the team pathway.

Observed result:

  • The wizard reports success.
  • The final daemon restart starts the new daemon and creates the local proxy CA.
  • Claude remains attached with _hypaware.mode: "base_url".
  • Running hyp attach claude manually afterward changes the marker to
    _hypaware.mode: "proxy" and installs the required proxy trust settings.

Code path

runInitWizard records any successful team login lane as joinedAlready:

joinedAlready: joined !== undefined

An already-enrolled hyp remote login can take the re-seed path, which updates
the forwarding identity but does not reinstall or restart the daemon.

runWizardFinale then derives its skips from status:

if (report?.daemon?.installed) finaleActions.skipDaemonInstall = true
const attached = (report?.clients ?? []).filter((c) => c.attached).map((c) => c.name)

The generic Claude attach probe reports attached: true whenever the
_hypaware marker exists. It returns marker version and port, but not
marker.mode, so base_url and proxy are indistinguishable.

runPickerFinale waits for the proxy CA only when daemon installation was not
skipped, skips clients in skipAttachClients, and restarts the daemon at the
end. In the joined-upgrade path this yields:

old daemon running, no proxy CA
-> skip daemon install
-> skip existing base-URL attachment
-> restart current daemon
-> proxy CA appears too late

Even if Claude were unattached, it would enter the attach loop before the final
restart. With no CA yet, the Claude adapter would select base_url, then the
restart would create the CA afterward.

Relevant files:

  • src/core/cli/wizard/index.js
  • src/core/cli/walkthrough.js
  • src/core/cli/remote_commands.js
  • src/core/daemon/status.js
  • hypaware-core/plugins-workspace/claude/src/index.js
  • hypaware-core/plugins-workspace/claude/src/settings.js

Expected behavior

An attended hyp init on a fleet-managed proxy-mode installation must not
silently finish with Claude attached in the wrong mode.

The flow should establish the desired daemon state before deciding the client
attachment is current:

start or restart the current daemon
-> wait for the proxy CA
-> compare the current attachment mode with the desired mode
-> attach or reattach when needed

If automatic migration is intentionally outside hyp init, the wizard must
report the mismatch and print the required hyp attach claude action instead
of recording the attach as a successful skip.

Acceptance criteria

  • Do not treat attached: true as proof that the desired attachment mode is active.
  • A joined upgrade with an existing base_url marker either migrates to proxy mode after CA readiness or prints an explicit required repair.
  • An unattached Claude client is not attached before the proxy-mode daemon has had a chance to create its CA.
  • Preserve the existing fast path for an attachment already current in proxy mode.
  • Add a regression test covering old daemon + base_url attachment -> package upgrade -> hyp init.
  • Add a regression test covering the same upgrade with Claude initially unattached.

Related design

LLP 0242 and LLP 0244 cover fresh proxy installs and explicit migration through
hyp attach claude, but do not cover this joined-upgrade wizard interaction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneutral:fixDelegate this issue to neutral for an autonomous fix attempt (reproduce -> fix -> PR)neutral:stuckneutral attempted this but cannot complete it autonomously — needs a human

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions