Skip to content

Fix resident autonomy, Skipper coordination, and Cowork contracts - #46

Merged
gitcommit90 merged 1 commit into
mainfrom
fix/sidebar-agent-status-identity
Aug 1, 2026
Merged

Fix resident autonomy, Skipper coordination, and Cowork contracts#46
gitcommit90 merged 1 commit into
mainfrom
fix/sidebar-agent-status-identity

Conversation

@gitcommit90

@gitcommit90 gitcommit90 commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Outcome

Repairs the combined 0.0.32 candidate regression set before native packaging:

  • scopes animated channel status to the exact resident identity;
  • recovers Apple resident NIC/default-route failures without replacing disks;
  • stops duplicate resident/Skipper escalation loops;
  • restores Skipper as the durable workspace-wide chief of staff, with usable skill metadata, cross-channel history, and scoped scheduling workflows;
  • aligns channel-control tool exposure with the exact requesting user's authority;
  • makes Cowork file contracts durable across follow-ups/restarts and rejects only newly-created incompatible command output;
  • removes retired demo/testing endpoint references from public and agent-facing documentation.

Verification so far

  • npm run typecheck
  • npm run build
  • npm run test:brief-browser (53/53)
  • node --test test/autonomy-platform.mjs test/channel-surfaces.mjs test/channel-computers.mjs (28/28)
  • node --test test/site.mjs test/desktop.mjs
  • git diff --check

Broader native-world/full-suite verification is continuing against this pushed commit while CI runs.

Summary by CodeRabbit

  • New Features

    • Apple-hosted workspaces can automatically repair guest-network connectivity.
    • Cowork workflows now validate generated notes, documents, presentations, whiteboards, and code outputs.
    • Skipper workflows include improved authorization, escalation handling, and recurring workflow controls.
    • Agent status updates are isolated to the correct channel agent.
  • Bug Fixes

    • Prevented duplicate escalations and unauthorized channel actions.
    • Improved workspace reservation matching and durable coworking behavior.
  • Documentation

    • Updated self-hosting, governance, release verification, and product documentation to reflect the current website and sandbox model.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds resident-scoped status handling, user-authorized Skipper workflows, durable Cowork output contracts, Apple guest-network recovery, expanded skill metadata, and removal of retired demo-host references.

Changes

Agent coordination and Cowork contracts

Layer / File(s) Summary
Resident-scoped status updates
src/client/app.ts, test/brief-regressions-browser.mjs
Status events now update channels only when the event targets the resident agent.
Scoped Skipper runtime and workflows
src/server/bots.ts, src/server/skills.ts, scripts/autonomy-benchmark.mjs, test/autonomy-platform.mjs, test/native-world.mjs
Skipper prompts, tools, workflows, history access, escalation handling, and skill metadata now use requesting-user scope and duplicate-escalation protection.
Durable Cowork format enforcement
src/server/cowork-contract.ts, src/server/bots.ts, src/server/index.ts, test/autonomy-platform.mjs
Cowork contexts and surface contracts validate new workspace outputs, remove incompatible files, synchronize artifacts, and preserve existing files.

Apple guest-network recovery

Layer / File(s) Summary
Apple guest-network detection and repair
src/server/channel-computers.ts, test/channel-computers.mjs, test/fake-container.mjs
Apple startup and reconciliation now repair unavailable guest networking when no concurrent work is active. Tests simulate failed networking and verify command and workspace recovery.

Retired host and public documentation cleanup

Layer / File(s) Summary
Retired demo host removal
desktop/workspace-target.cjs, site/server.mjs, site/content.mjs, test/site.mjs, CHANGELOG.md
Hosted-workspace detection uses subdomain labels. The retired demo redirect and related site references were removed.
Public guidance and release metadata
docs/GOVERNANCE.md, docs/VISION.md, docs/release-notes-template.md, public/index.html, CHANGELOG.md
Public guidance, verification wording, bundle cache metadata, and changelog entries were updated.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RequestingUser
  participant AgentRuntime
  participant CoworkContract
  participant Workspace
  RequestingUser->>AgentRuntime: start scoped agent work
  AgentRuntime->>CoworkContract: derive durable surface contract
  AgentRuntime->>Workspace: snapshot and modify workspace
  AgentRuntime->>CoworkContract: validate new outputs
  CoworkContract->>Workspace: remove incompatible files and synchronize artifacts
