[P1] Expose Tree-sitter query/capture APIs to Prolog #97

Closed
opened 2026-08-18 14:15:17 +00:00 by lost-rob0t · 4 comments
lost-rob0t commented 2026-08-18 14:15:17 +00:00 (Migrated from github.com)

Parent: #93
Depends on: #94, #95, #96

Goal

Expose Tree-sitter's structural query engine to Prolog so language adapters can be expressed mostly as declarative query packs plus Prolog normalization rules rather than hard-coded C tree walkers.

Required low-level query surface

Provide repository-convention predicates equivalent in semantics to:

ts_query_compile(+Language, +QuerySource, -Query).
ts_query_capture(+Query, +TreeOrParse, -Capture, -Node).
ts_query_match(+Query, +TreeOrParse, -Match).
ts_query_range(+QueryCursor, +Range, -Outcome).

Exact names/arity may differ. Support enough query metadata to report compile errors with byte/point information and error kind.

Query execution must preserve the owning language/tree lifetime rules established by #94.

Prolog-first language adapters

Keep language-specific extraction logic out of C.

Support query packs conceptually like:

languages/python/
  definitions.scm
  references.scm
  calls.scm
  imports.scm

languages/javascript/
  definitions.scm
  references.scm
  calls.scm
  imports.scm

The concrete on-disk convention may be refined, but the API must allow a language adapter to register named query purposes without modifying the foreign layer.

Example semantic shape:

language_query(python, definitions, QueryRef).
language_query(python, calls, QueryRef).

Query provenance

A capture used to create KB facts must be attributable to:

  • language;
  • grammar identity/version;
  • query pack/query identity/version or content hash;
  • parse generation;
  • captured node source span.

Changing a query pack must not leave old extracted facts silently looking current.

Capture model

Represent capture names as safe atoms/strings and captured syntax nodes through the #96 node identity model.

Support multiple captures per match without losing match grouping. For example a function-definition match may capture both the definition node and the name node; a call match may capture caller context and callee expression.

Do not force callers to reconstruct grouping from a flattened capture stream if Tree-sitter exposes match boundaries.

Predicate/query safety

Tree-sitter query source is data consumed by Tree-sitter. It must never be converted into arbitrary Prolog callables or directives.

Language query packs are availability/extraction configuration, not execution authority.

Malformed query source returns a structured compile error; it must not crash the Prolog process.

Performance / bounded execution

Support bounded query execution over:

  • whole parse;
  • a syntax subtree;
  • an explicit byte/point range where Tree-sitter permits;
  • selected named query packs.

Avoid forcing a full materialized #96 CST merely to run a query when the native tree is available.

Acceptance criteria

  • Prolog can compile and execute a Tree-sitter query against a parsed tree.
  • Query compile errors include structured location/type information.
  • Captures preserve capture names, node identities, and match grouping.
  • The same generic query API works for at least three grammars.
  • Python definitions can be extracted by a query pack without Python-specific C code.
  • JavaScript definitions/calls can be extracted by a different query pack through the same API.
  • Query execution can be limited to a subtree/range where supported.
  • Query-pack provenance/version is available to downstream semantic facts.
  • Replacing a query pack can be detected as a new extraction generation rather than silently reusing old facts.
  • Malformed/adversarial query text cannot execute Prolog or crash the runtime.
  • Deterministic tests cover zero matches, multiple matches, nested captures, repeated capture names, malformed queries, grammar/query mismatch, Unicode ranges, and query reload.

Non-goals

  • No universal semantic ontology in this issue.
  • No requirement that every grammar ship identical capture names.
  • No language-specific C visitors.
  • No model-generated unrestricted executable Prolog.

Refs #93 #94 #95 #96

