From c235f0fddd7f5686bcba43b44b18395958eec1a0 Mon Sep 17 00:00:00 2001 From: iamnbutler Date: Mon, 19 Oct 2026 16:54:57 -0400 Subject: [PATCH 1/3] fix(channel): admit stop and kill like ask, and hide @ace from blocked teammates With collaborator agent access off, a teammate could stop or kill the owner's run, and their composer still offered Ace mode and the @ace mention. Stop and kill now carry an author that gateways stamp from Tailscale, and the channel admits them like ask. A blocked teammate's composer shows only Chat mode; a saved Ace draft keeps its words without the mention until access returns. Why: packages/channel/src/channel.ts#class Channel | stop and kill go through #mayInvoke like ask; whoever can't start a run can't end one Why: apps/host/src/gateway.ts#function authored | stop and kill always get the verified author, even when an older client sent none, or the owner's own stop is refused --- ...T78X1E0KAE-every-command-but-serve-must.md | 6 +- ...S1RP81MQCE0-a-hosted-channel-s-location.md | 6 +- ...MC0KH3Q6BN-a-hosted-channel-must-be-rea.md | 6 +- ...YNMKAC8BT5B-a-move-to-a-cloud-workspace.md | 5 +- ...TMTSE6Y5B8-stop-and-kill-always-get-the.md | 8 ++ ...GN565PYN6R-a-frozen-compute-channel-run.md | 5 +- ...6TCNZGMVDS-stop-and-kill-go-through-may.md | 8 ++ apps/app/src/composer.tsx | 97 +++++++------------ apps/host/src/cli.ts | 2 +- apps/host/src/gateway.ts | 18 ++-- apps/host/src/manage.ts | 7 +- packages/channel/src/channel.ts | 8 +- packages/channel/src/protocol.ts | 5 +- 13 files changed, 91 insertions(+), 90 deletions(-) create mode 100644 .lane/memory/apps/host/src/gateway.ts/01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md create mode 100644 .lane/memory/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md diff --git a/.lane/memory/apps/host/src/cli.ts/01M4YY5SXJFQK8VXT78X1E0KAE-every-command-but-serve-must.md b/.lane/memory/apps/host/src/cli.ts/01M4YY5SXJFQK8VXT78X1E0KAE-every-command-but-serve-must.md index 9dee7729..fe6a7275 100644 --- a/.lane/memory/apps/host/src/cli.ts/01M4YY5SXJFQK8VXT78X1E0KAE-every-command-but-serve-must.md +++ b/.lane/memory/apps/host/src/cli.ts/01M4YY5SXJFQK8VXT78X1E0KAE-every-command-but-serve-must.md @@ -4,9 +4,9 @@ anchor: function main created: 2026-10-15T04:47:23Z norm: '1' sig: 7d5d3f63a3bddde4 -body_hash: 397cc128a3b3cb7c -raw_hash: 55881f356849ef02 -vouched: 2026-10-19T16:56:54Z +body_hash: 2274b654de30a8ac +raw_hash: 23940716838db5e6 +vouched: 2026-10-19T20:55:05Z lines: 253-482 --- diff --git a/.lane/memory/apps/host/src/gateway.ts/01M4YVZ6KGNQ7MFS1RP81MQCE0-a-hosted-channel-s-location.md b/.lane/memory/apps/host/src/gateway.ts/01M4YVZ6KGNQ7MFS1RP81MQCE0-a-hosted-channel-s-location.md index daefd1f8..463f084c 100644 --- a/.lane/memory/apps/host/src/gateway.ts/01M4YVZ6KGNQ7MFS1RP81MQCE0-a-hosted-channel-s-location.md +++ b/.lane/memory/apps/host/src/gateway.ts/01M4YVZ6KGNQ7MFS1RP81MQCE0-a-hosted-channel-s-location.md @@ -4,9 +4,9 @@ anchor: function handle created: 2026-10-15T04:08:49Z norm: '1' sig: e597b5fbc8e664ce -body_hash: ef8527c95dcbf51a -raw_hash: 3d4e766de43b3348 -vouched: 2026-10-19T18:26:01Z +body_hash: 67b82b247b0adc3f +raw_hash: f2b48d8004d3b7cb +vouched: 2026-10-19T20:55:05Z lines: 266-519 --- diff --git a/.lane/memory/apps/host/src/gateway.ts/01M4Z2BCKRNHVMYEMC0KH3Q6BN-a-hosted-channel-must-be-rea.md b/.lane/memory/apps/host/src/gateway.ts/01M4Z2BCKRNHVMYEMC0KH3Q6BN-a-hosted-channel-must-be-rea.md index 676b95f5..30353740 100644 --- a/.lane/memory/apps/host/src/gateway.ts/01M4Z2BCKRNHVMYEMC0KH3Q6BN-a-hosted-channel-must-be-rea.md +++ b/.lane/memory/apps/host/src/gateway.ts/01M4Z2BCKRNHVMYEMC0KH3Q6BN-a-hosted-channel-must-be-rea.md @@ -4,9 +4,9 @@ anchor: function handle created: 2026-10-15T06:00:20Z norm: '1' sig: e597b5fbc8e664ce -body_hash: ef8527c95dcbf51a -raw_hash: 3d4e766de43b3348 -vouched: 2026-10-19T18:26:02Z +body_hash: 67b82b247b0adc3f +raw_hash: f2b48d8004d3b7cb +vouched: 2026-10-19T20:55:06Z lines: 281-561 --- diff --git a/.lane/memory/apps/host/src/gateway.ts/01M5APK9YCQH467YNMKAC8BT5B-a-move-to-a-cloud-workspace.md b/.lane/memory/apps/host/src/gateway.ts/01M5APK9YCQH467YNMKAC8BT5B-a-move-to-a-cloud-workspace.md index 8660c874..a3ad3764 100644 --- a/.lane/memory/apps/host/src/gateway.ts/01M5APK9YCQH467YNMKAC8BT5B-a-move-to-a-cloud-workspace.md +++ b/.lane/memory/apps/host/src/gateway.ts/01M5APK9YCQH467YNMKAC8BT5B-a-move-to-a-cloud-workspace.md @@ -4,8 +4,9 @@ anchor: function handle created: 2026-10-19T18:25:49Z norm: '1' sig: e597b5fbc8e664ce -body_hash: ef8527c95dcbf51a -raw_hash: 3d4e766de43b3348 +body_hash: 67b82b247b0adc3f +raw_hash: f2b48d8004d3b7cb +vouched: 2026-10-19T20:55:06Z lines: 379-692 --- diff --git a/.lane/memory/apps/host/src/gateway.ts/01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md b/.lane/memory/apps/host/src/gateway.ts/01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md new file mode 100644 index 00000000..96abe504 --- /dev/null +++ b/.lane/memory/apps/host/src/gateway.ts/01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md @@ -0,0 +1,8 @@ +--- +id: 01M5AZ4CX0CX0QP8TMTSE6Y5B8 +anchor: function authored +created: 2026-10-19T20:54:58Z +norm: '1' +--- + +stop and kill always get the verified author, even when an older client sent none, or the owner's own stop is refused diff --git a/.lane/memory/apps/host/src/manage.ts/01M53BRYK06ZK7SQGN565PYN6R-a-frozen-compute-channel-run.md b/.lane/memory/apps/host/src/manage.ts/01M53BRYK06ZK7SQGN565PYN6R-a-frozen-compute-channel-run.md index 0ef123fd..43cfae13 100644 --- a/.lane/memory/apps/host/src/manage.ts/01M53BRYK06ZK7SQGN565PYN6R-a-frozen-compute-channel-run.md +++ b/.lane/memory/apps/host/src/manage.ts/01M53BRYK06ZK7SQGN565PYN6R-a-frozen-compute-channel-run.md @@ -4,8 +4,9 @@ anchor: function kill created: 2026-10-16T22:01:59Z norm: '1' sig: 513ab7051807bd68 -body_hash: c5c00bce00544277 -raw_hash: 8b791f6674195e35 +body_hash: 679a9e727fe00a07 +raw_hash: 0c7e17ee0991afa6 +vouched: 2026-10-19T20:55:06Z lines: 116-143 --- diff --git a/.lane/memory/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md b/.lane/memory/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md new file mode 100644 index 00000000..b3cbe05e --- /dev/null +++ b/.lane/memory/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md @@ -0,0 +1,8 @@ +--- +id: 01M5AZ4CKBK8Q49Z6TCNZGMVDS +anchor: class Channel +created: 2026-10-19T20:54:58Z +norm: '1' +--- + +stop and kill go through #mayInvoke like ask; whoever can't start a run can't end one diff --git a/apps/app/src/composer.tsx b/apps/app/src/composer.tsx index b8b77d19..0a2b9444 100644 --- a/apps/app/src/composer.tsx +++ b/apps/app/src/composer.tsx @@ -22,9 +22,10 @@ const MODES = [ { id: "chat", name: "Chat", placeholder: "Mention @ace to ask the agent" }, ACE_MODE, ]; -// Teammates keep the Ace mode and their drafts while the owner has turned invocation off. -const BLOCKED_MODES = [{ id: "chat", name: "Chat", placeholder: "Message the channel" }, ACE_MODE]; +// A teammate the owner hasn't let invoke sees no @ace; the stored mode brings it back with access. +const BLOCKED_MODES = [{ id: "chat", name: "Chat", placeholder: "Message the channel" }]; const MENTIONS = [{ name: "ace", avatar: aceAvatar }]; +const NO_MENTIONS: typeof MENTIONS = []; export const EFFORTS: Record = { off: "Off", minimal: "Minimal", @@ -60,17 +61,6 @@ type Props = { accessory?: ReactNode; }; -/** The channel refuses these too; holding them here keeps the draft instead of failing a send. */ -function useInvocation(shared: boolean | undefined, owner: boolean, mode: string) { - const [mentioned, setMentioned] = useState(false); - const blocked = shared === false && !owner; - return { - blocked, - refused: blocked && (mode === "ace" || mentioned), - onText: (text: string) => setMentioned(ACE.test(text)), - }; -} - /** Below the composer: its attachment tray rises over the space above it and takes clicks there. */ export function Notice({ children, action }: { children: ReactNode; action?: ReactNode }) { return ( @@ -84,22 +74,6 @@ export function Notice({ children, action }: { children: ReactNode; action?: Rea ); } -/** Why a teammate's invoking draft is held while the owner has turned invocation off. */ -function Refusal({ mode, onChat }: { mode: string; onChat: () => void }) { - return ( - - {mode === "ace" ? "Switch to Chat" : "Remove @ace"} - - } - > - The owner has turned off teammate agent invocation.{" "} - {mode === "ace" ? "Switch to Chat" : "Remove @ace"} to send this as a message. - - ); -} - /** A failed admission keeps the draft and attachments available for retry. */ export function Composer( { @@ -125,7 +99,10 @@ export function Composer( const [attached, setAttached] = useState([]); // Kept beside the channel's draft so a deliberate mode and an unsent model pick survive relaunch. const scope = `/channels/${channel.id}`; - const [mode, changeMode] = useLocalStorage(`ace:mode:${scope}`, "ace"); + const [stored, changeMode] = useLocalStorage(`ace:mode:${scope}`, "ace"); + // The channel refuses a blocked teammate's ask, stop, and kill too. + const blocked = shared === false && channel.owner !== user; + const mode = blocked ? "chat" : stored; const [models, setModels] = useState(); const [modelError, setModelError] = useState(); const status = useSyncExternalStore(host.subscribe, () => host.status); @@ -135,6 +112,13 @@ export function Composer( composer.current?.set(ACE.test(draft) ? draft : `@ace ${draft}`); onDraftLoaded(); }, [draft, onDraftLoaded]); + // A saved Ace draft keeps its words as a message; its mention returns with access, from the mode. + useEffect(() => { + if (!blocked) return; + const doc = composer.current?.get(); + const text = doc ? serialize(doc) : ""; + if (ACE.test(text)) composer.current?.set(text.replace(/(^|\s)@ace\b\s*/gi, "$1").trim()); + }, [blocked]); // Each withdrawn message returns once, ahead of whatever the user has typed since. const restored = useRef(new Set()); useEffect(() => { @@ -147,7 +131,7 @@ export function Composer( // One leading mention invokes the whole draft; an empty Ace-mode composer holds only that. const text = [...mine.map((message) => message.text), doc ? serialize(doc) : ""] .map((part) => part.replace(LEADING, "").trim()).filter(Boolean).join("\n\n"); - composer.current?.set(`@ace ${text}`); + composer.current?.set(blocked ? text : `@ace ${text}`); const images = mine.flatMap((message) => message.images || []); const files = mine.flatMap((message) => message.files || []); if (images.length || files.length) { @@ -171,7 +155,7 @@ export function Composer( : `Stopped before ${mine.length} of your queued messages ran`, { description: `${mine.length === 1 ? "It's" : "They're"} back in the composer.` }, ); - }, [returned, user]); + }, [returned, user, blocked]); // An offline channel can't answer; the conversation already says so, so don't blame providers. const offline = channel.state === "offline"; useEffect(() => { @@ -223,27 +207,15 @@ export function Composer( } // Automatic stays offered so a chat whose model lost its key can hand the choice back. choices.unshift({ id: "auto", name: "Automatic", vendor: "" }); - const { blocked, refused, onText } = useInvocation(shared, channel.owner === user, mode); - // A mention invokes in Chat mode too, so sending as a message drops it from the draft. - const toChat = () => { - changeMode("chat"); - const doc = composer.current?.get(); - const text = doc ? serialize(doc) : ""; - if (ACE.test(text)) composer.current?.set(text.replace(/(^|\s)@ace\b\s*/gi, "$1").trim()); - }; // Formatting tools crowd a phone's composer; they stay one tap away. const phone = useMedia("(width < 40rem)"); async function send(text: string, mode: string, attached: Attachment[]) { if (sending.current) return; - const invoke = mode === "ace" || ACE.test(text); + // A blocked teammate's typed "@ace" is just text. + const invoke = !blocked && (mode === "ace" || ACE.test(text)); const body = text.trim(); if (!body && !attached.length) return; - if (invoke && blocked) { - return void toast.error("Could not invoke agent", { - description: "The owner has turned off teammate agent invocation.", - }); - } // The channel would refuse it for want of a key; setup keeps the draft for sending after. if (mode === "ace" && models?.length === 0 && !modelError && onProviders) { return onProviders(); @@ -301,8 +273,7 @@ export function Composer( modes={blocked ? BLOCKED_MODES : MODES} mode={mode} onModeChange={changeMode} - onTextChange={onText} - mentions={MENTIONS} + mentions={blocked ? NO_MENTIONS : MENTIONS} models={choices} model={model} onModelChange={(value) => changePick({ model: value })} @@ -314,25 +285,23 @@ export function Composer( busy={busy} submitBusy={pending} submitLabel={waiting} - canStop={busy} - onStop={() => void host.channel(channel.id, { op: "stop", chat: id })} - canSend={ready && status === "open" && !pending && !refused} + canStop={busy && !blocked} + onStop={() => void host.channel(channel.id, { op: "stop", chat: id, author: user })} + canSend={ready && status === "open" && !pending} clearOnSend={false} onSend={({ doc, mode, attachments }) => void send(serialize(doc), mode, attachments)} /> - {refused - ? - : mode === "ace" && !offline && models?.length === 0 && ( - - {modelError ? "Provider settings" : "Set up a provider"} - - )} - > - {modelError || "Add a provider to use Ace. You can still send messages in Chat mode."} - - )} + {mode === "ace" && !offline && models?.length === 0 && ( + + {modelError ? "Provider settings" : "Set up a provider"} + + )} + > + {modelError || "Add a provider to use Ace. You can still send messages in Chat mode."} + + )} ); } diff --git a/apps/host/src/cli.ts b/apps/host/src/cli.ts index 6068f2c2..c233f6fd 100755 --- a/apps/host/src/cli.ts +++ b/apps/host/src/cli.ts @@ -457,7 +457,7 @@ async function main() { return console.log((await session.request<{ chat: number }>(body)).chat); } case "stop": - return void (await session.request({ op: "stop", chat: chat() })); + return void (await session.request({ op: "stop", chat: chat(), author: catalog.user })); } } finally { session.close(); diff --git a/apps/host/src/gateway.ts b/apps/host/src/gateway.ts index f68e9a15..2dece82a 100644 --- a/apps/host/src/gateway.ts +++ b/apps/host/src/gateway.ts @@ -376,6 +376,16 @@ const localOps = new Set([ "terminal-close", ]); +type ChannelRequest = Extract["request"]; + +/** The verified person replaces any claimed author. Older clients send stop and kill without one. */ +function authored(request: ChannelRequest, user: string): ChannelRequest { + if (request.op === "stop" || request.op === "kill" || "author" in request) { + return { ...request, author: user }; + } + return request; +} + async function handle( socket: ServerWebSocket, request: HostRequest, @@ -649,9 +659,7 @@ async function handle( if (client.user !== catalog.user) throw new Error("Only the channel's owner can kill it"); terminals.closeChannel(request.channel); } - const forwarded = "author" in request.request - ? { ...request.request, author: client.user } - : request.request; + const forwarded = authored(request.request, client.user); const target = await connection(client, request.channel); return target.request(forwarded, watch, trace); } @@ -668,9 +676,7 @@ async function handle( if (request.request.op === "kill" && client.user !== hosted.owner) { throw new Error("Only the channel's owner can kill it"); } - const forwarded = "author" in request.request - ? { ...request.request, author: client.user } - : request.request; + const forwarded = authored(request.request, client.user); const target = await connection(client, request.channel, hosted.hosted); return target.request(forwarded, watch, trace); } diff --git a/apps/host/src/manage.ts b/apps/host/src/manage.ts index 223bd9cb..7e82667f 100644 --- a/apps/host/src/manage.ts +++ b/apps/host/src/manage.ts @@ -196,10 +196,11 @@ function seed(info: ChannelInfo, changes: Changes, lane: { name: string } | unde } export async function kill(id: string): Promise { - const { hosted, compute } = catalog.read(id); + // Only the owner reaches this, through archive, delete, or ace kill. + const { hosted, compute, owner } = catalog.read(id); if (hosted) { if (compute && await frozen(id)) return; - return request(id, { op: "kill" }); + return request(id, { op: "kill", author: owner }); } const connection = await Connection.running(id); if (!connection) return; @@ -207,7 +208,7 @@ export async function kill(id: string): Promise { try { await Promise.race([ (async () => { - await connection.request({ op: "kill" }); + await connection.request({ op: "kill", author: owner }); // The reply only confirms the abort; the worker closes sockets after storage and tools. await connection.closed; })(), diff --git a/packages/channel/src/channel.ts b/packages/channel/src/channel.ts index 3e8c6ae6..fe6aa1b9 100644 --- a/packages/channel/src/channel.ts +++ b/packages/channel/src/channel.ts @@ -379,9 +379,15 @@ export class Channel { const entry = request.entry as EntryId; return edit(this.#harness, id, entry, request.author, request.text, context); } - case "stop": + case "stop": { + this.#author(request.author); + // Whoever can't start a run here can't end the owner's either. + await this.#mayInvoke(request.author); return (await this.#conversation(request.chat)).abort(context); + } case "kill": + this.#author(request.author); + await this.#mayInvoke(request.author); return this.kill(); case "share": return this.#share(request); diff --git a/packages/channel/src/protocol.ts b/packages/channel/src/protocol.ts index be8dc36c..0d68f7ad 100644 --- a/packages/channel/src/protocol.ts +++ b/packages/channel/src/protocol.ts @@ -226,8 +226,9 @@ export type Request = | { op: "delete"; chat?: ChatId; author: string; entry: EntryId } /** Replace the text of the author's own human message, for people and later model context. */ | { op: "edit"; chat?: ChatId; author: string; entry: EntryId; text: string } - | { op: "stop"; chat?: ChatId } - | { op: "kill" } + /** Stop and kill are admitted like `ask`. Older clients omit `author`; gateways stamp it anyway. */ + | { op: "stop"; chat?: ChatId; author: string } + | { op: "kill"; author: string } | { op: "share"; author: string; shared: boolean } | { op: "desktop"; author: string; enabled: boolean } | { op: "rename"; author: string; name: string } From c695a30b10413ca99bc5eb94e6d42aacb7f26c96 Mon Sep 17 00:00:00 2001 From: iamnbutler Date: Mon, 19 Oct 2026 16:55:16 -0400 Subject: [PATCH 2/3] lane: sync agent-access memory --- ...01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md | 4 ++++ ...01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md | 4 ++++ 2 files changed, 8 insertions(+) rename .lane/{memory => attic}/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md (67%) diff --git a/.lane/memory/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md b/.lane/attic/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md similarity index 67% rename from .lane/memory/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md rename to .lane/attic/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md index b3cbe05e..0c868f96 100644 --- a/.lane/memory/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md +++ b/.lane/attic/packages/channel/src/channel.ts/01M5AZ4CKBK8Q49Z6TCNZGMVDS-stop-and-kill-go-through-may.md @@ -3,6 +3,10 @@ id: 01M5AZ4CKBK8Q49Z6TCNZGMVDS anchor: class Channel created: 2026-10-19T20:54:58Z norm: '1' +sig: c905677fa4be33c1 +body_hash: 69f52b41268c803d +raw_hash: eb621c3d81f78e67 +lines: 151-985 --- stop and kill go through #mayInvoke like ask; whoever can't start a run can't end one diff --git a/.lane/memory/apps/host/src/gateway.ts/01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md b/.lane/memory/apps/host/src/gateway.ts/01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md index 96abe504..77c71924 100644 --- a/.lane/memory/apps/host/src/gateway.ts/01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md +++ b/.lane/memory/apps/host/src/gateway.ts/01M5AZ4CX0CX0QP8TMTSE6Y5B8-stop-and-kill-always-get-the.md @@ -3,6 +3,10 @@ id: 01M5AZ4CX0CX0QP8TMTSE6Y5B8 anchor: function authored created: 2026-10-19T20:54:58Z norm: '1' +sig: 57e007663f34cc44 +body_hash: 642651b36a1ec33e +raw_hash: 3eb9f837a1e9ecef +lines: 382-387 --- stop and kill always get the verified author, even when an older client sent none, or the owner's own stop is refused From dfada0736faf86d653bbd87bdb1f5cbd0eb345d9 Mon Sep 17 00:00:00 2001 From: iamnbutler Date: Mon, 19 Oct 2026 16:57:54 -0400 Subject: [PATCH 3/3] chore: confirm notes after rebasing onto provider setup --- ...M4YQG7BVWEFZPD56A2BA0VE9-mode-ace-mode-channels-id-an.md | 6 +++--- ...M4ZSEZBJJ3AMEBTR7SH36FW4-models-are-read-only-while-t.md | 6 +++--- ...1M4ZYQVGB6C87WBEV12WPQ8PF-a-withdrawn-message-returns.md | 6 +++--- ...M5AYX7F0E4JW72ECJTK6SNZK-every-provider-link-opens-se.md | 5 +++-- ...M5AZ0WJH0JC0ANYXJZEBSZFF-section-buttons-focus-themse.md | 5 +++-- ...M4XQKND0900E94CG3BXBEJP7-a-run-s-end-is-read-from-the.md | 6 +++--- ...1M4YFFTK7TWGKENJAD1W10HJJ-the-desktop-default-changes.md | 6 +++--- ...1M4YPJQB6KKEW1YTRD08YCYJY-only-gateways-admit-clients.md | 6 +++--- ...M4ZH31DXZK0Y57C97DP84ZKX-handoffs-learns-queued-hando.md | 6 +++--- ...M53CAGW2RVRKCYF5BCJRTZX2-a-fork-s-starting-lane-is-re.md | 6 +++--- 10 files changed, 30 insertions(+), 28 deletions(-) diff --git a/.lane/memory/apps/app/src/composer.tsx/01M4YQG7BVWEFZPD56A2BA0VE9-mode-ace-mode-channels-id-an.md b/.lane/memory/apps/app/src/composer.tsx/01M4YQG7BVWEFZPD56A2BA0VE9-mode-ace-mode-channels-id-an.md index fe77e1ab..10534840 100644 --- a/.lane/memory/apps/app/src/composer.tsx/01M4YQG7BVWEFZPD56A2BA0VE9-mode-ace-mode-channels-id-an.md +++ b/.lane/memory/apps/app/src/composer.tsx/01M4YQG7BVWEFZPD56A2BA0VE9-mode-ace-mode-channels-id-an.md @@ -4,9 +4,9 @@ anchor: function Composer created: 2026-10-15T02:50:44Z norm: '1' sig: 6e0e6c5c8afbd01a -body_hash: c26ff8b1e57b818f -raw_hash: 6f6bb4ad6bd95eb3 -vouched: 2026-10-19T20:51:12Z +body_hash: 5f7b73ecdc92491d +raw_hash: 92a0017bb10f2de6 +vouched: 2026-10-19T20:57:54Z lines: 99-282 --- diff --git a/.lane/memory/apps/app/src/composer.tsx/01M4ZSEZBJJ3AMEBTR7SH36FW4-models-are-read-only-while-t.md b/.lane/memory/apps/app/src/composer.tsx/01M4ZSEZBJJ3AMEBTR7SH36FW4-models-are-read-only-while-t.md index 3b1627dc..8c228415 100644 --- a/.lane/memory/apps/app/src/composer.tsx/01M4ZSEZBJJ3AMEBTR7SH36FW4-models-are-read-only-while-t.md +++ b/.lane/memory/apps/app/src/composer.tsx/01M4ZSEZBJJ3AMEBTR7SH36FW4-models-are-read-only-while-t.md @@ -4,9 +4,9 @@ anchor: function Composer created: 2026-10-15T12:44:15Z norm: '1' sig: 6e0e6c5c8afbd01a -body_hash: c26ff8b1e57b818f -raw_hash: 6f6bb4ad6bd95eb3 -vouched: 2026-10-19T20:51:12Z +body_hash: 5f7b73ecdc92491d +raw_hash: 92a0017bb10f2de6 +vouched: 2026-10-19T20:57:54Z lines: 101-290 --- diff --git a/.lane/memory/apps/app/src/composer.tsx/01M4ZYQVGB6C87WBEV12WPQ8PF-a-withdrawn-message-returns.md b/.lane/memory/apps/app/src/composer.tsx/01M4ZYQVGB6C87WBEV12WPQ8PF-a-withdrawn-message-returns.md index 7583d282..1cbf792e 100644 --- a/.lane/memory/apps/app/src/composer.tsx/01M4ZYQVGB6C87WBEV12WPQ8PF-a-withdrawn-message-returns.md +++ b/.lane/memory/apps/app/src/composer.tsx/01M4ZYQVGB6C87WBEV12WPQ8PF-a-withdrawn-message-returns.md @@ -4,9 +4,9 @@ anchor: function Composer created: 2026-10-15T14:16:28Z norm: '1' sig: 6e0e6c5c8afbd01a -body_hash: c26ff8b1e57b818f -raw_hash: 6f6bb4ad6bd95eb3 -vouched: 2026-10-19T20:51:12Z +body_hash: 5f7b73ecdc92491d +raw_hash: 92a0017bb10f2de6 +vouched: 2026-10-19T20:57:54Z lines: 104-326 --- diff --git a/.lane/memory/apps/app/src/settings.tsx/01M5AYX7F0E4JW72ECJTK6SNZK-every-provider-link-opens-se.md b/.lane/memory/apps/app/src/settings.tsx/01M5AYX7F0E4JW72ECJTK6SNZK-every-provider-link-opens-se.md index a07bbd69..93986cf1 100644 --- a/.lane/memory/apps/app/src/settings.tsx/01M5AYX7F0E4JW72ECJTK6SNZK-every-provider-link-opens-se.md +++ b/.lane/memory/apps/app/src/settings.tsx/01M5AYX7F0E4JW72ECJTK6SNZK-every-provider-link-opens-se.md @@ -4,8 +4,9 @@ anchor: function Settings created: 2026-10-19T20:51:03Z norm: '1' sig: 8d6f8142ef1a23f2 -body_hash: 5ebe48e26d37220b -raw_hash: a4c1b368058b0077 +body_hash: ab1332a896bdd893 +raw_hash: b048e59ec08c6130 +vouched: 2026-10-19T20:57:54Z lines: 325-537 --- diff --git a/.lane/memory/apps/app/src/settings.tsx/01M5AZ0WJH0JC0ANYXJZEBSZFF-section-buttons-focus-themse.md b/.lane/memory/apps/app/src/settings.tsx/01M5AZ0WJH0JC0ANYXJZEBSZFF-section-buttons-focus-themse.md index 8b77846d..9e0a0458 100644 --- a/.lane/memory/apps/app/src/settings.tsx/01M5AZ0WJH0JC0ANYXJZEBSZFF-section-buttons-focus-themse.md +++ b/.lane/memory/apps/app/src/settings.tsx/01M5AZ0WJH0JC0ANYXJZEBSZFF-section-buttons-focus-themse.md @@ -4,8 +4,9 @@ anchor: function Settings created: 2026-10-19T20:53:03Z norm: '1' sig: 8d6f8142ef1a23f2 -body_hash: 632e6f14cd21b9a8 -raw_hash: a17e7f834c859315 +body_hash: ab1332a896bdd893 +raw_hash: b048e59ec08c6130 +vouched: 2026-10-19T20:57:54Z lines: 325-545 --- diff --git a/.lane/memory/packages/channel/src/channel.ts/01M4XQKND0900E94CG3BXBEJP7-a-run-s-end-is-read-from-the.md b/.lane/memory/packages/channel/src/channel.ts/01M4XQKND0900E94CG3BXBEJP7-a-run-s-end-is-read-from-the.md index d1705063..10c6d4dd 100644 --- a/.lane/memory/packages/channel/src/channel.ts/01M4XQKND0900E94CG3BXBEJP7-a-run-s-end-is-read-from-the.md +++ b/.lane/memory/packages/channel/src/channel.ts/01M4XQKND0900E94CG3BXBEJP7-a-run-s-end-is-read-from-the.md @@ -4,9 +4,9 @@ anchor: class Channel created: 2026-10-14T17:33:22Z norm: '1' sig: c905677fa4be33c1 -body_hash: 5a0314d40ff6a649 -raw_hash: 6384441db3491561 -vouched: 2026-10-19T20:53:00Z +body_hash: b94131a282fede50 +raw_hash: 0632800a47dcc747 +vouched: 2026-10-19T20:57:54Z lines: 114-792 --- diff --git a/.lane/memory/packages/channel/src/channel.ts/01M4YFFTK7TWGKENJAD1W10HJJ-the-desktop-default-changes.md b/.lane/memory/packages/channel/src/channel.ts/01M4YFFTK7TWGKENJAD1W10HJJ-the-desktop-default-changes.md index a83541e9..51d5213e 100644 --- a/.lane/memory/packages/channel/src/channel.ts/01M4YFFTK7TWGKENJAD1W10HJJ-the-desktop-default-changes.md +++ b/.lane/memory/packages/channel/src/channel.ts/01M4YFFTK7TWGKENJAD1W10HJJ-the-desktop-default-changes.md @@ -4,9 +4,9 @@ anchor: class Channel created: 2026-10-15T00:30:42Z norm: '1' sig: c905677fa4be33c1 -body_hash: 5a0314d40ff6a649 -raw_hash: 6384441db3491561 -vouched: 2026-10-19T20:53:00Z +body_hash: b94131a282fede50 +raw_hash: 0632800a47dcc747 +vouched: 2026-10-19T20:57:54Z lines: 114-792 --- diff --git a/.lane/memory/packages/channel/src/channel.ts/01M4YPJQB6KKEW1YTRD08YCYJY-only-gateways-admit-clients.md b/.lane/memory/packages/channel/src/channel.ts/01M4YPJQB6KKEW1YTRD08YCYJY-only-gateways-admit-clients.md index cd161225..f6cd0b81 100644 --- a/.lane/memory/packages/channel/src/channel.ts/01M4YPJQB6KKEW1YTRD08YCYJY-only-gateways-admit-clients.md +++ b/.lane/memory/packages/channel/src/channel.ts/01M4YPJQB6KKEW1YTRD08YCYJY-only-gateways-admit-clients.md @@ -4,9 +4,9 @@ anchor: class Channel created: 2026-10-15T02:34:37Z norm: '1' sig: c905677fa4be33c1 -body_hash: 5a0314d40ff6a649 -raw_hash: 6384441db3491561 -vouched: 2026-10-19T20:53:00Z +body_hash: b94131a282fede50 +raw_hash: 0632800a47dcc747 +vouched: 2026-10-19T20:57:54Z lines: 114-794 --- diff --git a/.lane/memory/packages/channel/src/channel.ts/01M4ZH31DXZK0Y57C97DP84ZKX-handoffs-learns-queued-hando.md b/.lane/memory/packages/channel/src/channel.ts/01M4ZH31DXZK0Y57C97DP84ZKX-handoffs-learns-queued-hando.md index ae296453..e5fe9e5a 100644 --- a/.lane/memory/packages/channel/src/channel.ts/01M4ZH31DXZK0Y57C97DP84ZKX-handoffs-learns-queued-hando.md +++ b/.lane/memory/packages/channel/src/channel.ts/01M4ZH31DXZK0Y57C97DP84ZKX-handoffs-learns-queued-hando.md @@ -4,9 +4,9 @@ anchor: class Channel created: 2026-10-15T10:17:55Z norm: '1' sig: c905677fa4be33c1 -body_hash: 5a0314d40ff6a649 -raw_hash: 6384441db3491561 -vouched: 2026-10-19T20:53:00Z +body_hash: b94131a282fede50 +raw_hash: 0632800a47dcc747 +vouched: 2026-10-19T20:57:54Z lines: 121-817 --- diff --git a/.lane/memory/packages/channel/src/channel.ts/01M53CAGW2RVRKCYF5BCJRTZX2-a-fork-s-starting-lane-is-re.md b/.lane/memory/packages/channel/src/channel.ts/01M53CAGW2RVRKCYF5BCJRTZX2-a-fork-s-starting-lane-is-re.md index 14ad1653..e3aea1df 100644 --- a/.lane/memory/packages/channel/src/channel.ts/01M53CAGW2RVRKCYF5BCJRTZX2-a-fork-s-starting-lane-is-re.md +++ b/.lane/memory/packages/channel/src/channel.ts/01M53CAGW2RVRKCYF5BCJRTZX2-a-fork-s-starting-lane-is-re.md @@ -4,9 +4,9 @@ anchor: class Channel created: 2026-10-16T22:11:35Z norm: '1' sig: c905677fa4be33c1 -body_hash: 5a0314d40ff6a649 -raw_hash: 6384441db3491561 -vouched: 2026-10-19T20:53:00Z +body_hash: b94131a282fede50 +raw_hash: 0632800a47dcc747 +vouched: 2026-10-19T20:57:54Z lines: 127-873 ---