Loading
sequenceDiagram
  participant AppleMachine
  participant FleetReconciliation
  participant VmnetServices
  participant GuestCommand
  AppleMachine->>FleetReconciliation: report failed guest network
  FleetReconciliation->>VmnetServices: recover shared networking
  FleetReconciliation->>AppleMachine: restart and verify machine
  AppleMachine->>GuestCommand: run command with restored network
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the outcome and verification, but it omits the required change type, release notes, numbered acceptance ledger, and checklist sections. Add the template sections, including one acceptance and evidence line for each requested item, release-note bullets, change-type selection, and completed verification checkboxes.
Docstring Coverage ⚠️ Warning Docstring coverage is 31.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary fixes for resident autonomy, Skipper coordination, and Cowork contracts.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sidebar-agent-status-identity

Comment @coderabbitai help to get the list of available commands.

@gitcommit90
gitcommit90 merged commit 2373cba into main Aug 1, 2026
5 of 6 checks passed
@gitcommit90
gitcommit90 deleted the fix/sidebar-agent-status-identity branch August 1, 2026 07:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (4)
test/brief-regressions-browser.mjs (1)

130-152: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Scope the working-row assertions to the target channel.

The selectors at Line 139 and Line 142 count every desktop sidebar row. The test also uses a separate mainChannel and does not reset other resident statuses. An unrelated working resident can make these assertions fail even when applyAgentStatusEvent is correct. Query the target channel row or reset all fixture residents to ready before asserting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/brief-regressions-browser.mjs` around lines 130 - 152, Scope the
working-row queries in the sidebarAgentIdentity evaluation to the target channel
represented by target.id, rather than counting all desktop sidebar rows. Update
both the dots count and workingRows selection to use that channel’s sidebar row,
preserving the existing assertions for Skipper rejection and resident acceptance
without relying on unrelated resident statuses.
test/site.mjs (1)

46-46: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Restore regression coverage for retired-host routing.

This assertion checks only manual text. It cannot detect an HTTP redirect for the retired host, and it does not check a hostname token. Add a request-level no-redirect check and explicit content checks for the retired references.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/site.mjs` at line 46, Extend the regression coverage around the existing
manual assertion to make an HTTP request to the retired host with redirects
disabled, asserting that no redirect response is returned and the response
contains the expected retired-host reference. Retain explicit content checks for
both the hostname token and the existing retired sandbox references, using the
test’s established request utilities.
test/channel-computers.mjs (1)

67-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding coverage for the fleet-reconciliation repair path.

