From 5aae5df5fb26ddbbf602f80d55309d8ebf6d00a0 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sat, 14 Nov 2026 14:24:50 +0000 Subject: [PATCH] Record conversation algorithm efficiency opportunities --- docs/roadmap/remediation.md | 99 ++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index 694dfc3..9c97d94 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -11,7 +11,7 @@ The implementation retains the intended boundaries: immutable parent-linked history, ordinary preparation and execution for continuations, a separate sequential coordinator, and explicitly selected observer-based groups. No runtime correctness defect or inadvertently strengthened restriction was identified. -The remaining finding concerns the durable public documentation in Stage 13. +The initial finding concerns the durable public documentation in Stage 13. Validation completed with the locally installed Go 1.27.3 toolchain, `GOTOOLCHAIN=local`, `GOWORK=off`, and a writable temporary build cache: @@ -20,6 +20,27 @@ Validation completed with the locally installed Go 1.27.3 toolchain, - `go vet ./...` passed. - `git diff --check` passed. +### Algorithmic Follow-Up + +A subsequent static audit of all 13 stages, at the same implementation baseline, +identified the two efficiency opportunities below. No additional ordinary +correctness bug or avoidable quadratic-time algorithm was found. No real-world +performance data was collected. + +The planned algorithms remain fixed: suffix-only immutable capture, iterative +history flattening, sequential coordination, synchronous observer delivery, and +map-based incremental group aggregation. The findings address extra allocation +and copying around those choices, not replacements for them. Complexity statements +describe implementation costs, not new public performance guarantees. + +For orientation, capture is linear in the new turn's message count; flattening is +linear in retained message count; coordinator bookkeeping is constant per turn, +excluding application callbacks and ordinary execution. Group updates are +expected constant time per event for fixed-length run identities, with linear +membership storage and linear full snapshots. An observer dispatch is linear in +its selected callbacks. These implementations do not rescan all prior turns or +group members on each incremental update. + ## 1. Complete The Public Exchange Capture And Continuation Contract **Priority:** P2. **Status:** Open. **Plan stage:** 13. @@ -63,3 +84,79 @@ private storage/allocation promises while documenting the behavior. prepared-execution, ownership, and repair tests and implementation. Validate the affected documentation links and diff. This is documentation remediation; it does not require changing runtime behavior or duplicating existing tests. + +## 2. Avoid Intermediate History Copies During Assembly And Inspection + +**Priority:** P3. **Status:** For consideration. **Plan stages:** 2 and 5. + +**Locations:** `completePreparationWithStructuredOutput` in +[the runner](../../internal/usecase/runner.go), `Exchange.Messages` in +[history storage](../../internal/domain/exchange.go), and +[`Exchange.Details`](../../exchange.go) with `fromDomainRenderedMessages` in +[facade conversion](../../convert.go). + +Let H be the captured history's message count and S the newly rendered and +caller-appended message count. Continuation preparation currently: + +1. allocates and copies S messages into the new suffix; +2. materializes H history messages into a detached intermediate slice; and +3. allocates the final H + S slice and copies both intermediate slices again. + +Thus assembly copies 2H + 2S message entries, rather than the H + S needed to +populate the final execution-owned buffer. Each pass also clones non-nil +cache-control structs. The public `Details` path similarly materializes a +detached domain history and then traverses it again to allocate public messages +and clone cache controls for a second time. Strings share immutable content; +these are message-header and cache-struct copies, not duplicate text-byte buffers. + +**Complexity:** Current and proposed assembly are both Θ(H + S) in time and +auxiliary space; details remain Θ(H). The opportunity removes an extra linear +pass and temporary allocations, not an asymptotic quadratic defect. Successive +full-history requests still entail work proportional to the sum of their history +lengths. This audit does not propose truncation or a different +conversation protocol. + +**Potential refactoring:** Add an internal fill/flatten helper that writes history +and the new message parts directly into one correctly sized final domain slice. +For inspection, consider an internal indexed traversal/projection helper that +fills the public destination without first constructing a complete domain slice. +Keep the immutable parent-linked representation, separate public types, and +detachment of every exposed mutable cache-control value. Prioritize the simple +assembly change; avoid adding a general projection framework solely to eliminate +the inspection intermediate. + +**Verification:** Reuse history ordering, cache-control mutation, branching, +prepared-execution, and mutating-client tests. Review the copy/allocation paths +statically. Do not add public allocation guarantees or exact-allocation tests. + +## 3. Size Observer Storage For Selected Callbacks + +**Priority:** P3. **Status:** For consideration. **Plan stage:** 9. + +**Location:** [`Compose`](../../internal/observation/compose.go). + +`Compose` allocates `selected` with capacity equal to every supplied observer +slot before filtering nil callbacks. The returned closure retains that backing +array even when only a small subset of slots survives. An all-nil input also +allocates the full temporary array before returning nil. + +Let K be the number of supplied slots and A the number of non-nil callbacks, +including intentionally repeated callbacks. Construction is Θ(K) time with +Θ(K) allocated storage, and a nonempty composition retains Θ(K) storage. +Dispatch is already Θ(A) and does not need changing. Selected-function storage +can instead be Θ(A), with constant storage for A = 0, while preserving Θ(K) +construction time. + +**Potential refactoring:** Count non-nil callbacks first, then allocate exactly A +slots and fill them in order. This trades a second linear scan for avoiding +storage proportional to disabled slots. Alternatively, append into an initially +nil slice for a simpler one-pass filter with amortized Θ(K) construction and +Θ(A) retained storage, accepting growth allocations for dense inputs. A +zero/single-callback fast path can also avoid an unnecessary fan-out closure. +The usual coordinator supplies only two slots, so its benefit is small; this is +a low-priority general-helper scalability opportunity, not a release blocker. + +**Verification:** Preserve copied function values, nil skipping, duplicate +delivery, supplied order, and ordinary panic propagation. Existing composition +and prepared-observer ownership tests protect those contracts; no benchmark or +new performance gate is required.