Skip to content

Resolve relation form coverage (2.6.6) - #263

Merged
leynos merged 26 commits into
mainfrom
2-6-6-resolve-relation-form-coverage
Jul 23, 2026
Merged

Resolve relation form coverage (2.6.6)#263
leynos merged 26 commits into
mainfrom
2-6-6-resolve-relation-form-coverage

Conversation

@lodyai

@lodyai lodyai Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds docs/execplans/2-6-6-resolve-relation-form-coverage.md — an
    ExecPlan for closing roadmap item 2.6.6 and conformance-register
    item 13 by widening the relation scanner and typed AST to cover
    the full Role × Kind × {paren, bracket} surface defined in
    docs/differential-datalog-parser-syntax-spec-updated.md §5.5.
  • Refreshes AGENTS.md to the upstream version from the memoryd
    1-1-1-record-evidence-store-engine-and-migration-policy branch.

Plan highlights

The plan was drafted with a planning subagent, validated against the
canonical archived upstream
(vmware-archive/differential-datalog, Parse.hs, last touched
2022-07-23) via firecrawl, then revised after a Logisphere
pre-implementation design review. Key decisions captured:

  • Symmetric AST: three-variant RelationRole { Input | Output | Internal } and RelationKind { Relation | Stream | Multiset },
    each paired with a *_keyword_present() predicate. Replaces the
    earlier asymmetric Option<RelationRole> proposal.
  • RelationBody enum (Fields | ElementType) for the paren/bracket
    body forms, with element_type() returning Option<&str> to honour
    the centralized Span→TextRange helper.
  • Five upstream deltas (D1–D5) folded into the spec doc in Milestone
    5: drop internal keyword, correct PrimaryKey shape, drop
    mandatory ;, add & ref form, cross-reference attribute prefix
    support.
  • Milestone 0 spike validates opaque preservation of spec-form
    lambda-style primary-key expressions before any scanner refactor
    lands; typed access deferred to follow-up 2.6.6.1.
  • Milestone 5 splits into three commits (spec deltas, ADR-002, user
    docs) so partial reviewer pushback does not bounce the rest.
  • proptest over the role × kind × body × ref × pk space is required
    in Milestone 3, not optional.
  • 8 stable diagnostics (D-REL-001..D-REL-008) with per-diagnostic
    recovery contracts and 23 parameterised rstest matrix cases plus
    4 behavioural cases.

Test plan

  • Run make markdownlint on the new ExecPlan and AGENTS.md.
  • Reviewers confirm the symmetric role/kind enum decision and the
    spec-delta reconciliation strategy.
  • Reviewers confirm the Milestone 0 spike scope and exit
    criteria.
  • Reviewers confirm the deferral of typed access to spec-form
    lambda primary keys (follow-up 2.6.6.1).

🤖 Generated with Claude Code

Summary by Sourcery

Document the execution plan and contributor guidelines for expanding relation form coverage and parser alignment work, without implementing any parser changes yet.

Documentation:

  • Add a detailed ExecPlan documenting milestones, decisions, risks, and test strategy for resolving relation role/kind/body-form coverage and aligning the parser with the updated syntax spec.
  • Refresh and expand AGENTS.md contributor guidance on documentation practices, testing strategy, refactoring workflow, dependency management, error handling, observability, and available tooling.

References

@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Changes

The parser now supports structured relation roles, kinds, reference markers, record or bracket bodies, primary-key diagnostics, and typed CST accessors. Cursor-based scanning adds recovery-aware parsing. Tests, property generators, documentation, spelling configuration, and quality-gate guidance were updated.

Relation Declaration Support

Layer / File(s) Summary
Typed relation AST surface
src/parser/ast/*, docs/adr-002-relation-role-kind-modelling.md
Adds typed relation metadata, CST inspection, public exports, and fallible body and primary-key accessors.
Cursor-driven relation scanner
src/parser/span_scanners/relations/*, src/parser/span_scanner.rs
Parses relation preambles, bodies, suffixes, diagnostics, recovery, and top-level candidates with cursor helpers.
Relation parser validation
src/parser/tests/*, tests/relation_form_grammar.rs, src/tokenizer.rs, Cargo.toml
Adds matrix, property, integration, scanner-regression, tokenizer, lexer-error, attribute, and diagnostic coverage.
Relation grammar documentation
docs/*
Documents grammar, AST contracts, diagnostics, conformance, execution plans, roadmap scope, and implementation notes.

Quality Gate Guidance

Layer / File(s) Summary
Quality-gate and spelling configuration
AGENTS.md, typos.toml
Documents expanded formatting, linting, spelling, and test gates, and updates Typos mappings.

Possibly related PRs

Suggested reviewers: leynos

Poem

Roles align and bodies bloom,
Cursors guide through parser gloom.
Keys are checked, diagnostics sing,
Tests give every form its wing.
Docs and gates now march in tune.

🚥 Pre-merge checks | ✅ 20
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change and includes the roadmap item reference 2.6.6.
Description check ✅ Passed The description is directly related to the relation coverage and documentation changes in this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Testing (Overall) ✅ Passed New proptest, matrix, grammar, scanner, and AST tests exercise valid forms, invalid diagnostics, round-trips, and malformed cases without mocks.
User-Facing Documentation ✅ Passed docs/users-guide.md documents the new relation syntax surface, defaults, primary-key limits, and D-REL-001..008 diagnostics.
Developer Documentation ✅ Passed PASS: developers-guide, design docs, ADR-002, roadmap 2.6.6, and the ExecPlan all reflect the relation API/tooling changes; no extra locale docs were found.
Module-Level Documentation ✅ Passed All touched Rust modules carry top-level //! docs, and the new scanner/AST modules explain their purpose and relationship to neighbours.
Testing (Unit And Behavioural) ✅ Passed PASS: Unit tests cover malformed bodies, primary-key errors, defaults and invariants; behavioural tests hit public ddlint::parse and assert accepted/rejected relation forms.
Testing (Property / Proof) ✅ Passed PASS: docs/execplans/... recommends proptest, and src/parser/tests/relation_proptest.rs adds a real generator over role/kind/body/ref/pk with round-trip and accessor checks.
Testing (Compile-Time / Ui) ✅ Passed PASS: The new relation coverage is exercised with runtime tests/proptest; no compile-time-only or broad UI-output surface was introduced.
Unit Architecture ✅ Passed PASS: relation accessors now surface fallibility via Result, scanner helpers are local and side-effect free, and no env/fs/network/global state use appears in touched modules.
Domain Architecture ✅ Passed PASS: The PR stays within parser/AST/docs boundaries; no HTTP, SQL, filesystem, env, or other adapter concerns appear in the changed code.
Observability ✅ Passed PASS: Parser changes surface failures via stable D-REL diagnostics and Result-returning accessors, so failures are diagnosable without extra telemetry.
Security And Privacy ✅ Passed PASS: The modified files are docs/tests/parser code only, and scans found no secrets, credentials, auth changes, or unsafe string-built sinks.
Performance And Resource Use ✅ Passed All new scans stay linear and bounded; the only notable allocations are intentional AST extraction trade-offs, documented in the ADR.
Concurrency And State ✅ Passed PASS: The touched parser/scanner code is single-owner and synchronous; no locks, async tasks, globals, or shared caches were introduced, and state stays local to each parse.
Architectural Complexity And Maintainability ✅ Passed PASS: relation/preamble/cursor modules isolate real seams, remove duplicate scans, and keep dependencies explicit; no generic framework, hidden hooks, or cycles introduced.
Rust Compiler Lint Integrity ✅ Passed No dead_code/unused suppressions were added; only test-scoped clippy::expect_used appears, and clone() usage is limited to spans, Strings, and parser combinators.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2-6-6-resolve-relation-form-coverage

Comment @coderabbitai help to get the list of available commands.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@sourcery-ai

sourcery-ai Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Refreshes AGENTS.md from upstream with clarified documentation, testing, and tooling guidelines, and adds a detailed ExecPlan document for roadmap item 2.6.6 that specifies how to extend the parser’s relation handling (role/kind/body forms, diagnostics, tests, milestones, and documentation updates).

File-Level Changes

Change Details Files
Refresh AGENTS.md guidelines to align with upstream wording and expand internal standards for documentation, testing, error handling, and observability.
  • Rephrase existing guidance for file-size limits, refactoring heuristics, and change quality/committing for clarity and consistency (e.g., wording, headings, and bullet structure).
  • Expand documentation maintenance rules to require ADRs for substantive decisions, explicit user/internal docs updates, and adherence to a documentation style guide.
  • Tighten testing policy to cover unit, behavioural, end-to-end, property, model-checking, and proof-based tests, including preferred crates and patterns for fixtures, mocks, and env-var handling.
  • Refine Rust coding guidelines around newtypes, error handling, lints, and expectations for using expect/unwrap, cap_std, and other ecosystem choices.
  • Add explicit testing, dependency management, error-handling, observability, and markdown-wrapping rules, plus a curated description of available debugging/performance tools in the environment.
AGENTS.md
Introduce an ExecPlan document that defines the design, milestones, and testing strategy for resolving relation form coverage in the parser (roadmap item 2.6.6).
  • Describe the target grammar and AST model for relation declarations, including symmetric RelationRole/RelationKind enums, RelationBody enum, and handling of ref forms and primary keys.
  • Document spec deltas against upstream DDlog, their reconciliation strategy, and the decision to preserve opaque primary-key expressions for now with a follow-up for typed access.
  • Lay out milestones for tokenizer audit, scanner refactor, typed AST introduction, primary-key handling, spec/docs updates, and verification, each with constraints, risks, and rollback strategies.
  • Define required diagnostics, recovery behaviour, and a comprehensive test matrix (including rstest and proptest) over role×kind×body×ref×primary-key combinations.
  • Capture decisions, risks, definition of done, validation commands, and references so reviewers can verify completeness and alignment with roadmap and conformance register items.
docs/execplans/2-6-6-resolve-relation-form-coverage.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos

leynos commented Jun 17, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

src/parser/tests/relation_proptest.rs

Comment on lines +42 to +58

    fn new(
        role: GeneratedRole,
        kind: GeneratedKind,
        body: GeneratedBody,
        is_ref: bool,
        wants_primary_key: bool,
    ) -> Self {
        let has_primary_key =
            wants_primary_key && role == GeneratedRole::Input && body == GeneratedBody::Record;
        Self {
            role,
            kind,
            body,
            is_ref,
            has_primary_key,
        }
    }

❌ New issue: Excess Number of Function Arguments
GeneratedRelation.new has 5 arguments, max arguments = 4

1 similar comment
@leynos

leynos commented Jun 17, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

src/parser/tests/relation_proptest.rs

Comment on lines +42 to +58

    fn new(
        role: GeneratedRole,
        kind: GeneratedKind,
        body: GeneratedBody,
        is_ref: bool,
        wants_primary_key: bool,
    ) -> Self {
        let has_primary_key =
            wants_primary_key && role == GeneratedRole::Input && body == GeneratedBody::Record;
        Self {
            role,
            kind,
            body,
            is_ref,
            has_primary_key,
        }
    }

❌ New issue: Excess Number of Function Arguments
GeneratedRelation.new has 5 arguments, max arguments = 4

@coderabbitai

This comment was marked as resolved.

@leynos

leynos commented Jun 20, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Excess Number of Function Arguments

src/parser/tests/relation_proptest.rs: GeneratedRelation.new

What lead to degradation?

GeneratedRelation.new has 5 arguments, max arguments = 4

Why does this problem occur?

Functions with many arguments indicate either a) low cohesion where the function has too many responsibilities, or b) a missing abstraction that encapsulates those arguments.
The threshold for the Rust language is 4 function arguments.

How to fix it?

Start by investigating the responsibilities of the function. Make sure it doesn't do too many things, in which case it should be split into smaller and more cohesive functions. Consider the refactoring INTRODUCE PARAMETER OBJECT to encapsulate arguments that refer to the same logical concept.

@coderabbitai

This comment was marked as resolved.

@pandalump
pandalump marked this pull request as ready for review June 22, 2026 19:23
@coderabbitai coderabbitai Bot added the Roadmap label Jun 22, 2026
coderabbitai[bot]

This comment was marked as resolved.

@leynos leynos changed the title Plan: resolve relation form coverage (2.6.6) Resolve relation form coverage (2.6.6) Jun 23, 2026
@lodyai
lodyai Bot force-pushed the 2-6-6-resolve-relation-form-coverage branch from be786c0 to b88449c Compare July 4, 2026 00:48
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Jul 19, 2026

Copy link
Copy Markdown
Owner

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

@lodyai
lodyai Bot force-pushed the 2-6-6-resolve-relation-form-coverage branch from c45e708 to 1ffb4c1 Compare July 19, 2026 17:11
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

@leynos

leynos commented Jul 21, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following now been resolved?

docs/differential-datalog-parser-syntax-spec-updated.md (1)

95-105: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win
Remove internal from the reserved keyword list.
§5.5 models an internal relation as the absence of a role, and the current parser contract only accepts input relation, output relation, and bare relation forms. Keeping internal in the reserved set makes the keyword table contradict the grammar and the implemented surface.

Suggested wording fix
-- **Keywords:** `type`, `function`, `extern`, `transformer`, `input`, `output`,
-  `internal`,`relation`,`stream`,`multiset`,`index`,`on`,`primary`,`key`,`apply`,`match`,`if`,`else`,`for`,`in`,`then`,`skip`,`true`,`false`,`var`,`mut`,`return`,`break`,`continue`.
+- **Keywords:** `type`, `function`, `extern`, `transformer`, `input`, `output`,
+  `relation`,`stream`,`multiset`,`index`,`on`,`primary`,`key`,`apply`,`match`,`if`,`else`,`for`,`in`,`then`,`skip`,`true`,`false`,`var`,`mut`,`return`,`break`,`continue`.
@@
-- Absence of Role means an internal relation. `internal` is not a reserved
--  keyword.
+- Absence of Role means an internal relation; this is represented implicitly,
+  not by a dedicated `internal` keyword.

Also applies to: 256-284

🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/differential-datalog-parser-syntax-spec-updated.md around lines 95 -
105, Remove the keyword internal from the reserved keywords list in the
Keywords bullet point, as it contradicts the grammar specification in section
5.5 which models internal relations as the absence of a role and only accepts
input relation, output relation, and bare relation forms. The keyword list
currently includes internal between extern and transformer and should have
it removed to align the documentation with the actual parser contract.

src/parser/ast/parse_utils/relation.rs (1)

3-7: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Update the module docs after removing relation_columns().
Lines 3-7 still claim that this module parses relation column lists, but the remaining helper only parses primary key clauses. Keep the docs aligned with the reduced surface.

Proposed wording
-//! These helpers parse relation column lists and `primary key` clauses using
-//! `chumsky`, allowing callers to validate structure without manual token
-//! juggling.
-//! They are shared by the span scanner and AST helpers to keep behaviour
-//! consistent.
+//! These helpers parse relation `primary key` clauses using `chumsky`,
+//! allowing callers to validate structure without manual token juggling.
🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @src/parser/ast/parse_utils/relation.rs around lines 3 - 7, The module
documentation at the beginning of the relation.rs file (the comment starting
with "//! These helpers parse relation column lists") is outdated after the
removal of the relation_columns() function. Update the module-level
documentation comment to remove the mention of "relation column lists" and
clarify that the module only parses relation primary key clauses using chumsky,
keeping the rest of the documentation about validation and consistency behavior.

codescene-access[bot]

This comment was marked as outdated.

relation.rs:
- primary_key() now renders chumsky `Simple<SyntaxKind>` recovery errors as
  human-readable diagnostics (via reason/expected/found + token symbols)
  instead of Debug struct dumps, since `SyntaxKind` has no `Display`.
- Extract a shared `body_inspection_error` helper mapping
  `MalformedBracket`/`MissingDelimiter` to their error vectors; `body()`,
  `element_type()`, and `columns()` short-circuit through it before handling
  their `Record`/`Bracket` success cases. Results and messages unchanged.
- relation/tests.rs: `malformed_preamble_delimiters_do_not_leak_body_names`
  now asserts `relations().is_empty()`, so it fails if any candidate
  (even nameless) is emitted, keeping the source context.
- inspect.rs: expand the tests module `//!` doc to describe the malformed
  bracket, invalid column list, malformed primary-key binder, and missing
  delimiter coverage.

Docs:
- AGENTS.md and developers guide: add `make nixie` (Mermaid validation) to
  the pre-commit / maintained-Markdown workflow.
- users guide: fix the D-REL-008 message to match the scanner output
  (trailing apostrophe before the closing inline-code marker).
- spec + execplan D2: document that the local grammar accepts a
  comma-separated compound binder list, distinct from upstream's single
  lambda-style binder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@leynos

leynos commented Jul 22, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following now been resolved?

docs/developers-guide.md (1)

123-125: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Run make nixie for Mermaid diagrams.
Add it to this workflow so maintained Markdown containing Mermaid diagrams is

validated alongside make markdownlint.
Triage: [type:docstyle]

🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/developers-guide.md around lines 123 - 125, Update the Markdown
validation workflow in the developers guide to include make nixie alongside make
markdownlint for maintained Markdown containing Mermaid diagrams, while
preserving the existing lint instructions and AGENTS.md reference.

Source: Coding guidelines

docs/users-guide.md (1)

121-121: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Match the D-REL-008 message exactly.
Add the missing final apostrophe before the closing inline-code marker. The scanner emits remove the surrounding '['/']'; the table currently documents remove the surrounding '['/'], so the fixed diagnostic text is inaccurate.

🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/users-guide.md at line 121, Update the D-REL-008 entry in the
documentation table so its inline diagnostic text exactly matches the scanner
output, including the missing final apostrophe before the closing inline-code
marker.

docs/differential-datalog-parser-syntax-spec-updated.md (1)

260-268: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Synchronize the compound-primary-key contract across the documents.
The final grammar accepts comma-separated primary-key binders, but both D2 decision records still describe a single binder. Update each location:

  • docs/differential-datalog-parser-syntax-spec-updated.md#L260-L268: revise the D2 delta/recommendation to document the compound-binder extension or distinguish upstream syntax from the local contract.
  • docs/execplans/2-6-6-resolve-relation-form-coverage.md#L48-L56: record the same final decision in the completed ExecPlan.
🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/differential-datalog-parser-syntax-spec-updated.md around lines 260 -
268, The D2 records inconsistently describe primary keys as accepting only a
single binder while the final grammar supports compound keys. In
docs/differential-datalog-parser-syntax-spec-updated.md lines 260-268, update
the D2 delta/recommendation to document comma-separated compound primary-key
binders or explicitly distinguish upstream syntax from the local contract; make
the same final-decision update in
docs/execplans/2-6-6-resolve-relation-form-coverage.md lines 48-56.

src/parser/ast/relation.rs (1)

106-190: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Collapse the repeated BodyInspection error match arms.
body(), element_type(), and columns() all repeat the identical MalformedBracket/MissingDelimiterErr(vec![...]) arms verbatim. This is the exact duplication CodeScene already flagged between body/element_type; columns() triples it up further.
Extract a single helper that turns a BodyInspection into an optional error, and let each accessor short-circuit on it before handling its own success case.

♻️ Proposed refactor
+fn body_inspection_error(inspection: &inspect::BodyInspection) -> Option<RelationParseErrors> {
+    match inspection {
+        inspect::BodyInspection::MalformedBracket => Some(vec![MALFORMED_BRACKET_BODY.to_string()]),
+        inspect::BodyInspection::MissingDelimiter => Some(vec![MISSING_BODY_DELIMITER.to_string()]),
+        inspect::BodyInspection::Record | inspect::BodyInspection::Bracket(_) => None,
+    }
+}
+
 pub fn body(&self) -> Result<RelationBody, RelationParseErrors> {
-    match inspect::inspect_body(&self.syntax) {
-        inspect::BodyInspection::Record => Ok(RelationBody::Fields(self.columns()?)),
-        inspect::BodyInspection::Bracket(element) => Ok(RelationBody::ElementType(element)),
-        inspect::BodyInspection::MalformedBracket => {
-            Err(vec![MALFORMED_BRACKET_BODY.to_string()])
-        }
-        inspect::BodyInspection::MissingDelimiter => {
-            Err(vec![MISSING_BODY_DELIMITER.to_string()])
-        }
-    }
+    let inspection = inspect::inspect_body(&self.syntax);
+    if let Some(err) = body_inspection_error(&inspection) {
+        return Err(err);
+    }
+    match inspection {
+        inspect::BodyInspection::Record => Ok(RelationBody::Fields(self.columns()?)),
+        inspect::BodyInspection::Bracket(element) => Ok(RelationBody::ElementType(element)),
+        inspect::BodyInspection::MalformedBracket | inspect::BodyInspection::MissingDelimiter => {
+            unreachable!("handled above")
+        }
+    }
 }
🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @src/parser/ast/relation.rs around lines 106 - 190, Extract a shared helper
near the relation accessors that maps BodyInspection::MalformedBracket and
BodyInspection::MissingDelimiter to their existing error vectors, returning no
error for valid inspections. Update body(), element_type(), and columns()
to short-circuit through this helper before handling their respective Record
and Bracket success cases, preserving all current results and error messages.

src/parser/ast/relation/inspect.rs (1)

180-186: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Update the stale module doc to cover the new error-path tests.
The //! comment only describes the delimiter guard, but this module now also exercises malformed bracket bodies, invalid column lists, malformed primary-key binder lists, and missing delimiters.

📝 Proposed doc update
mod tests {
-    //! Regression tests for the delimiter guard that stops preamble scanning
-    //! before a body delimiter when a malformed node lacks a relation name.
+    //! Regression tests for the delimiter guard that stops preamble scanning
+    //! before a body delimiter when a malformed node lacks a relation name,
+    //! plus `BodyInspection` error-path coverage for malformed bracket
+    //! bodies, invalid record column lists, malformed primary-key binder
+    //! lists, and missing body delimiters.

As per coding guidelines, "Every Rust module must begin with a module-level //! comment explaining its purpose and utility."

🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @src/parser/ast/relation/inspect.rs around lines 180 - 186, The module-level
documentation in the tests module is stale and incomplete. Update the //!
comment above mod tests to describe that the regression tests cover delimiter
guards plus malformed bracket bodies, invalid column lists, malformed
primary-key binder lists, and missing delimiters.

Source: Coding guidelines

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== PR HEAD ==='
git show -s --format='%H%n%s' HEAD

echo
echo '=== Target documentation excerpts ==='
for spec in \
  'docs/developers-guide.md:100:145' \
  'docs/users-guide.md:105:130' \
  'docs/differential-datalog-parser-syntax-spec-updated.md:88:112' \
  'docs/differential-datalog-parser-syntax-spec-updated.md:248:278' \
  'docs/execplans/2-6-6-resolve-relation-form-coverage.md:38:70'; do
  file="${spec%%:*}"
  rest="${spec#*:}"
  start="${rest%%:*}"
  end="${rest##*:}"
  echo "--- ${file}, Lines ${start}-${end} ---"
  nl -ba "$file" | sed -n "${start},${end}p"
done

echo
echo '=== Relation accessor outline and implementation ==='
ast-grep outline src/parser/ast/relation.rs --items all
nl -ba src/parser/ast/relation.rs | sed -n '85,220p'

echo
echo '=== Inspection test-module documentation ==='
rg -n -C5 'mod tests|Regression tests|BodyInspection|malformed bracket|invalid record|missing body' \
  src/parser/ast/relation/inspect.rs
nl -ba src/parser/ast/relation/inspect.rs | sed -n '160,215p'

echo
echo '=== Exact D-REL-008 diagnostic source ==='
rg -n -C4 'D_REL_008|D-REL-008|surrounding' src/parser/span_scanners/relations.rs src/parser

echo
echo '=== Existing body-inspection helper references ==='
rg -n -C3 'inspected_element_type|body_inspection_error|inspect_body' \
  src/parser/ast/relation.rs src/parser/ast/relation/inspect.rs

Length of output: 1971


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_lines() {
  file="$1"
  start="$2"
  end="$3"
  echo "--- ${file}, Lines ${start}-${end} ---"
  awk -v start="$start" -v end="$end" \
    'NR >= start && NR <= end { printf "%6d  %s\n", NR, $0 }' "$file"
}

echo '=== PR HEAD ==='
git show -s --format='%H%n%s' HEAD

echo
echo '=== Target documentation excerpts ==='
show_lines docs/developers-guide.md 100 145
show_lines docs/users-guide.md 105 130
show_lines docs/differential-datalog-parser-syntax-spec-updated.md 88 112
show_lines docs/differential-datalog-parser-syntax-spec-updated.md 248 278
show_lines docs/execplans/2-6-6-resolve-relation-form-coverage.md 38 70

echo
echo '=== Relation accessor implementation ==='
show_lines src/parser/ast/relation.rs 85 220

echo
echo '=== Inspection test-module documentation ==='
rg -n -C5 'mod tests|Regression tests|BodyInspection|malformed bracket|invalid record|missing body' \
  src/parser/ast/relation/inspect.rs || true
show_lines src/parser/ast/relation/inspect.rs 160 215

echo
echo '=== Exact D-REL-008 diagnostic source ==='
rg -n -C4 'D_REL_008|D-REL-008|surrounding' src/parser/span_scanners/relations.rs src/parser || true

echo
echo '=== Existing body-inspection helper references ==='
rg -n -C3 'inspected_element_type|body_inspection_error|inspect_body' \
  src/parser/ast/relation.rs src/parser/ast/relation/inspect.rs || true

Length of output: 40005


@leynos All five findings are resolved against current PR head 824bcdebfaf8eef29361c8884a4ae6b329e1db7b.

Mark these review comments resolved:

  1. docs/developers-guide.md — Mermaid validation
    Lines 123–126 now require make markdownlint for maintained Markdown and explicitly require make nixie when that Markdown contains Mermaid diagrams, while retaining the AGENTS.md reference.

  2. docs/users-guide.md — D-REL-008 text
    Line 121 exactly matches the scanner diagnostic:
    bracket-wrapped primary key clauses are not supported; remove the surrounding '['/']'
    The closing apostrophe is present.

  3. Compound primary-key contract documents

    • docs/differential-datalog-parser-syntax-spec-updated.md Line 267 defines PrimaryKey with one or more comma-separated LcName binders.
    • docs/execplans/2-6-6-resolve-relation-form-coverage.md Line 53 explicitly distinguishes upstream’s single binder from the completed local contract’s comma-separated binder list.
  4. src/parser/ast/relation.rs — duplicated BodyInspection errors
    The shared body_inspection_error() helper centralizes malformed-bracket and missing-delimiter errors. inspected_element_type() owns the common inspection path used by body() and element_type(), while columns() short-circuits through the same helper. The repeated error match arms are gone without weakening the fallible accessor contract.

  5. src/parser/ast/relation/inspect.rs — test-module Rustdoc
    The mod tests documentation now covers delimiter guards, malformed/unclosed bracket bodies, invalid record column lists, malformed primary-key binder lists, and missing delimiters.

No further code changes, AI-agent prompt, suppression message, or follow-up issue is required. Static inspection is complete; retain the repository quality gates as the final runtime validation.

Refine the developer guide's parser-module and boundary-rule coverage of
the relation span scanner so relations.rs (candidate discovery,
orchestration, body/primary-key parsing, disambiguation, span collection,
recovery), relations/cursor.rs (cursor/trivia/balanced-block mechanics),
and relations/preamble.rs (role/kind preamble + D-REL-001..003) each state
their ownership, and note the scanner produces spans that ast/relation.rs
then exposes as typed accessors.

Expand the contributor-workflow section: the required pre-commit sequence
(make fmt, check-fmt, lint, test) matching AGENTS.md, and how make lint,
make spelling, and make markdownlint relate to the spelling gate, without
duplicating the command implementations. Docs only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/developers-guide.md (1)

117-131: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Pre-commit gate contract disagrees between AGENTS.md and docs/developers-guide.md. One root cause: the two files state different rules for when make markdownlint/make nixie are required, and docs/developers-guide.md explicitly (and wrongly) claims its shorter list matches AGENTS.md.

  • docs/developers-guide.md#L117-L131: Either drop the "matching AGENTS.md" claim or extend the numbered list to the same six unconditional gates AGENTS.md documents; do not present make markdownlint/make nixie as merely conditional if AGENTS.md requires them unconditionally.
  • AGENTS.md#L137-L140: If the conditional wording in docs/developers-guide.md (gate on Markdown/Mermaid changes) is the intended policy, update this list to match rather than listing all six gates unconditionally.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/developers-guide.md` around lines 117 - 131, Align the pre-commit gate
contract between docs/developers-guide.md lines 117-131 and AGENTS.md lines
137-140: choose one policy for make markdownlint and make nixie, then update
both files consistently. If the conditional Markdown/Mermaid policy is intended,
remove the “matching AGENTS.md” claim and revise AGENTS.md’s unconditional list;
otherwise extend the developers guide’s numbered sequence to include both gates
unconditionally.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/developers-guide.md`:
- Around line 117-131: Align the pre-commit gate contract between
docs/developers-guide.md lines 117-131 and AGENTS.md lines 137-140: choose one
policy for make markdownlint and make nixie, then update both files
consistently. If the conditional Markdown/Mermaid policy is intended, remove the
“matching AGENTS.md” claim and revise AGENTS.md’s unconditional list; otherwise
extend the developers guide’s numbered sequence to include both gates
unconditionally.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b30cd730-e112-4b5d-b8e4-a6e51c978232

📥 Commits

Reviewing files that changed from the base of the PR and between 177d125 and f59bb5f.

📒 Files selected for processing (8)
  • AGENTS.md
  • docs/developers-guide.md
  • docs/differential-datalog-parser-syntax-spec-updated.md
  • docs/execplans/2-6-6-resolve-relation-form-coverage.md
  • docs/users-guide.md
  • src/parser/ast/relation.rs
  • src/parser/ast/relation/inspect.rs
  • src/parser/ast/relation/tests.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/shared-actions (auto-detected)

The developer guide claimed its four-item pre-commit sequence matched
AGENTS.md while presenting make markdownlint / make nixie as conditional,
but AGENTS.md lists all six gates unconditionally. Extend the numbered
sequence to fmt, check-fmt, lint, test, markdownlint, nixie and drop the
conditional Markdown/Mermaid framing so the two files agree. Docs only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/developers-guide.md`:
- Around line 130-132: Update the documentation sentence so the independent
clauses are separated by a comma: use “Markdown sources, and `make nixie`
validates...” while preserving the existing meaning and command references.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dec60103-2fe1-494f-8ab1-3c90f50b0c00

📥 Commits

Reviewing files that changed from the base of the PR and between f59bb5f and a19f516.

📒 Files selected for processing (1)
  • docs/developers-guide.md
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/shared-actions (auto-detected)

Comment thread docs/developers-guide.md Outdated
Add the missing comma before "and" joining the two independent clauses
describing make markdownlint and make nixie. Docs only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No quality gates enabled for this code.

@leynos
leynos merged commit 3889f3b into main Jul 23, 2026
7 checks passed
@leynos
leynos deleted the 2-6-6-resolve-relation-form-coverage branch July 23, 2026 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants