Skip to content

fix(knowledge): scope the on-loop DB guard out of store construction (#8231) - #8331

Open
bolichen97 wants to merge 1 commit into
mainfrom
fix/init-schema-loop-guard-8231
Open

fix(knowledge): scope the on-loop DB guard out of store construction (#8231)#8331
bolichen97 wants to merge 1 commit into
mainfrom
fix/init-schema-loop-guard-8231

Conversation

@bolichen97

Copy link
Copy Markdown
Collaborator

Summary

On every gateway launch the knowledge store logged a spurious on-loop DB warning (#8231). setup_knowledge_routes() reads the gateway's lazy knowledge_store property at route registration, before the socket binds, so KnowledgeStore.__init__ — schema init, migrations, graph load — runs on the event-loop thread on every boot, by the constructor's own documented design. OnLoopDBGuard.check() fires at the db accessor for every caller, so the deliberate construction take warned on each start.

What changed

  • src/kiro_crew/on_loop_db.py: OnLoopDBGuard gains a ContextVar-scoped allow_on_loop() context manager (mirrors history.allow_on_loop_persist, but per guard instance so one store's vetted take cannot mute another's diagnostic). check() returns early only inside such a block; nothing about its global behaviour changes. Module docstring updated (the history opt-out is now mirrored here), ContextVar name slugified, module-level-singleton requirement documented (a ContextVar seen by any Context is never collected).
  • src/kiro_crew/knowledge/store.py: the constructor wraps exactly _init_schema() / _migrate() / _load_graph() in the opt-out. The suppression ends with the with block — the six non-constructor _load_graph() call sites and every reader/writer path stay fully guarded, and strict mode still raises there.
  • test/test_knowledge_store_onloop_db.py: new TestConstructionOnLoopIsSanctioned — construction on the loop is silent and does not raise under strict, a genuine on-loop reader take immediately after construction still warns, the opt-out resets on exception (exact == 1 warn count), and an AST mutation guard pins the with block body to exactly the three init calls (a call dedented out AND a fourth call joining in both red).
  • test/test_knowledge_ingestion_off_loop.py: _RecordingGuard stub mirrors the new API and its suppression semantics (load-bearing: without it the store constructor raises AttributeError under the monkeypatch).
  • docs/system-specs/modules/knowledge.md: guard section documents the constructor opt-out, naming the REAL call site (route registration, pre-bind) and the real cost.

What this deliberately does NOT do

The sanctioned take is not free: _migrate() runs an unconditional writer-locked orphan sweep and _load_graph() full-scans entities/entity_relations on that same pre-bind boot path, so a large knowledge profile can still stall the loop there. Moving that work off the boot path (defer the graph load like the FTS rebuild, or construct the store off route registration) needs a design decision and is filed as #8329. This PR only removes the spurious diagnostic for the take that is deliberate; it does not weaken check() globally nor silence the warning category.

Review

Two pre-push model-pinned lanes ran. GPT (gpt-5.6-sol): NO-FINDINGS with scenario evidence (ContextVar task/thread isolation, suppression scope, __slots__, exception safety, cross-OS, recorder fidelity). Opus (claude-opus-5): 1 BLOCKING + 4 CONCERNS, all verified real and all addressed — the BLOCKING was the first draft's FALSE rationale ("lazily from an async handler", "cheap") written into comments and the spec; comments/docs now name the real call site and cost, and the underlying boot-path work is #8329. The four CONCERNS (module-docstring contradiction, textual-order mutation guard, over-broad caplog assert, ContextVar naming/lifetime) are fixed in this head.

Tests

  • python -m pytest test/test_knowledge_store_onloop_db.py test/test_knowledge_ingestion_off_loop.py test/test_no_blocking_call_on_loop.py test/test_auto_research_onloop_db.py test/test_folder_watcher_off_loop_guard.py test/test_knowledge.py — 302 passed (plus the 82-test focused set re-run after review fixes).
  • Mutation-verified both directions: removing the opt-out reds 4 construction tests; unconditionally suppressing the guard on-loop reds 10 reader-side tests; dedenting calls out of the with block reds the AST guard.
  • Local gates green at CI pins: black-baseline, isort, flake8 (7.1.0), mypy (1282 files), subprocess-encoding, brand-name, docs-lint, sync-io-in-async.

Pattern harvest

Rule candidate: a diagnostic-suppression change must record WHY the suppressed signal is safe to lose, verified against the real call graph — a plausible-but-unchecked rationale ("lazy", "cheap") written into docs is worse than no rationale, because the next reader builds on it.
Class: comment-contradicts-code / false-rationale-in-spec.

Closes #8231

@bolichen97
bolichen97 requested a review from a team as a code owner September 4, 2026 00:12
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Design-level review of 21b9b0e973616243620b4d63508bd1720d3a0c60 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Design-Verdict: PASS

Scoped ContextVar opt-out mirrors the established history.py pattern, pins its one sanctioned use with an AST test, and honestly tracks the real boot-stall as #8329.

[DESIGN-REVIEWED] 21b9b0e

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed 21b9b0e973616243620b4d63508bd1720d3a0c60 — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 21b9b0e

Verdict parsed from the review's SHA-scoped output markers for commit 21b9b0e973616243620b4d63508bd1720d3a0c60.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 21b9b0e973616243620b4d63508bd1720d3a0c60: <one-sentence reason>

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — ✅ PASS

Premise-level review of 21b9b0e973616243620b4d63508bd1720d3a0c60 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All counts verified. Writing the review.

First-Principles-Verdict: PASS

A guard that cannot represent a vetted take warns falsely every boot and burns its 60s throttle window; this fixes that at the guard, cause filed for the rest.

What this change ships

Intent: stop the on-loop DB warning that fires on every gateway launch for the store construction that is deliberate (#8231) — a FIX.

  1. Gateway boot no longer logs the on-loop DB warning — justified
  2. Boot warning no longer consumes the 60s throttle window, so a real violation right after boot now warns — justified
  3. Strict mode no longer turns boot-time store construction into a crash — justified
  4. Guards gain a scoped allow_on_loop() opt-out — justified; 1 consumer (store.py:387), but the per-instance ContextVar cannot live anywhere smaller than the guard, and it mirrors the recorded history.allow_on_loop_persist mechanism (history.py:335) without duplicating it (the guards' separation is a documented decision)
  5. Every non-constructor path stays guarded, pinned by an AST test — justified
  6. Spec + docstrings updated same commit — mandated by AGENTS.md
  7. Test stub mirrors the new API — justified (monkeypatched constructor raises without it)

The fix sits at the mechanism of the reported defect (the guard had no way to mark a sanctioned take); the deeper loop-stall cause is declared out of scope and filed (#8329), which the contract accepts. Delete-option checked: not reading the store at route registration is not a deletion — setup_knowledge_routes (knowledge.py:1996) wires the ingestion pipeline around the instance.

Subtractions

  • on_loop_db.py:193 — drop "whose schema init is cheap and intentionally synchronous" from the allow_on_loop docstring. The description says the false "cheap" rationale was scrubbed ("comments/docs now name the real call site and cost"), and the same PR's store.py comment says "Deliberate is not free" — yet the new API's one exemplar re-plants "cheap", and its only consumer is exactly the not-cheap take.

[FIRST-PRINCIPLES-REVIEWED] 21b9b0e

…8231)

setup_knowledge_routes() reads the gateway's lazy knowledge_store property
at route registration, before the socket binds, so KnowledgeStore.__init__
(schema init, migrations, graph load) runs on the event-loop thread on
every launch -- by the constructor's documented design. OnLoopDBGuard fires
at the db accessor for every caller, so each boot logged a spurious
on-loop warning for a take that is deliberate.

Give OnLoopDBGuard a ContextVar-scoped allow_on_loop() opt-out (mirroring
history.allow_on_loop_persist, but per guard instance so one store's
vetted take cannot mute another's diagnostic) and wrap exactly the
constructor's three init calls in it. The suppression ends with the with
block: the six non-constructor _load_graph() call sites and every
reader/writer path stay fully guarded, and strict mode still raises there.

Sanctioned is not free: _migrate() runs an unconditional writer-locked
orphan sweep and _load_graph() full-scans two tables on that same boot
path. Moving that work off the loop needs a design decision and is filed
as #8329; this change only removes the spurious diagnostic.

Regression tests pin both directions: construction on the loop is silent
(and does not raise under strict) while a genuine on-loop reader take
immediately after construction still warns/raises; the opt-out resets on
exception; an AST mutation guard pins the with block's body to exactly the
three init calls, so a call dedented out or a fourth call joining in both
fail the test.

Closes #8231
@bolichen97
bolichen97 force-pushed the fix/init-schema-loop-guard-8231 branch from 159a113 to 21b9b0e Compare September 4, 2026 00:41
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ human override accepted

Human judgment by @bolichen97 overrides the GPT 5.6 finding for 21b9b0e973616243620b4d63508bd1720d3a0c60; the recorded reason is authoritative for this commit.

This comment is updated in place on each push.

The model was not re-run because an authorized human decision supersedes it.

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 21b9b0e973616243620b4d63508bd1720d3a0c60: <one-sentence reason>

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 4, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator Author

Disposition: REBUT (override) — span=src/kiro_crew/knowledge/store.py:387 "Constructor bypasses the on-loop database guard"

  • The demanded fix reverts the issue this PR closes. Issue on_loop_db warning during knowledge store _init_schema on startup #8231's fix strategy explicitly authorizes "a narrowly-scoped guard suppression around the construction-time init only" (option b in the issue). Removing the opt-out and dedenting the three calls restores the every-boot spurious warning — the exact defect on_loop_db warning during knowledge store _init_schema on startup #8231 exists to remove — and breaks the regression test test/test_knowledge_store_onloop_db.py that pins construction-silent behavior.
  • The on-loop boot cost is real, acknowledged, and tracked — not hidden by this PR. The constructor's on-loop execution (schema init, writer-locked migration sweep, _load_graph() full scan) predates this PR and is the constructor's documented design; moving that work off the boot path is filed as follow-up KnowledgeStore is built eagerly on the pre-bind boot path: writer-locked sweep + graph scan on the loop #8329 and cited in the code comment directly above the block (store.py:380-386). The guard never prevented this cost — it only logged it, once per boot, burning the 60s throttle window so a REAL violation right after boot was silently suppressed.
  • Scope is minimal and pinned. The suppression ends with the with block: exactly _init_schema() / _migrate() / _load_graph() at construction. All six non-constructor _load_graph() call sites and every reader/writer path stay fully guarded, enforced by an AST mutation guard (test_knowledge_store_onloop_db.py:338-346) that fails if the block body grows.
  • Strict mode: raising during the documented, deliberate constructor take would crash the gateway on every boot — that is the spurious behavior class, not a protection regression. Genuine on-loop accesses on reader paths still raise/warn (mutation-verified both directions).

Sibling lanes on the same head: Opus 4.8 — no findings; First Principles (Fable 5) — PASS, explicitly judging each consequence (no boot warning, strict-mode non-crash, scoped opt-out) justified.

@bolichen97

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt 21b9b0e: The demanded fix reverts issue #8231's explicitly-authorized scoped suppression (option b in the issue), restores the every-boot spurious warning, and breaks the regression test; the on-loop boot cost is pre-existing, documented in-code, and tracked as #8329.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@bolichen97 marked the gpt AI finding as false positive, not applicable, or explicitly accepted for 21b9b0e973616243620b4d63508bd1720d3a0c60.

The demanded fix reverts issue #8231's explicitly-authorized scoped suppression (option b in the issue), restores the every-boot spurious warning, and breaks the regression test; the on-loop boot cost is pre-existing, documented in-code, and tracked as #8329.

This decision applies only to this commit. A new push requires a new judgment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

readiness: action required A blocking check or review needs attention

Projects

None yet

Development

Successfully merging this pull request may close these issues.

on_loop_db warning during knowledge store _init_schema on startup

1 participant