Skip to content

feat(validators): add runtime schema validators (BDK-002)#183

Merged
flyingrobots merged 7 commits intomainfrom
roadmap/bedrock
Feb 11, 2026
Merged

feat(validators): add runtime schema validators (BDK-002)#183
flyingrobots merged 7 commits intomainfrom
roadmap/bedrock

Conversation

@flyingrobots
Copy link
Owner

@flyingrobots flyingrobots commented Feb 11, 2026

Summary

  • Adds src/validators.js — runtime enforcement of GRAPH_SCHEMA.md constraints (node ID grammar, edge types, confidence type safety, self-edge rejection, prefix classification)
  • Wires validateEdge() into createEdge() so all edges are validated at write time
  • Moves EDGE_TYPES canonical source to validators module (backwards-compatible re-export from edges.js)
  • Updates all existing tests to use schema-valid prefix:identifier node IDs

What's validated now

Check Behavior
Node ID format Must match prefix:identifier regex, max 256 chars
Edge type Must be one of 8 known types
Confidence Must be finite number in [0.0, 1.0] — rejects NaN, Infinity, strings
Self-edges Forbidden for blocks and depends-on
Unknown prefix Warning (not error) — allows organic taxonomy growth

Test plan

  • 42 new validator tests (pure functions, no graph setup)
  • All 28 existing tests updated and passing (70 total)
  • npx vitest run green

Ref: #180

Summary by CodeRabbit

  • New Features

    • Exposed validator utilities and EDGE_TYPES via the public API.
    • Standardized prefixed node identifiers (e.g., file:, spec:, task:).
  • Bug Fixes / Behavior Changes

    • Centralized and improved edge validation with clearer errors, warnings, and self-edge rules.
    • Directive parsing tightened to ignore empty/whitespace targets.
  • Tests

    • Added comprehensive validator tests and updated existing tests for new ID format.
  • Chores

    • CI/test script adjustments.

Implements GRAPH_SCHEMA.md constraints as runtime validators:
- New src/validators.js with node ID, edge type, confidence, and
  composite edge validation (self-edge rejection, prefix warnings)
- EDGE_TYPES canonical source moved to validators, re-exported by edges
- createEdge() now validates IDs, type safety, and self-edges
- 42 new validator tests, existing tests updated for schema-valid IDs
- Add Unreleased section to CHANGELOG with validator additions
- Update GUIDE.md node ID examples to use prefix:identifier format
- Document validator exports in library usage section
- Update commit directive examples with schema-valid targets
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Warning

Rate limit exceeded

@flyingrobots has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 27 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

This PR centralizes node/edge schema validation into a new validators.js, refactors edges.js to use validateEdge, re-exports validator utilities from index.js, updates tests to use prefixed node IDs, and tweaks directive parsing and CI/test scripts.

Changes

Cohort / File(s) Summary
Validators & Public API
src/validators.js, src/index.js
Add validators.js with constants (NODE_ID_REGEX, NODE_ID_MAX_LENGTH, CANONICAL_PREFIXES, SYSTEM_PREFIXES, ALL_PREFIXES, EDGE_TYPES), prefix utilities, and validators (validateNodeId, validateEdgeType, validateConfidence, validateEdge, extractPrefix, classifyPrefix). Re-export these from src/index.js.
Edge logic
src/edges.js
Remove local EDGE_TYPES and inline validation; import and call validateEdge; re-export EDGE_TYPES from validators. createEdge now throws on validator errors and logs warnings.
Parsing tweak
src/hooks.js
Adjust DIRECTIVE_PATTERN capture from (.+) to (\S.*) to avoid matching empty/whitespace-only targets.
Tests updated/added
test/validators.test.js, test/edges.test.js, test/hooks.test.js, test/views.test.js
Add comprehensive validator tests; update existing tests to use prefixed node IDs (file:, spec:, task:, doc:) and assert new validation message/content and behaviors (invalid IDs, confidence bounds, self-edge rules, etc.).
CI & Scripts
.github/workflows/ci.yml, package.json
Grant contents: read permission in CI workflow; prepend NODE_OPTIONS='--disable-warning=DEP0169' to test scripts.
Misc
src/index.js (re-export), other small adjustments
Public API expanded to include validation utilities via main index; no breaking changes to create/query/remove edge signatures.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant Edges as "src/edges.js"
participant Validators as "src/validators.js"
participant Graph as "Graph Store"
Client->>Edges: call createEdge(source,target,type,confidence,rationale)
Edges->>Validators: validateEdge(source,target,type,confidence)
Validators-->>Edges: { valid, errors[], warnings[] }
alt valid == false
Edges-->>Client: throw aggregated validation error
else valid == true
Edges->>Graph: ensure nodes exist; create edge object
Graph-->>Edges: edge created/ack
Edges-->>Client: return created edge (log warnings if any)
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through code to centralize the checks,
Moved rules to one burrow, no more scattered pecks.
Prefixes snug—file, spec, task in a row,
Tests guard the tunnels where validations go. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a new validators.js module with runtime schema validators. It is specific, concise, and clearly conveys the primary purpose of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch roadmap/bedrock

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (1)
test/hooks.test.js (1)

12-56: ⚠️ Potential issue | 🔴 Critical

Update parseDirectives tests to use prefixed node ID format.

The tests use bare paths (e.g., docs/auth-spec.md, src/session.js, api/endpoints.md) that will fail validation when processCommit passes them to createEdge. Since validateEdge enforces prefix:identifier format, these directives will throw errors in real usage:

  • docs/auth-spec.md → rejected (missing prefix)
  • src/session.js → rejected (missing prefix)
  • api/endpoints.md → rejected (missing prefix)

Replace bare paths with prefixed formats consistent with the system's node ID grammar:

  • docs/auth-spec.mdfile:docs/auth-spec.md or spec:auth
  • src/session.jsfile:src/session.js or module:auth
  • api/endpoints.mdfile:api/endpoints.md or spec:api

Tests like "handles BLOCKS and DEPENDS-ON" already use correct format (task:deploy, module:auth), so follow that pattern.

🤖 Fix all issues with AI agents
In `@src/edges.js`:
- Line 6: Remove the unused import alias `_EDGE_TYPES` from the import statement
in src/edges.js; keep importing `validateEdge` only (i.e., change `import {
validateEdge, EDGE_TYPES as _EDGE_TYPES } from './validators.js'` to import just
`validateEdge`) since `EDGE_TYPES` is already re-exported later with `export {
EDGE_TYPES } from './validators.js'`, ensuring no other references to
`_EDGE_TYPES` (or renaming) remain in the file.
- Around line 27-31: createEdge currently ignores validateEdge's result.warnings
so unknown-prefix warnings are never surfaced; update createEdge to handle
warnings from validateEdge (the object returned by validateEdge used in
createEdge) by iterating over result.warnings and emitting them (e.g.,
console.warn with a clear message and the warning text) before proceeding or
alternatively include result.warnings in the function's return value so callers
can see them; ensure you reference validateEdge, the result variable, and
result.warnings in your change.

In `@src/validators.js`:
- Around line 15-23: The JSDoc for CANONICAL_PREFIXES is ambiguous about
containing system prefixes; update the comment or the data so intent is clear:
either change the CANONICAL_PREFIXES JSDoc to explicitly state "superset
including system prefixes (includes SYSTEM_PREFIXES such as 'commit')" or
refactor the arrays so CANONICAL_PREFIXES and SYSTEM_PREFIXES are disjoint and
introduce a computed union (e.g., ALL_PREFIXES = [...CANONICAL_PREFIXES,
...SYSTEM_PREFIXES]) used by classifyPrefix; ensure classifyPrefix still checks
SYSTEM_PREFIXES first if you keep the superset approach and update
references/tests accordingly.
- Around line 130-155: The self-edge check in validateEdge runs even when source
or target IDs are invalid, causing redundant/self-edge errors; update
validateEdge so the SELF_EDGE_FORBIDDEN check (the branch that tests source ===
target and SELF_EDGE_FORBIDDEN.includes(type)) only runs when both
validateNodeId(source) and validateNodeId(target) returned valid (use
srcResult.valid && tgtResult.valid) to suppress the self-edge message for
already-invalid IDs while keeping all other validations (validateEdgeType,
validateConfidence) intact.

