Skip to content

fix(core): reject duplicate nonrepeatable directives - #693

Merged
flyingrobots merged 5 commits into
dx/first-contributor-fast-pathsfrom
source/nonrepeatable-directive-collisions
Jul 5, 2026
Merged

flyingrobots merged 5 commits into
dx/first-contributor-fast-pathsfrom
source/nonrepeatable-directive-collisions

Conversation

@flyingrobots

@flyingrobots flyingrobots commented Jul 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • rejects duplicate non-repeatable custom directives during GraphQL lowering, including base/extension and extension/extension collisions
  • preserves ordered arrays only for directives explicitly declared repeatable
  • documents the IR directive encoding rule and records the fix in the changelog

Validation

  • cargo test -p wesley-core --test lowering_validation directive -- --nocapture
  • cargo test -p wesley-core -- --nocapture
  • cargo clippy -p wesley-core --all-targets -- -D warnings
  • cargo xtask docs-check
  • pnpm run preflight
  • git diff --check
  • pre-push Rust product preflight

Closes #683

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of repeated directives so valid repeatable ones are preserved, while invalid duplicates are now rejected more consistently.
  • New Features

    • Added clearer security-tooling guidance, including current baseline expectations and criteria for evaluating future scanners and security gates.
  • Documentation

    • Expanded security and validation docs, refreshed directive reference tables, and added a new security-tooling topic to the documentation map.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@flyingrobots, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a19ae73c-8be8-4f9d-b100-ddc43748f93c

📥 Commits

Reviewing files that changed from the base of the PR and between 2049c6d and cb8afc7.

📒 Files selected for processing (2)
  • crates/wesley-core/src/adapters/apollo.rs
  • docs/reference/directives.md
📝 Walkthrough

Walkthrough

This PR adds directive-repeatability tracking to the Apollo SDL lowering adapter: it detects repeatable directives from SDL documents, threads that information through type/field/argument/schema-operation extraction, and rejects duplicate non-repeatable directives while accumulating repeatable ones as arrays. It also adds a new security-tooling documentation topic referenced across several docs.

Changes

Repeatable Directive Lowering

Layer / File(s) Summary
Repeatable-directive detection and insertion semantics
crates/wesley-core/src/adapters/apollo.rs
Adds repeatable_directive_names_from_document, TypeBuildAccumulator, and changes insert_directive_value to return Result, erroring on non-repeatable duplicates and appending arrays for repeatable ones.
Type/field/argument construction using repeatability
crates/wesley-core/src/adapters/apollo.rs
Threads repeatable_directives through build_type_from_aggregate, merge_definition, extension merging, collect_fields, build_field, build_input_field, and field-argument builders via extract_directives_with_repeatability.
Schema operation listing repeatability wiring
crates/wesley-core/src/adapters/apollo.rs
Propagates repeatable_directives into list_schema_operations_sdl, collect_schema_operations_from_object, schema_operation_from_field, and operation-argument helpers.
Duplicate/repeatable directive test coverage
crates/wesley-core/tests/lowering_validation.rs
Adds tests for same-location duplicates, base+extension collisions, multi-extend collisions, repeatable accumulation, and undefined-directive duplication.
Directive documentation of IR encoding rule
docs/reference/directives.md
Reformats the directive support table and adds an "IR Encoding Rule" section describing repeatable/non-repeatable duplicate handling.

Security Tooling Documentation

Layer / File(s) Summary
New security-tooling topic document
docs/topics/security-tooling.md, docs/truth-manifest.json
Adds a new document covering security baseline, evaluation matrix, gate admission rules, and near-term fits, plus its manifest entry.
Cross-doc references and changelog entry
CHANGELOG.md, SECURITY.md, docs/topics/README.md, docs/topics/ci-workflows.md, docs/topics/validation.md
Adds cross-links and a changelog entry pointing to the new security-tooling document.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related issues

Possibly related PRs

  • flyingrobots/wesley#513: Modifies the same SDL directive canonicalization/duplicate-handling logic in apollo.rs and its tests.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description has a summary and validation, but omits most required template sections like Why, Changes, Risk, Backout, and checklist items. Add the missing template sections, especially Why, Changes, Risk, Backout, and the checklist or issue-tracking items required by this repo.
