fix(runtime): epic records carry sub-flow tasks and session ids; docs reconciled with the landed flow API - #83
Merged
Conversation
…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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Unit 14 — final integration of the new flow API on
feat/new-flow-api.Epic records (engine ↔ runtime recorder)
LiveCallgainstask(andresumable); the engine'sCallkeeps the task it was called with, and the runner's recorder writes both into thecalled/beganrecords.tree(epic)now reads back each call's task.sessionrecord 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_Namingsink, 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"?".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.agentsis now the agents behind the open sessions, andRecorder.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.tree.resume.jsonl, via the stand-inclaude.Also fixed
flowcontext the old runtime registered, althoughtelemetry.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 bytests/integration/runtime/test_reported.py.coganchor/places.py,agents/pi.pyandagents/config.pyno longer point atflowing.checking/driving.Left as is, on purpose
Needs,Goal,Remote,IsolatedandAgentDefaultsare dead as flow API. They are still declared inspecs/coganchor/agents.mdand exported fromhmz.coganchor.agents, so removing them is not clean without a spec change the flow rewrite does not force.specs/tui.mdstill requires it ("MUST draw the board a flow and a person share…", keyd). The code path is therefore kept even though a flow-API run never has one. The docs say so.Epic._sessionsstill keeps one small(backend, id)pair per session so that logs written late get linked when the run ends.Docs
--resume,resume.jsonlandpicked_up.Hmz.read/runner/run,Refused,fakes, and the whole ofRun.run.tapenow readresume.jsonl, andtapes/stage.pyis ported to today'sEpic. GIFs were not re-rendered.HmzSurfacesuses the real SDK surface and gen-plan params.chat's roles, workspace andonline=ALL.failedrather than on nothing #39:orchestrator;BudgetExceededand "three failures in a row" endings;aot, the agent-cleanup pair andrecursive_lean_prover.-especs;/afkmakes it away;Run.close();/resumeis described as implemented;hmz.prices,hmz.providers,hmz.telemetry) are fixed.pnpm buildandpnpm check:anchorspass.Specs (only lines that conflicted)
runtime/SPEC.md: the Recorder'sbegan/named/closed/finishedmethods; a called flow's record says its task; the run holds no session past its close.runtime/flowing.md: theLiveCallfields, the Recorder protocol, and when asessionjournal record is written.runtime/doing.md:Run.agentsmeans 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.pnpm install --frozen-lockfile && pnpm build && pnpm check:anchorspass.claudeon 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'scalledrecord carries the subflow's task, and both sessions are recorded by id.demo:countswas stopped by-b output_tokens=4(exit 0,hmz exec: stopped -- …). The journal holdssessionrecords with the CLI's ids, and state is{done: 2}.--resumepicked it up (picked_uprecorded) and finished it with{done: 3}.🤖 Generated with Claude Code