Merge nucleic/lucid-quartz-otter into dev

This commit is contained in:
2026-07-12 23:01:22 -07:00
parent 904ef11456
commit 03ac36779d
7 changed files with 25 additions and 25 deletions
@@ -408,7 +408,7 @@ final class HostConnection {
releaseChannel: BuildInfo.current.channel.releaseChannel, releaseChannel: BuildInfo.current.channel.releaseChannel,
// Mesh "join": advertise roster gossip so a host pushes its group view — the phone // Mesh "join": advertise roster gossip so a host pushes its group view — the phone
// then auto-learns and connects to every Mac in the mesh, not just the one it scanned. // then auto-learns and connects to every Mac in the mesh, not just the one it scanned.
// Also offer this phone as a low-tier AFM executor (CARBON_RUNNER §5) when the // Also offer this phone as a low-tier AFM executor (COVALENCE_RUNNER §5) when the
// OS has Foundation Models — a runner host's mesh queue may place background work // OS has Foundation Models — a runner host's mesh queue may place background work
// here; the interactive tiers stay on desktop-class devices by the queue's rules. // here; the interactive tiers stay on desktop-class devices by the queue's rules.
clientCaps: WireClientCapabilities( clientCaps: WireClientCapabilities(
@@ -683,7 +683,7 @@ final class HostConnection {
// resolves (success or failure). Correlation by requestID happens in RemoteStore. // resolves (success or failure). Correlation by requestID happens in RemoteStore.
callbacks.projectCreated(outcome) callbacks.projectCreated(outcome)
case .intelligenceRequest(let request): case .intelligenceRequest(let request):
// A runner host delegated one AFM job here (docs/CARBON_RUNNER.md §5) — it only // A runner host delegated one AFM job here (docs/COVALENCE_RUNNER.md §5) — it only
// ever sends these after this app advertised `canProvideIntelligence`. Generate off // ever sends these after this app advertised `canProvideIntelligence`. Generate off
// the event stream (a model call takes seconds) and answer with the same id. // the event stream (a model call takes seconds) and answer with the same id.
Task { [weak self] in Task { [weak self] in
@@ -704,7 +704,7 @@ final class HostConnection {
// The owner's runner-pool credential (item 4) — inert until the phone grows a // The owner's runner-pool credential (item 4) — inert until the phone grows a
// pool-management surface; Macs are the managers today. // pool-management surface; Macs are the managers today.
.runnerPoolCredential: .runnerPoolCredential:
// Carbon runner credential verbs (docs/CARBON_RUNNER.md §6): a runner host // Covalence runner credential verbs (docs/COVALENCE_RUNNER.md §6): a runner host
// asking for / mirroring sealed credentials. Inert here until the phone-side vault // asking for / mirroring sealed credentials. Inert here until the phone-side vault
// lands — and a host only sends these to clients that advertised the matching // lands — and a host only sends these to clients that advertised the matching
// `WireClientCapabilities`, which this app doesn't yet. // `WireClientCapabilities`, which this app doesn't yet.
@@ -4,7 +4,7 @@ import NucleicProtocol
import FoundationModels import FoundationModels
#endif #endif
/// The phone-side executor for delegated intelligence work (docs/CARBON_RUNNER.md §5, /// The phone-side executor for delegated intelligence work (docs/COVALENCE_RUNNER.md §5,
/// item 6): a runner host pushes `HostMsg.intelligenceRequest` at this device — the mesh AFM /// item 6): a runner host pushes `HostMsg.intelligenceRequest` at this device — the mesh AFM
/// queue only ever sends it the lower tiers (`completion`/`background`), which don't need /// queue only ever sends it the lower tiers (`completion`/`background`), which don't need
/// desktop tok/s — and this renders the shared `IntelligenceDelegate` template on the local /// desktop tok/s — and this renders the shared `IntelligenceDelegate` template on the local
@@ -99,7 +99,7 @@ final class RemoteStore: ObservableObject {
} }
/// The mesh's runner-presence cards (Macs / cloud runners advertising capacity), sorted by /// The mesh's runner-presence cards (Macs / cloud runners advertising capacity), sorted by
/// host name — the phone's window into the Carbon dispatch candidate pool. Keyed by the full /// host name — the phone's window into the Covalence dispatch candidate pool. Keyed by the full
/// `deviceID` (distinct from `PairedHost.fingerprint`), so it's presented as its own section /// `deviceID` (distinct from `PairedHost.fingerprint`), so it's presented as its own section
/// rather than cross-matched against the directly-paired Macs. /// rather than cross-matched against the directly-paired Macs.
var meshRunnerCards: [(hostID: String, presence: RunnerPresence)] { var meshRunnerCards: [(hostID: String, presence: RunnerPresence)] {
@@ -142,11 +142,11 @@ final class RemoteStore: ObservableObject {
return (descriptor, candidates) return (descriptor, candidates)
} }
/// Dispatch a new chat to the abstract **Carbon** destination from the phone: rank eligible /// Dispatch a new chat to the abstract **Covalence** destination from the phone: rank eligible
/// hosts by the shared scorer and try them in order, one at a time with a correlated, /// hosts by the shared scorer and try them in order, one at a time with a correlated,
/// idempotent ack (a timeout retries the same candidate once before moving on). On success /// idempotent ack (a timeout retries the same candidate once before moving on). On success
/// routes to the landed session. Mirrors `AppStore.dispatchChatToMesh`. The phone stamps /// routes to the landed session. Mirrors `AppStore.dispatchChatToMesh`. The phone stamps
/// itself as the Carbon origin, so the landed session is Carbon-managed (its owner keeps it /// itself as the Covalence origin, so the landed session is Covalence-managed (its owner keeps it
/// on the optimal host between turns); the phone can't own sessions, so the origin exclusion /// on the optimal host between turns); the phone can't own sessions, so the origin exclusion
/// is naturally satisfied by every candidate. /// is naturally satisfied by every candidate.
func dispatchChatToMesh( func dispatchChatToMesh(
@@ -165,8 +165,8 @@ final class RemoteStore: ObservableObject {
backend: nil, excluding: excluded).first backend: nil, excluding: excluded).first
else { else {
showError(tried == 0 showError(tried == 0
? "No Carbon host can take this chat right now." ? "No Covalence host can take this chat right now."
: "No Carbon host could take this chat (\(tried) tried).", sessionID: nil) : "No Covalence host could take this chat (\(tried) tried).", sessionID: nil)
return return
} }
tried += 1 tried += 1
@@ -179,7 +179,7 @@ final class RemoteStore: ObservableObject {
let request = StartChatRequest( let request = StartChatRequest(
projectID: targetProjectID, message: text, model: model, effort: effort, projectID: targetProjectID, message: text, model: model, effort: effort,
auto: auto, requestID: requestID, auto: auto, requestID: requestID,
carbonOriginDeviceID: IdentityStore.deviceID()) covalenceOriginDeviceID: IdentityStore.deviceID())
var outcome = await sendDispatch(request, on: conn, timeout: .seconds(10)) var outcome = await sendDispatch(request, on: conn, timeout: .seconds(10))
if outcome == nil { if outcome == nil {
outcome = await sendDispatch(request, on: conn, timeout: .seconds(5)) outcome = await sendDispatch(request, on: conn, timeout: .seconds(5))
@@ -409,7 +409,7 @@ final class RemoteStore: ObservableObject {
/// "Add a project" (Projects tab): the phone asks a connected host advertising /// "Add a project" (Projects tab): the phone asks a connected host advertising
/// `canCreateProjects` to clone a git URL and register it (CLOUD_RUNTIME §4.3) — how a /// `canCreateProjects` to clone a git URL and register it (CLOUD_RUNTIME §4.3) — how a
/// fresh Carbon runner gets its first project. The outcome arrives asynchronously as /// fresh Covalence runner gets its first project. The outcome arrives asynchronously as
/// `HostMsg.projectCreated`, correlated by the request id below; the project row itself /// `HostMsg.projectCreated`, correlated by the request id below; the project row itself
/// rides the dashboard push. /// rides the dashboard push.
enum AddProjectState: Equatable { enum AddProjectState: Equatable {
@@ -2191,7 +2191,7 @@ final class RemoteStore: ObservableObject {
// Never originated from here (connection-internal, or handled by dedicated loops). // Never originated from here (connection-internal, or handled by dedicated loops).
// `requestPairingCode`/`cancelPairingCode` are sent straight to the chosen host by // `requestPairingCode`/`cancelPairingCode` are sent straight to the chosen host by
// `requestPairingCode()`/`cancelPairingCode()`, not through this owner-routing switch. // `requestPairingCode()`/`cancelPairingCode()`, not through this owner-routing switch.
// The runner verbs (intelligence results, credential mesh — CARBON_RUNNER §5–6) will // The runner verbs (intelligence results, credential mesh — COVALENCE_RUNNER §5–6) will
// ride their own executor/vault loops when the phone side lands; nothing routes them here. // 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 // `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. // phone grows that UI — a brand-new project has no owner to route by.
@@ -2394,7 +2394,7 @@ final class RemoteStore: ObservableObject {
// "Add a device" mint is handled directly against a live host, not via demoHandle; // "Add a device" mint is handled directly against a live host, not via demoHandle;
// the demo path short-circuits in `requestPairingCode()` with a stand-in code. // the demo path short-circuits in `requestPairingCode()` with a stand-in code.
.requestPairingCode, .cancelPairingCode, .respondMacPair, .requestPairingCode, .cancelPairingCode, .respondMacPair,
// Carbon runner verbs (CARBON_RUNNER §5–6) — demo has no runner host. // Covalence runner verbs (COVALENCE_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. // Remote project creation (CLOUD_RUNTIME §4.3) — demo has no host to clone on.
.createProject, .createProject,
@@ -18,9 +18,9 @@ struct StartChatComposer: View {
/// project page's "+", so the chat always lands in that project. /// project page's "+", so the chat always lands in that project.
var lockedProject: WireProject? = nil var lockedProject: WireProject? = nil
@State private var projectID: ProjectID? @State private var projectID: ProjectID?
/// Carbon (mesh work queue): run on the project's own Mac (false) or on Carbon (true) — /// Covalence (mesh work queue): run on the project's own Mac (false) or on Covalence (true) —
/// auto-routed to the best eligible mesh host and kept on the optimal host between turns. /// auto-routed to the best eligible mesh host and kept on the optimal host between turns.
/// The phone itself can't run sessions, so every Carbon candidate is already "not here". /// The phone itself can't run sessions, so every Covalence candidate is already "not here".
/// Shown only when a connected peer could actually take it. /// Shown only when a connected peer could actually take it.
@State private var runOnMesh = false @State private var runOnMesh = false
@State private var autoOverride: Bool? @State private var autoOverride: Bool?
@@ -89,19 +89,19 @@ struct StartChatComposer: View {
? "Auto-approve is always on for Nucleic Control chats — they run autonomously." ? "Auto-approve is always on for Nucleic Control chats — they run autonomously."
: "Auto-approve safe actions; destructive ones still ask.") : "Auto-approve safe actions; destructive ones still ask.")
} }
// Carbon (mesh work queue): when an eligible peer holds this repo, offer "Carbon" so // Covalence (mesh work queue): when an eligible peer holds this repo, offer "Covalence" so
// the chat routes to whichever host fits — and moves between hosts as availability // the chat routes to whichever host fits — and moves between hosts as availability
// changes — rather than always running on its own owner. // changes — rather than always running on its own owner.
if meshAvailable { if meshAvailable {
Menu { Menu {
Picker("Run on", selection: $runOnMesh) { Picker("Run on", selection: $runOnMesh) {
Text("This Mac").tag(false) Text("This Mac").tag(false)
Text("Carbon").tag(true) Text("Covalence").tag(true)
} }
.pickerStyle(.inline) .pickerStyle(.inline)
} label: { } label: {
Label( Label(
runOnMesh ? "Carbon" : "This Mac", runOnMesh ? "Covalence" : "This Mac",
systemImage: runOnMesh ? "antenna.radiowaves.left.and.right" : "desktopcomputer") systemImage: runOnMesh ? "antenna.radiowaves.left.and.right" : "desktopcomputer")
.font(.caption) .font(.caption)
.foregroundStyle(Palette.accent) .foregroundStyle(Palette.accent)
@@ -1,10 +1,10 @@
import SwiftUI import SwiftUI
import NucleicProtocol import NucleicProtocol
/// The phone's **Mesh Info** screen — the iOS analogue of the Mac's Carbon Mesh Viewer, reached /// The phone's **Mesh Info** screen — the iOS analogue of the Mac's Covalence Mesh Viewer, reached
/// from Settings ▸ Mesh ▸ "Mesh info". A read-only diagnostics surface over the mesh as this phone /// from Settings ▸ Mesh ▸ "Mesh info". A read-only diagnostics surface over the mesh as this phone
/// sees it: overall connection health, the Macs this phone is directly paired with (live status + /// sees it: overall connection health, the Macs this phone is directly paired with (live status +
/// transport), the mesh's runner-presence cards (the Carbon dispatch candidate pool with capacity / /// transport), the mesh's runner-presence cards (the Covalence dispatch candidate pool with capacity /
/// projects), and a live tail of fleet activity. Structural metadata only — never prompt/draft /// projects), and a live tail of fleet activity. Structural metadata only — never prompt/draft
/// content, matching the Mac viewer's redaction invariant. /// content, matching the Mac viewer's redaction invariant.
/// ///
@@ -82,7 +82,7 @@ struct MeshInfoView: View {
} header: { } header: {
Text("Runner capacity") Text("Runner capacity")
} footer: { } footer: {
Text("Hosts advertising capacity for Carbon-dispatched chats, and the projects " Text("Hosts advertising capacity for Covalence-dispatched chats, and the projects "
+ "they hold.") + "they hold.")
} }
} }
@@ -52,7 +52,7 @@ struct ProjectsView: View {
.refreshable { store.refreshSessions() } .refreshable { store.refreshSessions() }
.toolbar { .toolbar {
// "Add a project" (CLOUD_RUNTIME §4.3): clone a git URL on a connected host — // "Add a project" (CLOUD_RUNTIME §4.3): clone a git URL on a connected host —
// how a fresh Carbon runner gets its first project. Hidden when no live // how a fresh Covalence runner gets its first project. Hidden when no live
// host advertises `canCreateProjects` (an older Mac would reject the verb). // host advertises `canCreateProjects` (an older Mac would reject the verb).
if store.canCreateProject { if store.canCreateProject {
ToolbarItem(placement: .primaryAction) { ToolbarItem(placement: .primaryAction) {
@@ -72,7 +72,7 @@ struct SettingsView: View {
if !pairedHosts.isEmpty { if !pairedHosts.isEmpty {
Section("Mesh") { Section("Mesh") {
// A read-only diagnostics view of the mesh as this phone sees it — the // A read-only diagnostics view of the mesh as this phone sees it — the
// iOS analogue of the Mac's Carbon Mesh Viewer. // iOS analogue of the Mac's Covalence Mesh Viewer.
NavigationLink { NavigationLink {
MeshInfoView() MeshInfoView()
} label: { } label: {
@@ -137,7 +137,7 @@ struct SettingsView: View {
Button { Button {
showScanner = true showScanner = true
} label: { } label: {
Label("Join a Carbon mesh", systemImage: "circle.dotted.and.circle") Label("Join a Covalence mesh", systemImage: "circle.dotted.and.circle")
} }
Button { Button {
showManualPair = true showManualPair = true
@@ -438,7 +438,7 @@ struct AddDeviceView: View {
} header: { } header: {
Text("Scan to join") Text("Scan to join")
} footer: { } footer: {
Text("On a new iPhone or iPad, open Nucleic Remote ▸ Join a Carbon mesh and scan this. " Text("On a new iPhone or iPad, open Nucleic Remote ▸ Join a Covalence mesh and scan this. "
+ "It joins the whole group — every Mac and device here.") + "It joins the whole group — every Mac and device here.")
} }