Out of Scope Changes check ⚠️ Warning The PR adds unrelated security-tooling docs, SECURITY.md, and changelog entries that are outside the directive-lowering work in #683. Move the security-tooling documentation and changelog updates into a separate PR unless they are explicitly part of the #683 scope.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: rejecting duplicate non-repeatable directives.
Linked Issues check ✅ Passed The lowering logic and tests implement #683: non-repeatable duplicates now error, repeatable directives stay ordered, and extension collisions are covered.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch source/nonrepeatable-directive-collisions

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.

@github-actions

github-actions Bot commented Jul 4, 2026 •

Copy link
Copy Markdown

🔍 The Case of Pull Request #693

Schema Sets

  • ecommerce
  • reference

Schema Set ecommerce

Plain-English Readout

  • Holmes (evidence investigation): The Holmes report is unavailable because the workflow finished without a readable holmes-report.json artifact.
  • Watson (independent verification): The Watson report is unavailable because the workflow finished without a readable watson-report.json artifact.
  • Moriarty (trend forecast): The Moriarty forecast is unavailable because the workflow finished without a readable moriarty-report.json artifact.

Suggested next actions

  1. Regenerate the HOLMES artifacts and make sure holmes-report.json is uploaded before trusting this PR summary.
  2. Regenerate the WATSON artifacts and make sure watson-report.json is uploaded before trusting this PR summary.
  3. Regenerate the MORIARTY artifacts and make sure moriarty-report.json is uploaded before trusting this PR summary.
🕵️ SHA-lock HOLMES full report for ecommerce (click to expand)

Report unavailable for holmes: readable holmes-report.md artifact not found.

🩺 Dr. WATSON full report for ecommerce (click to expand)

Report unavailable for watson: readable watson-report.md artifact not found.

🔮 Professor MORIARTY full report for ecommerce (click to expand)

Report unavailable for moriarty: readable moriarty-report.md artifact not found.


Schema Set reference

Plain-English Readout

  • Holmes (evidence investigation): The Holmes report is unavailable because the workflow finished without a readable holmes-report.json artifact.
  • Watson (independent verification): The Watson report is unavailable because the workflow finished without a readable watson-report.json artifact.
  • Moriarty (trend forecast): The Moriarty forecast is unavailable because the workflow finished without a readable moriarty-report.json artifact.

Suggested next actions

  1. Regenerate the HOLMES artifacts and make sure holmes-report.json is uploaded before trusting this PR summary.
  2. Regenerate the WATSON artifacts and make sure watson-report.json is uploaded before trusting this PR summary.
  3. Regenerate the MORIARTY artifacts and make sure moriarty-report.json is uploaded before trusting this PR summary.
🕵️ SHA-lock HOLMES full report for reference (click to expand)

Report unavailable for holmes: readable holmes-report.md artifact not found.

🩺 Dr. WATSON full report for reference (click to expand)

Report unavailable for watson: readable watson-report.md artifact not found.

🔮 Professor MORIARTY full report for reference (click to expand)

Report unavailable for moriarty: readable moriarty-report.md artifact not found.


📚 Glossary (what the Holmes terms mean)
  • HOLMES: Wesley’s main evidence investigation. It decides whether the cited proof is strong enough to justify shipping this commit.
  • WATSON: An independent verification pass. It checks Holmes’s citations and score math instead of trusting them blindly.
  • MORIARTY: A readiness forecast over time. It is advisory trend analysis, not the release gate itself.
  • Schema coverage score (SCS): How much of the schema has direct supporting evidence across generated artifacts and cited proof.
  • Test confidence index (TCI): How much test evidence exists for constraints, policies, relationships, and operations.
  • Migration risk index (MRI): How risky the schema change is to roll out. Lower is better.
  • Evidence trust: Whether the report is backed by exact citations, whole-file citations, or coarse references. Weak trust means the claim may be directionally right but not specific enough to trust blindly.
  • Citation quality: A count of exact line-span citations versus whole-file or coarse references.
  • ELEMENTARY: Ready to ship based on the current evidence.
  • REQUIRES INVESTIGATION: More work or review is needed before shipping.
  • YOU SHALL NOT PASS: Do not ship this change in its current state.

Machine-readable reports are grouped by schema set in workflow artifacts.


Filed at 221B Repository Street

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/wesley-core/src/adapters/apollo.rs (1)

