Skip to content

The Factory manager answers, stops, and is cleared rather than archived - #2608

Draft
ZeroPoint95 wants to merge 10 commits into
devfrom
zeropoint95/foreman-fixes
Draft

ZeroPoint95 wants to merge 10 commits into
devfrom
zeropoint95/foreman-fixes

Conversation

@ZeroPoint95

Copy link
Copy Markdown
Collaborator

The Factory manager answers questions, can be stopped, and is cleared instead of archived.

What changed

  • Stop is bounded. The app's agents.stop carries within (ms). A turn that hasn't let go 10 s later is abandoned and ends stopped by the person. A lent factory stage is only interrupted.
  • The manager gets its own folder. A manager working in the codeaf home is made again in <floor>/chats/foreman when the factory starts or its door opens. In the codeaf home every save swept the whole folder, so factory_floor never returned. The old conversation is stopped, archived and titled "Factory manager (earlier)".
  • A mark on disk says it's the factory's. factory-owner.json gets foreman: true, so the manager reads as factory_owned after a relaunch.
  • Clear. New factory.foreman_fresh {factory} (hello feature factory.foreman_fresh) starts the manager over. Its door now reopens a manager that was archived or closed.
  • The app hears replacements. New event factory.foreman_changed {factory, agent, replaced}.
  • One manager at a time. Opens take turns, and a replaced manager is put away after the new one answers.
  • factory_floor is bounded and knows more.
    • A read waits at most 20 s, an action at most 60 s, and a stop returns at once.
    • New repos ask.
    • shipped takes days (up to 90).
    • Every answer starts with the whole factory's counts.
  • Broader brief. The manager may answer from the app state sent with a message (afi-now, app-places) and from its other tools, not only factory_floor.
  • Docs: PROTOCOL.md, internal/manual/chat/factory.md, change entry.
  • Desktop side: Agent-Field/codeaf-desk#406.

How it was checked

  1. Ran the new tests by name; all pass: 11 in internal/session, 3 in internal/remote, 1 in internal/appwire, 9 in cmd/codeaf.
  2. TestABoundedStopAbandonsATurnThatWouldNotLetGo failed once on a rerun: the test read the journal before the abandon wrote its line. Fixed in the test; it passes 20 of 20 under -race.
  3. Manual gates pass: go generate ./internal/manual, the packed-manual test and the Manual tests.
  4. Full suite not run locally. Two cmd/codeaf tests fail on this machine on untouched dev too: TestL4HostedSurfaceQuit* and TestFactoryRetryActionsDoNotReportStopped.
  5. Not yet seen with a live model. A desktop build carrying this engine is being hand-tested now.

Checklist

  • A change entry
  • The manual knows about it
  • Only my own paths are staged

🤖 Generated with Claude Code

ZeroPoint95 and others added 10 commits November 11, 2026 23:54
The desktop app's Factory manager answered nothing, could not be stopped
and could be archived out of reach.

- Stop is bounded: the app's stop carries its bound over the wire
  (Interrupt's `within`) and the engine abandons a turn that has not let
  go ten seconds later (session.Agent.InterruptWithin). A lent factory
  stage is interrupted but never abandoned from the app.
- A foreman whose conversation works in the codeaf home is made again
  in <floor>/chats/foreman; the one it replaces is stopped and archived.
- factory_floor waits a bounded time on the factory and returns at once
  when the turn is stopped.
- factory.foreman_open is the person's own open and takes a closed or
  archived manager out of Closed. factory.foreman_fresh starts the
  manager over in a new conversation (the app's Clear).
- factory_floor: `repos` counts jobs by repository and state, `shipped`
  takes `days` and counts merged pull requests, and every table opens
  with the whole factory's counts. The brief no longer limits the
  manager to factory_floor.

The change entry still needs its pull request number.

Co-Authored-By: Claude <[email protected]>
The desktop app starts each message to the manager with the afi-now
block Afi is sent. The brief and factory_floor's description say what
it is, that "Waiting on you" there is the person, and to read the
factory for what it does not say.

Co-Authored-By: Claude <[email protected]>
An independent review found the first change fixed the manager only
when it was opened by its own button.

- The manager's conversation carries a mark beside its journal, so it is
  the factory's after a relaunch too, and an app that had read it as an
  ordinary chat is told when the mark is given.
- The factory puts its manager right as it starts: one in a refused
  folder is made again and the old one stopped and archived, so a tab
  the app brings back never writes to it as the manager.
- Opens are answered one at a time, the new manager is answered before
  the old one is put away, and the brief's policy read is bounded.
- A replaced manager is the person's own chat again, titled
  "Factory manager (earlier)".
- factory_floor says the factory's counts on what shipped and on an ask
  nothing answers. The docs say what the code does.
- The real agents are asserted to satisfy the bounded-stop interfaces.

Co-Authored-By: Claude <[email protected]>
- The start-time settle is a chore of the factory host, so it never
  writes the floor after a close has begun; putting the replaced
  conversation away stays off it.
- The store names the new manager before any mark is written, and a
  sweep at start retires a conversation a cut-short making left marked.
- A replaced manager's new name is written through its conversation, so
  it still reads "Factory manager (earlier)" when it is opened again.
- The brief and factory_floor name both blocks the app may put ahead of
  a message, afi-now and app-places.

Co-Authored-By: Claude <[email protected]>
A tab the app brought back went on showing the replaced manager with a
box to write in. The engine now sends factory.foreman_changed
{factory, agent, replaced} on every replacement so a window swaps that
tab for the manager.

The replaced conversation is renamed in its journal without being
opened when nothing holds it (session.RetitleConversation): opening it
in the folder it was moved out of, to write one line, was the cost the
move exists to end.

Co-Authored-By: Claude <[email protected]>
…at once

The clock's abandon closes the turn's events before it writes its journal
line, so reading the journal the instant the events ended sometimes found
nothing. It failed about one run in three under -race; it now passes 20 of
20 there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Fable 5.2 <[email protected]>
PROTOCOL.md: both sides added a section after the agents table; both stay.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
The guard law (TestEveryGoroutineInTheGuardedTreeIsGuarded) refuses a bare
go statement here. A read that panics now answers nothing, and the bounded
wait returns an empty policy as it does for a slow read.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
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