8000 feat(parser): read transact and retract one fact at a time; cow_update (#550 PR 1) by adityamukho · Pull Request #684 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

feat(parser): read transact and retract one fact at a time; cow_update (#550 PR 1) - #684

Merged
adityamukho merged 3 commits into
v3from
feat/550-parser
Oct 22, 2026
Merged

adityamukho merged 3 commits into
v3from
feat/550-parser

Conversation

@adityamukho
8000 Copy link
Copy Markdown
Collaborator

PR 1 of 3 for #550 (streaming transactions, part of #473). Spec: docs/superpowers/specs/2026-10-21-streaming-transactions-design.md (#683). Plan: docs/superpowers/plans/2026-10-21-550-streaming-transactions.md (added here).

No change in behaviour: every statement still takes the small path.

Parser (spec §3)

  • Parser reads tokens on demand from a Lexer (byte offsets, keeps its first error); parse_edn finishes lexing before reporting, so a lexer error still beats a structure error. A keep flag checks structure without holding values.
  • transact/retract go to parser/statement.rs, which holds one fact at a time and reports today's error: the first error of the earliest phase (tokens, structure, command, fact, materialisation, valid windows). Phase 3 runs in today's check order, which is not text order (PRS-075 before PRS-042).
  • read_statement (pass 1) keeps at most TX_CHUNK_FACTS (16,384 until PR 3's measurement) materialised facts. A larger statement is read again (pass 2) from the offset after the last kept fact; Statement::facts appends the chunks for now.
  • Materialisation and window errors are returned with the facts, so Minigraf::execute still gives API-014 on a read-only database before them.

B+tree (spec §6)

  • btree::cow_update(root, inserts, deletes, …): deletes then inserts in one copy-on-write descent. An emptied leaf or internal node leaves its parent, an emptied tree is root 0, a missing/unsorted/repeated delete is INT-049. cow_insert is cow_update with no deletes.

Deviations from the spec (plan decisions 6, 7, 11)

  • Pass 1 keeps TX_CHUNK_FACTS facts, not + 1, and marks the statement large when one more follows; the acceptance bound then holds exactly.
  • Phase 5–6 errors are deferred to Statement::facts to keep the read-only order.
  • PageAllocator::release moves to PR 2, its first caller.

Tests

  • Differential: the old whole-input parser (kept under cfg(test)) against the reader over every 0–3 token sequence of 34 statement tokens in 10 templates plus a multi-error corpus, same command or error, and the same facts or error through the write path at chunk sizes 1, 2, 3 and default; asserts 24 codes are reached and pass 2 runs.
  • cow_update property tests against a BTreeSet model (0–60K keys, random and contiguous deletes), verify-style walk each step, old pages unchanged, freed exact; delete-all → root 0.
  • Full suite: 1,735 tests (1,721 passing, 14 ignored). Clippy clean incl. both wasm targets. Codex review: no findings.

🤖 Generated with Claude Code

https://claude.ai/code/session_019kY61Y11gcRD91Y6b7jbGT

adityamukho and others added 2 commits October 21, 2026 21:26
#550)

PR 1 of #550 (streaming transactions), no change in behaviour.

The parser reads tokens on demand from a Lexer instead of a whole-input
Vec<Token>. transact and retract go to a statement reader that holds one
fact at a time and keeps today's error order: errors are found in phases
(tokens, EDN structure, the command, each fact, materialisation, valid
windows), and the reader reports the first error of the earliest phase,
with the command phase in today's check order. Pass 1 keeps at most
TX_CHUNK_FACTS materialised facts; a larger statement is read again
(pass 2) from the offset after the last kept fact. Every statement still
takes the small path: Statement::facts appends pass 2's chunks.
Materialisation and window errors come with the facts, so a read-only
database still reports API-014 before them.

btree::cow_update applies sorted deletes and inserts copy-on-write in one
descent: a leaf or internal node left empty leaves its parent, a tree
left empty is root 0, and a delete of a missing key is INT-049.
cow_insert is cow_update with no deletes.

Differential tests run the old whole-input parser (kept under cfg(test))
against the reader at chunk sizes 1-3; property tests check cow_update
against a BTreeSet model.

Plan: docs/superpowers/plans/2026-10-21-550-streaming-transactions.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kY61Y11gcRD91Y6b7jbGT
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kY61Y11gcRD91Y6b7jbGT
@codecov
codecov Bot commented Oct 21, 2026
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.50102% with 27 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/query/datalog/parser.rs 89.89% 19 Missing ⚠️
src/query/datalog/parser/statement.rs 97.67% 5 Missing ⚠️
src/db.rs 90.90% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@adityamukho
adityamukho merged commit 3ea155b into v3 Oct 22, 2026
24 of 25 checks passed
@adityamukho
adityamukho deleted the feat/550-parser branch October 22, 2026 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0