Skip to content

fix(runtime): epic records carry sub-flow tasks and session ids; docs reconciled with the landed flow API - #83

Merged
futrime merged 4 commits into
feat/new-flow-apifrom
flow-api/u14-integration
Sep 25, 2026
Merged

futrime merged 4 commits into
feat/new-flow-apifrom
flow-api/u14-integration

Conversation

@futrime

@futrime futrime commented Sep 25, 2026

Copy link
Copy Markdown
Member

Unit 14 — final integration of the new flow API on feat/new-flow-api.

Epic records (engine ↔ runtime recorder)

  • Sub-flow calls carry their task. LiveCall gains task (and resumable); the engine's Call keeps the task it was called with, and the runner's recorder writes both into the called/began records. tree(epic) now reads back each call's task.
  • The resume journal carries real session ids. A session record is written once the CLI has named the session: at open where the id is known then (fakes), otherwise on the first spend the turn reports after naming (a _Naming sink, used only for an unnamed session's turns), with the turn's end as the fallback. One record per session, none for a session never named, and a failure to write it is logged rather than replacing the turn's outcome. FakeAgentDriver(names_late=True) stands in for a CLI that names late. The engine tells the recorder too (Recorder.named), so a late-named non-coganchor session goes into the epic by its id instead of "?".
  • The recorder holds only open sessions. Recorder.closed(session) is new, and the run's spend now comes from the engine's own reckoning (Recorder.began(spent), the totals its budget is held to). So nothing is lost from a turn that is still accounting after its session closed. Run.agents is now the agents behind the open sessions, and Recorder.finished() freezes the total once the run ends.
  • Epic.links(only) copied every session to link one, which made a run of n sessions O(n²). Found by the 10k-session test, which went from 4.6s to 1s.
  • Tests:
    • A 10k-session loop on the fake kit, asserting that memory held by the recorder stays bounded and the usage totals are right.
    • Recorder-hears-everything (task, began, closed).
    • A late-named session journaled once, and journaled mid-turn.
    • Late-named fake sessions going into the epic by id.
    • The recorder's usage equals the engine's.
    • Sub-flow tasks in tree.
    • Session ids in resume.jsonl, via the stand-in claude.

Also fixed

  • Failure reports had lost the flow context the old runtime registered, although telemetry.SENT (shown when consent is asked) still promises it. The runner registers it again: the flows running, their depth and how long they have run, plus each role's CLI, model, effort, account by name, permission and skills. It never includes the task. Covered by tests/integration/runtime/test_reported.py.
  • coganchor/places.py, agents/pi.py and agents/config.py no longer point at flowing.checking/driving.

Left as is, on purpose

  • The coganchor markers Needs, Goal, Remote, Isolated and AgentDefaults are dead as flow API. They are still declared in specs/coganchor/agents.md and exported from hmz.coganchor.agents, so removing them is not clean without a spec change the flow rewrite does not force.
  • The TUI board: specs/tui.md still requires it ("MUST draw the board a flow and a person share…", key d). The code path is therefore kept even though a flow-API run never has one. The docs say so.
  • Epic._sessions still keeps one small (backend, id) pair per session so that logs written late get linked when the run ends.

Docs

  • CLI:
    • The real error lines, with argparse's usage line only for a line it cannot read.
    • Every environment is probed first.
    • Exit 0 for a run its budget stopped.
    • --resume, resume.jsonl and picked_up.
  • SDK: Hmz.read/runner/run, Refused, fakes, and the whole of Run.
  • Tracing records.
  • The daemon demo and run.tape now read resume.jsonl, and tapes/stage.py is ported to today's Epic. GIFs were not re-rendered.
  • HmzSurfaces uses the real SDK surface and gen-plan params.
  • chat's roles, workspace and online=ALL.
  • The flow catalogue now matches feat(flows)!: move the small flows and aot to the new flow API flowverse#34–fix(agents): a turn that failed closes on a failed rather than on nothing #39:
    • the role is orchestrator;
    • params and defaults;
    • BudgetExceeded and "three failures in a row" endings;
    • the rlcr quiz runs only when somebody is there;
    • humanize1 has no default flow;
    • the lane flows' scratch storage and shared lock;
    • new pages for aot, the agent-cleanup pair and recursive_lean_prover.
  • TUI reference and user guide:
    • auto roles are not listed;
    • env rows are typed as -e specs;
    • the outworlder is answered at the prompt, and /afk makes it away;
    • a third ctrl+c calls Run.close();
    • /resume is described as implemented;
    • no board for a flow-API run.
  • Imports of nonexistent modules (hmz.prices, hmz.providers, hmz.telemetry) are fixed.
  • pnpm build and pnpm check:anchors pass.

Specs (only lines that conflicted)

  • runtime/SPEC.md: the Recorder's began/named/closed/finished methods; a called flow's record says its task; the run holds no session past its close.
  • runtime/flowing.md: the LiveCall fields, the Recorder protocol, and when a session journal record is written.
  • runtime/doing.md: Run.agents means open sessions.

Verification

  • uv run pre-commit run --all-files: all hooks pass.
  • uv run pytest (all tiers, system tier without --run-agents): 4158 passed, 110 skipped.
  • Docs: pnpm install --frozen-lockfile && pnpm build && pnpm check:anchors pass.
  • The testing-flows page's test examples were extracted and run: 7 pass.
  • E2E, with the stand-in claude on PATH and a flow that calls a subflow:
    • hmz exec -f demo -a worker=claude/claude-haiku-4-5:high -b cost=1 "…": the epic's called record carries the subflow's task, and both sessions are recorded by id.
    • The resumable demo:counts was stopped by -b output_tokens=4 (exit 0, hmz exec: stopped -- …). The journal holds session records with the CLI's ids, and state is {done: 2}.
    • --resume picked it up (picked_up recorded) and finished it with {done: 3}.

🤖 Generated with Claude Code

futrime and others added 4 commits September 25, 2026 13:13
…hold no closed session

A flow a run called was written into the epic with no task, since the engine told its
recorder of a call without one; LiveCall now carries the task (and whether the flow is
resumable), and the runner's recorder writes both into the call's record.

A resumable run's journal wrote a session's id as it opened, which for every real CLI is
before it has named one, so every record said null. The engine now writes the record once the
CLI has named the session: as it opens where the id is known then, else at the end of the first
turn that names it -- still one record per session, none for a session never named. The fake
kit's FakeAgentDriver(names_late=True) stands in for a CLI that names a session late.

The runner's recorder kept every session handle the run opened, to add up what they spent. The
engine now tells a recorder when a session closes (Recorder.closed), and the recorder folds
what it spent into a running total and lets go of it, holding only open sessions.

Epic.links(only) copied every session the run had opened to link one, which made a run of n
sessions O(n^2); it looks the one up.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
places.py, agents/pi.py and agents/config.py named hmz.runtime.flowing.checking and
.driving, which went with the old flow API.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…urn, say what ran

Review fixes to the previous commit:

- The recorder read a run's spend by summing its sessions, so it froze a session's
  spend as it closed and lost what a turn still accounting after that added. The
  engine now hands a recorder its own reckoning of the run (`Recorder.began`) -- the
  same totals its budget is held to -- and the recorder keeps only the sessions still
  open, for `Run.close` to interrupt. `Run.agents` is now the agents behind the open
  sessions, so it no longer grows by one per session either.
- A session named by its CLI as a long first turn went was journaled only when that
  turn ended, which a run killed mid-turn never reached. The first spend the turn
  reports after the CLI named it now writes it down; the turn's end remains the
  fallback, and a failure to write it is logged rather than replacing the turn's
  outcome.
- A driver with no coganchor agent behind it that names its sessions late was written
  into the epic as session "?". The engine now tells a recorder when such a session
  is named (`Recorder.named`), and the epic and the journal say the same id.
- A report of humanize's own failure had lost the `flow` context the old runtime
  registered, though `telemetry.SENT` still promises it: the runner registers it
  again, off the running tree and the drivers of the runs going now -- flows, depth,
  how long, and each role's CLI, model, effort, account, permission and skills, never
  a task.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- CLI: the real `hmz exec: error:` lines (argparse's usage line first only for a line
  it cannot read), every env probed before the flow, exit 0 for a run its budget
  stopped, `--resume` and `resume.jsonl`/`picked_up`.
- SDK: `Hmz.read/runner/run` as they are, `Refused` and `fakes`, and the whole of
  `Run`; epics' `state` and `picks_up`. `HmzSurfaces` says the same, and its params
  demo is `humanize1:gen-plan`'s real fields.
- Tracing: the epic's `began`/`called`/`usage` records and `resume.jsonl`; the daemon
  demo and the run tape read `resume.jsonl` rather than `state.json`, and the tape's
  stage writes its invented runs with today's `Epic` and journal (GIFs not
  re-rendered).