964-971: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Promote extract_directives_with_repeatability out of ApolloLoweringAdapter
It doesn’t use adapter state, so the ApolloLoweringAdapter::new(0) calls in field_argument_from_input_value, schema_operation_from_field, and operation_argument_from_input_value are unnecessary ceremony. Make it a free function or associated fn to remove those throwaway adapters.

🤖 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 `@crates/wesley-core/src/adapters/apollo.rs` around lines 964 - 971, Move the
directive extraction logic out of ApolloLoweringAdapter since
extract_directives_with_repeatability does not depend on adapter state. Update
field_argument_from_input_value, schema_operation_from_field, and
operation_argument_from_input_value to call a free function or associated
function directly instead of constructing ApolloLoweringAdapter::new(0) just to
invoke it. Keep the existing repeatable_directives and directives handling
behavior unchanged while removing the throwaway adapter instances.
🤖 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/reference/directives.md`:
- Around line 41-53: Update the IR Encoding Rule wording to match the
implementation in the directives docs: clarify that repeatability is determined
from SDL directive definitions rather than “unknown custom directives,” and
state that directives not declared repeatable are treated as non-repeatable.
Also revise the duplicate-collision example to explicitly mention
extension-to-extension collisions, along with base-definition and extension
collisions, and keep the canonical Wesley alias example aligned with the `@wes_`*
collision behavior.

---

Nitpick comments:
In `@crates/wesley-core/src/adapters/apollo.rs`:
- Around line 964-971: Move the directive extraction logic out of
ApolloLoweringAdapter since extract_directives_with_repeatability does not
depend on adapter state. Update field_argument_from_input_value,
schema_operation_from_field, and operation_argument_from_input_value to call a
free function or associated function directly instead of constructing
ApolloLoweringAdapter::new(0) just to invoke it. Keep the existing
repeatable_directives and directives handling behavior unchanged while removing
the throwaway adapter instances.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ce6b303e-6f59-4fe1-a93d-72f008c2044c

📥 Commits

Reviewing files that changed from the base of the PR and between 1cf3d1a and 2049c6d.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • SECURITY.md
  • crates/wesley-core/src/adapters/apollo.rs
  • crates/wesley-core/tests/lowering_validation.rs
  • docs/reference/directives.md
  • docs/topics/README.md
  • docs/topics/ci-workflows.md
  • docs/topics/security-tooling.md
  • docs/topics/validation.md
  • docs/truth-manifest.json

Comment thread docs/reference/directives.md
@flyingrobots

Copy link
Copy Markdown
Owner Author

Activity Summary

Code Lawyer pass completed for PR #693.

Item Severity Source File / Scope Commit Outcome
Clarify directive repeatability docs P3 PR inline thread docs/reference/directives.md ac8f10ba Reworded IR Encoding Rule to say repeatability comes from SDL directive definitions and duplicate non-repeatable directives fail across base and extension-to-extension collisions.
Remove throwaway directive-extraction adapters P5 PR review nit crates/wesley-core/src/adapters/apollo.rs cb8afc7c Converted extract_directives_with_repeatability to an associated helper and removed ApolloLoweringAdapter::new(0) ceremony at extraction-only call sites.
Review thread resolution N/A PR PRRT_kwDOPoavfs6OXevD N/A Resolved via GraphQL after fix push.

Validation:

  • export GH_PAGER=cat && git status --porcelain
  • git fetch origin
  • gh auth status
  • gh api graphql ... comments/reviews/reviewThreads ...
  • git diff origin/main...HEAD
  • RED/GREEN stale docs wording check
  • RED/GREEN throwaway extraction adapter check
  • cargo xtask docs-check
  • pnpm exec prettier --check docs/reference/directives.md
  • cargo fmt --check
  • cargo test -p wesley-core --test lowering_validation
  • cargo clippy -p wesley-core --all-targets -- -D warnings
  • git diff --check origin/main...HEAD
  • pnpm run preflight
  • push-time Rust product preflight
  • gh pr checks 693 --repo flyingrobots/wesley

Merge-gate note: local validation and GitHub checks are green, the worktree is clean, and unresolved review threads are zero. The strict gate remains locked because there are zero submitted approvals and the visible CodeRabbit top-level comment includes a review-limit notice even though the status context reports pass.

@flyingrobots
flyingrobots merged commit 9e4565d into dx/first-contributor-fast-paths Jul 5, 2026
16 checks passed
@flyingrobots
flyingrobots deleted the source/nonrepeatable-directive-collisions branch July 5, 2026 05:44
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