From 396a5c1694e673b64d78d27d2d5c67448a7e0615 Mon Sep 17 00:00:00 2001 From: Andrew Blakeslee Moore Date: Fri, 10 Jul 2026 21:04:39 +0000 Subject: [PATCH] Close the runner dispatch gap: createProject wire verb + boot project seeding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ANTIMATTER_RUNNER §0.2 item 1, both layers. A fresh runner could pair but not receive work — startChat needs an existing project and transfer import rejects unknown ones. (a) Interim: nucleicd reads NUCLEIC_RUNNER_PROJECTS (git URLs) and clones + registers each as a controlled project at boot. Idempotent by normalized origin remote (AppStore.projectMatching(remote:)), so a persistent-disk reboot never stacks repo-2 clones; a failed seed logs and moves on. (b) Wire verb per the §11.4 additive recipe: WireCreateProjectRequest (gitURL/branch/name, decode-defaulted optionals), ClientMsg.createProject gated on new WireCapabilities.canCreateProjects (decode-default false), ConnectionHandler control-scope handling into a defaulted-reject SyncHostBridge hook, AppStore conformance via addClonedProject (controlled clone; new optional branch passes through git clone --branch), iOS RemoteStore switches handled inertly, round-trip + legacy-tolerance tests. Verified: Linux nucleicd build + protocol suite (166 green) in the swift 6.3 container; boot smoke test — seed cloned on boot 1, skipped as already registered on boot 2; macOS nucleicd/NucleicApp build + protocol/sync/ transfer suites green; iOS xcodebuild green. Co-Authored-By: Claude Fable 5 --- NucleicRemote/NucleicRemote/Models/RemoteStore.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/NucleicRemote/NucleicRemote/Models/RemoteStore.swift b/NucleicRemote/NucleicRemote/Models/RemoteStore.swift index e62632e..6594893 100644 --- a/NucleicRemote/NucleicRemote/Models/RemoteStore.swift +++ b/NucleicRemote/NucleicRemote/Models/RemoteStore.swift @@ -1674,11 +1674,13 @@ final class RemoteStore: ObservableObject { // `requestPairingCode()`/`cancelPairingCode()`, not through this owner-routing switch. // The runner verbs (intelligence results, credential mesh — ANTIMATTER_RUNNER §5–6) will // ride their own executor/vault loops when the phone side lands; nothing routes them here. + // `createProject` (CLOUD_RUNTIME §4.3) will go straight to a user-chosen host when the + // phone grows that UI — a brand-new project has no owner to route by. case .hello, .ping, .listPeers, .addressUpdate, .meshRoster, .registerLiveActivity, .endLiveActivity, .registerPushToStartToken, .setForeground, .transferOffer, .transferChunk, .transferCommit, .transferCancel, .fetchTranscript, .requestPairingCode, .cancelPairingCode, .respondMacPair, - .intelligenceResult, .credentialManifest, .credentialProvision: + .intelligenceResult, .credentialManifest, .credentialProvision, .createProject: break } } @@ -1867,7 +1869,9 @@ final class RemoteStore: ObservableObject { // the demo path short-circuits in `requestPairingCode()` with a stand-in code. .requestPairingCode, .cancelPairingCode, .respondMacPair, // Antimatter runner verbs (ANTIMATTER_RUNNER §5–6) — demo has no runner host. - .intelligenceResult, .credentialManifest, .credentialProvision: + .intelligenceResult, .credentialManifest, .credentialProvision, + // Remote project creation (CLOUD_RUNTIME §4.3) — demo has no host to clone on. + .createProject: break // passive / already handled by the seeded fixtures (demo has no mesh peers) } }