This test exercises the boot-time repair path (ensureChannelComputerRunning, channel-computers.ts Line 846). The new deferral logic in reconcileOne (channel-computers.ts Lines 1534-1540), which skips repair while canStopChannelComputer returns false, has no visible direct test coverage in this diff. Consider adding a scenario that simulates an active obligation on an Apple channel and asserts that reconcileChannelComputers defers rather than forcing a stop.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/channel-computers.mjs` around lines 67 - 71, Add a direct
fleet-reconciliation test alongside the existing Apple VM repair coverage that
simulates an active obligation causing canStopChannelComputer to return false,
then invokes reconcileChannelComputers and verifies repair is deferred without
forcing the computer to stop. Keep the existing boot-time
ensureChannelComputerRunning assertions unchanged.
src/server/channel-computers.ts (1)

125-126: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Key the Apple network repair throttle to the active incident.

appleNetworkRepairAt suppresses apple(["system", "start"]) for 30 seconds across all Apple machines. An independent failure can therefore receive only machine stop and machine run. The fake container clears .network-down only during system start, so this path can throw "channel computer network remained unavailable after automatic repair".

Cross-file test-order coupling is not present because the channel-computer test runs in its own test process.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/channel-computers.ts` around lines 125 - 126, Update the Apple
network repair throttle represented by appleNetworkRepairAt so it is scoped to
the active incident or machine rather than shared across all Apple machines;
ensure a new independent failure can invoke apple(["system", "start"]) even when
another machine was repaired within the 30-second window, while preserving
deduplication for repeated repairs of the same incident.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/server/bots.ts`:
- Around line 1887-1889: Update the authorization-tool name list in the Skipper
error branch near the result handling conditional to include schedule_workflow,
list_workflows, and set_workflow_status, so unauthorized calls use the existing
authority-boundary error message instead of the generic unavailable-tool
message.
- Around line 1813-1814: Replace the duplicated host-or-personal-owner
authorization expression in the tool-name branch with the existing
skipperControlAuthorized helper defined near line 190, while preserving the
agent kind and allowed tool checks.

In `@src/server/channel-computers.ts`:
- Around line 588-623: Update repairAppleGuestNetwork and its caller
reconcileOne to use an atomic channel-scoped repair/admission gate held through
machine stop, restart, and health verification. Acquire the gate before checking
terminal sessions or active work, count the current repair operation when
evaluating competing commands, and prevent runChannelCommand or
openChannelTerminal from admitting new work until repair completes; do not rely
on a standalone re-check after work can begin.
- Around line 1534-1540: Move the shared active-work safety check into
repairAppleGuestNetwork so it runs before restarting the Apple guest network or
stopping the machine, while preserving ensureChannelComputerRunning’s
caller-specific allowance for its own command or turn. Remove the duplicated
caller-side check only if the centralized API can retain that distinction.
Ensure reconciliation deferrals are treated as retryable: do not increment
errors, mark provision_status as error, record failed activity, or expose
last_error.

---

Nitpick comments:
In `@src/server/channel-computers.ts`:
- Around line 125-126: Update the Apple network repair throttle represented by
appleNetworkRepairAt so it is scoped to the active incident or machine rather
than shared across all Apple machines; ensure a new independent failure can
invoke apple(["system", "start"]) even when another machine was repaired within
the 30-second window, while preserving deduplication for repeated repairs of the
same incident.

In `@test/brief-regressions-browser.mjs`:
- Around line 130-152: Scope the working-row queries in the sidebarAgentIdentity
evaluation to the target channel represented by target.id, rather than counting
all desktop sidebar rows. Update both the dots count and workingRows selection
to use that channel’s sidebar row, preserving the existing assertions for
Skipper rejection and resident acceptance without relying on unrelated resident
statuses.

In `@test/channel-computers.mjs`:
- Around line 67-71: Add a direct fleet-reconciliation test alongside the
existing Apple VM repair coverage that simulates an active obligation causing
canStopChannelComputer to return false, then invokes reconcileChannelComputers
and verifies repair is deferred without forcing the computer to stop. Keep the
existing boot-time ensureChannelComputerRunning assertions unchanged.

In `@test/site.mjs`:
- Line 46: Extend the regression coverage around the existing manual assertion
to make an HTTP request to the retired host with redirects disabled, asserting
that no redirect response is returned and the response contains the expected
retired-host reference. Retain explicit content checks for both the hostname
token and the existing retired sandbox references, using the test’s established
request utilities.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2e0bf148-6976-4b00-804c-276f0a4b9d89

📥 Commits

Reviewing files that changed from the base of the PR and between 7a1cca7 and 25e0f18.

📒 Files selected for processing (23)
  • CHANGELOG.md
  • desktop/workspace-target.cjs
  • docs/GOVERNANCE.md
  • docs/VISION.md
  • docs/release-notes-template.md
  • public/index.html
  • scripts/autonomy-benchmark.mjs
  • site/content.mjs
  • site/manual.html
  • site/server.mjs
  • src/client/app.ts
  • src/server/bots.ts
  • src/server/channel-computers.ts
  • src/server/cowork-contract.ts
  • src/server/index.ts
  • src/server/skills.ts
  • test/autonomy-platform.mjs
  • test/brief-regressions-browser.mjs
  • test/channel-computers.mjs
  • test/desktop.mjs
  • test/fake-container.mjs
  • test/native-world.mjs
  • test/site.mjs
💤 Files with no reviewable changes (4)
  • site/manual.html
  • test/desktop.mjs
  • docs/VISION.md
  • site/server.mjs

Comment thread src/server/bots.ts
Comment on lines +1813 to 1814
} else if (["list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations", "schedule_workflow", "list_workflows", "set_workflow_status"].includes(name)
&& agent?.kind === "skipper" && (hostAuthorized || Boolean(q1("SELECT 1 FROM channels WHERE id=? AND personal_main_owner_id=?", channelId, requestUserId)))) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Reuse skipperControlAuthorized instead of duplicating the authorization check.

This condition repeats the same logic already defined in skipperControlAuthorized (Line 190). Duplicated authorization logic can drift out of sync if one copy is updated and the other is not. Call the shared helper here instead.

♻️ Proposed fix
-    } else if (["list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations", "schedule_workflow", "list_workflows", "set_workflow_status"].includes(name)
-      && agent?.kind === "skipper" && (hostAuthorized || Boolean(q1("SELECT 1 FROM channels WHERE id=? AND personal_main_owner_id=?", channelId, requestUserId)))) {
+    } else if (["list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations", "schedule_workflow", "list_workflows", "set_workflow_status"].includes(name)
+      && agent?.kind === "skipper" && skipperControlAuthorized(channelId, requestUserId, hostAuthorized)) {
       result = String(await executeSkipperControlTool(name, args, requestUserId, hostAuthorized));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} else if (["list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations", "schedule_workflow", "list_workflows", "set_workflow_status"].includes(name)
&& agent?.kind === "skipper" && (hostAuthorized || Boolean(q1("SELECT 1 FROM channels WHERE id=? AND personal_main_owner_id=?", channelId, requestUserId)))) {
} else if (["list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations", "schedule_workflow", "list_workflows", "set_workflow_status"].includes(name)
&& agent?.kind === "skipper" && skipperControlAuthorized(channelId, requestUserId, hostAuthorized)) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/bots.ts` around lines 1813 - 1814, Replace the duplicated
host-or-personal-owner authorization expression in the tool-name branch with the
existing skipperControlAuthorized helper defined near line 190, while preserving
the agent kind and allowed tool checks.