- Flows, against humanfia/flowverse#34-#39: `orchestrator` (was `orchestrateor`),
  params and defaults, what ends each loop (`BudgetExceeded`, three failures in a
  row), the rlcr quiz only when somebody is there, humanize1 having no default flow,
  the lane flows' scratch storage and shared source lock, and pages for aot, the
  agent-cleanup pair and recursive_lean_prover, which the catalogue lacked.
- chat's roles and workspace as declared; sessions close as soon as nothing holds
  them; the architecture page without the deleted legacy modules.
- TUI reference and user guide: setting a flow up by role with auto roles unlisted,
  env roles typed as `-e` spells them, the outworlder at the prompt and `/afk`,
  ctrl+c's third press, `/resume` as implemented, and the board as a flow-API run
  has none.
- Imports that named modules which do not exist (`hmz.prices`, `hmz.providers`,
  `hmz.telemetry`).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@futrime
futrime merged commit 88281f8 into feat/new-flow-api Sep 25, 2026
2 of 3 checks passed
@futrime
futrime deleted the flow-api/u14-integration branch September 25, 2026 13:48
futrime added a commit that referenced this pull request Sep 25, 2026
#83 grew the Recorder protocol by three methods and called them
unconditionally, so a recorder written against the first three --
flowverse's recursive_lean_prover tests have one -- raised
AttributeError at the start of every run. A recorder missing any of the
three is now completed with no-ops once per run; one answering all six
is called directly, as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
futrime pushed a commit that referenced this pull request Sep 25, 2026
fix(runtime): epic records carry sub-flow tasks and session ids; docs reconciled with the landed flow API
futrime pushed a commit that referenced this pull request Sep 25, 2026
#83 grew the Recorder protocol by three methods and called them
unconditionally, so a recorder written against the first three --
flowverse's recursive_lean_prover tests have one -- raised
AttributeError at the start of every run. A recorder missing any of the
three is now completed with no-ops once per run; one answering all six
is called directly, as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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