feat(logs): run identity, transient definitions, and real session provenance - #423
Merged
Merged
Conversation
`flow logs -o json` served a DTO that dropped `id` and `completedAt` even though both sat on the stored record, so consumers had no stable per-run handle and no way to tell when a run finished — only how long it took. Transient runs were worse. `--cmd` recorded its command, but `--spec` passed an empty string, so a spec run left behind a ref naming an executable that was never written to disk and nothing at all describing what it did. Recording the spec closes that: every run can now say what it executed. Threading a third string through recordRunStart/recordExecution would have made four positional strings at each call site, so command/spec/label move into a transientMeta struct, mirroring the existing provenance struct. The text metadata block moves into printRecordMetadata — adding the spec line pushed PrintLastRecord past the cognitive-complexity limit, and the block was already a long run of near-identical optional-field branches. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mcp-go reports the literal string "stdio" as the session id for every stdio connection (server/stdio.go) — it identifies the transport, not a session. Taken at face value it meant every run from every client, across every conversation, was recorded under one session id, making `flow logs --session` useless and leaving history with no way to tell one agent session from another. flow's MCP server is stdio-only and a client spawns its own `flow mcp` process per connection, so the process is exactly the session boundary. A UUID resolved once per process supplies the id the transport can't. Substitution only kicks in when the transport gives us nothing usable, so a future transport issuing genuine per-connection ids keeps them. Records written before this still carry "stdio"; consumers grouping by session need a fallback for them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Source distinguished a terminal from an agent, but not a terminal from a GUI: a run
launched by clicking Execute in a desktop app recorded as "cli", because that is what
flow assumes when nothing says otherwise. Anything embedding flow behind a UI was
therefore invisible as a distinct origin in its own history.
Source is compared as a plain string throughout — the filter does an EqualFold, not a
lookup against a fixed set — so the vocabulary is open by construction. The constants
say which values flow itself produces; an embedder can record its own without a change
here. The comment now says that, since the previous wording ("the recognized values")
read as a closed enum it never was.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A client had no way to learn the session its runs would be tagged with. Over stdio the transport carries no identity, so the id exists only inside the server — leaving a client to infer which history records were its own from timing, which is exactly the guesswork the id exists to remove. get_info already reports the connection's context and is the documented first call, so the id belongs there. The server has always known it; `get_execution_logs --mine` resolves the same value internally. This only makes it readable. The point is to keep conversation identity out of flow entirely. A client that wants to group runs by conversation reads this once per connection and keeps its own conversation -> session mapping; flow stores a session, and never needs to know what the caller does with it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ref names the workspace, so that was never missing — but not which checkout of it. Sibling git worktrees produce byte-identical refs from different directories, and an ad-hoc run's --dir does not appear anywhere at all. History could say a run happened in `mochi` while being unable to say which mochi. The directory is the one correlation signal a client cannot reconstruct from what was already stored, which is why it earns a field where the workspace name would only have duplicated the ref. Defaults to the process working directory — the caller's cwd, which for an agent or editor is the project it is working in. Ad-hoc runs override it with their resolved --dir, so the record names where the command actually ran rather than where flow happened to be invoked from. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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.
Summary
Execution history could not answer three questions it should have been able to: which run is this, what did it actually do, and who ran it. Each gap traced to something already stored but not exposed, or not captured at all.
Notable Changes
idandcompletedAtnow reachflow logs -o json. Both were on the stored record and dropped by the output DTO, leaving consumers with no stable per-run handle and no way to tell when a run finished — only how long it took.Transient
--specruns record their definition.--cmdrecorded its command, but--specpassed an empty string, so a spec run left behind a ref naming an executable that was never written to disk and nothing at all describing what it did. AddsSpecto the record.Each stdio MCP server process gets a real session id. mcp-go reports the literal string
"stdio"as the session id for every stdio connection (server/stdio.go) — it identifies the transport, not a session.A client can read its own session id from
get_info. Over stdio the id exists only inside the server, so a client had to infer which records were its own from timing.workingDirrecords where a run executed. The ref names the workspace but not which checkout of it — sibling git worktrees produce byte-identical refs from different directories, and an ad-hoc run's--dirappeared nowhere. Defaults to the process cwd; ad-hoc runs override with their resolved--dir.