Comment thread src/server/bots.ts
Comment on lines +1887 to +1889
else result = agent?.kind === "skipper" && ["create_channel", "list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations"].includes(name)
? `Error: this user is not authorized to use ${name} in this channel.`
: `Error: tool ${name} is not available.`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add the workflow tool names to the "not authorized" error branch.

schedule_workflow, list_workflows, and set_workflow_status are gated by skipperControlAuthorized (Line 1813-1814), the same as create_channel and the other listed tools. This list at Line 1888 does not include them. An unauthorized Skipper call to one of these three tools falls through to the generic Error: tool ${name} is not available. instead of the accurate authority-boundary message. This contradicts the prompt instruction at Line 221 to explain the authority boundary rather than imply the capability is missing.

🐛 Proposed fix
-            else result = agent?.kind === "skipper" && ["create_channel", "list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations"].includes(name)
+            else result = agent?.kind === "skipper" && ["create_channel", "list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations", "schedule_workflow", "list_workflows", "set_workflow_status"].includes(name)
               ? `Error: this user is not authorized to use ${name} in this channel.`
               : `Error: tool ${name} is not available.`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
else result = agent?.kind === "skipper" && ["create_channel", "list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations"].includes(name)
? `Error: this user is not authorized to use ${name} in this channel.`
: `Error: tool ${name} is not available.`;
else result = agent?.kind === "skipper" && ["create_channel", "list_channels", "inspect_channel", "archive_channel", "restore_channel", "delete_channel", "inspect_fleet", "care_for_channel_computer", "list_obligations", "schedule_workflow", "list_workflows", "set_workflow_status"].includes(name)
? `Error: this user is not authorized to use ${name} in this channel.`
: `Error: tool ${name} is not available.`;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/bots.ts` around lines 1887 - 1889, Update the authorization-tool
name list in the Skipper error branch near the result handling conditional to
include schedule_workflow, list_workflows, and set_workflow_status, so
unauthorized calls use the existing authority-boundary error message instead of
the generic unavailable-tool message.

Comment on lines +588 to +623
async function repairAppleGuestNetwork(computer: ChannelComputer): Promise<void> {
if (computer.backend !== "apple") return;
if (!appleNetworkRepair) {
appleNetworkRepair = (async () => {
// Avoid repeatedly bouncing shared vmnet while several machines detect
// the same fleet-wide outage during one reconciliation pass.
if (now() - appleNetworkRepairAt > 30_000) {
if (platform() === "darwin") {
const label = `gui/${process.getuid?.() ?? 501}/com.apple.container.container-network-vmnet.default`;
const kicked = await spawnCollected("/bin/launchctl", ["kickstart", "-k", label], { timeoutMs: 30_000 });
if (kicked.code !== 0) throw new Error(kicked.stderr.toString("utf8").trim() || "Apple shared VM network service could not restart");
}
const started = await apple(["system", "start"], { timeoutMs: 90_000 });
if (started.code !== 0) throw new Error(started.stderr.toString("utf8").trim() || "Apple container services could not restart");
appleNetworkRepairAt = now();
}
})().finally(() => { appleNetworkRepair = null; });
}
await appleNetworkRepair;
const competingCommands = Number(q1(`SELECT COUNT(*) n FROM channel_computer_obligations
WHERE channel_id=? AND kind='command' AND status='active'`, computer.channel_id)?.n || 0);
const runningTurns = Number(q1("SELECT COUNT(*) n FROM agent_turns WHERE channel_id=? AND state='running'", computer.channel_id)?.n || 0);
if ([...terminalSessions.values()].some((session) => session.channelId === computer.channel_id)
|| competingCommands > 1 || runningTurns > 1) {
throw new Error("resident computer network is unavailable; automatic repair is waiting for concurrent work to finish");
}
const stopped = await apple(["machine", "stop", computer.machine_id], { timeoutMs: 90_000 });
if (stopped.code !== 0 && !/not running|stopped/i.test(Buffer.concat([stopped.stderr, stopped.stdout]).toString("utf8"))) {
throw new Error(stopped.stderr.toString("utf8").trim() || "network repair could not stop the channel computer");
}
const restarted = await apple(["machine", "run", "-n", computer.machine_id, "--", ...guestWords("/bin/sh", "-lc", APPLE_GUEST_NETWORK_CHECK)], { timeoutMs: 90_000 });
if (restarted.code !== 0 || !await appleGuestNetworkHealthy(computer)) throw new Error("channel computer network remained unavailable after automatic repair");
run("UPDATE channel_computers SET observed_state='running',provision_status='ready',last_health=?,last_error='',updated=? WHERE channel_id=?", now(), now(), computer.channel_id);
recordComputerActivity(computer.channel_id, "Recovered the resident computer's network without replacing its Linux disk.", "complete");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Confirm channel-lock coverage around command dispatch relative to repairAppleGuestNetwork's stop/restart.
ast-grep run --pattern 'withChannelLock($_, $_)' --lang typescript src/server/channel-computers.ts
rg -n 'function runChannelCommand|kind=.command.|status=.active.' src/server/channel-computers.ts -C5

Repository: gitcommit90/1Helm

Length of output: 21994


🏁 Script executed:

#!/bin/bash
# Inspect the lock implementation, the complete command/turn dispatch paths, and reconcileOne callers.
rg -n 'withChannelLock|runChannelCommand|agent_turns|reconcileOne|repairAppleGuestNetwork|ensureChannelComputerRunning' src/server -g '*.ts' -C4
printf '\n--- channel-computers.ts 560-630 ---\n'
sed -n '560,630p' src/server/channel-computers.ts
printf '\n--- channel-computers.ts 800-875 ---\n'
sed -n '800,875p' src/server/channel-computers.ts
printf '\n--- channel-computers.ts 930-1015 ---\n'
sed -n '930,1015p' src/server/channel-computers.ts
printf '\n--- reconcile region ---\n'
sed -n '1460,1575p' src/server/channel-computers.ts

Repository: gitcommit90/1Helm

Length of output: 50373


🏁 Script executed:

#!/bin/bash
# Read only the exact sections needed to determine whether the lock covers command execution
# and whether reconcileOne acquires the same lock before repairAppleGuestNetwork.
printf '%s\n' '--- lock implementation ---'
sed -n '118,142p' src/server/channel-computers.ts
printf '%s\n' '--- command lifecycle ---'
sed -n '935,957p' src/server/channel-computers.ts
printf '%s\n' '--- terminal lifecycle ---'
sed -n '957,1042p' src/server/channel-computers.ts
printf '%s\n' '--- turn admission and execution ---'
sed -n '1320,1365p' src/server/bots.ts
sed -n '1418,1475p' src/server/bots.ts
printf '%s\n' '--- reconcile and repair callers ---'
sed -n '1490,1562p' src/server/channel-computers.ts

Repository: gitcommit90/1Helm

Length of output: 19953


Serialize network repair with channel work before machine stop. reconcileOne calls repairAppleGuestNetwork without withChannelLock. The lock in ensureChannelComputerRunning ends before runChannelCommand starts isolated or spawnCollected, and before openChannelTerminal creates its PTY. New work can therefore start after the checks, while competingCommands > 1 still permits one active command. Use an atomic repair/admission gate that accounts for the current command; a standalone re-check is insufficient.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/channel-computers.ts` around lines 588 - 623, Update
repairAppleGuestNetwork and its caller reconcileOne to use an atomic
channel-scoped repair/admission gate held through machine stop, restart, and
health verification. Acquire the gate before checking terminal sessions or
active work, count the current repair operation when evaluating competing
commands, and prevent runChannelCommand or openChannelTerminal from admitting
new work until repair completes; do not rely on a standalone re-check after work
can begin.

