M2 review: two regressions the green suite hid, and the reports
The post-implementation review of M2, plus the three corrections it took
to make the evidence true. Reports:
planning/reports/M2-BASELINE-REPORT.md 868 lines, the measurements
planning/reports/M2-IMPLEMENTATION-REPORT.md 758 lines, the reading of them
Verdict is PASS, accept with non-blocking debt, proceed to M3. Every M2
requirement is met and the ones that matter were tested by running the
build rather than reading it: a cloud endpoint written straight into
SQLite with sqlite3, behind the API's back, still refused at the wire;
trusted-LAN HTTPS against the real second machine with verification on;
captures showing zero packets outside loopback and the approved host.
Three defects, all found by running the shipped image.
The memory bank was dead. M2 removed Settings.api_key_plain with the API
key, and memorybank's two provider factories still read it. It failed
inside a fire-and-forget task, so no user error, no log anyone would
read, and no test — every memory test stubs those factories. All 604
tests passed with summaries and embeddings silently not happening.
The configurable model timeout never reached the turn engine. Stored,
validated, exposed in the API, rendered in the UI, and not passed to the
provider. M2's own exit criterion was half met: the constant had moved
but the setting did nothing.
And requirements.lock still pinned quickjs, psycopg and cryptography, so
the setup path DEVELOPMENT.md gives a new developer would have
reinstalled all three.
Both code defects now have the test that would have caught them: one
constructs every provider factory from a real Settings row, one drives
the turn endpoint, the chat endpoint and the summariser and asserts the
configured timeout arrives at each. That is the lesson worth keeping from
this milestone — after removing an attribute, build each consumer from a
real object; after adding a setting, prove it lands. Both failures were
in background or plumbing paths, which is exactly where a subtractive
change cannot see itself.
606 tests pass, up from 604. Lint, build and image are clean. Every
runtime result in the baseline report came from an image built after
these fixes; the reports say plainly that commit 8c65ae9 itself does not
contain them.
Also recorded: 88 test node IDs disappeared and every one is accounted
for — 64 whole files whose subject was removed, 5 replaced by a better
file, 15 individually retired with their features, and 4 renames. No
meaningful coverage was lost, and the eight files that used a JavaScript
counter as instrumentation kept their assertions by moving the counter to
the world-state engine.
Six planning recommendations are reported, not applied. Three are marked
before M3: the threat model still describes the inherited SSRF guard's
opposite rule, TECHNICAL-DESIGN §5.1 still marks two hardening items
open, and the endpoint policy is a load-bearing security decision that
exists only as a module docstring and deserves an ADR.
M3 is clear to start. Its chokepoints are untouched or simplified — the
rollback paths now carry one shared state instead of two — and the Phase
0B undo/redo spike still applies. No M3 work here: Undo still deletes and
there is still no Redo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017foPNqFjAJa2Ngebf5mEfL
This commit is contained in:
co-authored by
Claude Opus 5
parent
8c65ae99de
commit
8652fe7cd8
@@ -142,26 +142,22 @@ _running: set[int] = set()
|
||||
_tasks: set[asyncio.Task] = set()
|
||||
|
||||
|
||||
# Both factories below use the user's own key by construction. They read the
|
||||
# endpoint and key from `Settings` and never from `auth.DEMO_*`, so
|
||||
# summarization and embedding cannot spend the shared demo key. Their call sites
|
||||
# are also skipped when `using_demo` is true.
|
||||
#
|
||||
# Do not change these to accept a `ProviderConfig`. `summary_model` and
|
||||
# `embedding_model` are free-form user input and are not on the demo allowlist.
|
||||
# Both factories read the endpoint and the model names straight off `Settings`.
|
||||
# They used to also read an API key, which is gone: Ollama does not use one and
|
||||
# M2 removed cloud providers. `summary_model` and `embedding_model` fall back to
|
||||
# the narrator model when the user has not named a separate one.
|
||||
def summary_provider(settings: models.Settings) -> OpenAICompatibleProvider:
|
||||
return OpenAICompatibleProvider(
|
||||
settings.endpoint_url,
|
||||
settings.api_key_plain,
|
||||
settings.summary_model or settings.model,
|
||||
settings.api_mode,
|
||||
settings.reasoning_max_tokens,
|
||||
settings.model_timeout_seconds,
|
||||
)
|
||||
|
||||
|
||||
def embedding_provider(settings: models.Settings) -> OpenAICompatibleProvider:
|
||||
return OpenAICompatibleProvider(
|
||||
settings.endpoint_url, settings.api_key_plain, settings.embedding_model
|
||||
settings.endpoint_url, settings.embedding_model
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user