This release includes 1 security fix for security teams reviewing exposed deployments.
Topics
+13 more
Affected surfaces
Summary
AI summaryUpdates autonomy/run.sh, Tests, and memory/vector_index.py across a mixed release.
Full changelog
Bug-hunt + greenfield-E2E hardening wave. A real first-time-user greenfield
fullstack E2E run (the first since v7.41.1) exposed three verified-completion
trust holes; a parallel adversarial bug-fleet found data-loss and concurrency
defects across the memory, event, MCP, app-runner, and provider subsystems. All
fixes are additive and reversible; the build_prompt bash<->Bun parity lock is
unchanged (60/60 golden fixtures byte-identical).
Fixed
- Memory vector index no longer destroys itself on save: VectorIndex.save() used
a tempfile suffix of ".npz.tmp", but numpy's savez appends ".npz", so the real
data was written to tmp+".npz" and a 0-byte file was atomically moved into
place. Every persisted index was being wiped on write. Suffix is now ".npz" so
the atomic replace moves the actual data (memory/vector_index.py). - Event bus subscribe() no longer drops events at or behind a subscriber's wall
clock: the previous since=last_check window silently skipped events whose
timestamp tied or trailed the poll time under clock skew. The time window is
removed; deduplication is now purely id-based via _processed_ids
(events/bus.py). - MCP resource handlers (continuity, memory index, pending tasks) return a
structured error envelope on any corrupt/unreadable state file instead of only
catching PathTraversalError (an unhandled JSONDecodeError previously bubbled
out); the memory-index handler parses and re-serializes so malformed JSON is
reported, not forwarded (mcp/server.py). - App-runner stop now reaps the full process tree on the default macOS path: when
setsid is unavailable, deep worker processes were orphaned because only the
direct child was signalled. Stop now snapshots descendants (BFS) once, then
TERM -> grace -> KILL. The crash-counter (_APP_RUNNER_CRASH_COUNT) also resets
to 0 on a healthy watchdog tick, so transient restarts no longer accumulate
toward a false permanent-failure state (autonomy/app-runner.sh). - Codex provider now pins the resolved model: provider_invoke and
provider_invoke_with_tier pass an explicit --model, so codex no longer silently
falls back to the installed CLI default (mispricing the run and ignoring
_codex_validate_model) (providers/codex.sh). - Dashboard XSS hardening: the council dashboard had no HTML escaping at all;
agent name/type/task and the memory-browser item name are now escaped before
insertion into the DOM (dashboard-ui/components/loki-council-dashboard.js,
loki-memory-browser.js; dashboard/static/index.html rebuilt). - Bun runner loop-termination correctness: council_approved,
council_force_approved, completion_promise_fulfilled, and running are now in
TERMINAL_STATUSES (mirroring run.sh), and the max-iteration guard uses >=
(was >) with the default raised to 1000 and read from MAX_ITERATIONS
(loki-ts/src/runner/state.ts, autonomous.ts). - Verified-completion evidence gate no longer reads a clean committed tree as
empty-diff fabrication when the run-start base SHA is unreachable (history
rewrite / reset --hard): the unreachable-base fallback marks the diff axis
inconclusive (pass-through) instead of blocking (autonomy/completion-council.sh).
Fixed (greenfield-E2E trust holes)
- Test-coverage gate is no longer fail-open on no-runner projects: when no test
runner is detected it now records pass:"inconclusive" instead of pass:true, so
"tests never ran" is no longer indistinguishable from "tests passed" in
test-results.json. The completion-council evidence gate already short-circuits
runner=="none" to pass-through (before the passed-is-False check), so genuine
no-test projects stay non-blocking while a detected runner that fails still
writes pass:false and blocks (autonomy/run.sh). - The critical-checklist hard gate now also guards the DEFAULT completion-promise
/ loki_complete_task route, not only the council-interval and dashboard
force-review paths. An agent that left a priority:critical checklist item
failing and claimed done on a non-council iteration previously bypassed the
checklist gate entirely (autonomy/run.sh). - New --allow-haiku flag on loki start: exports LOKI_ALLOW_HAIKU=true so a
first-time evaluator can run the cheaper local-testing tier explicitly. Opt-in
only; the default development tier remains opus (autonomy/loki).
Tests
- New regression coverage: tests/memory/test_vector_index_save_load.py,
tests/mcp/test_resource_corrupt_state.py, tests/test_event_bus_subscribe_skew.py,
tests/test-app-runner-tree-stop.sh, tests/test-cli-allow-haiku-flag.sh,
tests/test-completion-route-checklist-gate.sh, tests/test-coverage-gate-fail-open.sh.
Evidence-gate unreachable-base case added to tests/test-evidence-gate.sh; codex
--model assertions added to tests/test-provider-invocation.sh.
Security Fixes
- Dashboard XSS hardening: escaped agent name/type/task and memory-browser item names before DOM insertion
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About Loki Mode
Multi-agent autonomous SDLC framework. Spec to deployed app. PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief. 5 AI providers, 11 quality gates.
Related context
Related tools
Beta — feedback welcome: [email protected]