Comment on lines +1534 to +1540
if (computer.backend === "apple" && !await appleGuestNetworkHealthy(computer)) {
if (!canStopChannelComputer(computer.channel_id)) {
throw new Error("resident computer network is unavailable; automatic repair is waiting for its active work to stop");
}
await repairAppleGuestNetwork(computer);
computer = channelComputer(computer.channel_id)!;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check how canStopChannelComputer's criteria compare to repairAppleGuestNetwork's inline checks, and whether last_error is user-facing.
rg -n 'function canStopChannelComputer' -A 15 src/server/channel-computers.ts
rg -n 'last_error' src/client/app.ts src/server/channel-computers.ts -C3

Repository: gitcommit90/1Helm

Length of output: 19097


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- repairAppleGuestNetwork and callers ---'
sed -n '580,625p' src/server/channel-computers.ts
sed -n '830,865p' src/server/channel-computers.ts
sed -n '1518,1555p' src/server/channel-computers.ts
printf '%s\n' '--- reconciliation and error handling ---'
rg -n 'reconcileOne|reconcileChannelComputers|recordComputerError|ensureChannelComputerRunning' src/server/channel-computers.ts -C 12
printf '%s\n' '--- all last_error consumers ---'
rg -n 'last_error|errors' src --glob '!src/server/channel-computers.ts' -C 3
printf '%s\n' '--- relevant type and API serialization ---'
sed -n '1,215p' src/server/channel-computers.ts

Repository: gitcommit90/1Helm

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path
p = Path("src/server/channel-computers.ts")
s = p.read_text()
checks = {
    "canStopChannelComputer definition": "export function canStopChannelComputer",
    "repairAppleGuestNetwork definition": "async function repairAppleGuestNetwork",
    "reconciliation catch": "recordComputerError",
    "deferred error text": "automatic repair is waiting for its active work to stop",
}
for label, needle in checks.items():
    print(f"{label}: {s.count(needle)} occurrence(s)")
for needle in checks:
    pass
# Print compact enclosing function ranges without executing repository code.
for name in ("canStopChannelComputer", "repairAppleGuestNetwork", "reconcileOne", "reconcileChannelComputers"):
    pos = s.find(name)
    print(f"{name}: first occurrence at line {s.count(chr(10), 0, pos)+1 if pos >= 0 else 'not found'}")
PY

Repository: gitcommit90/1Helm

Length of output: 542


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path
s = Path("src/server/channel-computers.ts").read_text()

# Standalone behavioral model of the two predicates as implemented.
def can_stop(terminal_sessions, resident_obligations, working_agents):
    return not terminal_sessions and not resident_obligations and not working_agents

def repair_allows(terminal_sessions, competing_commands, running_turns):
    return not terminal_sessions and competing_commands <= 1 and running_turns <= 1

cases = [
    ("one active command and one running turn", False, True, True, 1, 1),
    ("two active commands", False, True, False, 2, 1),
    ("one working agent", False, False, True, 0, 0),
    ("terminal session", True, False, False, 0, 0),
]
for name, terminal, obligation, agent, commands, turns in cases:
    left = can_stop(terminal, obligation, agent)
    right = repair_allows(terminal, commands, turns)
    print(f"{name}: canStop={left}, repairAllows={right}, same={left == right}")

# Confirm the shared-runtime restart occurs before repair's local safety check.
repair = s[s.index("async function repairAppleGuestNetwork"):s.index("const isolatedBackend")]
restart = repair.index('await apple(["system", "start"]')
safety = repair.index("const competingCommands")
print("repair restart precedes safety check:", restart < safety)

# Confirm reconciliation converts the deferral into a recorded error.
reconcile = s[s.index("async function reconcileOne"):s.index("export function startChannelComputerReconciler")]
print("deferral thrown:", "automatic repair is waiting for its active work to stop" in reconcile)
print("reconcile catch calls recordComputerError:", "catch (error) { errors++; recordComputerError(row.channel_id, error); }" in reconcile)
PY

printf '%s\n' '--- precise client exposure ---'
sed -n '1148,1172p' src/client/channel.ts

Repository: gitcommit90/1Helm

Length of output: 3667


Move the safety check before the shared Apple network restart.

ensureChannelComputerRunning intentionally allows its own command or turn, while reconciliation rejects active work. Preserve this caller-specific allowance, but centralize the common safety logic.

repairAppleGuestNetwork currently restarts the shared network before checking active work. Check safety before restarting the shared service and before stopping the machine.

Treat reconciliation deferrals as retryable. They currently increment errors, set provision_status='error', record failed activity, and expose last_error in the channel UI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/channel-computers.ts` around lines 1534 - 1540, Move the shared
active-work safety check into repairAppleGuestNetwork so it runs before
restarting the Apple guest network or stopping the machine, while preserving
ensureChannelComputerRunning’s caller-specific allowance for its own command or
turn. Remove the duplicated caller-side check only if the centralized API can
retain that distinction. Ensure reconciliation deferrals are treated as
retryable: do not increment errors, mark provision_status as error, record
failed activity, or expose last_error.

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