In `@test/validators.test.js`:
- Around line 102-116: Add an explicit test and inline comment clarifying that
'commit' is classified as 'system' due to prefix precedence: update the test
suite for classifyPrefix (function classifyPrefix in tests) to include a
specific "commit precedence" test that asserts classifyPrefix('commit') ===
'system' and add a short comment referencing CANONICAL_PREFIXES and
SYSTEM_PREFIXES to explain that SYSTEM_PREFIXES is checked first; alternatively,
if the duplication of 'commit' in CANONICAL_PREFIXES is unintended, remove it
from CANONICAL_PREFIXES in src/validators.js so classifyPrefix behaviour matches
intent.

- Remove unused _EDGE_TYPES import alias in edges.js
- Surface validateEdge() warnings via console.warn in createEdge()
- Separate CANONICAL_PREFIXES (18 user-facing) from SYSTEM_PREFIXES;
  add ALL_PREFIXES computed union for convenience
- Guard self-edge check behind valid IDs to avoid redundant errors
- Update parseDirectives tests to use prefixed node IDs
- Add classifyPrefix precedence test and self-edge guard test
…#180)

The warning originates from roaring → @mapbox/node-pre-gyp calling
url.resolve() during native binary loading. Not fixable in our code.
Use NODE_OPTIONS to propagate --disable-warning to vitest workers.
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 11, 2026
- hooks.js: change \s*(.+) to \s*(\S.*) in DIRECTIVE_PATTERN to
  eliminate polynomial backtracking on whitespace-heavy inputs
- ci.yml: add explicit `permissions: contents: read` per least-privilege
@flyingrobots
Copy link
Owner Author

@coderabbitai review please

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

@flyingrobots, I'll review the changes in PR #183.


🧠 Learnings used
Learnt from: flyingrobots
Repo: neuroglyph/git-mind PR: 169
File: docs/templates/code-review-feedback.md:26-33
Timestamp: 2025-09-16T17:10:27.477Z
Learning: The user (flyingrobots) uses Obsidian to view/edit Markdown files and prefers to keep Obsidian-specific syntax like collapsible callout markers (e.g., `[!NOTE]-` for collapsible callouts) even if they're not GitHub-compatible.
✅ Actions performed

Review triggered.

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@package.json`:
- Around line 22-23: The package.json scripts "test" and "test:watch" use
POSIX-only inline NODE_OPTIONS='--disable-warning=DEP0169' which breaks on
Windows; either install and use cross-env and update those scripts to prefix
with cross-env (e.g., cross-env NODE_OPTIONS=--disable-warning=DEP0169) or
remove the inline env and set the same option in Vitest config by adding
test.poolOptions.forks.execArgv = ['--disable-warning=DEP0169'] in
vitest.config.js; choose one approach, update the "test" and "test:watch" script
entries accordingly, and ensure cross-env is added to devDependencies if you
pick that option.

In `@src/validators.js`:
- Around line 50-54: The exported function extractPrefix currently assumes
nodeId is a string and will throw if called with null/undefined or non-string;
add a defensive type guard at the start of extractPrefix (e.g., check typeof
nodeId !== 'string' or nodeId == null) and return null for non-string input so
callers of extractPrefix (and public API consumers) don't get a TypeError; keep
the existing behavior for strings (find ':' and slice) and update any unit tests
to assert null is returned for null/undefined/non-string inputs.

- Add type guard to extractPrefix() for null/undefined/non-string input
- Move --disable-warning=DEP0169 from POSIX-only NODE_OPTIONS in
  package.json to vitest.config.js poolOptions for cross-platform compat
- Add extractPrefix non-string input test
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 11, 2026
- package.json engines: >=22.0.0
- CI matrix: [22, 24]
- GUIDE.md prerequisites updated
@flyingrobots flyingrobots merged commit 3b63c0c into main Feb 11, 2026
5 checks passed
@flyingrobots flyingrobots deleted the roadmap/bedrock branch February 11, 2026 03:18
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