Parent: #93 Depends on: #94, #95, #96 ## Goal Expose Tree-sitter's structural query engine to Prolog so language adapters can be expressed mostly as declarative query packs plus Prolog normalization rules rather than hard-coded C tree walkers. ## Required low-level query surface Provide repository-convention predicates equivalent in semantics to: ```prolog ts_query_compile(+Language, +QuerySource, -Query). ts_query_capture(+Query, +TreeOrParse, -Capture, -Node). ts_query_match(+Query, +TreeOrParse, -Match). ts_query_range(+QueryCursor, +Range, -Outcome). ``` Exact names/arity may differ. Support enough query metadata to report compile errors with byte/point information and error kind. Query execution must preserve the owning language/tree lifetime rules established by #94. ## Prolog-first language adapters Keep language-specific extraction logic out of C. Support query packs conceptually like: ```text languages/python/ definitions.scm references.scm calls.scm imports.scm languages/javascript/ definitions.scm references.scm calls.scm imports.scm ``` The concrete on-disk convention may be refined, but the API must allow a language adapter to register named query purposes without modifying the foreign layer. Example semantic shape: ```prolog language_query(python, definitions, QueryRef). language_query(python, calls, QueryRef). ``` ## Query provenance A capture used to create KB facts must be attributable to: - language; - grammar identity/version; - query pack/query identity/version or content hash; - parse generation; - captured node source span. Changing a query pack must not leave old extracted facts silently looking current. ## Capture model Represent capture names as safe atoms/strings and captured syntax nodes through the #96 node identity model. Support multiple captures per match without losing match grouping. For example a function-definition match may capture both the definition node and the name node; a call match may capture caller context and callee expression. Do not force callers to reconstruct grouping from a flattened capture stream if Tree-sitter exposes match boundaries. ## Predicate/query safety Tree-sitter query source is data consumed by Tree-sitter. It must never be converted into arbitrary Prolog callables or directives. Language query packs are availability/extraction configuration, not execution authority. Malformed query source returns a structured compile error; it must not crash the Prolog process. ## Performance / bounded execution Support bounded query execution over: - whole parse; - a syntax subtree; - an explicit byte/point range where Tree-sitter permits; - selected named query packs. Avoid forcing a full materialized #96 CST merely to run a query when the native tree is available. ## Acceptance criteria - [ ] Prolog can compile and execute a Tree-sitter query against a parsed tree. - [ ] Query compile errors include structured location/type information. - [ ] Captures preserve capture names, node identities, and match grouping. - [ ] The same generic query API works for at least three grammars. - [ ] Python definitions can be extracted by a query pack without Python-specific C code. - [ ] JavaScript definitions/calls can be extracted by a different query pack through the same API. - [ ] Query execution can be limited to a subtree/range where supported. - [ ] Query-pack provenance/version is available to downstream semantic facts. - [ ] Replacing a query pack can be detected as a new extraction generation rather than silently reusing old facts. - [ ] Malformed/adversarial query text cannot execute Prolog or crash the runtime. - [ ] Deterministic tests cover zero matches, multiple matches, nested captures, repeated capture names, malformed queries, grammar/query mismatch, Unicode ranges, and query reload. ## Non-goals - No universal semantic ontology in this issue. - No requirement that every grammar ship identical capture names. - No language-specific C visitors. - No model-generated unrestricted executable Prolog. Refs #93 #94 #95 #96
Owner

RAGE handoff from slice #96 (PR #342)

Where this loop begins

  1. Dependency gate (resolved): this issue depended on #94, #95, #96 (PR #342) — all three are now merged to main (#342 merged 2026-09-02T19:26:52Z). Dependency gate is closed; the queue was re-read per the #334 hardening-lane contract at slice start. (Stale "not yet merged" blocker prose removed 2026-09-02 during #97 realization closeout.)
  2. Worktree: fresh ~/git/worktrees/prolog-rlm-issue-97 from current main (branch rage/97-query-capture-apis). Reuse-if-exists rule applies; never create a second worktree for a checked-out branch.
  3. Run identity: initialize the run log with ~/.config/opencode/skills/rage/scripts/init-run.py 97 query-capture-apis --repo <checkout>. It records the immutable 40-char start SHA on branch rage/97-query-capture-apis; the run-log org file (rage/97-query-capture-apis.org) opens with the established * Run identity block.
  4. Mode: ADADR (control plane research/README.md, human-gated). The loop begins at Analyze/research — not implementation. Research approval authorizes design only; design approval authorizes implementation.

