Repository navigation
Conversation
An execute that writes may carry expect_revision (with optional expect_relations and expect_epoch): its writes commit only if no relation in scope (the named relations closed over the persistent rules that derive them, or the whole knowledge graph) and no persistent rule changed after that revision. The check runs under the knowledge graph's write lock with the commit, so of concurrent writers expecting one revision of one scope at most one commits. A refused program applies nothing and fails with the new precondition_failed code. Every published snapshot carries a change log stamping, per base relation and for the rules, the revision of the last snapshot that changed them, computed at publish by comparing with the previous snapshot.
…o in-scope writers
jsam
marked this pull request as draft
October 4, 2026 21:04
# Conflicts: # src/protocol/handler.rs # src/storage_engine/program_commit.rs
jsam
marked this pull request as ready for review
October 5, 2026 08:09
This was referenced Oct 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
I want you to really hyper focus on making the symbolic engine, you know, crisp and really truly production ready.
(Context: plan ~/firstmate/data/nsdl-plan/report.md §6.1, GitHub milestone 7. Item EN-8:
expect_revisionprecondition onexecute— why: exact semantics for thestrictguard mode (challenge-2 §2.2))Substance of the referenced plan item: EN-8 adds an
expect_revisionprecondition to the engine'sexecuterequest, needed for the hosted decision API's beta. It gives exact semantics to the decision layer'sstrictguard mode: a decision made by a model on a state window seen atrevision_seencommits only if the window's base relations have not changed since that revision; the check is relation-level, so any write to those relations, by any session, refuses the decision (it suits low-write graphs; the default guard stayscandidate_still_valid). Per the plan,executerefuses withprecondition_failedwhen a relation in scope changed after the given revision, and challenge-2 §2.2 asked that specs be able to opt into "state_unchanged" with exact semantics.What Changed
executeframes accept three new optional fields:expect_revision, plusexpect_relationsandexpect_epoch, which both require it. A writing program commits only if nothing in scope changed after that revision. The scope is the named relations and every relation persistent rules derive them from, or the whole knowledge graph whenexpect_relationsis absent; a change to any persistent rule also counts. If the check fails, nothing is applied and the request fails with the newprecondition_failederror code. A revision from another engine run (an epoch mismatch) fails the same way.preconditionmodule. Each published snapshot now carries a change log that records the revision at which each base relation and the persistent rules last changed. The commit path checks the precondition against this log before applying any writes.expect_revision. Also updated: the AsyncAPI spec, the WebSocket guide's new "Revision Preconditions" section, the errors spec, and the HTML API docs. There are new unit tests and an integration suite (tests/ws_expect_revision_tests.rs).Risk Assessment
✅ Low: The fix round adds a conservative fast path: a clean shared view joins without re-evaluation only when the subscriber's snapshot ChangeLog shows no rule change and no change to any relation in the view's dependency closure since the view's revision. It falls back to waiting for untracked state (HNSW), for revisions older than
since, and for in-flight or due refreshes, and it reuses the existing unchanged-refreshadvancepublication, so the exact-revision guarantee still holds.Testing
I built the real server and ran it on a throwaway data directory. Over WebSocket I drove 10 scenarios covering the EN-8 strict-guard semantics and the shared-view join fix, and all 10 passed. Refusals left nothing applied; I confirmed this with follow-up queries. A latency check on an 80k-row view showed that after an unrelated write, a new subscriber joins at the current revision without re-evaluation (0.21s against about 4s). A dependency write still re-evaluates and returns the new row. I also ran the targeted integration test (5 passed) and the unit tests (50 passed). The server and temp files are removed. The worktree is clean.
Evidence: Live /ws transcript of the EN-8 scenarios S1–S10
Evidence: Shared-view join latency: unrelated vs dependency write
first subscriber (cold evaluation): revision=24 rows=80200 took=4.308s second subscriber, no write: revision=24 took=0.225s unrelated write at revision 25 third subscriber after UNRELATED write: revision=25 rows=80200 took=0.212s dependency write (edge) at revision 26 fourth subscriber after DEPENDENCY write: revision=26 rows=80201 took=3.952sEvidence: Targeted test output
Evidence: Driver scripts
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed ✅
src/protocol/subscription/views.rs:213- Subscribing to a shared view can now cost a full re-evaluation.attachjoins a live view at once only whenlive.latest.revision >= revision, whererevisionis the graph's current snapshot revision (connection.rs:92). A view's revision only moves forward when the view itself refreshes, and that happens only when its dependencies change. So after any write to an unrelated relation of the same knowledge graph, every new subscriber to a clean shared view takes the Waiting path, which starts an evaluation (it is coalesced while one is in flight). Example: subscribe to?a(X), then+b(1)in the same graph, then a second client subscribes to?a(X). The second client now waits for?a(X)to be re-evaluated, where before it joined the cached result. This is correct and conservative: it makes a subscription'srevisionusable asexpect_revisionwithout spurious refusals. On graphs with many writes and many shared subscribers it adds evaluation load. This is a deliberate tradeoff (commit b3c3300), noted for awareness only.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
cargo build --bin inputlayer-server, then started it on a throwaway data dir (/tmp, port 18731) withINPUTLAYER_ADMIN_PASSWORD; drove it over real WebSocket connections using a Pythonwebsocketsclient in a disposable venvdrive.py: scenarios S1–S10 (strict commit, in-scope write refusal, whole-graph scope, foreign epoch, malformed expectations, 6-client race, shared-view join at the current revision, dependency-write and rule-change adversarial checks, stale-then-fresh revision)latency.py 400: built an 80,200-row transitive-closure shared view and timed subscribe after no write, after an unrelated write and after a dependency writecargo test --test ws_expect_revision_tests(5 passed)cargo test --lib -- expect_revision precondition subscription::connection subscription::views(50 passed, includingan_unrelated_write_lets_a_new_subscriber_join_at_the_current_revision)✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.