feat(#18): composite Bifrost endpoint — build_combined_app (Deliverable 1)
One ASGI app fronting BOTH the memory.* and affect.* planes (:8392), so a single bound Worldtree session both remembers AND shows live PAD. Closes #18 end-to-end (D2 PAD read-endpoint shipped v0.17.14; D1 was bifrost-blocked, now unparked by bifrost 0.10.0's public build_combined_app + FR-1 resolved — zero Worldtree change). - provider/combined.py: build_combined_provider_app wraps bifrost.consumer.build_combined_app over both stores + mounts the shared affect read route. Advertises both caps by store presence; per-route call-time isolation is bifrost's (INV-013). - affect_store.py: extract add_affect_read_route shared helper (the D2 INV-007 promise — composite + standalone mount the SAME read route over the same affect.db, INV-011). - opfeed.py: plane='combined' derives the OpEvent plane per request path (memory-call->memory, affect-call->affect, handshake->combined; INV-012). - serve_combined.py + ratatoskr-combined-provider console script on :8392 (additive — standalone :8390/:8391 untouched, INV-014). - contract: 18.contract.md § Deliverable 1 (INV-009..INV-014); D1 un-deferred. Latent bug fixed (exposed by the contract-mandated memory `search` dispatch test running through TestClient = a worker thread): open_memory_store lacked check_same_thread=False — the SAME sqlite thread-safety bug already fixed in the affect store (D2). The composite serves the memory plane over HTTP, so a memory-call on uvicorn's threadpool would trip it. Fix: check_same_thread=False + PRAGMA busy_timeout=5000 (memory contract Concurrency note). heid-code-review panel (Groa/Hulda/Regin): ZERO drift findings; the implementation matches INV-009..INV-014 at function-block level. Folded the genuine test-fidelity fix (memory leg describe_store -> search per the contract TEST) + added the PRE-001/PRE-002 guard tests. Suite 486 -> 502 green.
This commit is contained in:
@@ -132,7 +132,13 @@ interpreted.
|
||||
|
||||
SQLite WAL (concurrent readers, single writer). `upsert_many`/`delete_many`
|
||||
serialize on the writer; `search`/`get` are concurrent reads. sqlite-vec index
|
||||
writes ride inside the upsert/delete transaction.
|
||||
writes ride inside the upsert/delete transaction. The connection is opened
|
||||
`check_same_thread=False` with `PRAGMA busy_timeout=5000` (mirrors the affect store):
|
||||
the provider is an ASGI app, so uvicorn/Starlette (and TestClient always) may run a
|
||||
handler off the connection's creating thread — the event loop serializes the sync
|
||||
sqlite calls, so this is safe; busy_timeout preps the composite/standalone two-process
|
||||
topology over the same db. (Surfaced by a TestClient-driven memory `search` through the
|
||||
#18 D1 combined provider — the direct-store tests structurally could not.)
|
||||
|
||||
## Division of labor (library vs store)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user