Contracts inherited from #94/#95/#96 that constrain this slice

  • Native handles stay private to the trusted parse operation; captures must project through the #96 closed node-identity model (rlm_project_syntax generations), never raw pointers.
  • Query source is data consumed by Tree-sitter — never converted to Prolog callables/directives; malformed query text yields structured compile errors with byte/point info, must not crash the runtime.
  • Grammar/query packs remain inert registration + trusted host activation (mirror the #96 transactional rlm_project_grammar_pack pattern); no pack grants execution/filesystem/network authority.
  • Provenance: language, grammar identity, query-pack content hash/identity, parse generation, captured span; replacing a query pack must yield a new extraction generation, never silently-current old facts.
  • Bounded execution over parse/subtree/byte-range; avoid forcing full #96 CST materialization when the native tree is available.
  • Preserve the canonical async direction (*_execute -> Future -> sync await) for any native materialization; cancellation/deadline semantics like #96.

Environmental intelligence from slice #96

  • Local native verification route: make tree-sitter-ffi inside nix develop (pkg-config tree-sitter); full grammar-bundle evidence via nix flake check path:. --no-update-lock-file --print-build-logs. The /usr/src/tree-sitter sources in scripts/build-tree-sitter-test-grammars.sh are CI-only provisioning (Ubuntu dev packages).
  • Tree-sitter 0.20.x API compatibility is a live constraint (v0.20.8 headers compile-checked in #96); query-engine API surface must be checked against 0.20 as well.
  • Paid OpenRouter lane (z-ai/glm-5.3-flash, repo var OPENROUTER_TEST_MODEL) is stochastic: #343 showed a one-off core_minimal_depth_1 verification-rejected answer that local replication cleared 6/6. Remedy for a red paid gate: confirm model pinning, replicate locally at exact head, re-run the job — never weaken the gate or claim fake-provider evidence.
  • Pre-existing #329 singleton warnings are unchanged noise; don't absorb them into this slice.

Suggested scope discipline (non-goals from #96 carry forward)

No universal semantic ontology (#98 owns normalization), no incremental reparsing (#99), no planner/product behavior, no second scheduler. Query packs: python definitions + javascript definitions/calls through one generic API as minimum grammar coverage.

## RAGE handoff from slice #96 (PR #342) ### Where this loop begins 1. **Dependency gate (resolved)**: this issue depended on #94, #95, #96 (PR #342) — all three are now **merged to `main`** (#342 merged 2026-09-02T19:26:52Z). Dependency gate is closed; the queue was re-read per the #334 hardening-lane contract at slice start. *(Stale "not yet merged" blocker prose removed 2026-09-02 during #97 realization closeout.)* 2. **Worktree**: fresh `~/git/worktrees/prolog-rlm-issue-97` from current `main` (branch `rage/97-query-capture-apis`). Reuse-if-exists rule applies; never create a second worktree for a checked-out branch. 3. **Run identity**: initialize the run log with `~/.config/opencode/skills/rage/scripts/init-run.py 97 query-capture-apis --repo <checkout>`. It records the immutable 40-char start SHA on branch `rage/97-query-capture-apis`; the run-log org file (`rage/97-query-capture-apis.org`) opens with the established `* Run identity` block. 4. **Mode**: ADADR (control plane `research/README.md`, human-gated). The loop begins at **Analyze/research** — not implementation. Research approval authorizes design only; design approval authorizes implementation. ### Contracts inherited from #94/#95/#96 that constrain this slice - Native handles stay private to the trusted parse operation; captures must project through the **#96 closed node-identity model** (`rlm_project_syntax` generations), never raw pointers. - Query source is **data consumed by Tree-sitter** — never converted to Prolog callables/directives; malformed query text yields structured compile errors with byte/point info, must not crash the runtime. - Grammar/query packs remain **inert registration + trusted host activation** (mirror the #96 transactional `rlm_project_grammar_pack` pattern); no pack grants execution/filesystem/network authority. - Provenance: language, grammar identity, query-pack content hash/identity, parse generation, captured span; replacing a query pack must yield a **new extraction generation**, never silently-current old facts. - Bounded execution over parse/subtree/byte-range; avoid forcing full #96 CST materialization when the native tree is available. - Preserve the canonical async direction (`*_execute -> Future -> sync await`) for any native materialization; cancellation/deadline semantics like #96. ### Environmental intelligence from slice #96 - Local native verification route: `make tree-sitter-ffi` inside `nix develop` (pkg-config tree-sitter); full grammar-bundle evidence via `nix flake check path:. --no-update-lock-file --print-build-logs`. The `/usr/src/tree-sitter` sources in `scripts/build-tree-sitter-test-grammars.sh` are CI-only provisioning (Ubuntu dev packages). - Tree-sitter **0.20.x API compatibility** is a live constraint (v0.20.8 headers compile-checked in #96); query-engine API surface must be checked against 0.20 as well. - Paid OpenRouter lane (`z-ai/glm-5.3-flash`, repo var `OPENROUTER_TEST_MODEL`) is stochastic: #343 showed a one-off `core_minimal_depth_1` verification-rejected answer that local replication cleared 6/6. Remedy for a red paid gate: confirm model pinning, replicate locally at exact head, re-run the job — never weaken the gate or claim fake-provider evidence. - Pre-existing #329 singleton warnings are unchanged noise; don't absorb them into this slice. ### Suggested scope discipline (non-goals from #96 carry forward) No universal semantic ontology (#98 owns normalization), no incremental reparsing (#99), no planner/product behavior, no second scheduler. Query packs: python definitions + javascript definitions/calls through one generic API as minimum grammar coverage.
Owner

Research approval recorded (ADADR control plane)

The research phase for this slice is approved; design work is authorized. Implementation remains blocked until the separate design-approval gate.

  • Record: research/tree-sitter-query-capture.org — RLM-RESEARCH-012 "Tree-sitter query/capture APIs through the #94 FFI"
  • Approval schema: prolog-rlm.research-approval.v1, #+approval_state: APPROVED
  • Actor: human operator (in-Emacs review; evidence verbatim: "I approved it as the human after reviewing it.")
  • Reviewed content: commit 4ab728553c65b574c440066f02aadbf9e9893225, blob 1974058b0ad9b1ed0d1596a09810e5f2523eb837 (binding machine-checked via git rev-parse --verify)
  • Decided at: 2026-09-02T20:26:54Z · validator make research-approval PASS (20 tracked files)
  • Branch/run log: rage/97-query-capture-apis, base 156bfe9b2caffa1b967e77bee51263ee9e85fb50

What the next slice consumer inherits

  • Resolved operator decisions: parse-generation reuse only when provably the same generation; query-extraction facts live in their own rlm_project_query-style sibling module (not inside rlm_project_syntax); the on-disk project KB persists under $PROJECT_ROOT/.kb/<kb tree> (operator-clarified epic intent, first recorded in this slice and on epic #93: https://github.com/lost-rob0t/prolog-rlm/issues/93#issuecomment-5515841794).
  • Designated open research question for the design phase: exact extraction-generation record shape and .kb tree layout (path scheme, journal/snapshot cadence, backend-neutral facade API) — the design must answer it from existing persist(File) precedent evidence or spawn bounded research first; the kill -9 restart fixture is its acceptance criterion.
  • Verified 0.20.x constraints: v0.20.8 api.h surface confirmed (26 query functions; 5 newer functions excluded); no native mid-scan query timeout → Prolog-driven step deadlines + match limit; predicates are host-evaluated → smallest slice rejects predicate-bearing packs structurally.
  • Repeated-capture-name representation (ordered capture list per match) is explained in rage/97-query-capture-notes.org awaiting operator confirmation.
## Research approval recorded (ADADR control plane) The research phase for this slice is **approved**; design work is authorized. Implementation remains blocked until the separate design-approval gate. - Record: `research/tree-sitter-query-capture.org` — **RLM-RESEARCH-012** "Tree-sitter query/capture APIs through the #94 FFI" - Approval schema: `prolog-rlm.research-approval.v1`, `#+approval_state: APPROVED` - Actor: human operator (in-Emacs review; evidence verbatim: "I approved it as the human after reviewing it.") - Reviewed content: commit `4ab728553c65b574c440066f02aadbf9e9893225`, blob `1974058b0ad9b1ed0d1596a09810e5f2523eb837` (binding machine-checked via `git rev-parse --verify`) - Decided at: `2026-09-02T20:26:54Z` · validator `make research-approval` PASS (20 tracked files) - Branch/run log: `rage/97-query-capture-apis`, base `156bfe9b2caffa1b967e77bee51263ee9e85fb50` ### What the next slice consumer inherits - **Resolved operator decisions**: parse-generation reuse only when provably the same generation; query-extraction facts live in their own `rlm_project_query`-style sibling module (not inside `rlm_project_syntax`); the on-disk project KB persists under `$PROJECT_ROOT/.kb/<kb tree>` (operator-clarified epic intent, first recorded in this slice and on epic #93: <https://github.com/lost-rob0t/prolog-rlm/issues/93#issuecomment-5515841794>). - **Designated open research question for the design phase**: exact extraction-generation record shape and `.kb` tree layout (path scheme, journal/snapshot cadence, backend-neutral facade API) — the design must answer it from existing `persist(File)` precedent evidence or spawn bounded research first; the kill -9 restart fixture is its acceptance criterion. - **Verified 0.20.x constraints**: v0.20.8 `api.h` surface confirmed (26 query functions; 5 newer functions excluded); no native mid-scan query timeout → Prolog-driven step deadlines + match limit; predicates are host-evaluated → smallest slice rejects predicate-bearing packs structurally. - Repeated-capture-name representation (ordered capture list per match) is explained in `rage/97-query-capture-notes.org` awaiting operator confirmation.
Owner

Design approval recorded (ADADR control plane) — realization handed to a fresh slice

The approved design is recorded in rage/97-query-capture-apis.org §Design phase on rage/97-query-capture-apis (design head bb729f427eb9e711964ca1474ec513c8d9ca6349 at approval, base research commit 4ab728553c65b574c440066f02aadbf9e9893225).

  • Design approval: APPROVED by the human operator, decided 2026-09-02T20:35:55Z; evidence recorded in the committed run log (#+design_approval_* block).
  • Operator direction: the Realize (TDD implementation) phase is executed by a fresh prompt slice, not the research/design session.
  • Handoff work order: rage/97-query-capture-realize-prompt.md (in-repo, same branch) — start evidence, approved-design summary, full TDD surface incl. the kill -9 .kb restart fixture, 0.20.x constraints, exact-head verification, PR/closing rules.
  • Scope boundary for the next worker: implement within the approved design only; #98/#99 and the predicate evaluator remain non-goals.

State: research APPROVED → design APPROVED → implementation authorized (next slice).

## Design approval recorded (ADADR control plane) — realization handed to a fresh slice The approved design is recorded in `rage/97-query-capture-apis.org` §Design phase on `rage/97-query-capture-apis` (design head `bb729f427eb9e711964ca1474ec513c8d9ca6349` at approval, base research commit `4ab728553c65b574c440066f02aadbf9e9893225`). - Design approval: **APPROVED** by the human operator, decided `2026-09-02T20:35:55Z`; evidence recorded in the committed run log (`#+design_approval_*` block). - Operator direction: the Realize (TDD implementation) phase is executed by a **fresh prompt slice**, not the research/design session. - Handoff work order: `rage/97-query-capture-realize-prompt.md` (in-repo, same branch) — start evidence, approved-design summary, full TDD surface incl. the kill -9 `.kb` restart fixture, 0.20.x constraints, exact-head verification, PR/closing rules. - Scope boundary for the next worker: implement within the approved design only; #98/#99 and the predicate evaluator remain non-goals. State: research APPROVED → design APPROVED → implementation authorized (next slice).
Owner

Realization complete — merged via Forgejo PR nsaspy/prolog-rlm#294

Implemented within the approved design (RLM-RESEARCH-012: research APPROVED → design APPROVED → realization authorized; both gates recorded above).

Merged state

  • Forgejo PR nsaspy/prolog-rlm#294 — merged into main, merge commit 037ea1f149a8…, exact reviewed head 6153b00a4cfd… (implementation commit c24e87c…; commits after it carry only the verifier evidence journal + .gitignore).
  • The layer sits below both runtime modes: no changes to rlm_direct, rlm_completion, rlm_plan, prompt compilation, SPEC, VERIFY, or any expert-tool abstraction.

Evidence (machine-recorded at exact head 13efeac… via the worktree verifier; prolog-verify check = pass)

  • Focused suites rlm_tree_sitter_query + rlm_project_query + fresh-process SIGKILL restart fixture: 20/20.
  • Full deterministic suite: 1179/1179; check_runtime, load_all (static load without optional FFI) pass.
  • Benchmark deterministic 16/16 (quality 1.00), deep-experiment 15/15; CLI demo --json pass.
  • Native make tree-sitter-ffi in nix develop pass; nix flake check path:. 4/4; git diff --check clean.
  • Note: Forgejo Actions is failing repository-wide (infrastructure side; service restart pending), so per operator decision the local gate set is the evidence of record for this slice. The two incompatible-ABI grammar tests remain covered by CI's grammar-script fixture once Actions is patched (pre-existing local-environment limitation).

Acceptance criteria → named deterministic tests (all at merged head)

Criterion Test(s)
Compile + execute query against parsed tree compile_metadata_and_match_grouping, next_capture_preserves_match_group
Structured compile errors with byte/point + kind compile_error_has_kind_and_byte_offset, malformed_pack_query_has_structured_location
Capture names, node identities (#96), match grouping captures_are_grouped_and_provenance_complete, next_capture_preserves_match_group
Same generic API, ≥3 grammars python_and_javascript_use_the_same_generic_query_api + c provenance test (python, javascript, c)
Python definitions, no Python-specific C query-pack extraction in rlm_project_query suite
JS definitions/calls via same API python_and_javascript_use_the_same_generic_query_api
Subtree / byte-range bounded execution subtree_and_byte_range_execution_are_bounded, cursor_ranges_and_close_are_structured
Query-pack provenance/version downstream captures_are_grouped_and_provenance_complete (grammar ref, pack hash, parse generation, span, source SHA-256)
Pack replacement = new extraction generation, never silently current replacing_a_pack_stales_old_extraction_and_changes_hash + publication-fencing tests (new_parse_publication_fences_prior_records_stale, reused_parse_publication_fences_prior_extraction_stale, journaled fencing surviving restart)
Adversarial query text cannot execute Prolog / crash query_source_is_data_not_a_callable, predicate_bearing_packs_are_rejected_without_evaluation, wrong_grammar_and_callable_source_fail_closed
Zero/multiple matches, repeated capture names, malformed, grammar mismatch, Unicode ranges, query reload zero_and_multiple_matches_remain_structured, malformed_pack_query_has_structured_location, wrong_grammar_and_callable_source_fail_closed, unicode_points_use_tree_sitter_byte_columns, replacing_a_pack_stales_old_extraction_and_changes_hash + restart fixture

Follow-ups (not part of this issue): #98 semantic normalization and #99 freshness/invalidation consume the fenced current/stale substrate; #96/#97 lock order and journal compatibility must be preserved there. Parent epic #93 stays open.

Closing as completed: implementation merged to canonical main with deterministic coverage of every acceptance criterion.

## Realization complete — merged via Forgejo PR nsaspy/prolog-rlm#294 Implemented within the approved design (RLM-RESEARCH-012: research APPROVED → design APPROVED → realization authorized; both gates recorded above). **Merged state** - Forgejo PR [nsaspy/prolog-rlm#294](https://git.starintel.actor/nsaspy/prolog-rlm/pulls/294) — **merged** into `main`, merge commit `037ea1f149a8…`, exact reviewed head `6153b00a4cfd…` (implementation commit `c24e87c…`; commits after it carry only the verifier evidence journal + `.gitignore`). - The layer sits below both runtime modes: no changes to `rlm_direct`, `rlm_completion`, `rlm_plan`, prompt compilation, SPEC, VERIFY, or any expert-tool abstraction. **Evidence (machine-recorded at exact head `13efeac…` via the worktree verifier; `prolog-verify check` = pass)** - Focused suites `rlm_tree_sitter_query` + `rlm_project_query` + fresh-process `SIGKILL` restart fixture: 20/20. - Full deterministic suite: 1179/1179; `check_runtime`, `load_all` (static load without optional FFI) pass. - Benchmark `deterministic` 16/16 (quality 1.00), `deep-experiment` 15/15; CLI `demo --json` pass. - Native `make tree-sitter-ffi` in `nix develop` pass; `nix flake check path:.` 4/4; `git diff --check` clean. - Note: Forgejo Actions is failing repository-wide (infrastructure side; service restart pending), so per operator decision the local gate set is the evidence of record for this slice. The two incompatible-ABI grammar tests remain covered by CI's grammar-script fixture once Actions is patched (pre-existing local-environment limitation). **Acceptance criteria → named deterministic tests** (all at merged head) | Criterion | Test(s) | |---|---| | Compile + execute query against parsed tree | `compile_metadata_and_match_grouping`, `next_capture_preserves_match_group` | | Structured compile errors with byte/point + kind | `compile_error_has_kind_and_byte_offset`, `malformed_pack_query_has_structured_location` | | Capture names, node identities (#96), match grouping | `captures_are_grouped_and_provenance_complete`, `next_capture_preserves_match_group` | | Same generic API, ≥3 grammars | `python_and_javascript_use_the_same_generic_query_api` + `c` provenance test (python, javascript, c) | | Python definitions, no Python-specific C | query-pack extraction in `rlm_project_query` suite | | JS definitions/calls via same API | `python_and_javascript_use_the_same_generic_query_api` | | Subtree / byte-range bounded execution | `subtree_and_byte_range_execution_are_bounded`, `cursor_ranges_and_close_are_structured` | | Query-pack provenance/version downstream | `captures_are_grouped_and_provenance_complete` (grammar ref, pack hash, parse generation, span, source SHA-256) | | Pack replacement = new extraction generation, never silently current | `replacing_a_pack_stales_old_extraction_and_changes_hash` + publication-fencing tests (`new_parse_publication_fences_prior_records_stale`, `reused_parse_publication_fences_prior_extraction_stale`, journaled fencing surviving restart) | | Adversarial query text cannot execute Prolog / crash | `query_source_is_data_not_a_callable`, `predicate_bearing_packs_are_rejected_without_evaluation`, `wrong_grammar_and_callable_source_fail_closed` | | Zero/multiple matches, repeated capture names, malformed, grammar mismatch, Unicode ranges, query reload | `zero_and_multiple_matches_remain_structured`, `malformed_pack_query_has_structured_location`, `wrong_grammar_and_callable_source_fail_closed`, `unicode_points_use_tree_sitter_byte_columns`, `replacing_a_pack_stales_old_extraction_and_changes_hash` + restart fixture | **Follow-ups (not part of this issue):** #98 semantic normalization and #99 freshness/invalidation consume the fenced `current`/`stale` substrate; #96/#97 lock order and journal compatibility must be preserved there. Parent epic #93 stays open. Closing as completed: implementation merged to canonical `main` with deterministic coverage of every acceptance criterion.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/prolog-rlm#97
No description provided.