Skip to content

VERIFICATION ONLY — do not merge: route-less seamless-deploy #460 Linux CI repro#464

Draft
kriszyp wants to merge 6 commits into
mainfrom
kris/seamless-deploy-verify
Draft

VERIFICATION ONLY — do not merge: route-less seamless-deploy #460 Linux CI repro#464
kriszyp wants to merge 6 commits into
mainfrom
kris/seamless-deploy-verify

Conversation

@kriszyp

@kriszyp kriszyp commented Jun 23, 2026

Copy link
Copy Markdown
Member

⚠️ VERIFICATION ONLY — DO NOT MERGE

Scratch branch verifying the route-less seamless deploy_component replication property for harper-pro#460 on Linux CI. Not a feature PR; do not review for merge, do not treat as a release candidate. Reviewers intentionally unassigned.

Topology

3-node route-less repro (integrationTests/cluster/seamlessDeploy.test.mjs): nodes C, A, hub B. A and C each add_node B, so A↔C is route-less (mesh/propagation-discovered, no static route). A boots with HARPER_TEST_HDBNODES_DECODE_FAIL=<C> to simulate the persistent #352 decode-miss for C; a deploy_component reload of A must keep replication from C alive via #460's reconstruct-and-resubscribe. SEAMLESS_NO_INJECT=1 is the local control.

Results — PASSES on Linux (local dev box + CI, Node 22/24/26)

Both the first CI run (single config) and local runs are green. Latest commit makes the suite a matrix over enableRootCAs ∈ {true, false}:

  • enableRootCAs=true — JJill's literal field shape (also the Harper default). ✅
  • enableRootCAs=false — strict probe with the bundled-root-CA safety net OFF. ✅

Local matrix: 6/6 pass. After the deploy reload, C's post-deploy write reaches A in ~10s in every variant.

Key findings (see test header for full trace)

  1. macOS 1006-flap was environmental. On Linux the 1006 close-code appears only transiently during initial mesh subscription (peer mid-boot) and self-heals in ~0.5–1.5s; no widening-backoff spiral. The non-recovering spiral (which also hit the routed hub) was a macOS loopback self-signed *-replication cert re-handshake artifact.
  2. The reconstructed descriptor's missing node.ca is NOT load-bearing. The outbound peer connection already runs rejectUnauthorized:true, and C's CA reaches A through the cluster CA-mesh availableCAs channel (replicator.ts), independent of the hdb_nodes row the injection strips. enableRootCAs=false passing proves the CA-mesh alone carries C's CA across the decode-strip + deploy.
  3. This test does not isolate harper#1464 — the deploy_component worker-reload leaves followers with zero replication subscriptions #460 reconstruct already self-heals per-worker via the CA-monitor scan (not gated by startOnMainThread), so #1464 is a main-thread de-dup/noise improvement here, not a separately observable correctness fix.

Generated by Claude (Opus 4.8). Verification artifact only.

kriszyp and others added 4 commits June 23, 2026 12:44
…nodes peers (#460)

A deploy_component reloads the worker pool, re-invoking startOnMainThread()
on the already-resolved main-thread module. Its whenThreadsStarted.then()
fires immediately with no base-copy, so the subscription scan runs while a
follower's replicated hdb_nodes rows still fail to decode. The scan did
`if (!node) continue`, silently skipping every undecodable peer, leaving the
follower with zero outbound subscriptions until a full restart.

Mirror the #352 auth-path fallback on the outbound path: when an hdb_nodes
key is range-visible but its value decodes to null, reconstruct a minimal
{ name, replicates: true } descriptor and still drive the subscription
listener. replicates:true is required (unlike the auth-only { name }) because
the subscription path gates on node.replicates; getNodeURL falls back to
wss://<name>:9933. Applied to both the startup scan (subscribeToNodeUpdates,
via the extracted pure helpers scanNodesForSubscription/resolveScannedNode/
reconstructNodeFromKey) and the put-event path in processNodeUpdateEvent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eloads (#460)

A deploy_component reload re-invokes replicator.startOnMainThread on the
same already-resolved main-thread module; its whenThreadsStarted.then()
re-fires and re-runs subscribeToNodeUpdates -> runNodeUpdateWatcher,
previously stacking a second unbounded watcher loop (and an extra
forEachReplicatedDatabase chain) on every deploy. Make the watcher
supersede its prior instance via a per-purpose generation token + iterator
close, namespaced so the subscription-management and replication-
confirmation watchers still run concurrently. Also clear the module-level
routes list before repopulating so routes don't accumulate across deploys.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…monitor watcher key) (#460)

Codex P1: the subscription scan reconstructed a descriptor for ANY null
range value, which would revive a genuine remove_node tombstone (a deleted
node leaves a clean-null row). Add probeNodeRow to disambiguate via the
point lookup: a throw = present-but-undecodable (#352/#1163) -> reconstruct;
a clean null = tombstone -> skip. resolveScannedNode now takes an injected
probe and refuses to revive deleted nodes.

Codex P2: monitorNodeCAs and the subscription manager both called
subscribeToNodeUpdates on the default watcher key, so the new supersede
behavior had the subscription-manager watcher stop the CA-monitor watcher
(CA rotations would stop updating replication TLS contexts). Give each
consumer a distinct key: 'subscription-manager', 'ca-monitor',
'replication-confirmation'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… hook (harper-pro#460 verification)

VERIFICATION-ONLY branch — not for merge. Carries an env-gated HARPER_TEST_HDBNODES_DECODE_FAIL
injection in scanNodesForSubscription (no-op in prod) + a 3-node route-less repro. Fails to
reconnect post-deploy on local macOS (loopback/self-signed-cert re-handshake 1006 flap — env
artifact; existing deploy+replication integration tests are green on Linux CI). Pushed so it can be
run on Linux/CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@claude

claude Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Reviewed; no blockers found.

(Verification-only branch per PR description — reviewed through commit b22d9d9.)

kriszyp and others added 2 commits June 23, 2026 16:45
enableRootCAs defaults to true, so the prior config already exercised it. Add
enableRootCAs=false as the discriminating probe: with the bundled-root-CA safety
net off, C's CA must arrive via the cluster CA-mesh availableCAs channel, not the
hdb_nodes row the decode injection strips. Both variants pass on Linux (6/6 local),
proving the reconstructed {name,replicates:true} descriptor's missing node.ca is
not load-bearing. Header updated: the macOS 1006 flap was environmental.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…or combined seamless check

Points the scratch branch's core submodule at harper#1464's branch
(kris/start-on-main-thread-once, 2 commits over v5.1.9; the MCP #1404 commit on
that branch is incidental) to verify the COMBINED #460 + #1464 stack keeps the
route-less seamless-deploy property. Local matrix: 6/6 pass; the #460 reconstruct
warn still fires post-deploy with #1464 present, confirming #1464's main-thread
once-per-component dedup does not suppress the per-worker CA-monitor reconstruct.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant