Repository navigation
Conversation
The three surfaces each expose a partial slice of a Session transcript: the Desktop export renders only what the viewport has loaded (long sessions truncate silently), the TUI copy is clipboard-bound, and the bundle exporter writes a machine-oriented archive. apache#5958 asks for the missing read-side path: persistence -> one complete, human-readable Markdown file. Add `maka session-export-markdown --workspace-root --session --out [--include-thinking]`. It reads every stored row through the session store's snapshot reader and renders the Desktop export's shape (`## You` / `### Tool calls` / `## Maka`) with the differences the issue asks for: - tool results are included (each call carries its redacted result), since they are exactly what a debugging reader needs; every string passes `redactSecrets`; - thinking stays out by default per the @kenji precedent on the Desktop export, with `--include-thinking` as the explicit opt-in; - operational rows (token usage, turn state, permission decisions, system notes, coordination) stay out. No wire, protocol, or storage-schema change; the Desktop renderer is left in place, so formatter ownership (the issue's open question) is untouched by this. Fixes apache#5958 Generated-by: GLM-5.3-Flash (ZCode)
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
At a8affc4e2feccfa97504696b1bd3e99dd3be5de9, I found four reproducible P2 issues in the new Markdown export. The command adds a separate Runtime reader and formatter, includes tool results, and makes thinking opt-in; it does not change the existing Desktop exporter. There were no previous reviews to resolve.
- [P2] Read the current transcript authority —
packages/runtime/src/session-transcript-export.ts:83. This reads legacysession_messages, whereas current conversations are projected fromruntime_events. In real execution stores, a completed invocation projected five persisted messages, but this exporter returned success withmessageCount: 0and only a title/timestamp. The existing host transcript reader already reads the event ledger. This is not an unflushed or partially completed turn. - [P2] Enforce no-overwrite at publication —
packages/cli/src/session-export-markdown-command.ts:91. An output created after the existence check was truncated and the command returned 0. An existing dangling symlink also passed the check and caused its target to be created. The initial check does not replace exclusive creation or atomic no-replace publication. - [P2] Redact every rendered tool-result branch —
packages/runtime/src/session-transcript-export.ts:216,220. A terminal command is inserted into its label without redaction, and validshell_runresults use the unredacted JSON fallback. Recognizable fixture credentials survived both paths, while terminal output was correctly redacted. File-path labels need the same treatment. This finding concerns tool results, not the existing Desktop choice to preserve user-authored text. - [P2] Preserve mid-turn user messages —
packages/runtime/src/session-transcript-export.ts:135. Selecting the first user row silently drops later steering messages in the same turn. Both a real ledger projection and valid persisted message rows reproduced this. Changing the storage reader alone would not fix the formatter.
Verification: Core, Storage, MCP, Runtime, Runtime Host, Eval, and CLI built successfully on Node 22.23.2. The six new Runtime tests, four new CLI tests, 25 adjacent bundle-export tests, and 107 CLI/read-model/host-transcript tests all passed: 142 tests, no skips. Scoped Biome and git diff --check passed. The additional probes used isolated SQLite stores and fabricated credentials; no actual user data or live provider was used. For the overwrite race, only the stat timing was controlled to create a second writer's file before the real export/write proceeded; the dangling-symlink reproduction required no interception.
Large sessions and fidelity limits: A synthetic legacy-table session with 1,200 turns/4,800 rows exported its first and last turns into 5,065,610 bytes in approximately 170 ms; observed RSS and heap-used increases during export were about 27.6 MiB and 23.7 MiB. This is a finite Linux sample, not an upper-bound guarantee: all source rows, grouping maps, output lines, and the final string are retained rather than streamed. Tool arguments and attachment details are not rendered, archived results remain placeholders, and grouping tools before all assistant text does not preserve within-turn chronology. Thinking is excluded by default and redacted when enabled; operational rows are omitted.
Compatibility and merge state: There is no protocol, epoch, or storage-schema change. At the same head, hosted checks showed 13 successes and one skipped installed-CLI Eval check; CI and CLI package validation passed. The branch merges without conflicts with main 66da38efd33475c979233c41bf98f9b8855a3dff; GitHub reports MERGEABLE/BLOCKED, so there is no source conflict, but that is not merge approval. The full monorepo suite, packaged CLI installation, macOS/Windows execution, and Desktop end-to-end tests were not rerun locally. The four correctness issues need addressing; the feature's default content policy and merge decision remain for the maintainers.
…omically Review fixes for the four reproducible P2s on apache#6036: - Read messages through the runtime event ledger read model; sessions older than the ledger fall back to their stored rows. A ledger-backed session no longer exports as a successful empty transcript. - Render every user message in a turn, so mid-turn steering corrections stop disappearing while the responses to them remain. - Redact terminal labels and the structured-result fallback; shell_run fields and terminal command lines no longer serialize verbatim into the export. - Create the destination exclusively after the friendly stat precheck: a path created between the check and the write, or a dangling symlink the check reads as absent, now reports destination_exists (exit 5) instead of being truncated or followed. Generated-by: GLM-5.3-Flash (ZCode)
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
At 842f3dada065e87dafc6015d450fd6efe5cc0b75, three earlier P2 issues are fixed and the tool-result redaction issue is only partially fixed; the remaining gap is graded P3.
| Earlier issue | Current result |
|---|---|
Reading only legacy session_messages |
Fixed: a real completed invocation projects and exports all five messages, including both answers and the steering input. |
| Overwriting a competing file or following a dangling symlink | Fixed: exclusive wx creation returns exit 5; the competing file survives and the symlink target is not created. |
| Unredacted structured results and labels | Partially fixed: terminal commands/output and the structured fallback are redacted, but file-result paths still bypass redaction. |
| Dropping mid-turn user messages | Fixed: both opening input and steering input appear in the output. |
Remaining P3 — redact file-result paths too. In packages/runtime/src/session-transcript-export.ts:242–247, file_diff.paths is interpolated into the label and file_write.path into the body without redactSecrets. Valid results written through the real Session store still export the synthetic secret-shaped markers sk-path-fixture123 and sk-write-fixture123 unchanged, although redactSecrets replaces both and the diff-body control is redacted. Apply redaction to these branches as well, or centrally to every tool-result label/body, and add regression tests for both result types.
Severity note: this is graded P3 rather than P2 because it needs a secret-shaped string inside a file path. That is reproducible with a fixture, but far less likely in practice than the command and output credentials fixed in this revision. It is still worth closing for consistency.
No additional issue was established in the new reader/publication changes. The existing role-grouped output still does not preserve interleaved narration order; this is not a new finding. The Runtime Host protocol and storage schema are unchanged.
Dependency/CLI builds, related tests and the real-store/competition probes pass locally. Hosted checks are green except the skipped CLI Eval lane; GitHub reports mergeable. This does not establish a human merge decision. The full monorepo suite, Windows/macOS probes and installed-package execution were not rerun.
Review follow-up on apache#6036 (Astro-Han P3): the file_diff label carried `content.paths` and the file_write line carried `content.path` without passing through `redactSecrets`, so a secret baked into a path or filename reached the export verbatim. Both labels now go through the same redactor as the diff and write bodies. Generated-by: GLM-5.3-Flash (ZCode)
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
At fb90098aa6c9206e8f9fd537875cd696df47280f, the remaining P3 file-path redaction finding is fixed. The file_diff label and file_write destination now pass through redactSecrets (packages/runtime/src/session-transcript-export.ts:242–255). An independent real-Session-store probe confirms that both synthetic secret-shaped paths and the diff-body marker are absent from the export, while an ordinary filename and the write byte count survive. The same probe fails on the previous reviewed head 842f3dad and passes again after restoring this head.
The increment changes only those two rendering branches and their regression tests; no rebase or unrelated implementation change was introduced. The earlier ledger-reader, steering-message and exclusive-destination fixes are unchanged, and the complete transcript/Bundle-export and CLI Markdown-command suites pass all 40 tests, including existing-file and dangling-symlink refusal. No additional P0–P3 issue was established in this increment. The role-grouped output still has the previously documented chronology limitation; this revision does not claim to change it. User-authored text and Session titles retain their existing treatment.
I read the current diff and compared it with the prior reviewed head, checked all result branches and their added assertions, and rebuilt the Runtime, Runtime Host, Eval and CLI against this batch's fresh dependency installation and unchanged dependency inputs. Biome checks and git diff --check pass. Protocol epoch and storage schema are unchanged. GitHub reports this exact head mergeable, with successful test, audit, package/platform checks and a skipped CLI Eval lane; merge-tree against fetched main 16a8f5b8 is clean.
This validates persisted fixtures and the local command implementation, not a full-monorepo run, live provider execution, or independent Windows/macOS testing. Feature adoption and merge remain human decisions.
|
Gentle ping — this one crossed the 3-day mark: checks green on |
liugddx
left a comment
There was a problem hiding this comment.
Reviewed exact head fb90098aa. The ledger reader, exclusive creation and result-branch redaction from earlier rounds hold up, and the runtime suite passes locally. Five things should change before this lands:
- P2: the export is not read-only.
createSessionStore()(session-transcript-export.ts:79) acquires the operational database in the defaultmigratemode. Pointed at an empty directory it createsruntime.sqlite, and against an older schema it would migrate a running Host's database.session-exportusesrequire_currentfor exactly this reason; please open read-only withrequire_current. - P2: grouping by role inside a turn (
:174-225) reorders events. A steering "STOP" prints before a tool call that actually preceded it, which misleads the debugging reader this command exists for. Please emit rows in stored order. - P2: tool output containing ``` closes the fence at
:275and corrupts the rest of the file. Size the fence from the longest backtick run in the body. - P2: this is a second copy of
renderConversationMarkdown, and it has already diverged. It uses a different redactor (@maka/core/redactionversus Desktop's display redactor, sopassword: …is redacted here but not on Desktop), and the steering fix exists only in this copy. Moving the pure renderer into core with options is roughly 60 lines; I'd do it now rather than defer, since #5958 asks for the same redaction and the same shape. I've answered #5958's open questions on the issue. - P2: scale. The renderer retains every row and joins one string. 1,500 turns with 200 KB results took about 586 MB RSS, and past roughly 512M characters V8 throws
Invalid string length. Please stream per turn to the file handle, or cap individual results, and include the long-session numbers #5958 promised.
Smaller items: --help exits 1; tool arguments are never rendered; subagent sessions are not included; and the operational-rows test passes even without the filter, because the literal token_usage can never appear in the output.
…tabase The export opened the session store in the default migrate mode, so pointing it at an empty directory created `runtime.sqlite` and an older schema would be migrated underneath a running Host (apache#6036 review). The export now opens with `require_current` and fails closed with a new `schema_unsupported` reason; `createSessionStore` gains the storage layer's `schemaMigration` option so callers can opt into read-side semantics. Generated-by: GLM-5.3-Flash (ZCode)
Desktop and the CLI each carried a `renderConversationMarkdown` copy and the two had already diverged — different redactors, the steering fix in only one of them (apache#6036 review; maintainer answer on apache#5958 makes the shared renderer a merge condition). The renderer now lives in core with options for copy strings, tool results, tool arguments, thinking and the redactor, and gains two things both surfaces were missing: - rows emit in stored order inside a turn, so a steering "STOP" prints where the user sent it instead of grouped ahead of later tool calls; - tool-result fences are sized from the body's longest backtick run, so a result containing ``` cannot close the fence and corrupt the rest of the file. An `emit` sink streams one chunk per turn so file exports never hold the whole document in memory. Generated-by: GLM-5.3-Flash (ZCode)
…renderer The runtime export now delegates to the core conversation renderer, dropping its private copy: rows emit in stored order inside a turn (a steering "STOP" sent after a tool call prints after it, not ahead of it), tool arguments render on the row, and result fences size past any backtick run in the body. The operational-rows test pins the whole document against a clean-session export instead of substring checks that passed even when the filter was broken. Generated-by: GLM-5.3-Flash (ZCode)
…nt sessions `exportSessionTranscriptMarkdownToFile` writes each rendered turn chunk to the file handle as it lands — peak memory stays bounded by the largest turn instead of the whole document — and renders sessions the main one spawned as subagents under their own titles, so the debugging export carries the whole story (apache#6036 review). Long-session numbers on the new regression (1,000 turns, ~48 MB of tool-result content, seeded fresh per run): 50,111,824 bytes written in 0.4s with +112 MB RSS — the rows themselves, not a second copy of the document. The old string path had to hold the row set plus the full joined document at once. Generated-by: GLM-5.3-Flash (ZCode)
… sessions, fix --help `exportSessionTranscriptMarkdownToFile` writes each rendered turn chunk to the destination as it lands (exclusive creation — an export never overwrites, and every knowable failure happens before the file opens), renders sessions the main one spawned as subagents under their own titles, and reports bytes plus subagent count. The CLI command wires the streaming path and now answers `--help` on stdout with exit 0 instead of a stderr usage error. Generated-by: GLM-5.3-Flash (ZCode)
|
All five P2s and the smaller items from your review of
One caveat to flag: streaming removes the duplicated document from memory, but the read side still materializes the session's rows before rendering — full O(1) memory would need read-model paging, which I kept out of this batch. CI is running on the new head. |
…e renderer The Desktop export now calls the core renderer with its locale copy and the light clipboard shape (no tool results, no thinking), so the two export surfaces share one implementation and one redactor instead of copies that had already diverged (apache#6036 review; maintainer answer on apache#5958). The renderer-architecture ledger records the dependency change. Generated-by: GLM-5.3-Flash (ZCode)
…-export-markdown # Conflicts: # apps/desktop/renderer-architecture.json # apps/desktop/src/renderer/features/conversation/model/conversation-markdown.ts
|
Follow-up: merged current main ( |
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
At 1ab2ca48286d4cd6bd3bacd41057d75531485542, three P2 issues remain: tool results are still moved ahead of intervening messages, reused tool-call IDs bind results to the wrong turn, and a short file write can silently produce an incomplete export. The read-only database requirement is also only partly satisfied (P3). Details and reproductions are attached inline.
The expansion from fb90098aa primarily addresses the previous requested changes, rather than adding another output format. Excluding changes brought in from main, the PR now changes 11 files (+1,984/−88), versus six files (+1,133/−0) at the previous head. It introduces the shared Core renderer, makes Desktop and Runtime use it, and adds the file-output path, tool arguments, direct subagent transcripts and successful help handling. A shared renderer and read-only opening were explicitly requested in the maintainer's answers.
| Previous request | Current result |
|---|---|
| Never create or migrate the source database | require_current now prevents creation and schema migration, but the Session store still opens a writable SQLite connection; a schema-current DELETE-journal fixture is changed to WAL during export. |
| Preserve stored chronology | User and assistant messages are no longer collected by role, but tool results still render at their earlier call site, before intervening steering messages. |
| Prevent embedded backticks from closing multiline result fences | The fence is now longer than the longest backtick run in the body; the regression tests pass. |
| Use one renderer and redactor for Desktop and CLI | Both consumers now delegate to Core and use its redactor. The previous duplicate formatter is removed. |
| Avoid one giant output string and provide long-session measurements | The CLI writes emitted chunks directly to the file. The 1,000-turn test produced 50,111,824 bytes in approximately 2.6 seconds with a measured 75 MB RSS increase on Linux. All source rows and grouping/result maps remain resident, so this sample does not establish a whole-session memory bound. The new writer also needs to handle partial writes. |
The earlier ledger-source, retained steering-message, secret-shaped file-path and exclusive-destination fixes still hold in persisted-fixture checks. Existing output files are preserved and dangling symlinks are refused. Thinking remains opt-in, operational rows stay excluded, and user-authored text and Session titles retain their existing treatment. Direct child subagent Sessions are included after the main transcript; this is not recursive export of all descendants.
Validation on this head: a clean dependency installation and normal root build succeeded; 11 complete test files passed all 300 tests with no skips. Core, Runtime, CLI and Desktop type checks, the Desktop production renderer build, strict renderer architecture checks, scoped Biome, git diff --check, and the protocol guard passed. The independent persisted-ledger and real-file probes reproduced the inline findings. The short-write test deliberately injected a successful partial write into a real file descriptor; it is an I/O fault model, not an observed disk incident. There were no live provider requests, full-monorepo tests, or independent Windows/macOS or native Electron runs.
The protocol epoch remains 220, with no protocol or storage-schema change. This head merges cleanly with fetched main 6c63fa057ed97916b77db3ff002a13636d6a564a; that synthetic merge was not separately built. At the final check, CI and dependency audit were queued. Three platform addon jobs had succeeded, but the Linux x64 job in CLI package validation was still queued. These are not completed validations. The previous changes-requested review remains on the old head and needs the reviewer's reconsideration after the remaining issues are addressed; this comment does not dismiss it or authorize merging.
…ead-only source Three review follow-ups on 1ab2ca4 (apache#6036): - Tool results render at their own stored position instead of being looked up at the call site: a result stored after an intervening steering message no longer prints ahead of it, and the session-wide toolUseId map is gone — provider tool-call ids are not session-unique, so the last-write-wins lookup bound results to the wrong turn. - `writeSync` may short-write; the file exporter now drains the whole buffer before reporting success instead of silently dropping the tail of a chunk. - The export's store connection is now a true read side: the storage layer gains `access: 'read'` (SQLite `query_only`, no WAL/journal configuration), so an export can no longer flip a writer's journal mode — the regression pins a DELETE-journal database stays DELETE. Generated-by: GLM-5.3-Flash (ZCode)
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
At 1457334515c6386338bbbce026c31b4754e530a3, the three P2 findings and the P3 source-database finding from 1ab2ca48 are fixed. No additional P0–P3 issue was established in this increment.
- Stored chronology and repeated tool IDs: Core now renders each result at its own stored row instead of looking it up while rendering the call (
packages/core/src/conversation-markdown.ts:166–184). Actual persisted Runtime events export the intervening steering message before the later result. Two independent turns reusing the same provider call ID retain both distinct results exactly once, in order. - Complete file writes: The writer encodes a chunk as UTF-8 and drains the remaining bytes before reporting success (
packages/runtime/src/session-transcript-export.ts:203–213). A real-descriptor fault-injection check that accepted only half of one chunk preserved all 20,644 output bytes, including multibyte text, after the retry. An injected I/O exception rejects the export and closes the descriptor. These are controlled I/O fault models, not observed disk incidents. - Read-side source access: Both export paths select
access: 'read'withrequire_current(packages/runtime/src/session-transcript-export.ts:89–92,163–166). The Storage connection enforces SQLitequery_only, skips journal configuration, and uses a separate cached connection from writers (packages/storage/src/operational-state-store.ts:200–254). Successful string and file exports left an isolated current-schema DELETE-journal database byte-for-byte unchanged. A reader's SQL write was rejected, while a concurrently held writer remained usable after export. This is connection-level query-only enforcement, not an assertion that the database is opened with the operating system's read-only flag.
The independent probes reproduce all four previous failures when the three affected modules are loaded from exact old commit 1ab2ca48, and pass with this head. Other dependencies remain at the new head in that comparison; it is not a separate full build of the old commit. Existing secret-shaped file-path redaction, destination preservation and dangling-symlink refusal controls also pass.
This is one follow-up commit affecting five files (+119/−29), with no rebase or additional feature expansion. A fresh dependency installation and normal clean build succeeded. Eleven complete test files passed 302 tests, no skips; Core, Runtime, CLI and Desktop type checks, strict renderer architecture checks, scoped Biome, whitespace checks and the protocol guard passed. This does not cover a full-monorepo run, native Electron, independent Windows/macOS execution, or live providers. The previously documented whole-session source-row memory cost remains; this increment does not establish a total-memory upper bound.
Epoch 220 and the storage schema are unchanged. The head merges cleanly with fetched main 6c63fa057ed97916b77db3ff002a13636d6a564a; the synthetic merge was not separately built. At the final check, CI, audit, and the Linux x64 package job were still queued; three other platform addon jobs had succeeded. The earlier human changes-requested review remains on its old commit and needs the reviewer's reconsideration. This comment does not dismiss it or authorize merging.
The storage dependency guard (local-persistence-dependencies) keeps concrete store construction out of production runtime sources. The transcript exporter built its own session store and event-ledger reader via `createSessionStore`/`openRuntimeEventReadPersistence`; the guard only caught this once this PR's storage changes pulled the storage suite into CI's changed-file test plan, so earlier heads stayed green. The exporter now receives two openers (`SessionTranscriptExportSources`) from its entry point, and the CLI command — the composition root for this surface — opens both read sources with the same `require_current` + `access: 'read'` options the exporter previously passed. No behavior change: same open options, same fall-back-to-legacy-rows policy, same `schema_unsupported` classification on a blocked open. Generated-by: GLM-5.3-Flash (ZCode)
|
Batch follow-up on the Guard failure (real, fixed in Race failure (pre-existing flake, not from this branch): The four review threads above are addressed at |
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
Incremental review from 14573345 to ebd03da9620a2b2e058ae8de5c94550ac4e0a1d9. The one new commit, ebd03da9, satisfies the storage dependency guard. The exporter no longer constructs createSessionStore/openRuntimeEventReadPersistence itself. Instead it receives SessionTranscriptExportSources openers, and the CLI command, as the composition root, supplies them.
I checked that behavior is unchanged:
- The CLI opener passes the same
{ schemaMigration: 'require_current', access: 'read' }options the exporter used before, so the read-only and no-migration guarantees from the previous round still hold. OperationalStateMigrationBlockedErrorthrown by the opener is still caught at both call sites and mapped toschema_unsupported.readSessionMessagesstill falls back to legacy rows when the ledger open fails or projects zero messages, and it now awaits the ledger'sclose()infinally.- The
as unknown as RuntimeEventStorecast moved from the exporter into the composition root unchanged.
Every existing test now supplies the same openers, including the read-only, journal-mode, schema-blocked and 1,000-turn memory tests. I found no P0–P3 issue in this increment. CI on this exact head passed, and the branch merges cleanly with main.
liugddx
left a comment
There was a problem hiding this comment.
Re-reviewed exact head ebd03da96. The five P2s from my last review are resolved: the read-only open (require_current plus query_only, so no runtime.sqlite on an empty workspace), rows in stored order, backtick-sized fences, the single core renderer, and streamed file writes. I reproduced the 1,000-turn numbers locally (50.1 MB, +49 MB RSS). Two things still need a change before merge:
- The shared renderer regresses the Desktop clipboard export.
flushAssistant()resetsinToolRun, and everytool_callcalls it first (conversation-markdown.ts:123,147), so each call gets its own### Tool callsheading. Rows also lost their-list marker, and the exported-at line lost its italics. The<redacted>→[redacted]switch is the intended #5958 alignment, but it needs a Desktop test pinning the new output and a CHANGELOG line. - A failure after
openSync(..., 'wx')leaves a partial file (for example,listHeadersthrowing, or ENOSPC). That file then blocks a retry withdestination_exists. Please unlink on failure, and have the CLI map the error to a clean exit.
Smaller items: subagent titles are emitted twice; grandchildren are silently skipped; tool arguments are always on and never truncated; and the scale test still passes when streaming is replaced by a joined string, so it doesn't guard the property it names.
…enderer flushAssistant() reset inToolRun before its empty check, so every tool_call reopened a `### Tool calls` section and the Desktop clipboard export regressed against its pre-shared-renderer shape. Only an emitted answer breaks a run now, tool rows carry their `- ` list marker again, and the Desktop adapter sets its exported-at line in italics. The `[redacted]` placeholder stays as the apache#5958 alignment; a Desktop test pins the whole clipboard shape and the CHANGELOG records it. Generated-by: GLM-5.3-Flash (ZCode)
|
All six findings are addressed — 1. The shared renderer regressed the Desktop clipboard export — fixed in ca8f80f.
2. A failure after
Smaller items
Verification on the pushed head: core renderer 7/7, Desktop clipboard tests 2/2, runtime transcript-export suite 19/19 (incl. the 1,000-turn run), CLI command suite 7/7; |
An export failure with no structured reason — a destination open error other than EEXIST, ENOSPC mid-write — escaped runMakaSessionExportMarkdownCli as an unhandled rejection and crashed the process. The command now catches it, prints the message on stderr and exits 1. Generated-by: GLM-5.3-Flash (ZCode)
Review notes on apache#6036, one shared write path: - A failure after openSync(..., 'wx') — listHeaders throwing, ENOSPC mid-write — left a partial file that blocked every retry with destination_exists. The finally now unlinks the file when the export did not complete, closing the handle first (an open handle blocks removal on Windows) and keeping the unlink best-effort so the original failure is the one reported. - Each subagent's title was emitted twice: a manual emit ahead of the renderer's own document head. The manual emit is gone. - Only direct children matched, so a grandchild (whose parent is itself a subagent) was silently dropped from the export. A breadth-first walk over subagentParent edges exports every descendant, shallowest first, with subagentSessions counting the whole tree. - renderSessionTranscriptMarkdown declared includeToolArguments but hardcoded true, silently ignoring the caller's choice; the option now passes through. - The scale test held even with streaming replaced by a joined string; a new test holds listHeaders open past the main render and asserts chunks already reached the file while the export is still running. Generated-by: GLM-5.3-Flash (ZCode)
|
CI triage for the red |
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
Incremental review from 1457334515c6386338bbbce026c31b4754e530a3 to 1ac5fd34afb64865e4e6324c3e8a93c53b1a2c53. This adds four commits on the same merge-base (6c63fa05), with no rebase: ebd03da96, ca8f80fca, 1e8170679 and 1ac5fd34a (8 files, +491/−68). Our previous round left no open findings. This round checks the fixes for the changes-requested review on ebd03da9. One new P2 regression and one P3 were found.
Items from the ebd03da9 changes-requested review
- Desktop clipboard shape: fixed, but it introduced a regression (P2 below). Rows have their
-marker again, consecutive calls share one### Tool callsblock, and the exported-at line is italic again. The per-turn---separator is kept. There is a Desktop test that pins this shape, and a CHANGELOG line documents the change to[redacted]. - Partial file after
openSync(..., 'wx'): fixed.finallynow closes the file and then unlinks it unless the export completed. In an independent probe with an injectedlistHeadersthrow, the export rejected and left no file. An EEXIST failure never setshandle, so an existing file is never removed. The CLI now catches errors that have no structured reason, prints them to stderr and exits with 1. - Duplicate subagent title: fixed. Each child heading appears once. The boundary between documents is clean.
- Grandchildren skipped: fixed. All descendants are exported, and
subagentSessionscounts the whole tree. The ordering claim is wrong, though (P3 below). includeToolArgumentsignored: fixed inrenderSessionTranscriptMarkdown. The CLI file export still includes tool arguments in full on purpose; the author offered to add a flag or a cap. That decision belongs to the human reviewer.- The scale test did not guard streaming: fixed. The new gated-
listHeaderstest checks for bytes on disk while the export is still pending. ebd03da96(storage openers injected by composition) keeps the samerequire_current+access: 'read'options and theschema_unsupportedmapping. It clears the storage dependency guard.
P2: a steering message no longer closes a tool-call run (packages/core/src/conversation-markdown.ts:145–149, introduced by ca8f80fca). The fix moved inToolRun = false below flushAssistant()'s early return. The user branch resets the run only through flushAssistant(), so a user/steering message that interrupts a tool run leaves inToolRun true. The next tool call or result then prints as a bullet directly under the steering message's ## You heading, with no ### Tool calls heading. That attributes the model's call to the user section. Probe input: user, tool_call read_file, steering user message, tool_call list_dir, assistant. On this head the output is ## You\n\nSTEERING…\n\n- \list_dir` — list tests. On 1457334, the same input put a ### Tool callsheading beforelist_dir. This affects both the CLI transcript and the Desktop clipboard export. Fix: set inToolRun = false` in the user branch, and add a test with a steering message between calls (or between a call and its result).
P3: subagent order is not "shallowest first" (packages/runtime/src/session-transcript-export.ts:270–281). The walk checks exportedIds.has(parentId) against the set while it is still being filled in the current pass. A grandchild that sorts after its parent in listHeaders() (sorted by id) is therefore exported in the same pass, ahead of later direct children. A grandchild that sorts before its parent lands one level later. The probe with headers [A, G(parent A), B] produced Main > ChildA > GrandG > ChildB. All sessions are included, so no content is lost. However, the order depends on how ids sort, and it contradicts the comment and commit message. All descendants also use the same # name heading, so the export does not show which session spawned which. Either check against the previous frontier for a real breadth-first order (or choose depth-first on purpose), and consider showing the parent in each subagent heading.
Validation on this head: a fresh npm ci --ignore-scripts plus dependency patches, and a full root build, succeeded. The Runtime transcript-export suite passed 20/20. The CLI command suite plus acp-artifact-memory-child-process passed 13/13. The Core renderer passed 7/7 and the Desktop conversation-markdown tests passed 2/2, with no skips. Biome on the touched files and git diff --check passed. This was not a full-monorepo run and included no Windows/macOS or native Electron runs.
Epoch and CI: no protocol or storage-schema files changed; epoch 220 is unaffected. The head merges cleanly with main 368f5c9a3; the synthetic merge was not separately built. In CI, the test job failed on one test: official ACP SDK exports and deletes a multipart Artifact through the real Host (packages/cli/src/__tests__/acp-artifact-memory-child-process.test.ts). It hit a 15 s ACP client timeout after an artifact.ingest operation_conflict. Nothing in this PR's diff touches ACP or Artifact paths, and the file passes locally on this exact head (6/6). I judge it a flaky failure not caused by this PR, but a maintainer rerun is needed to get a green test. All package, platform and audit jobs passed. The human changes-requested review from ebd03da9 is still in place. This comment does not dismiss it or authorize merging.
|
Follow-up on the CI rerun: I merged The new That is the known race in this test: open upstream PR #6134 ("fix(test): synchronize escaped descendant before supervisor fault", opened 2026-10-17) describes it exactly — the test arms its late-write timers during startup, so slow scheduling under parallel load can consume the timer budget before the fault is injected — and changes only the test. This PR touches nothing near that file, and Local verification on the pushed merge head e43a41e: the full So: still pre-existing flakiness of the real-child-process suites under CI load, not this PR. Another rerun of the failed job should confirm; the flake should disappear permanently once #6134 lands. |
…ction `flushAssistant()` returns before resetting `inToolRun` when no answer text is buffered, so a steering user message left the previous tool run open. A call stored after that `## You` block then rendered as a bare bullet under the user text instead of reopening `### Tool calls`, regressing the Desktop clipboard shape pinned in apache#6036. This is the P2 from that review: a user message, like an emitted answer, ends the section. The new core test is red before this change (7/8: the second call has no `### Tool calls` heading after `## You`) and green after (8/8). Desktop conversation-markdown tests: 2/2. Biome check: clean. Generated-by: DeepSeek Harness (deepseek-flash)
|
The For the record on the earlier red: The 10-18 review P2 is fixed in |
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
Incremental review: 1ac5fd3 → d927b83. The range is a merge of main (e43a41e, no conflict resolution in the remerge diff) and one fix commit, d927b83.
Prior findings:
- P2, a steering message did not end a tool run: fixed. The
userbranch now setsinToolRun = falseafterflushAssistant(), so a call after a## Youblock reopens### Tool calls. The new core test covers exactly this shape (tool call, steering message, tool call). - P3, subagent export order is not shallowest-first: open (optional, untouched by this range).
- The six items from liugddx's changes-requested review stay fixed.
New findings: none.
CI: all checks pass on d927b83 (the earlier ACP timeout did not recur). Mergeable. No protocol files are touched.
The frontier walk tested each header against every id exported so far, so a grandchild that sorts after its parent in `listHeaders()` was exported in the same pass, ahead of its parent's later siblings. The document order then depended on how random session ids sort instead of the shallowest- first order the comment promises (apache#6036 review, P3). A level now tests only the previous level's frontier, so every direct child of a level renders before any deeper session. The new test pins the worst case (headers ordered parent, grandchild, sibling) and is red before this change: the grandchild renders between its parent and its sibling (86, 262, 174), green after (86, 174, 262). The whole export suite is 21/21 and Biome is clean. Generated-by: GLM-5.3-Flash (ZCode)
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
Incremental review: d927b83 → 7b48e89 (fast-forward, one commit: "keep the subagent export in breadth-first order").
Prior P3 (subagent export order depended on how session ids sort, not shallowest-first): fixed. Each pass of the frontier walk now only accepts headers whose parent is in the previous level (frontierIds), instead of any session exported so far. So every child of a level is emitted before any deeper session, whatever order listHeaders() returns. exportedIds still prevents a session from being exported twice, so a malformed parent cycle cannot loop. The new test pins the parent, grandchild, sibling ordering that failed before.
All earlier findings on this PR are now closed. New findings: none.
CI: the checks that have finished on 7b48e89 pass; two are still running. Mergeable. No protocol files are touched.
|
@liugddx Both items from your review of
Smaller items: duplicate subagent titles deduplicated; grandchildren exported (whole tree, breadth-first — The automated reviewer's final pass on |
|
Hi @liugddx — both blockers from your Oct 14 review (head
The two incremental-review findings are closed as well: the steering-message Two of your smaller items I have not individually re-verified and would value your eye on: whether the scale test now guards the streaming property (vs. passing under a joined-string implementation), and tool-argument truncation in the shared renderer. Whenever you have a moment, could you take another pass? |
Summary
Fixes #5958. The three surfaces each expose a partial slice of a Session transcript: the Desktop export renders only what the viewport has loaded (long sessions truncate silently), the TUI copy is clipboard-bound, and the bundle exporter writes a machine-oriented archive. This adds the missing read-side path: persistence to one complete, human-readable Markdown file.
It reads every stored row through the session store's snapshot reader and renders the Desktop export's shape (
## You/### Tool calls/## Maka) with the differences the issue asks for:redactSecrets;--include-thinkingas the explicit opt-in;No wire, protocol, or storage-schema change. On the issue's open questions: the thinking/tool-result boundary above is my proposed default and is easy to flip; formatter ownership is deliberately untouched — the Desktop renderer stays where it is, and converging the two implementations into a shared package can follow once that question is decided.
Verification
packages/runtimenew suite (session-transcript-export.test.ts, 6 tests: full fidelity, redaction, thinking flag, operational rows, structured failures, pure renderer)packages/clinew suite (session-export-markdown-command.test.ts, 4 tests: happy path, never-overwrite, missing session exit 2, missing args exit 1)session-export.test.tsbiome checkon all touched filesnpm run check:asf-headerstsc -bruntime /tsc --noEmitcli@maka/evalTS2307 on this machine (module dist not built locally), reproducible onmainwithout this changeNot run locally: the full
packages/clitest suite has threecompiled*tests that depend on a built launcher; they fail identically onmainwithout this change (verified by stashing) and are exercised by CI on the PR head.AI use
Implemented with GLM-5.3-Flash (ZCode). The review-P2 fix at
d927b8398was produced with DeepSeek Harness (deepseek-flash). Human-reviewed.Checklist
biome checkandcheck:asf-headerspass on touched files