mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-11 10:01:27 -10:00
8f7e4a0748094de92aa17e534bf54839b2cecaab
19
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7e45e66110 |
Preserve provider failure diagnostics across cleanup and restart / 保留收尾与重启后的模型请求失败诊断 (#11152)
* fix: preserve provider failure diagnostics across cleanup and restart Problem: Failed requests could reopen without their failure identity or the transport evidence needed to investigate them. Root cause: Cleanup replaced terminal recovery metadata, HTTP/2 protocol errors fell through classification, and request observations were process-local. Fix: Preserve failure metadata at the shared cleanup boundary, recognize HTTP/2 transport codes without enabling retries, and persist bounded redacted request evidence atomically with turn completion. Localize failure summaries and document additive persistence compatibility. Verification: Full root Go suite, owning-package and focused race tests, desktop history/export regressions, frontend tests and typecheck, Chromium interaction checks, Windows provider cross-compilation, and repolint passed. * fix: align diagnostic contracts and isolate lifecycle test fixtures Problem: CI rejected stale desktop contracts and an error type assertion; Windows lifecycle tests also timed out around filesystem finalization. Root cause: The additive diagnostic field was not regenerated into the host contract. Transport classification used a direct error assertion. Functional checkpoint and cancellation tests unnecessarily coupled live state assertions to multiple durable writes under short completion deadlines. Fix: Regenerate the contract, reject wrapped API errors using errors.As, and use existing in-memory checkpoint/controller fixtures for live semantics. Retain all assertions and dedicated durable maintenance, checkpoint reload, and cold-export coverage without changing production timeouts or CI gates. Verification: Pinned golangci-lint 2.12.2, repolint, focused provider/control tests, three race-test repetitions, checkpoint persistence reload, frontend typecheck, and diff checks passed locally. * fix: structure transport diagnostics and bound failed-turn evidence Problem: Transport classification depended on error wording, UI projections dropped structured diagnostics, successful requests persisted peer addresses, and bounded request history could silently appear complete after eviction. Root cause: Diagnostic identity was converted back to prose across transport and presentation boundaries, while lifetime-wide request eviction lacked bounded per-turn accounting and unsuccessful-turn persistence gating. Fix: Classify exported HTTP/2 types and exact stdlib type/code identities; carry diagnostic fields through all notice/history paths; persist only failed, interrupted, or recovery-required turn evidence; and record per-turn dropped counts and truncation, marking unavailable accounting incomplete. Verification: Typed and real TLS connection/stream/GOAWAY tests, provider/control race checks, cold-export and success-persistence regressions, per-turn loss tests, frontend projection tests, Chromium three-locale interactions, production frontend build, and bundle budgets passed. Preserve model bytes and retry policy. * fix: keep optional diagnostics from blocking terminal commits Problem: Encoding optional provider evidence could prevent required turn-end events from committing. Persisted free-text transport errors duplicated the structured evidence, and generated detail text duplicated HTTP/2 codes. Root cause: Optional diagnostic errors escaped the shared terminal-event builder, while transport prose was retained at multiple presentation boundaries. Fix: Warn and omit failed diagnostic records while preserving required terminal events. Remove transportError and its byte truncation. Leave transport-code rendering to the structured frontend presenter. Update export documentation. Verification: Real invalid-timestamp regression covers failed/interrupted/ recovery-required closures; synchronous and Desktop-send failures retain durable turn/end and cold-export identity. Structured-evidence, no-prose, presentation, and model-context tests pass, as do frontend typecheck and affected suites. |
||
|
|
2dfa1ca44c |
fix(transcript): stream live deltas for sessions on the legacy projection
A session opened from a legacy topic path follows its transcript through the legacy projection (storageBackend "legacy"). There every turn event, text and reasoning deltas included, takes the next ledger sequence, so each follow change advanced commitSeq by one but carried no firstSeq. The desktop follow client treats a change without firstSeq as a display frame that must ride the current cut, rejected the very first change of the turn as "transcript frame cut mismatch", dropped the subscription and re-baselined once a second. No delta reached the reducer, so neither thinking nor answer streamed and the reply appeared whole at turn end. The stream_attempt commit on that path also asked for a reset, because the legacy path never recorded a result sequence. Recording the message event's sequence covers rounds with text or reasoning, but a tool-call- only round and an interrupted round publish no message event at all. Projection.Apply now publishes the sequence each envelope occupies as the change's firstSeq. A commit settles on the recorded message sequence or, when the round had no message event, on its own sequence: the agent emits the commit only after the round's record is durably appended, so that sequence is already covered. The entry is dropped at the commit so the map stays bounded. ApplyFrame (the exclusive runtime path) is unchanged. Test: TestLegacyTopicTranscriptFollowStreamsDeltasTheRendererAccepts opens a legacy topic through StartTopicActivation on a real App with a scripted streaming provider, follows through TranscriptFollowForTab and applies the renderer's acceptance rules (mirroring transcriptFollowClient.ts validate: coverage, sampling, resultKind, records-based result identity with its 192 cap). Subtests run a streamed reply, a tool-call-only round and a cancelled round, each followed by a streamed reply. - main-v2: all three fail with "frame_cut_mismatch at revision 3". - message-sequence fix only: tool-call-only and cancelled rounds fail with "revision_gap" at the commit. - this change: all pass, every delta delivered with no re-baseline. Replaying captured follow responses through the real TranscriptFollowClient accepted 0 deltas before and all of them after. Fixes #10968 |
||
|
|
50f3d33a50 |
fix(transcript): an interrupted turn keeps its provider error visible
A turn_done with status interrupted or recovery_required took the generic "turn interrupted" branch in both renderers (the transcript projection and the desktop reducer), which ran before the err branch and dropped err, detail and diagnostic. Turns persisted by 1.38.7 as recovery_required with an HTTP 402 therefore replay as an unexplained interruption. The interrupted branch now also emits the provider_request_failed notice when the turn carries an error whose diagnostic is not a cancellation. The cancellation test reads the diagnostic kind, now named provider.FailureKindCancelled, rather than the error text; a user stop still shows only the interrupted notice. Tests: TestInterruptedTurnKeepsProviderFailure (internal/transcript) and interrupted-turn-provider-error.test.ts both fail on the base and pass here. |
||
|
|
6448d8c985 |
fix(transcript): reconcile queued guidance by message ID / 修复队列引导重复记录 (#10723)
* fix(transcript): reconcile queued guidance by message identity Problem: A queued guidance insertion could appear twice when its live event and durable history row reached the Desktop in different orders. Unapplied guidance warnings had the same duplicate-row failure. Root cause: Live receipts and canonical records used unrelated display identities, while some legacy history rows omitted the owning message ID. Fix: Assign one message ID to each guidance insertion, retain legacy record addresses, normalize older history identities, and merge event and canonical rows by identity. Preserve inbox consumption receipts independently of display and cover applied and unapplied guidance in local, remote, and browser paths. Verification: Focused Go and frontend regressions, root Go suite, frontend transcript suite, Chromium DOM transcript workload, typecheck, and repolint passed. * test(frontend): typecheck steer transcript regressions Problem: The new transcript regressions executed successfully but their fixture types failed the repository test-typecheck gate. Root cause: Inferred literal state types were narrower than reducer results, while broad item and history interfaces hid the notice-specific fields required by assertions. Fix: Type the reducer state at its public boundary and narrow notice items explicitly without changing the behavioral assertions. Verification: pnpm test:typecheck, canonical user display test, and steer transcript test passed. |
||
|
|
3476556ee8 |
Defer historical session loading and add bounded native paging / 延迟历史会话加载并加入有界原生分页 (#10664)
* Improve historical session startup and lazy loading * Fix history preparation retirement across readers Problem: source replacement and immediate reopening could expose a closed SQLite cache to retained history readers. Root cause: reader cancellation did not follow preparation retirement, the last release removed cache ownership before close, and compatibility paging opened a separate owner. Fix: share preparation across both APIs, propagate source cancellation, retain and drain cache-close barriers, and retire unbound borrowers during shutdown. Verification: deterministic shared-reference, replacement, immediate reopen, compatibility cursor and shutdown tests passed with the related history paging race suite. * Index history read fences and extend lazy catalog pages Problem: paging repeatedly cloned the registry and scanned every source mapping, while existing groups, time filters and pinned shells bypassed lazy catalog reads. Root cause: read invalidation lacked immutable reverse indexes and source fences could mix a captured WAL view with live metadata. Fix: share exact-publication lifecycle tokens and one verification per validation; reuse lazy pages for all-session views, frozen time filters and automatic pinned shells; capture source fences from their listing transaction. Document remaining full-materialization and recovery limits. Verification: registry, history lifecycle and catalog paging race suites; deterministic WAL-capture replacement regression; transcript tests; full root Go suite. Desktop full partition sweep remains in progress. * Validate fresh macOS images and join history batch workers * Page native history outlines and resolve direct read anchors * Read schema-one history through cancellable native projections * Handle unused history roots and verify packaged native readers * Page grouped history without materializing every session Problem: group filters expanded all legacy rows and loaded unrelated canonical headers. Disappeared history roots could also be omitted from completeness. Root cause: group membership forced the full snapshot adapter, and listing availability independently skipped absent roots instead of using discovery. Fix: retain immutable catalog pages with source-key membership predicates, admit canonical group and pin members before Stat, and use metadata discovery state for absent roots. Keep source hashes and persisted schemas unchanged. Verification: catalog and Desktop pagination/organization regressions, related race tests, sidebar browser interactions, and stronger packaged legacy reader checks. Root-wide validation and the new packaged group check continue separately. * Share native history preparation with compatibility content readers Problem: Unbound history field requests could enter compatibility repair after native paging had already prepared a read-only view of the same source. Root cause: Paging and content RPCs borrowed different history preparation owners and did not share cancellation and source validation boundaries. Fix: Centralize native pager borrowing and use it for compatibility field reads, including explicit targets, while retaining unsupported-format readers. Verification: Focused paging/content regressions and race tests pass, including Unicode chunk reads, unchanged authoritative bytes, and peer cancellation. The native package harness now exercises unbound content reads as well. * Bound queued history iterators and resolve original compatibility sources Problem: Rotating discovery retained one descriptor per historical root, and cold compatibility RPCs rejected global files after workspace restoration. Root cause: Scan admission had no retained-iterator budget; read validation mistook the destination workspace for the captured historical source root. Fix: Limit queued discovery to eight iterators with a visible-workspace reserve, retaining admitted progress. Share known-root source resolution across cold paging, field reads, and legacy previews outside App.mu. Verification: Catalog full race suite and Desktop focused race tests pass. Tests cover retained progress, priority switching, eventual completion, old global source reads, full Unicode content, and unknown/symlink root rejection. The packaged smoke caught the original directory failure; retain compact page diagnostics so an absent field ref identifies its actual read error. * Filter historical metadata pages without materializing the library Problem: Sidebar text queries bypassed lazy paging and built every legacy session row before returning a small matching page. Root cause: The bounded catalog adapter excluded text requests because SQL case conversion could not preserve display-layer Unicode/title semantics. Fix: Filter bounded catalog batches through the existing Go matching rules inside the retained WAL snapshot. Read captured source identities instead of resolving candidate files and account for retained query text. Verification: Catalog and Desktop focused race tests cover sparse matches, Unicode, cancellation, fixed-cut continuation, source keys and localized titles. Sidebar browser interaction tests pass. Native smoke now also checks text filtering within a group; sparse queries can still scan all metadata. * fix(desktop): admit explicit group targets without scanning history Problem: ordinary group edits enumerated all legacy source pages before applying a workspace organization mutation. Root cause: group commands shared manual reordering's full-source admission. Fix: admit only resolved group targets inside the revision CAS, normalize physical source keys, retain explicit ungrouping fences, and recheck source adoption and lifecycle ownership inside the registry transaction. Verification: organization and group regressions pass with the race detector, including deterministic adoption-before-commit rejection and late preference import. Document the remaining full-source manual and legacy preference paths. * fix(desktop): decouple catalog admission from metadata refresh Problem: catalog startup and filesystem event delivery waited for whole project/topic metadata transactions and restored-path index writes. Root cause: startup and the watch loop synchronously owned these writes, while user edits started independent unjoined metadata goroutines. Fix: register watches before restored identities settle, enqueue restored paths, and coalesce all metadata refresh triggers into one cancellable worker joined by the catalog lifecycle. Publish admission without waiting on writes. Verification: catalog/sidebar regressions and race tests pass. Deterministic coverage holds a real SQLite writer during admission, blocks refreshes to verify coalescing, and checks cancellation and lifecycle wakeup ownership. Whole-projection metadata reconciliation and synchronous database integrity validation remain explicitly documented acceptance gaps. * refactor(history): separate projection readers and preparation stages Split native pager source validation, DAG projection, compatibility windows, catalog paging, and controller usage accounting into focused owners. Remove the unreachable continuation rebind in the empty-key topic branch. Preserve source validation, transaction boundaries, and snapshot ownership without increasing lint baselines. Verification: repository lint; agent, sessioncatalog and session package suites; focused Desktop history/catalog/snapshot/navigation tests; frontend typecheck and transcript suite. * fix(history): serialize discovery progress with catalog writers Problem: the 100k native discovery fixture stalled with SQLITE_BUSY. Root cause: progress publication bypassed the process-local mutation lock while other catalog writers used it. Fix: route progress through the same boundary and preserve its generation predicate and cancellation behavior. Add a production-package scale harness and record the incomplete history.12 result without relaxing its gate. Verification: focused metadata/reconcile/catalog race tests, repository lint, script syntax check; native scale harness smoke and history.12 measurement exposed the failure. A fresh package run is still required. * fix(history): move metadata integrity audits behind startup admission Problem: cached catalog opening still scanned every database page before returning a sidebar page. Fix: open advisory metadata separately from the full background audit while keeping content projection validation synchronous. Corruption revokes the generation, stops its work, closes all read leases, and reopens through the existing validated quarantine path with a monotonic revision floor. Old cursors return stale_cursor; canceled or transient audits cannot quarantine data, and retries remain bounded. Verification: root Go suite; projectiondb and sessioncatalog race suites; Desktop catalog/history/snapshot race regressions; real CHECK-constraint corruption, source preservation, lease closure, late publication, cancellation and retry tests; repository lint. Native package performance acceptance remains pending. * fix(history): avoid redundant discovery and source-wide metadata writes Problem: Large legacy catalogs could finish discovery then immediately restart, while registry refresh rewrote unrelated discovered topics. Root cause: Startup recovery used the full-root invalidation notification alongside watcher-owned discovery; metadata membership reset and orphan cleanup scanned all topics. Fix: Publish only registry metadata after reservation recovery, and use the existing metadata_present flag with an optional partial index to constrain membership refresh. Source mutation retains topic cleanup ownership. Record incomplete history.13 scale evidence and warmup progress. Verification: sessioncatalog suite, focused catalog race tests, Desktop startup/catalog/history race tests, repolint, JavaScript syntax check, and diff whitespace checks passed. New package scale acceptance remains required. * fix(history): bound directory watching and merge undispatched invalidations Problem: Large catalogs continued to restart discovery after the initial scan. Root cause: Catalog monitoring bypassed the platform directory backend and used macOS kqueue registration that enumerates children and opens per-file handles. Unwatched roots were also invalidated on every metadata tick, and queued jobs retained pre-dispatch changes as unnecessary follow-up scans. Fix: Reuse native directory watching, preserve canonical event/access routing, separate watch retries from the rotating audit, and merge invalidations before scan dispatch while retaining genuine in-flight source changes. Verification: Focused catalog queue and Desktop catalog/watcher race tests pass, including 512-file native registration under a 256-descriptor process limit, canonical events, recovery gaps, durable journals and late file discovery. Repolint and diff checks pass. Record the incomplete history.14 scale evidence; the new production package still requires measurement. * fix(history): preserve cold reads when execution recovery fails Problem: lease-blocked native navigation could leave a blank transcript, and cache failures could silently start full compatibility replay. Root cause: passive readiness refresh switched startup-error tabs to controller-dependent Follow; activation failure settled independent history state. Native preparation did not distinguish ordinary errors from explicit unsupported formats, and root invalidation retained native watcher registrations. Fix: coalesce matching cold reads, fence rebuild/reconnect paths, and let only read failures settle history errors. Restrict compatibility fallback to explicit unsupported results, positively identify ancient event envelopes, and remove replaced native watches. Verification: deterministic activation regressions (59 assertions), frontend typecheck/lint, transcript suite, loading browser tests, focused agent/Desktop race tests and Go lint pass. Root full suite previously passed; Desktop default package timeout remains under investigation with exhaustive deterministic shards. Production history.15 failure is documented; new-package acceptance remains pending. * refactor(history): share runtime rebuild subscription handling Problem: the cold-read fence duplicated rebuild handling and exceeded the existing initial bundle budget by 380 bytes. Root cause: single-tab and settings-wide rebuilds maintained equivalent subscription ownership logic in separate branches. Fix: iterate the affected identities through one stop/invalidate/rebuild path, retaining the cold-read and activation guards without changing the asset budget. Verification: activation regressions (59 assertions), prompt lifecycle tests and TypeScript checks pass; the complete production build will verify the unchanged bundle gate. * fix(history): coalesce startup watches before resuming discovery * fix(history): keep startup locale sync out of discovery * feat(history): add shared on-demand native full-text search * feat(history): add bounded discovery source diagnostics * desktop: ignore noisy root watcher writes * desktop: drain native watch backlog before initial history discovery * refactor(history): remove retired startup migration workers * fix(history): coalesce watcher overflow before journal writes * fix(history): replace invalid scans at slice boundaries Problem: large metadata discovery finished obsolete generations before replaying queued root changes, while unchanged rows rewrote topic projections. Root cause: invalidations were consumed only at EOF and discovery always published full upserts. Fix: supersede invalid iterators between slices with bounded coalescing; preserve incomplete journals and recheck unchanged rows transactionally before updating scan presence only. Verification: sessioncatalog/historywork race suites, deterministic restart and projection regressions, Desktop watcher/startup race tests, and sessioncatalog lint pass. Native scale acceptance remains pending. * perf(history): project registry metadata in bounded slices Problem: registry refresh held the catalog writer for the entire registry and rewrote unchanged metadata. Root cause: metadata-only discovery reused the atomic full-projection refresh and a whole-task timeout restarted large observations. Fix: serialize cancellable observations, share background slice admission, compare persisted rows, defer paged retirement until input completes, and bound each writer transaction. Preserve atomic refresh for other catalog modes. Verification: root Go suite, catalog/historywork race suites, Desktop catalog race coverage, frontend typecheck/transcript and loading/sidebar/navigation/scroll browser gates pass. Retain the preceding history.24 package's 90-run native scale evidence separately. * feat(history): resume interrupted checkpoint index preparation * test(history): verify checkpoint preparation across process exit * feat(history): resume streamed legacy display index imports * refactor(history): separate maintenance admission and publication steps * feat(history): resume native event preparation across process exit * fix(history): preserve cold reading windows during passive readiness refresh * test(history): record production scale results and exercise native cache paging * perf(history): load cold refresh proof on demand * perf(history): defer session restoration policy with its reader proof * perf(history): keep restoration policy outside the eager module graph * feat(history): resume DAG preparation across all durable phases * fix(history): include protected windows in resident cache capacity * docs(history): document DAG resume and native cache findings * fix(history): release evicted read bindings without affecting replacements * test(history): qualify native cache resources and startup scale * docs(history): record history.29 cache qualification * test: align history migration fixtures with current schemas Keep the junction migration regression focused on the last pre-invalidation schema and derive the projection schema assertion from the migration ledger. Complete the history hydration Meta fixture so frontend test type checking covers the current contract. * fix: align startup bundle gate with measured producer output Problem: the history startup PR exceeded the raw frontend bundle gate by 275 bytes on the Linux producer and the migration regression comment exceeded repolint's essay budget. Root cause: the earlier budget ceiling was based on a pre-rebase producer measurement, while the test fixture note was four lines at a three-line position limit. Fix: set the raw initial gate to the smallest measured 2056.6 KiB ceiling, keep all compressed and chunk budgets unchanged, and condense the migration note without removing coverage. Verification: node scripts/check-bundle-budget.mjs; go run ./tools/repolint; focused sessioncatalog migration tests; git diff --check. * fix: format desktop catalog runtime Problem: the desktop producer gate rejected one unformatted composite literal in session catalog runtime code. Root cause: the latest history loading changes left the pinned-only field alignment outside gofmt output. Fix: apply the repository formatter without changing behavior. Verification: gofmt -l ., git diff --check, and go run ./tools/repolint. * fix: use passing producer bundle ceiling Problem: the Desktop producer still exceeded the raw startup bundle gate by 112 bytes after the previous measured adjustment. Root cause: the Linux CI build measured 2106070 bytes while the 2056.6 KiB ceiling allowed only 2105958 bytes. Fix: set the raw initial budget to the smallest 2056.8 KiB ceiling that contains the producer result; compressed, chunk, CSS, locale, and residency budgets remain unchanged. Verification: node scripts/check-bundle-budget.mjs, go run ./tools/repolint, gofmt -l ., and git diff --check. * fix: allow Windows history sources to be replaced during paging Problem: Windows pager fencing tests failed when a source or event log was replaced while a display index was being built.\n\nRoot cause: os.Open uses a Windows sharing mode that denies delete and rename, so the deterministic source-change interleaving failed before the pager could validate the new pathname identity.\n\nFix: add a platform-owned replaceable read helper. Windows opens sources with read, write, and delete sharing; Unix keeps the ordinary descriptor. All legacy pager builders, event-kind probing, and paged event/DAG reads use the shared helper.\n\nVerification: go test ./internal/agent -count=1; GOOS=windows GOARCH=amd64 go test -c ./internal/agent; go run ./tools/repolint; go test ./...; git diff --check. * fix: match Windows replaceable read handle flags Problem: the first shared-delete handle still left the DAG source replacement interleaving failing on Windows.\n\nRoot cause: the native source handle did not use the same reparse-aware backup semantics as the repository's proven replaceable regular-file reader.\n\nFix: align the fileops helper flags with the existing Windows repair reader while retaining read, write, and delete sharing.\n\nVerification: GOOS=windows GOARCH=amd64 go test -c ./internal/agent; focused pager tests pass on the host. * fix: grant Windows pager handles replace access Problem: atomic replacement of a DAG event log was still denied on Windows despite delete sharing.\n\nRoot cause: the replacement operation also needs delete access on the existing native source handle.\n\nFix: request DELETE together with GENERIC_READ while retaining read, write, and delete sharing.\n\nVerification: GOOS=windows GOARCH=amd64 go test -c ./internal/agent. * fix: make Windows source replacement regression portable Problem: the pager source-fencing regression used os.Rename(temp, existing) while the target was open, which Windows rejects; granting DELETE access then broke ordinary concurrent rewrites.\n\nRoot cause: the test encoded Unix replacement semantics that are unavailable for an open Windows target, while the production reader must remain compatible with normal writers.\n\nFix: keep the shared-delete read handle at read access and model replacement by moving the old pathname aside before installing the new file. The test still verifies a changed native identity is rejected before publication.\n\nVerification: focused pager source-change tests, GOOS=windows GOARCH=amd64 go test -c ./internal/agent, go run ./tools/repolint, and git diff --check. * fix: join startup cold history on runtime ready Problem A runtime-ready event could start ordinary session hydration while startup cold history was still in flight, issuing a duplicate history read for the same session. Root cause The ready reconciliation only shared the normal session-load owner. Cold startup reads were tracked separately, so the readiness path did not join that owner. Fix Join matching cold-history promises before starting ordinary hydration. After the certified window settles, install the live follower and continue ancillary hydration with the cached window. Keep the failure path on the existing reader and record the measured 163-byte startup bundle increase with the smallest producer-safe budget update. Verification - pnpm exec tsx src/__tests__/ready-event-meta-sync.test.tsx - pnpm typecheck - pnpm test:typecheck - pnpm lint:hooks - pnpm test:transcript - pnpm build - go run ./tools/repolint - git diff --check * Fix protected history windows and catalog context races Problem Navigation could install a transcript before the active tab was pinned, allowing the resident cache budget to evict the just-opened window. Catalog callbacks could also reread the mutable App context while the lifecycle test replaced it, producing a data race. Root cause Active-tab pinning was deferred to a post-paint effect, and the restored catalog watcher used the App context accessor instead of its owning worker context. Fix Publish the active pin at the dispatch boundary before the first history page commits. Let the catalog watcher pass its existing context into historical discovery while retaining the default accessor for synchronous callers. Verification - tab-switch-hydration: 101 passed - desktop TestConcurrentRebuildSessionCatalogCallersShareFailure with -race: 3 runs passed - desktop TestHistorySliceSourceField/cold_index_hit: 100 runs passed - pnpm typecheck and pnpm test:typecheck passed - pnpm lint:hooks and pnpm test:transcript passed - go run ./tools/repolint passed - git diff --check passed * Fix Windows history upgrade acceptance and test cleanup Problem: Windows CI rejected visible upgraded history and could not remove a test source directory. Root cause: the UI acceptance helper required an activation button even after lazy history had rendered, while the test closed its historical service after TempDir cleanup. Fix: accept a healthy visible transcript without activation and close the test app services before removing the source directory. Keep pending and recovery-state rejection covered. Verification: focused desktop Go test, go vet, repolint, golangci-lint, and diff checks passed. Windows PowerShell and installer checks remain for CI. * Align history CI checks with lazy legacy loading Problem: the Desktop CI matrix failed startup worker, cold index, and packaged upgrade checks after history loading changed. Root cause: those checks still assumed startup discovery took the old coordinator lock, equal-timestamp sidecars were trustworthy, and opening a legacy tab automatically migrated it without rewriting JSONL. The current shutdown path snapshots an active legacy tab. Fix: deterministically block the actual startup worker, establish sidecar ordering for the index-hit fixture, and verify legacy path, authored content, registry non-import, restart, and backups in the packaged fixture. Verification: focused desktop tests with repeated and race runs, upgradefixture tests, go vet, repolint, golangci-lint, and diff checks passed. Windows packaged acceptance remains the terminal CI gate. |
||
|
|
a785237e60 |
fix(transcript): keep the user row ahead of its live output / 修复用户消息被本轮输出插到前面 (#10639)
* fix(transcript): keep a user row ahead of its live output Problem: Streamed reasoning, answer text, and tool calls could render above the user message that started the turn. Later segments of the same turn then continued below the bubble. Root cause: acceptBusiness copied a business record into the follower change before filling an empty TurnID. Export and reload read the buffer, which had the turn identity; the live change did not. Desktop attaches already-mounted output to that turn only when the durable user row carries the same turnId, so the output stayed on the previous formal anchor or ahead of the prompt. Fix: Publish the assigned TurnID with the change record. Place live rows after the submission anchor captured at send time when that user row has no turnId, and move same-turn formal output back behind its user. Keep a resident turnId when a projection update omits it, and stamp the active turn onto a live answer that arrived before the identity did. Verification: go test ./internal/transcript/ -count=1 -run TestAcceptBusinessPublishesTheTurnIDItAssigns desktop/frontend src/__tests__/submission-handoff.test.ts * Preserve sampling order and the offscreen reader during transcript settlement Problem: assigning turn identities could move later live answers ahead of earlier samples and tools. Batched deltas could also clear the newer-history flag while the reader remained on an older page. Root cause: the user anchor overrode every existing formal predecessor, and predecessor lookup ignored newly settled rows while retaining reclaimed ones. The offscreen batch path leaked a temporary history flag into visible state. Fix: preserve surviving and newly formal predecessors within the owning user segment, and keep the reader's history flag while updating its offscreen tail. Document both invariants and add six deterministic regressions. Five fail on the previous PR head; all pass after the fix, including the ordinary-event sibling of the batched stream path. The production raw bundle measures 2102574 B versus 2100795 B on the base (+1779 B, 0.085%). Set only its existing ratchet to 2053.5 KiB, preserving the established 186 B Linux producer difference. Other budgets are unchanged. Verification: transcript Go package; frontend test:typecheck; submission handoff and output-order suites; test:transcript; submission and transcript Chromium suites; production build and check:bundle; repolint; diff check. |
||
|
|
355fa9fc12 |
Fix tool result identity, state handoff and historical projection (#10590)
Sparse completion events and later history hydration could erase durable tool identity, append duplicate result rows after the final answer, and downgrade completed state. Preserve canonical metadata, repair uniquely matchable legacy checkpoint identities, and reconcile bounded resident records through one conflict-aware projection with stable tool keys and anchored local notices. Keep distinct conflicting formal results independently readable and prevent old session requests from updating a new binding. Preserve pagination, content-on-demand and existing resident-memory limits without changing provider payloads, prompts, session exports or the persistent message format. Harden CI at the observed failure boundaries: carry frontend producer attempts into artifact consumers, attribute actual bounded Markdown Worker listeners, synchronize reconnect assertions with retained lifecycle publications, and use a fresh bounded functional wait for packaged upgrade history. Retain native geometry, visible history, restart integrity and independent startup gates. Verification includes transcript/store/follower/reducer regressions, 240- and 1,000-turn browser scenarios, native Electron layout, backend and race suites, packaged Windows first-import/restart acceptance, and all three full memory-screening shards. Real remote-host validation remains unavailable; binding tests do not replace it. No release is published by this change. |
||
|
|
65067d2bbd |
Fix compaction ownership, cancellation, and durable operation recovery
Problem: manual compaction could appear stuck, ignore Stop, lose its outcome after reload, or overlap other foreground work. Automatic recovery could install a projection after cancellation. Root cause: maintenance bypassed shared runtime ownership and turn-independent persistence; client history and snapshots lacked consistent operation ordering. Fix: centralize maintenance admission, cancellation, commit fencing, durable lifecycle records, and queue handoff. Reconcile versioned operation cards across desktop, remote, and CLI; classify empty history safely and preserve recovery details. Verification: root and Desktop Go suites, deterministic maintenance regressions, focused Go race tests, frontend typechecks, transcript tests, production build, contract checks, and Chromium interaction/scroll benchmarks passed. Updated English and Chinese behavior documentation. |
||
|
|
4756bc56ce |
Merge pull request #10550 from SivanCola/fix/transcript-snapshot-record-identity
fix(transcript): make snapshot record identity total / 修复快照记录身份缺失 |
||
|
|
6e1a45bd3d |
test(transcript): satisfy integer range lint
Problem: The CI lint job rejected a fixed-count checkpoint regression loop under the Go 1.22 intrange rule. Root cause: The test used the pre-Go-1.22 three-clause form for a constant integer range. Fix: Use the native integer range syntax. Verification: - go test ./internal/transcript -run 'Test.*Checkpoint' -count=1 - golangci-lint run --timeout=5m - git diff --check |
||
|
|
7c91c2e88f |
fix(transcript): make snapshot record identity total
Problem: Interrupted and outside-turn display frames could reach transcript snapshots without a record identity. Desktop then rejected the snapshot during hydration, and persisted checkpoints could reproduce the failure on every reopen. Root cause: The projection only derived identities from tool calls, message IDs, or positive business sequences. Zero-sequence display frames had no fallback identity, snapshot publication did not validate uniqueness, and Desktop mutated resident transcript state before all validation completed. Fix: Assign projection-scoped identities at the transcript owner, validate every frozen snapshot, repair legacy checkpoint rows, and normalize compatible old-peer snapshots. Stage Desktop store replacement until the reducer accepts the cut while preserving in-flight content ownership. Verification: - go test ./... -count=1 - go vet ./internal/transcript ./internal/control - go run ./tools/repolint - pnpm test:transcript - pnpm build - TypeScript production and test typechecks |
||
|
|
e7a5b149e3 |
feat(attachments): admit images at the session boundary
Problem: Composer and CLI image references could lose their bytes before the provider request, leaving path text to fall through to tools and Bash. Root cause: Image preparation was split across focus-sensitive Desktop RPCs, temporary draft credentials, controller state, and request-time model routing instead of one durable session admission boundary. Fix: Admit ordered image batches before creating the user turn, freeze accepted sources into session-owned image inputs, bind Desktop targets to session identity, and preserve legacy provider serialization and CLI path behavior. Verification: Focused attachment, control, provider, boot, serve, tool, Desktop, and frontend suites passed on the latest main-v2 base. Frontend typecheck, repolint, and git diff checks also passed. |
||
|
|
2797455a1d |
Fix transcript initialization crash during migration
Problem: malformed legacy transcript baselines could crash the Desktop service while startup migration restored a nil projection. Root cause: session runtime construction discarded NewProjection errors and continued into RestoreRuntime without a valid projection. Fix: propagate typed initialization failures, release session ownership on every failed path, keep healthy migrations running, add content-free local diagnostics, and queue a deduplicated telemetry-gated exception for the crash dashboard. Verification: session and transcript package suites, focused Desktop crash/migration tests, targeted race tests, crash worker tests, and worker typecheck pass. |
||
|
|
b1a4e016b3 |
Complete fixed-snapshot session exports / 完善固定快照会话导出 (#10471)
* Complete fixed-snapshot session exports Problem: Session exports could silently contain only the resident history window, omit tool payloads, and show unloaded tool results as stopped after workspace switches. Root cause: Export commands read renderer-owned items instead of an authoritative fixed session boundary, while tool execution state and content availability were inferred from the same paginated projection. Fix: Add fixed export snapshots, watermark-bounded persistence, complete forward history traversal, host-owned local and remote export operations, streamed visual output, reliable publication, cross-page tool observations, and expanded lifecycle diagnostics. Verification: Run root and Desktop test suites, focused race tests, repository and Go linters, frontend type checks and transcript suites, browser visual export probes, and native macOS save/cancel smoke tests. * test(desktop): align remote export contract Problem: The desktop frontend CI still asserted that remote exports serialize the visible resident transcript. Root cause: The source-contract test predated fixed host-owned export snapshots and contradicted the new export boundary. Fix: Assert that remote exports pass an explicit session selector through runSessionExport to BeginSessionExportForTarget, and guard against restoring the resident-transcript Markdown path. Verification: - pnpm exec tsx src/__tests__/remote-project-tree.test.tsx - pnpm test:typecheck - pnpm test:transcript * test(desktop): update export behavior contracts Problem: The complete frontend CI still encoded two pre-snapshot export assumptions: direct renderer imports from the command hook and missing tool results being treated as stopped. Root cause: The source and status contracts were not updated when export orchestration moved behind a lazy host-snapshot operation and tool execution state was separated from content availability. Fix: Verify the two-stage lazy export import path and require missing tool results to remain unknown without authoritative termination evidence. Verification: - pnpm exec tsx src/__tests__/bundle-contract.test.ts - pnpm exec tsx src/__tests__/history-tool-status.test.ts - pnpm test:typecheck - REASONIX_TEST_CONCURRENCY=2 node frontend/scripts/run-ci-tests.mjs (452/452) |
||
|
|
738e9b956e |
Unify transcript recovery and completion with Follow v2 / 统一会话同步与完成机制 (#10385)
* Unify transcript recovery and completion through runtime-owned v2 Problem: completed or reconnecting chats could lose visible output, infer incorrect run state, or display an intermediate duration. Root cause: independent history, event-ledger and runtime snapshots described different cuts, and sampling settlement could precede its business commit. Fix: publish canonical batches and independently versioned sampling frames from the session runtime; use one mandatory Follow v2 consumer for local and remote chat, persistence barriers, stable identities and bounded canonical paging. Preserve old session logs and provider serialization. Verification: root and Desktop Go suites, transcript/session/control race tests, 371 frontend suites, typechecks, production build, Chromium and 42 macOS Electron layout scenarios; Windows cross-compilation. Native Windows verification follows on this branch. * Keep contributor prompt instructions outside transcript migration Problem: changing contributor AGENTS text affects repository instruction inputs. Root cause: protocol documentation had also been copied into the contributor instruction file. Fix: retain the existing instructions and keep migration details in the bilingual user documentation. Verification: cache and provider serialization guards passed; no runtime code changed. * Separate transcript bookkeeping and honor native viewport geometry Problem: transcript additions exceeded existing complexity and file-size budgets, and the Windows layout fixture assumed odd native widths were exact CSS widths. Root cause: runtime reduction, settlement publication and store contracts were embedded in larger owners; 200% Windows scaling rounded a requested 1009px surface to 1010px. Fix: extract cohesive helpers/types without changing publication order or provider bytes; test representable sizes on both sides of the launcher threshold and measure actual CSS geometry. Verification: repolint, transcript/type/hooks checks and focused Go tests pass; Windows native tests and race checks exercise the extracted boundaries. * Migrate remote regression fixtures to transcript Follow Route mock remote output through the mandatory Follow stream and keep metadata separate from snapshot cuts. Assert prefix preservation and ordered completion instead of legacy history rebases. Use unique mock sampling identities across turns and wait for pane transitions in native layout tests. * Use reverse slice iteration for transcript retractions * Give explicit transcript retries a fresh snapshot A retry during ancillary hydration could join an already-installed old snapshot. Mark explicit retry reads as fresh so they supersede the previous load while ordinary startup reads still coalesce. Force a pending ancillary read in the regression and verify its late completion cannot overwrite the replacement. |
||
|
|
658fe6eb06 |
feat(desktop): index the complete conversation in the turn navigator
Problem: The turn navigator derived its entries from the mounted transcript window. A long tool-heavy conversation fills the first body page with execution records, so a window holding fewer than two user questions hid the rail entirely until the reader pressed "load earlier messages" repeatedly. Switching away and back rebuilt the window and could hide it again, loaded markers were renumbered from 1 because the ordinal came from the window, and a turn outside it could not be reached at all. Root cause: Navigation had no source of truth for "which turns exist". The only index was the loaded prefix, so completeness, identity and ordering were all coupled to how much body a client had paged in. Fix: - internal/transcript publishes a bounded turn outline beside the body pages, bound to the same immutable snapshot, revision and event coverage. Entries carry the user record's stable RecordID, optional MessageID, the absolute turn ordinal, the record's order inside that snapshot, and two previews built from display bodies only: 50 grapheme clusters of the prompt and 120 of the last non-empty assistant body in that turn's group. Reasoning, tool output, submitted text and injected context never enter an entry. - The index is built once per frozen cut, so repeated reads reuse one pass, body paging never shrinks it, and its previews count against the existing snapshot cache budget and lifetime. - GET /transcript/outline serves it, advertised to remotes as transcript-outline-v1. TranscriptOutlineAPI is an optional capability beside TranscriptProjectionAPI, so an existing controller keeps compiling and an unsupported route answers 404/405/501 rather than an empty page. - The frontend keeps one shared outline store for local and remote sessions, fenced by tab generation and snapshot identity. A recycled cut is reported as stale; the body is only replaced when the reader explicitly retries. - The rail merges the complete outline with loaded turns, matching by MessageID first and stable RecordID second, so numbering stays absolute and loading an earlier page neither renumbers nor drops a mark. - Selecting an unloaded turn starts a jump transaction that reuses the ordinary older-history paging one page at a time, waits for the progressive mount to advance, and writes the viewport only once the target node is really mounted. Reader intent, an explicit cancel, a newer target, or a session/snapshot replacement ends the pending transaction without taking scroll control back. - Manual paging and navigation jumps share one queue: a page already in flight is awaited rather than submitted twice. Verification: - go test ./internal/transcript/ ./internal/control/ ./internal/serve/ - go test -race ./internal/transcript/ - cd desktop && go test ./... - cd desktop/frontend && pnpm test:transcript && pnpm test:remote && pnpm test:typecheck && pnpm build - CHAT_BROWSER=chromium node bench/chat-transcript.mjs (240 and 1000 turns, zero errors; input P95 137.6ms, switch P95 38.2ms, longest task 218ms, heap growth 0.33MiB) Compatibility: Additive. No persisted session format, provider message, tool schema, permission or prompt-cache byte changes. |
||
|
|
4daa815be8 |
Refactor chat, permissions, and Windows sandbox around Harness / 以 Harness 重构聊天、权限与 Windows 沙箱 (#10209)
* feat: align chat and permissions with Harness Replace the virtualized transcript and split approval/sandbox policy with a natural-flow chat surface, stable node subscriptions, unified permission presets, precise session grants, and platform sandbox enforcement. Port the Harness-style process rows, turn footer, navigator, file presentation, and full-access confirmation while preserving Reasonix history and provider contracts. Add the Windows restricted-token sandbox and fail-closed capability reporting, together with migration, remote compatibility, documentation, and acceptance evidence. * chore: refresh repolint baseline for one-shot refactor Record the deliberate carry-forward from the transcript, remote presentation, permission, and Windows sandbox changes. The refreshed baseline also captures size and complexity reductions produced by the same extraction work. * fix: align permission refactor with CI contracts * fix: stabilize cross-platform permission CI Problem: The permission refactor left headless Windows tests on the workspace sandbox, exposed Windows-only lint findings, and let the transcript browser resolve Playwright assets from the wrong directory. Root cause: Tests used the interactive mode setter for a headless controller, direct Bash fixtures did not stamp their intended unrestricted preset, the transcript benchmark imported Playwright before normalizing its browser path, and Windows-tagged files had not been linted locally. Fix: Use the headless permission entry point, make Bash fixture intent explicit, normalize the transcript benchmark root before importing Playwright, and apply the Windows lint corrections without changing sandbox behavior. Verification: - go test ./... - cross-platform golangci-lint for linux, darwin, and windows - Windows amd64 cross-compilation for boot, builtin, and winsandbox tests - transcript Chromium browser replay for 240 and 1,000 turns - go run ./tools/repolint * test: harden native transcript and shell contracts Problem: The Linux native-scrollbar regression clicked the bottom arrow instead of the scrollbar thumb, and direct shell-contract tests inherited the new workspace-write default on Windows hosts without a sandbox backend. Root cause: The browser test used a fixed bottom-edge coordinate, while shell fixtures invoked Bash outside the controller path and therefore had no host-stamped permission preset. Fix: Compute the native thumb center from scrollbar geometry, retain CI screenshots as artifacts, and mark direct shell execution fixtures with an explicit full-access test context while preserving restricted-sandbox tests. Verification: - go test ./internal/tool/builtin -count=1 - Windows amd64 cross-compilation for internal/tool/builtin - GOOS=windows golangci-lint run --timeout=5m ./... - Chromium transcript replay for 240 and 1,000 turns - go run ./tools/repolint * perf: bound cumulative transcript mounting Problem: The 1,000-turn Linux browser replay exceeded the 500 ms long-task budget while cumulative history pages were mounted. Root cause: Transcript subtree mutations repeatedly rescanned all loaded rows, and each 60-turn history page committed its full natural-flow DOM in one frame. Fix: Observe direct chat-node additions only, retain per-row resize observation for internal content changes, enumerate direct row children, and reveal prepended history across bounded adjacent-frame commits without unmounting existing rows. Verification: frontend typecheck; chat natural-flow and scroll-controller tests; Chromium transcript replay (1,000 turns: 122.7 ms input P95, 161 ms longest task, 0 px anchor drift); repolint clean. * fix: keep transcript hydration synchronous Problem: The progressive history mount delayed initial and replacement transcript content by one frame, breaking remote hydration visibility contracts. Root cause: The bounded reveal path treated every order change like a history prepend, including an empty initial order and authoritative session replacement. Fix: Restrict progressive rendering to a contiguous non-empty suffix with newly added leading nodes; hydrate, replace, and grow the tail synchronously. Verification: remote-session-surface 101/101; frontend typecheck; chat natural-flow and scroll-controller tests; Chromium transcript replay within input and long-task budgets. * fix: stabilize transcript and Windows CI Problem: Linux transcript hydration remapped every mounted node on each history page and exceeded the 500ms long-task budget. The Windows project-session migration test also raced asynchronous catalog startup. Root cause: The order subscriber owned the full React child map even while progressive hydration intentionally retained the previous order reference. The catalog test requested reconciliation before the catalog had been published. Fix: Memoize the node-seat mapping by rendered-order identity so only committed history chunks reconcile. Wait for catalog publication before requesting the production reconcile path, and move shared catalog polling helpers out of the oversized test file. Verification: - 1,000-turn Chromium transcript benchmark: max long task about 249ms - frontend typecheck and hooks lint - project CLI migration tests, 10 repetitions - repolint and git diff checks * perf: bound cumulative transcript layout Problem: Linux 1000-turn transcript replay still exceeded 500ms after seat memoization because each history page reconciled existing seats and the turn rail forced layout of every loaded mark. Root cause: Progressive prepend kept one flat React child list, unchanged turns were reprojected, and the navigator read scroll geometry and rendered all marks after every page. Fix: Keep immutable 24-node seat chunks, cache unchanged turn projections, isolate row layout, window rail marks while retaining full loaded-turn geometry, and make benchmark waits target exact mounted anchors without weakening thresholds. Verification: - Chromium 1000-turn: max 196ms, input P95 119ms, 2407ms full mount - Full transcript test suite - Frontend build, typecheck, lint and bundle checks - Go migration tests 10x - Repository lint and diff checks * Serialize permission changes with approval commits Problem: permission revisions could change while an older approval was still recording and installing its session grant, exposing a mixed snapshot and allowing cross-version authorization. Root cause: mode changes, grant revocation, approval resolution, and permission snapshot reads used separate synchronization boundaries. Fix: establish permissionMu -> promptResolveMu -> permissionStateMu ordering, publish preset/revision/grants atomically, cancel the captured old turn outside the state mutation, and cover both legal concurrent orderings with a deterministic barrier test. Verification: go test -race ./internal/control (including five repeated targeted runs), Windows amd64 cross-compilation, and repository lint all pass. * Preserve chat nodes across history prepends Problem: loading older history repartitioned existing messages under different chunk parents, remounting their DOM and losing selection, focus, and local disclosure state. Root cause: the rendered order was grouped into position-derived SeatChunk components and regrouped whenever a prefix crossed a 24-node boundary. Fix: render every business node under one stable parent, progressively reveal only the new flat prefix, and publish the committed mounted order so navigation never advertises a missing target. Verification: transcript unit tests cover 1/5/23/24/25/48/49-node boundaries and 60 resident DOM identities; Chromium, WebKit, and Electron layout and 240/1000-turn production replays pass. * Clarify full-access host execution semantics Problem: product copy implied that Reasonix filesystem and network sandbox guarantees continued to apply after selecting full access. Root cause: permission labels were updated without consistently documenting Harness-style unsandboxed execution across the desktop, CLI, bot, Windows, and site surfaces. Fix: state that full access runs with the current OS account, retains explicit pre-launch host denies, and does not constrain behavior inside the launched process. Verification: desktop locale typecheck/build, documentation tests, site tests, and full-text consistency checks pass. * Stabilize virtual rail navigation coverage Problem: the Windows Electron layout check sometimes reached the test after the active turn had already scrolled the Harness-style virtual rail to its tail, leaving the early turn mark unmounted. Fix: explicitly scroll the rail to its loaded start before the early keyboard jump, then to its loaded tail before the final jump. Verification: Chromium reports 39 passing geometry scenarios and Electron reports 42. * Make permission ordering test platform-neutral Problem: the Windows control runner correctly reports restricted presets unavailable before its native sandbox is initialized, so the new concurrency test failed before reaching the transaction it was meant to exercise. Fix: drive the same serialized Controller mode-change path directly; platform capability rejection remains covered separately at the public preset boundary. Verification: the ordering suite passes ten times under the race detector and internal/control cross-compiles for Windows amd64. |
||
|
|
e36ef93a2f |
Simplify execution and completion semantics / 精简执行与完成语义 (#10198)
* Simplify execution and completion semantics Problem: Host-derived quality contracts, readiness gates, ordinary todo continuation, and a separate Goal evaluator could prolong or block turns after the model had finished, while mixing model claims with observed execution facts. Root cause: Execution safety, model completion judgment, and result presentation shared a single quality-policy pipeline. Legacy delivery mode also propagated through session, CLI, ACP, worktree, and recovery paths. Fix: Retire delivery mode and host quality obligations, keep Plan preapproval and execution safety boundaries, drive Goal continuation from structured model reports without an evaluator, and render facts separately from declarations. Preserve legacy reads, explicit check recovery, historical evidence, and old remote state without reactivating retired policy. Verification: - root and desktop Go suites - focused root and desktop race suites - frontend test:all and production build - lint, generated contracts, cache guard, browser and native Electron checks Cache impact: One-time provider prefix change from retired tool discovery and updated tool descriptions. Serialization and ordering remain stable within the version. * Fix transcript history formatting Problem: The pull request's Linux and macOS test jobs stopped at the repository-wide gofmt gate for internal/transcript/history.go. Root cause: A composite literal added during historical-check projection was not aligned by gofmt before the initial push. Fix: Apply gofmt to the affected transcript history source. Verification: - gofmt -l . returns no files - go test ./internal/transcript passes - git diff --check passes * Normalize subagent receipt paths for display Problem: The Windows isolated agent job rendered changed paths with backslashes while the stable host-receipt contract and tests require slash-separated paths. Root cause: The simplified subagent completion path now exposes native receipt paths directly, so Windows filepath normalization leaked into provider-visible attestation text. Fix: Normalize only the rendered receipt and claim-violation path copies to forward slashes. Keep native paths intact for write-scope enforcement and audit state. Verification: - focused host receipt and subagent completion tests pass - deterministic backslash input test covers the platform-independent output - repository gofmt and git diff checks pass * Refresh desktop migration inventory Problem: The upstream CI refactor added one classified desktop CI job while this branch removes retired delivery surfaces, leaving the merged inventory count stale. Fix: Regenerate the desktop migration inventory with the current generator after merging main-v2. Verification: - go test -p 2 ./... -timeout 300s - go test -p 2 ./... -timeout 300s (desktop) - pnpm test:all && pnpm build - make lint * Wait for dock fixture hydration Problem: The dock browser benchmark could close Overview before the delayed bench session hydration completed. The authoritative hydrate then replaced the empty-state picker while Playwright was clicking Files. Root cause: The benchmark waited for the composer but not for the selected session snapshot, even though the fixture intentionally expands asynchronously. Fix: Wait for the fixture completion marker before mutating dock state. Verification: - node bench/dock-view-state.mjs (three consecutive runs) - pnpm test:app-browser - REASONIX_SETTINGS_BROWSERS=chromium pnpm test:settings-browser |
||
|
|
27a45a260f |
fix(transcript): unify history snapshot and live event projection / 统一历史快照与实时事件的投影 (#9983)
* fix(transcript): unify history snapshot and live event projection
Problem:
Reasonix desktop 1.38.2 renders duplicated session content. When the
persisted history snapshot runs ahead of the live event stream, transcript
hydration appends already-rendered messages again ([A,B,C] + [A,B] ->
[A,B,C,A,B]), and events replayed after hydration can be dropped because
queued events are re-enqueued after the replay cursor already advanced.
Root cause:
History hydration dedupe only matched exact equality between the tail of
history and the head of the live stream. Message identity was not carried
through sampling events, the event merger, or persistence, so local,
remote, restore, cancel, and paging paths each maintained their own
projection logic with mismatched boundaries.
Fix:
- Thread message identity (Message.ID) through sampling events, the event
merger, and persistence; identity stays out of model requests.
- Merge history and live streams by message ID through one projection
shared by local Wails sessions and remote Serve sessions, with atomic
snapshot boundaries (snapshot plus covered event sequence committed
together) and receipt dedupe separated from commit.
- Controller now persists first, projects second, publishes events last.
- New shared Go package internal/transcript owns display record types and
streaming coalescing; the snapshot API supports paging and 64KiB content
chunking.
- Restore path installs a display checkpoint verified against the session
summary; legacy Serve surfaces get a degradation notice.
- Extract shared modules (remoteStatus, historyItems, historyTypes,
transcriptContentResolver, event extension surface, ledger metrics) and
split oversized functions to satisfy repolint without baseline changes.
Verification:
- go run ./tools/repolint: clean, no baseline update.
- go test ./internal/{control,serve,event,turnevent,transcript,agent,store}/...: ok.
- go test -race ./internal/{control,turnevent,event,transcript}/...: ok.
- cd desktop && go test .: ok.
- frontend: tsc --noEmit, pnpm test:transcript (incl. transcript-store 68
passed), transcript-snapshot-client, new-session-load-race (51 passed),
turn-event-projection-reset: all pass.
* chore(frontend): ratchet locale/raw bundle budgets for transcript projection
The legacy-transcript degradation notice adds one short zh-TW string,
pushing the zh-TW locale chunk to 65551 B gzip (64.015 KiB) over the
64.0 KiB ceiling; zh stays at 64793 B under its existing 63.3 KiB
ceiling. Ratchet only the zh-TW ceiling one decimal to 64.1 KiB.
The unified transcript projection (snapshot client/state, content
resolver, extracted history-items and remote-status owners) adds a
measured 24.5 KiB raw on the initial path (2458.7 KiB total) while gzip
stays at 459.1 KiB inside the existing 469.3 KiB budget. Ratchet the
raw ceiling to 2458.8 KiB with 0.1 KiB of build headroom.
Verification: node scripts/check-bundle-budget.mjs passes all budgets
after a production build.
* style(transcript): satisfy golangci modernize and staticcheck receivers
CI lint flagged the new internal/transcript package: integer-range loops,
a copyloopvar in the nested-ref test, WaitGroup.Go modernization, and
inconsistent Buffer receiver names. Apply the mechanical modernizations
and unify Buffer methods on one receiver name; no behavior change.
Also point the clear-session identity contract test at historyTypes.ts,
where SessionClearResult moved during the shared-module extraction (the
types.ts re-export keeps the import surface unchanged).
Verification: golangci-lint 2.12.2 run ./... reports 0 issues in both the
root and desktop modules; go test ./internal/transcript/ ok;
clear-session-identity-contract test passes.
* fix(transcript): deduplicate active snapshot records
Problem: active records could be returned both in the page and activeRecords, causing the frontend to reject the snapshot; long-history snapshots also scanned settled turns under the projection mutex.\n\nFix: suppress duplicate active records, add frontend defensive deduplication, and bound active-owner discovery to the current turn when identity is available.\n\nVerification: go test ./internal/transcript; frontend tsc; transcript snapshot client and projection reset tests.
* fix(transcript): preserve recovery actions and bounded replay
Problem: installing an authoritative snapshot could hide recovery actions, strand long user messages at their preview, or stall remote replay on a legal oversized ledger page.
Root cause: terminal display metadata was omitted, content patches confused message identity with mounted keys, and replay used a different wire budget from its reader. The row renderer also omitted the recovery callback.
Fix: retain terminal recovery and read receipts, bind recovery actions through the production row renderer, match snapshot content by stable message identity while preserving mounted keys, and recover oversized replay through bounded snapshot content. Copy checkpoint metadata without serializing immutable bodies under the projection lock.
Verification: regression cases failed before these repairs and pass afterward. Related root Go packages, the full desktop module, targeted race suites, frontend transcript/remote/stream suites, typechecks, production build, repolint and go vet pass. Browser checks confirm full content and recovery command delivery; the native Electron smoke passes. A 32 MiB checkpoint capture benchmark improves from about 130 ms and 128 MB allocated to 11 ms and 14 MB allocated.
* chore(transcript): retain main-v2 bundle budgets after integration
Problem: the earlier transcript branch carried bundle ceiling increases measured before the Electron migration.
Root cause: those measurements no longer describe the integrated bundle.
Fix: restore the unchanged main-v2 ceilings and remove the obsolete measurement notes.
Verification: the integrated production bundle passes the original limits at 2396 KiB initial raw assets and 57 KiB for the Traditional Chinese locale.
* fix(transcript): satisfy current Go iteration lint rules
Problem: the integrated branch retained an integer loop flagged by intrange and introduced a backwards slice loop flagged by modernize.
Fix: use the equivalent integer range and slices.Backward forms without changing iteration order or recovery selection.
Verification: golangci-lint passes for affected root packages and the desktop module; focused control and transcript tests pass.
* docs(desktop): regenerate transcript host inventory
Problem: full root tests detected that the migration inventory still described 580 commands after the transcript APIs raised the host contract to 592.
Fix: regenerate both inventory representations from the integrated desktop sources, preserving the existing classification policy.
Verification: go test ./tools/desktopinventory passes, including the source-archive check without Git.
* fix(transcript): keep recovery tokens out of displayed prompts
Problem: connecting the recovery button through a plain prompt would show its internal command and token as the optimistic user message.
Fix: preserve separate display and submission text through local and remote transcript prompt ports. The visible action uses existing localized copy while the controller receives the unchanged recovery token.
Verification: production row-renderer assertions, local submission lifecycle, remote composer/reconciliation tests, frontend typechecks and production build pass. A real-browser button click reports localized display text and the correct token-bearing submission, with no console errors.
* test(desktop): share browser asset loader in discovered suites
Problem: the full discovered frontend run failed only at topicbar-region because its transitive SVG import reached Node without an asset loader.
Root cause: dedicated suites used the existing SVG/image/CSS loader while the discovery runner registered only the CSS loader.
Fix: use the same existing asset loader for all discovered component suites; no test is excluded and no product rendering changes.
Verification: the previously failing topicbar suite passes through that loader; the final full discovery run remains enabled.
* test(desktop): advertise only callable host fixture methods
Problem: the remote runtime browser replay timed out after generated transcript methods were added to a fallback table with undefined implementations.
Root cause: the test preload advertised every object key as a callable method, falsely enabling snapshot negotiation and preventing history hydration.
Fix: derive the stub contract from callable table entries, preserving its live update behavior. Add a regression for adding and removing optional snapshot support.
Verification: the new stub test, session-load race tests, frontend typecheck and the complete app-browser chain pass. The original runtime-state browser reproduction now restores durable history after lost completion and switches back to the local session without errors.
|