refactor(local_tool_runtime): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 11s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / rust-surface (push) Failing after 18s
CI Pipeline / go-surface (push) Failing after 21s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 35s
CI Pipeline / lint (push) Canceling
CI Pipeline / unit-tests (push) Canceling
CI Pipeline / canary (push) Canceling
CI Pipeline / type-check (push) Canceling
CI Pipeline / gitea-offline (push) Canceling
Auto-version and Release / release (push) Canceled after 45s

Honest parallelism where it is real: PrefetchContextLengths fans one
goroutine per model over the same discovery seams (the single-threaded
Python oracle cannot express this), with the registry keeping its lock
discipline for interleaved readers. The loop's tool semantics stay
deliberately sequential — tool results feed the next model turn.

Phase B battery: fan-out results equal the sequential path row-by-row,
cache warm after prefetch, and a 16-worker -race hammer interleaving
ContextLength / registry reads / ResetContextLengthCache / Prefetch.
This commit is contained in:
Nick committed 2026-10-13 07:01:01 +01:00
1 parent d6cbc05951
commit f9ab75fd1e
2 files changed
+123

No files matched your search

+40
View File
@@ -0,0 +1,40 @@
package main
// phaseb.go — Phase B language-advantage pass (dichotomy wave). The port
// keeps the Python loop's deliberately sequential tool semantics; the
// places where parallelism is REAL are the per-model context discoveries
// (independent /api/show calls) and the registry's concurrent readers.
// PrefetchContextLengths fans one goroutine per model — impossible to
// express this cheaply in the single-threaded Python oracle — while the
// registry keeps its lock discipline for interleaved readers/writers.
import "sync"
// PrefetchContextLengths — discover windows for many models concurrently
// (bounded fan-out over the same seams as ContextLength: IsCloudPinned,
// CloudTransportFor, NewLocalTransport, RecordFailure). The module cache
// is warmed as each result lands; results are keyed by model. Failures
// degrade to ContextLengthFallback exactly like the sequential path.
func PrefetchContextLengths(models []string, baseURL string, maxConcurrency int) map[string]int {
if maxConcurrency < 1 {
maxConcurrency = 1
}
results := make(map[string]int, len(models))
var mu sync.Mutex
var wg sync.WaitGroup
semaphore := make(chan struct{}, maxConcurrency)
for _, model := range models {
wg.Add(1)
go func(model string) {
defer wg.Done()
semaphore <- struct{}{}
defer func() { <-semaphore }()
window := ContextLength(model, baseURL)
mu.Lock()
results[model] = window
mu.Unlock()
}(model)
}
wg.Wait()
return results
}
+83
View File
@@ -0,0 +1,83 @@
package main
// phaseb_test.go — the Phase B battery: concurrent context discovery
// parity (fan-out results equal the sequential oracle path, frozen rows
// included) and a -race hammer over the registry's interleaved readers,
// writers and resets.
import (
"fmt"
"sync"
"testing"
"time"
)
func TestPhaseBPrefetchMatchesSequential(t *testing.T) {
doc := loadTruth(t)
rows := decodeRows(t, doc, "module_context_length")
savedPinned, savedLocal := IsCloudPinned, NewLocalTransport
defer func() { IsCloudPinned, NewLocalTransport = savedPinned, savedLocal }()
IsCloudPinned = func(model string) bool { return false }
discoveries := 0
var mu sync.Mutex
NewLocalTransport = func(baseURL string) (CloudTransport, error) {
mu.Lock()
discoveries++
mu.Unlock()
return stubCloud{window: 4096, err: nil}, nil
}
ResetContextLengthCache()
models := []string{"m/a", "m/b", "m/c", "m/d", "m/e"}
prefetched := PrefetchContextLengths(models, "http://localhost:11434", 4)
if len(prefetched) != len(models) {
t.Fatalf("prefetch %d results, want %d", len(prefetched), len(models))
}
ResetContextLengthCache()
for _, model := range models {
sequential := ContextLength(model, "http://localhost:11434")
if prefetched[model] != sequential {
t.Errorf("%s: prefetch %d != sequential %d", model, prefetched[model], sequential)
}
}
// the fan-out must have warmed the cache — second pass is all cache hits
hitsBefore := discoveries
PrefetchContextLengths(models, "http://localhost:11434", 4)
if discoveries != hitsBefore {
t.Errorf("second prefetch re-discovered (%d -> %d) — cache not warmed", hitsBefore, discoveries)
}
_ = rows
}
func TestPhaseBRegistryHammer(t *testing.T) {
savedLocal := NewLocalTransport
defer func() { NewLocalTransport = savedLocal }()
NewLocalTransport = func(baseURL string) (CloudTransport, error) {
time.Sleep(time.Microsecond)
return stubCloud{window: 4096, err: nil}, nil
}
ResetContextLengthCache()
var wg sync.WaitGroup
for worker := 0; worker < 16; worker++ {
wg.Add(1)
go func(worker int) {
defer wg.Done()
for i := 0; i < 50; i++ {
switch i % 4 {
case 0:
ContextLength(fmt.Sprintf("hammer/%d", worker), "http://localhost:11434")
case 1:
contextLengthMutex.Lock()
_ = len(contextLengths)
contextLengthMutex.Unlock()
case 2:
ResetContextLengthCache()
default:
PrefetchContextLengths([]string{fmt.Sprintf("hammer/%d", worker)}, "http://localhost:11434", 2)
}
}
}(worker)
}
wg.Wait()
ResetContextLengthCache()
}