Skip to content

Adds MCP server for AI assistant integration - #202

Merged
logbie merged 25 commits into
mainfrom
Dev1
Jan 2, 2026
Merged

Adds MCP server for AI assistant integration#202
logbie merged 25 commits into
mainfrom
Dev1

Conversation

@logbie

@logbie logbie commented Jan 2, 2026

Copy link
Copy Markdown
Collaborator

This introduces a Model Context Protocol (MCP) server to enable AI assistants, like Claude, to interact with WFL codebases. The wfl-lsp binary can now be run with a --mcp flag to expose a suite of tools and workspace resources over a JSON-RPC interface.

Key Features & Improvements

  • AI Integration (MCP Server): Exposes 6 tools (parse, analyze, typecheck, lint, completions, symbol info) and 5 workspace resources (files, symbols, diagnostics, config, file contents) for AI-powered development. Includes comprehensive documentation, examples, and test reports.
  • Analyzer Performance: Optimizes semantic analysis by changing scope handling to use reference counting (Rc). This improves performance on deeply nested code by avoiding expensive cloning and preventing quadratic complexity.
  • Crypto Library Hardening: Overhauls the wflhash implementation with a secure, buffered sponge construction, adds DoS protection, and formalizes the algorithm in a new specification document.
  • Language Updates:
    • Adds a new input() function to get user input from the console.
    • Updates error handling syntax from catch: to the more explicit when error:.
  • Static Analysis Fixes: Corrects several false positive warnings for unused variables, particularly in nested declarations and custom count loops.

Additionally, the integration test runner has been refactored to use PowerShell Jobs for more reliable timeout handling.

Summary by CodeRabbit

  • New Features

    • Model Context Protocol (MCP) server and client examples for Claude Desktop integration
    • New input() stdlib function and function-call syntax with parenthesized invocation
    • New MCP tools: parse, analyze, typecheck, lint, completions, symbol info
  • Bug Fixes

    • Error-handler syntax updated from catch: to when error:
    • Improved variable scoping/isolation and cross-platform subprocess handling
  • Documentation

    • Comprehensive MCP guides, API reference, architecture and integration docs
  • Tests

    • New semantic, scope, performance and MCP test suites

✏️ Tip: You can customize this high-level summary in your review settings.

Improves the accuracy of unused variable detection in two key scenarios.

First, the analyzer now correctly tracks variable usage within the initializers of nested variable declarations, preventing false positives.

Second, custom counter variables in count loops are now always marked as used, resolving cases where they were incorrectly flagged if not referenced within the loop body.

Adds comprehensive tests to cover these fixes and prevent regressions.
Replaces the `Start-Process` and `WaitForExit` logic with the `Start-Job` cmdlet for executing test programs.

This change provides a more robust and idiomatic PowerShell method for handling process timeouts and ensures cleaner termination of hanging tests.
Replaces `Box` with `Rc` for parent scope references in the semantic analyzer. This change addresses a performance bottleneck where creating nested scopes required expensive, recursive clones, leading to quadratic complexity in deeply nested code.

Using reference counting allows child scopes to share an immutable reference to their parent, making the creation of new scopes a cheap, constant-time operation. This significantly improves analysis speed for complex control flow structures.

Adds comprehensive correctness and performance test suites to validate the new implementation and prevent regressions.
Replaces the `catch` keyword with the more descriptive `when error`.

This also standardizes the caught exception variable from `error_message` to `error`, improving consistency.
Applies standard formatting to Rust source files.

This change enhances code consistency and readability without altering any underlying logic.
Refactors the crypto module to implement a more robust and performant stateful design for the WflHash algorithm.

This change introduces a proper sponge construction using an internal buffer, allowing for the correct and efficient processing of streaming data. The core permutation function is heavily optimized by removing `black_box` calls, and its mixing step is corrected to ensure invertibility. Additionally, rotation constants are improved for better diffusion.

Padding and finalization logic is now integrated directly into the state machine, simplifying the hashing process.
(re)Implements a 100MB input size limit on hashing functions to prevent resource exhaustion from overly large inputs.

Exposes a new, more direct function for hashing raw binary data, bypassing the standard value type system.
Updates subprocess and interpreter tests to correctly execute shell commands on Windows by using `cmd /C`.

Consolidates the logic for locating the test binary into a single helper function across multiple test files. This refactoring eliminates code duplication and improves maintainability. The new helper also checks for the debug binary, making it easier to run tests during development.
Introduces a new native function, 'input', to read a line of text from standard input. This enables scripts to receive data from the user at runtime and can optionally display a prompt.

The function's type signature is registered with the static analyzer for type safety. An example script is also added to demonstrate its usage.
Prints a warning to standard error when any of the custom `wfl` hash or MAC functions are used. This ensures users are aware that these functions are experimental, provide no security guarantees, and should not be used in security-sensitive contexts.
Introduces a frozen, immutable specification for the WFLHASH1 cryptographic algorithm.

This document incorporates critical corrections to the algorithm's logic, including MAC key parameter mixing, salt zero-padding, and standard HKDF usage. It provides a definitive reference for implementation and includes a comprehensive JSON test suite with 20 valid test vectors.

Additionally, updates local development settings to support the WFL language server.
Introduces a Model Context Protocol (MCP) server mode to the WFL language server, enabling AI assistants like Claude to analyze and interact with WFL codebases.

The language server can now be launched with a `--mcp` flag to expose a suite of tools for code analysis (parsing, diagnostics, completions) and resources for workspace-level context (files, symbols, configuration).

The server architecture is refactored to use a shared core for analysis logic, ensuring consistency between the existing LSP and the new MCP modes.

Adds extensive documentation, including user guides, API references, architecture details, and example clients to support the new feature.
Adds a comprehensive test report for the WFL MCP server implementation.

The report validates the functionality of all tools, resources, and error handling mechanisms against a real workspace. It confirms that the server is feature-complete, backward compatible with the existing LSP, and production-ready.
Copilot AI review requested due to automatic review settings January 2, 2026 11:22
@claude

claude Bot commented Jan 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @logbie's task —— View job


Code Review for MCP Server Integration PR

I've completed a comprehensive review of this substantial PR that adds Model Context Protocol (MCP) server support to WFL. Here's my detailed analysis:

Review Tasks:

  • Analyze MCP server implementation for security and best practices
  • Review crypto library hardening (WFLHASH changes)
  • Examine analyzer performance optimizations
  • Check test coverage and quality
  • Assess documentation completeness
  • Review backward compatibility considerations

🔍 Overall Assessment

This is a high-quality, well-engineered PR that adds significant value to the WFL ecosystem. The code demonstrates excellent security practices, comprehensive testing, and thorough documentation.

✅ Strengths

1. MCP Server Implementation (wfl-lsp/src/mcp_server.rs)

  • Excellent Security: Proper input validation on all parameters with appropriate error codes
  • Robust Error Handling: Comprehensive JSON-RPC 2.0 error responses with proper error codes (-32601, -32602, -32603)
  • Clean Architecture: Well-structured with clear separation of concerns between tool handlers
  • Resource Management: Proper file system access controls with workspace root validation
  • Testing: Comprehensive test suite covering both success and error scenarios

2. Crypto Library Hardening (src/stdlib/crypto.rs)

  • Security-First Design: DoS protection with MAX_INPUT_SIZE constant (100MB limit)
  • Proper Cryptographic Practices: Uses zeroize for secure memory cleanup
  • Constant-Time Operations: Leverages subtle crate for constant-time comparisons
  • Buffered Sponge Construction: Implements proper WFLHASH with buffering and state management
  • Memory Safety: Implements Drop trait for secure state cleanup

3. Analyzer Performance Optimizations (src/analyzer/mod.rs)

  • Smart Performance Fix: Changed from Box<Scope> to Rc<Scope> to prevent O(N²) cloning in nested scopes
  • Well-Documented: Clear comments explaining the performance benefits (lines 62-64)
  • Comprehensive Testing: Dedicated performance tests verify sub-500ms execution for deeply nested code
  • Backward Compatible: No breaking changes to the analyzer API

4. Test Coverage & Quality

  • Excellent Coverage:
    • MCP server: 6 unit tests covering initialization, tools list, parse success/failure
    • Performance tests: 4 comprehensive tests for nested control structures
    • Crypto: Updated with secure implementation
    • Integration: Complete test report (MCP_TEST_REPORT.md) showing 100% functionality
  • Realistic Test Scenarios: Tests cover real-world usage patterns and edge cases
  • Performance Validation: Tests verify O(N) vs O(N²) complexity improvements

5. Documentation Excellence

  • Comprehensive Guides: 4 new documentation files covering MCP usage, API reference, architecture, and Claude Desktop integration
  • Clear Examples: Practical examples with copy-pasteable configurations
  • Updated CLAUDE.md: Excellent integration with development workflow documentation
  • Test Reports: Professional test report documenting all 6 tools and 5 resources

🔧 Technical Highlights

Security Considerations ✅

  • Input Validation: All MCP tools validate required parameters before processing
  • File System Safety: Workspace root validation prevents directory traversal
  • Error Information Disclosure: Appropriate error messages without sensitive data leakage
  • DoS Protection: Crypto functions have input size limits
  • Memory Security: Proper zeroization of sensitive cryptographic state

Performance Improvements ✅

  • Scope Optimization: Rc-based scope sharing prevents expensive cloning
  • Measured Improvements: Tests show <500ms for 20-level nested structures
  • Realistic Benchmarks: Mixed control flow tests simulate real code patterns

Backward Compatibility ✅

  • Syntax Evolution: Clean migration from catch: to when error: syntax
  • Test Coverage: Extensive backward compatibility testing across TestPrograms
  • No Breaking Changes: All existing functionality preserved

🚀 Minor Suggestions

  1. Security Enhancement: Consider adding rate limiting to MCP server requests in production environments
  2. Error Context: MCP error responses could include more context for debugging (optional data field usage)
  3. Resource Caching: Workspace scanning operations could benefit from caching for large projects
  4. Symbol Resolution: The get_symbol_info tool could be enhanced with more detailed symbol analysis

📋 Code Quality Metrics

  • Lines Changed: 6,556 additions, 595 deletions - significant but well-structured
  • Test Coverage: Comprehensive with unit, integration, and performance tests
  • Documentation: Excellent with 4 new guides and updated project docs
  • Security: Strong cryptographic practices and input validation
  • Performance: Measurable improvements with regression protection

🎯 Recommendation

✅ APPROVE - This PR represents excellent engineering work that:

  • Adds substantial value through AI integration capabilities
  • Maintains high security and performance standards
  • Provides comprehensive documentation and testing
  • Preserves backward compatibility
  • Follows WFL's development best practices

The MCP server implementation opens up exciting possibilities for AI-powered WFL development while maintaining the language's commitment to security and performance.

@coderabbitai

coderabbitai Bot commented Jan 2, 2026

Copy link
Copy Markdown
Contributor

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds a Model Context Protocol (MCP) JSON-RPC server and shared analysis core, refactors analyzer scopes to use Rc, adds function-call parsing, introduces an input builtin, reworks WFLHASH internals and wrappers, updates tests and test runner, and adds extensive MCP documentation and examples.

Changes

Cohort / File(s) Summary
MCP server & shared core
wfl-lsp/src/lib.rs, wfl-lsp/src/main.rs, wfl-lsp/src/core.rs, wfl-lsp/src/mcp_server.rs
New WflLanguageCore for document lifecycle and analysis; full JSON-RPC MCP server (initialize, tools, resources, run_server); main can dispatch --mcp vs LSP; public MCP types and handlers added.
Parser: function-call postfix
src/parser/expr/primary.rs
Adds parsing of parenthesized argument lists to create FunctionCall nodes as a postfix operation on primary expressions, preserving accurate source positions.
Analyzer scope refactor
src/analyzer/mod.rs
Changes Scope.parent from Option<Box<Scope>> to Option<Rc<Scope>>; updates scope push/pop and with_parent API to Rc semantics across control-flow constructs.
Static analyzer loop handling
src/analyzer/static_analyzer.rs
CountLoop now carries variable_name: Option<String>; variable-collection/usage marking updated; shadowing and loop-variable tests added/updated.
Stdlib: input builtin & type registration
src/stdlib/core.rs, src/stdlib/typechecker.rs, src/builtins.rs
New native_input reading stdin with optional prompt; registered as input in stdlib and typechecker; builtins list and arity updated.
WFLHASH redesign
src/stdlib/crypto.rs, wflhash/wflhashspec.md
Reworked buffered length-aware sponge, fixed ARX G-function, block processing (absorb/finalize/squeeze), new public wrappers (wflhash256/512, salted, mac), and added frozen spec + vectors.
Main: stdlib type registration
src/main.rs
Calls added to register stdlib types prior to analysis/typechecking on multiple execution paths.
Test helpers & cross-platform tests
tests/* (many), scripts/run_integration_tests.ps1
Centralized get_wfl_binary_path() helper added across many tests; run_integration_tests.ps1 switched to background-job timeout semantics; Windows-specific cfg branches and command adjustments added.
Analyzer tests (correctness & perf)
tests/analyzer_scope_correctness_test.rs, tests/analyzer_scope_performance_test.rs
New correctness tests for scope behavior and performance tests validating Rc-based scope handling under deep nesting.
Misc test updates & formatting
src/interpreter/tests.rs, various tests
Minor formatting fixes and test harness adjustments.
Test programs & new helpers
TestPrograms/complex_expression_catch_test.wfl, TestPrograms/unicode_catch_test.wfl, generate_hash.wfl, hash_output.txt
Replaced catch: with when error: and updated error variable usage; added hash script and output.
Examples, scripts, reports
wfl-lsp/examples/*, wfl-lsp/MCP_TEST_REPORT.md
New simple MCP client example (Rust), Bash/PowerShell test scripts, README for examples, and MCP test report artifact.
Docs: MCP guides & integration
CLAUDE.md, Docs/guides/claude-desktop-integration.md, Docs/guides/wfl-mcp-guide.md, Docs/guides/wfl-mcp-api-reference.md, Docs/technical/wfl-mcp-architecture.md, wflhash/wflhashspec.md
Extensive new documentation covering MCP architecture, API, integration, examples, and WFLHASH spec.
Build & config
.claude/settings.local.json, wfl-lsp/Cargo.toml, .github/workflows/claude-code-review.yml, README.md
Added enabledMcpjsonServers config, expanded allowed Bash entries, added serde dependency to wfl-lsp, allowed_bots input in workflow, and duplicate MCP section in README.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant MCP as "WFL MCP Server\n(wfl-lsp --mcp)"
    participant Core as "WflLanguageCore\n(Parser/Analyzer/TypeChecker)"
    participant FS as "FileSystem"

    Client->>MCP: initialize (JSON-RPC)
    MCP-->>Client: initialize response (capabilities)

    Client->>MCP: tools/list
    MCP-->>Client: list of tools

    Client->>MCP: parse_wfl {source}
    MCP->>Core: lex & parse source
    Core-->>MCP: AST / parse result
    MCP-->>Client: parse result

    Client->>MCP: analyze_wfl {source}
    MCP->>Core: analyze & typecheck
    Core-->>MCP: diagnostics
    MCP-->>Client: diagnostics

    Client->>MCP: resources/list
    MCP->>FS: enumerate workspace files
    FS-->>MCP: file list
    MCP-->>Client: resources list
Loading
sequenceDiagram
    participant Parser
    participant Primary as "Primary Expr Parser"
    participant Args as "Argument List Parser"
    participant AST

    Parser->>Primary: parse_primary_expression()
    Primary->>Primary: parse base expression

    alt next token is LeftParen
        Primary->>Args: consume '('
        Args->>Args: parse zero-or-more expressions separated by ','
        Args->>Args: require ')'
        Args-->>Primary: Vec<args>
        Primary->>AST: emit FunctionCall(base, args) with base position
        Primary->>Primary: continue postfix loop with FunctionCall as base
    else other postfix (., [)
        Primary->>Primary: handle property/indexing
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 Hooray, I hopped into the tree,

Scopes now share like friends of me.
Calls in parens clap their paws,
MCP opens helpful jaws.
A tiny input prompt — carrots, please!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.42% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main feature being added: MCP server support for AI assistant integration via the --mcp flag on wfl-lsp.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2db07cf and cc565c9.

📒 Files selected for processing (2)
  • src/analyzer/static_analyzer.rs
  • src/typechecker/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/typechecker/mod.rs
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code according to cargo fmt standards
Ensure Rust code passes clippy linter with no warnings (cargo clippy --all-targets --all-features -- -D warnings)

**/*.rs: Lint clean: run cargo clippy --all-targets --all-features -- -D warnings with no violations
Use snake_case for function and file names
Use CamelCase for types and traits
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/analyzer/static_analyzer.rs
src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.rs: Update bytecode implementation when modifying parser features
Use zeroize and subtle crates for cryptographic security operations
Use hkdf and sha2 crates for key derivation in crypto operations

Files:

  • src/analyzer/static_analyzer.rs
**/*.{rs,toml}

📄 CodeRabbit inference engine (AGENTS.md)

Format Rust code with cargo fmt --all following Rust 2024 edition conventions (see .rustfmt.toml)

Files:

  • src/analyzer/static_analyzer.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Integration Tests (ubuntu-latest)
  • GitHub Check: Build, Test, Clippy
  • GitHub Check: Integration Tests (windows-latest)
🔇 Additional comments (4)
src/analyzer/static_analyzer.rs (4)

438-486: LGTM! Loop variable registration now complete.

The implementation correctly registers loop variables during the collection phase:

  • WhileLoop: Recursively processes body statements
  • ForEachLoop: Registers the loop variable (item_name) and processes body
  • CountLoop: Registers the optional custom loop variable (variable_name) when present and processes body

This addresses the issue from the past review where CountLoop variables weren't being registered in the usages map.


516-519: Critical fix for nested variable declarations.

This change ensures that variables referenced in nested variable declaration initializers (e.g., inside if statements or loops) are properly marked as used. Previously, only top-level variable declarations were processed in the first pass (lines 198-203), causing false-positive unused variable warnings.


586-606: Loop variable handling is now consistent across loop types.

The implementation correctly marks custom CountLoop variables as used automatically (lines 600-605), which is consistent with ForEachLoop behavior (lines 576-578). This design decision treats loop variables as part of the loop's interface—even if not explicitly referenced in the body, declaring them is intentional and should not trigger unused variable warnings.


1741-1928: Comprehensive test coverage addresses previous review feedback.

The test suite effectively validates the static analysis fixes:

  1. test_nested_variable_declaration_tracks_usage: Verifies variables used in nested variable declaration initializers are tracked (fixes the bug where x in store y as x + 5 inside an if block was incorrectly reported as unused)

  2. test_count_loop_custom_variable_not_unused: Confirms custom loop variables are not flagged as unused even when not referenced in the body

  3. test_count_loop_custom_variable_used_in_body: Directly addresses the past review comment by verifying end-to-end correctness when the custom loop variable is actually referenced in the body

  4. test_deeply_nested_variable_usage and test_count_loop_default_variable: Provide additional edge case coverage

All tests follow consistent patterns and include descriptive assertion messages.


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.

Copilot AI 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.

Pull request overview

This PR introduces a Model Context Protocol (MCP) server to enable AI assistants like Claude to interact with WFL codebases, alongside several performance improvements and language updates.

Key changes:

  • Adds MCP server implementation with 6 tools and 5 workspace resources for AI-powered development assistance
  • Optimizes analyzer performance by switching to reference-counted scopes (Rc)
  • Overhauls crypto library with secure buffered sponge construction and formal specification

Reviewed changes

Copilot reviewed 41 out of 42 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
wflhash/wflhashspec.md Adds frozen specification for WFLHASH1 algorithm with test vectors
wfl-lsp/src/mcp_server.rs Implements MCP server with JSON-RPC 2.0 tools and resources
wfl-lsp/src/main.rs Adds --mcp flag routing to enable MCP server mode
wfl-lsp/src/lib.rs Refactors to use shared WflLanguageCore
wfl-lsp/src/core.rs Extracts shared analysis logic for LSP and MCP
src/stdlib/typechecker.rs Registers new input() function type signature
src/stdlib/crypto.rs Rewrites wflhash with buffered sponge construction
src/stdlib/core.rs Implements input() function for console input
src/builtins.rs Adds input to builtin function list
src/analyzer/static_analyzer.rs Fixes unused variable detection for nested contexts
src/analyzer/mod.rs Changes scope parent to Rc for performance
tests/*.rs Updates test infrastructure for cross-platform compatibility
Docs/guides/*.md Adds comprehensive MCP documentation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wfl-lsp/src/mcp_server.rs
}

/// Run the MCP server on stdin/stdout
pub async fn run_server() -> Result<(), Box<dyn std::error::Error>> {

Copilot AI Jan 2, 2026

Copy link

Choose a reason for hiding this comment

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

The MCP server entry point function lacks test coverage. Consider adding integration tests that spawn the server and verify the complete request/response flow, similar to the unit tests for individual handlers.

Copilot uses AI. Check for mistakes.
Improves code readability and maintainability by applying consistent formatting across the codebase. This mainly involves breaking up long lines in function calls, macros, and declarations.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/builtins.rs
Comment on lines 218 to +221
"print" => 1,
"typeof" | "type_of" => 1,
"isnothing" | "is_nothing" => 1,
"input" => 1,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Allow input() to accept optional prompt

native_input was added to read user input and explicitly allows zero or one argument, but get_function_arity still reports that input requires exactly one parameter. The type checker uses this arity when inferring builtin function types, so a call like input() (no prompt) now fails type checking even though the runtime implementation supports it. This makes the new builtin unusable without a dummy argument.

Useful? React with 👍 / 👎.

@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: 20

Caution

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

⚠️ Outside diff range comments (6)
src/interpreter/mod.rs (3)

6115-6128: Cross‑platform cmd/args selection looks good; fix rustfmt failure

The conditional (cmd, args) setup for Windows vs non‑Windows and passing use_shell = false exercises the safe argument‑based path through IoClient::execute_command, which aligns with the subprocess‑sanitization and Tokio async guidelines. The CI failure from cargo fmt --check points at this region, so please run cargo fmt --all to normalize attribute placement/indentation before merging.

As per coding guidelines, this should be rustfmt‑clean.


6209-6221: Update comment to match new arg‑based execution in test_capture_process_output

The comment still refers to “no args = shell execution”, but this test now passes explicit cmd and args, which goes through the non‑shell code path in spawn_process. Suggest updating the comment to avoid confusion with the interpreter’s use_shell/sanitizer behavior.

Proposed comment tweak
-        // Use shell command that works cross-platform (no args = shell execution)
+        // Use a simple echo command that works cross-platform via explicit cmd/args

6239-6251: Keep test_wait_for_process_completion comment consistent with arg‑based spawn

Same as above: this test now uses explicit cmd and args with use_shell = false, so the existing “no args = shell execution” wording is stale. Aligning the comment with the actual behavior will make the intent clearer to future maintainers.

Proposed comment tweak
-        // Use shell command that works cross-platform (no args = shell execution)
+        // Use a simple echo command that works cross-platform via explicit cmd/args
tests/modulo_operator_test.rs (1)

159-159: Update to new error handling syntax.

Line 159 uses the deprecated catch: syntax instead of the new when error: syntax. Per the PR objectives, the language has replaced catch: with when error: to standardize the exception variable. While this is test code, maintaining consistency with the language update improves test maintainability.

🔎 Proposed fix
 try:
     store r as 5 % 0
     change result to "FAIL: No error raised"
-catch:
+when error:
     change result to "PASS"
 end try
tests/subprocess_security_test.rs (2)

128-144: Fix formatting violations flagged by pipeline.

The pipeline reports cargo fmt --check failures on the assertion at line 144 (reported as line 141 pre-change). The assertion message is too long and needs formatting.

🔎 Apply cargo fmt to fix

Run the following command to automatically fix formatting:

cargo fmt --all

Or manually format line 144 to comply with rustfmt rules (likely needs line breaking for the long assertion message).

As per coding guidelines: Format Rust code using cargo fmt --all.


157-172: Fix formatting violations flagged by pipeline.

The pipeline reports cargo fmt --check failures on the assertion at line 172 (reported as line 169 pre-change). The assertion message is too long and needs formatting.

🔎 Apply cargo fmt to fix

Run the following command to automatically fix formatting:

cargo fmt --all

Or manually format line 172 to comply with rustfmt rules (likely needs line breaking for the long assertion message).

As per coding guidelines: Format Rust code using cargo fmt --all.

🧹 Nitpick comments (14)
scripts/run_integration_tests.ps1 (1)

139-145: Consider displaying test output on failure for easier debugging.

The job captures test output (line 141) but never displays it. When a test fails, no diagnostic information is shown, making it harder to debug failures. Consider returning and displaying the output for failed tests.

🔎 Optional enhancement to display output on failure

Modify the script block to return both exit code and output:

            # Run with timeout using background job
            $job = Start-Job -ScriptBlock {
                param($binaryPath, $testFile)
                $output = & $binaryPath $testFile 2>&1
                $exitCode = $LASTEXITCODE
-                # Return only the exit code as a structured object
-                return @{ ExitCode = $exitCode }
+                # Return exit code and output
+                return @{ ExitCode = $exitCode; Output = ($output | Out-String) }
            } -ArgumentList (Resolve-Path $BinaryPath).Path, $wflFile.FullName

Then display output on failure:

                if ($exitCode -eq 0) {
                    Write-Host "[SUCCESS] PASS $($wflFile.Name)" -ForegroundColor Green
                } else {
                    Write-Host "[ERROR] FAIL $($wflFile.Name) (exit code: $exitCode)" -ForegroundColor Red
+                    if ($result.Output) {
+                        Write-Host "  Output:" -ForegroundColor Gray
+                        Write-Host $result.Output -ForegroundColor Gray
+                    }
                    $failedPrograms++
                }
wfl-lsp/examples/README.md (2)

79-111: Consider adding resource cleanup and error handling to examples.

The Python example spawns a subprocess but doesn't demonstrate proper cleanup (process termination) or error handling. While the note on line 203 mentions these concerns, the examples should at least hint at production patterns.

🔎 Enhanced Python example with cleanup
import subprocess
import json

# Start MCP server
proc = subprocess.Popen(
    ['wfl-lsp', '--mcp'],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True
)

try:
    # Send request
    request = {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "parse_wfl",
            "arguments": {
                "source": "store x as 5"
            }
        }
    }
    
    proc.stdin.write(json.dumps(request) + '\n')
    proc.stdin.flush()
    
    # Read response
    response = json.loads(proc.stdout.readline())
    print(response)
finally:
    # Clean up
    proc.terminate()
    proc.wait(timeout=5)

113-140: Consider adding error handling to Node.js example.

Similar to the Python example, the Node.js code doesn't show cleanup or error handling patterns.

🔎 Enhanced Node.js example
const { spawn } = require('child_process');

const server = spawn('wfl-lsp', ['--mcp']);

// Handle errors
server.on('error', (err) => {
  console.error('Failed to start server:', err);
});

// Send request
const request = {
  jsonrpc: '2.0',
  id: 1,
  method: 'tools/call',
  params: {
    name: 'parse_wfl',
    arguments: {
      source: 'store x as 5'
    }
  }
};

server.stdin.write(JSON.stringify(request) + '\n');

// Read response
server.stdout.on('data', (data) => {
  const response = JSON.parse(data.toString());
  console.log(response);
  // Clean up after receiving response
  server.kill();
});

// Timeout safety
setTimeout(() => {
  server.kill();
}, 5000);
generate_hash.wfl (1)

5-6: Minor: Fix comment numbering.

Both comment lines are numbered "1." Consider using sequential numbering or removing the first comment since "Get user input" more accurately describes the following code section.

🔎 Proposed fix
-// 1. Generate the hash
 // 1. Get user input

Or use sequential numbering:

-// 1. Generate the hash
-// 1. Get user input
+// 1. Get user input
README.md (1)

250-290: Consider: Potential content duplication in README.

The AI-generated summary indicates that the MCP section content appears in two places within the README, which could create maintenance burden. Consider consolidating into a single section or using references to avoid duplication.

Based on coding guidelines requiring README updates with significant changes.

Docs/technical/wfl-mcp-architecture.md (2)

30-61: Add language specifier to fenced code block.

The ASCII architecture diagram should specify a language (e.g., text or plaintext) to satisfy markdownlint MD040 and improve accessibility for screen readers.

🔎 Proposed fix
-```
+```text
 ┌──────────────────────────────────────────────────────────────┐
 │                      wfl-lsp Binary                          │

309-319: Add language specifier to directory structure code block.

Similar to the ASCII diagram, this directory structure block should specify a language to satisfy MD040.

🔎 Proposed fix
-```
+```text
 wfl-lsp/
 ├── src/
 │   ├── main.rs          # Entry point, mode selection (50 lines)
src/analyzer/mod.rs (1)

500-505: Defensive fallback to empty scope is unusual but safe.

The Scope::new() fallback when then_scope.parent is None should be unreachable given the code flow (scope is created with a parent on line 491). Consider adding a debug assertion or comment clarifying this is a safety fallback.

🔎 Suggested clarification
                 let outer_scope = if let Some(parent_rc) = &then_scope.parent {
                     Rc::try_unwrap(parent_rc.clone()).unwrap_or_else(|rc| (*rc).clone())
                 } else {
-                    Scope::new() // Shouldn't happen, but provide fallback
+                    // Unreachable: scope created with parent on line 491
+                    debug_assert!(false, "then_scope should always have a parent");
+                    Scope::new()
                 };
wfl-lsp/src/core.rs (1)

167-190: Hardcoded URI in related diagnostic information.

The URI file:///document.wfl is hardcoded for all related diagnostic notes. While functional, this could be confusing when analyzing files with different names. Consider passing the actual document URI or using a placeholder that indicates it's a synthetic location.

wfl-lsp/examples/test_mcp_server.sh (1)

14-22: Test helper suppresses stderr which may hide diagnostics.

The 2>/dev/null redirect suppresses all stderr output including MCP server startup messages and potential error information. Consider using a flag or environment variable to optionally show stderr for debugging.

🔎 Suggested enhancement
 # Function to send JSON-RPC request and pretty-print response
 send_request() {
     local name=$1
     local request=$2
 
     echo -e "${BLUE}[Test] $name${NC}"
-    echo "$request" | wfl-lsp --mcp 2>/dev/null
+    if [ "${DEBUG:-}" = "1" ]; then
+        echo "$request" | wfl-lsp --mcp
+    else
+        echo "$request" | wfl-lsp --mcp 2>/dev/null
+    fi
     echo ""
 }

Usage: DEBUG=1 ./test_mcp_server.sh to see stderr output.

Docs/guides/wfl-mcp-guide.md (1)

258-265: Add language specifier to fenced code block.

The code block showing workspace config output should have a language specifier for proper syntax highlighting.

🔎 Proposed fix
-**Returns:**
-```
-timeout_seconds = 60
-logging_enabled = false
-debug_report_enabled = true
-log_level = info
-```
+**Returns:**
+```ini
+timeout_seconds = 60
+logging_enabled = false
+debug_report_enabled = true
+log_level = info
+```

Based on coding guidelines, this aligns with markdown best practices.

wfl-lsp/examples/simple_mcp_client.rs (1)

8-17: Consider adding child process cleanup.

The spawned wfl-lsp process is not explicitly terminated or waited for. While the OS will clean it up when the parent process exits, it's better practice to explicitly manage the child process lifecycle.

🔎 Suggested enhancement

Add cleanup at the end of main:

println!("========================================");
println!("All examples completed successfully!");
println!("========================================");

// Clean up child process
drop(stdin);
drop(reader);
let _ = child.wait();

Ok(())
src/stdlib/crypto.rs (2)

380-380: Consider a less noisy warning mechanism.

Emitting a warning to stderr on every crypto function call will flood logs and may mask other important messages. Consider alternatives:

  1. Warn once per process using a static flag
  2. Use the log crate with warn! level so users can control verbosity
  3. Document the experimental status prominently instead
🔎 Proposed refactor: Warn once using std::sync::Once
+use std::sync::Once;
+
+static CRYPTO_WARNING: Once = Once::new();
+
+fn warn_experimental_crypto() {
+    CRYPTO_WARNING.call_once(|| {
+        eprintln!(
+            "WARNING: WFL crypto functions are experimental \
+             and provide no security guarantees. USE AT OWN RISK."
+        );
+    });
+}
+
 pub fn native_wflhash256(args: Vec<Value>) -> Result<Value, RuntimeError> {
-    eprintln!("WARNING: WFL crypto functions are experimental and provide no security guarantees. USE AT OWN RISK.");
+    warn_experimental_crypto();
     // ... rest unchanged
 }

Also applies to: 405-405, 424-424, 447-447


398-402: Binary hashing function doesn't emit security warning.

native_wflhash256_binary is the only function that doesn't emit the experimental warning. For consistency, consider adding the warning here as well, or documenting why it's exempt (e.g., internal use only).

🔎 Proposed fix: Add warning for consistency
 pub fn native_wflhash256_binary(input: &[u8]) -> Result<String, RuntimeError> {
+    warn_experimental_crypto(); // If using the Once-based helper
     let params = WflHashParams::new(32);
     let hash = wflhash_core(input, &params)?;
     Ok(bytes_to_hex(&hash))
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d68b5df and 5ca2884.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (41)
  • .claude/settings.local.json
  • CLAUDE.md
  • Docs/guides/claude-desktop-integration.md
  • Docs/guides/wfl-mcp-api-reference.md
  • Docs/guides/wfl-mcp-guide.md
  • Docs/technical/wfl-mcp-architecture.md
  • README.md
  • TestPrograms/complex_expression_catch_test.wfl
  • TestPrograms/unicode_catch_test.wfl
  • generate_hash.wfl
  • hash_output.txt
  • scripts/run_integration_tests.ps1
  • src/analyzer/mod.rs
  • src/analyzer/static_analyzer.rs
  • src/builtins.rs
  • src/interpreter/mod.rs
  • src/main.rs
  • src/stdlib/core.rs
  • src/stdlib/crypto.rs
  • src/stdlib/typechecker.rs
  • tests/analyzer_scope_correctness_test.rs
  • tests/analyzer_scope_performance_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/split_functionality.rs
  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_security_test.rs
  • tests/subprocess_test.rs
  • tests/zero_arg_action_error_propagation_test.rs
  • wfl-lsp/Cargo.toml
  • wfl-lsp/MCP_TEST_REPORT.md
  • wfl-lsp/examples/README.md
  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/examples/test_mcp_server.ps1
  • wfl-lsp/examples/test_mcp_server.sh
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/lib.rs
  • wfl-lsp/src/main.rs
  • wfl-lsp/src/mcp_server.rs
  • wflhash/wflhashspec.md
🧰 Additional context used
📓 Path-based instructions (15)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using cargo fmt --all (see .rustfmt.toml)
Lint clean: run cargo clippy --all-targets --all-features -- -D warnings with no warnings
Use snake_case for function and file names in Rust
Use CamelCase for types and traits in Rust
Use SCREAMING_SNAKE_CASE for constants in Rust
Review SECURITY.md; avoid logging secrets and prefer zeroization for sensitive data in Rust code

**/*.rs: Use Rust Edition 2024 for all Rust code in this project
Format all Rust code with 'cargo fmt --all'
Run 'cargo clippy --all-targets --all-features -- -D warnings' to enforce linting rules

Files:

  • src/stdlib/typechecker.rs
  • tests/string_escape_sequences.rs
  • src/main.rs
  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_test.rs
  • src/builtins.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • src/stdlib/core.rs
  • tests/subprocess_security_test.rs
  • tests/analyzer_scope_correctness_test.rs
  • tests/split_functionality.rs
  • wfl-lsp/src/lib.rs
  • tests/analyzer_scope_performance_test.rs
  • wfl-lsp/src/main.rs
  • src/analyzer/static_analyzer.rs
  • wfl-lsp/examples/simple_mcp_client.rs
  • src/stdlib/crypto.rs
  • src/interpreter/mod.rs
  • tests/zero_arg_action_error_propagation_test.rs
  • src/analyzer/mod.rs
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/mcp_server.rs
src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Component documentation required for all major modules

Files:

  • src/stdlib/typechecker.rs
  • src/main.rs
  • src/builtins.rs
  • src/stdlib/core.rs
  • src/analyzer/static_analyzer.rs
  • src/stdlib/crypto.rs
  • src/interpreter/mod.rs
  • src/analyzer/mod.rs
src/stdlib/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Use WFLHASH custom cryptographic hash function for memory and cryptographic operations

Files:

  • src/stdlib/typechecker.rs
  • src/stdlib/core.rs
  • src/stdlib/crypto.rs
**/*.wfl

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.wfl: Natural language syntax in WFL: use 'store name as "value"' and 'check if x is greater than 5'
Use static typing with intelligent type inference in WFL programs
Use comprehensive error handling with try/when/otherwise blocks in WFL
WFL code must pass linting with 'wfl --lint program.wfl'

Files:

  • generate_hash.wfl
  • TestPrograms/unicode_catch_test.wfl
  • TestPrograms/complex_expression_catch_test.wfl
Docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Keep documentation current in Docs/ directory and update relevant indexes when adding features; major changes warrant a Dev Diary note

Files:

  • Docs/guides/claude-desktop-integration.md
  • Docs/technical/wfl-mcp-architecture.md
  • Docs/guides/wfl-mcp-api-reference.md
  • Docs/guides/wfl-mcp-guide.md
Docs/**

📄 CodeRabbit inference engine (CLAUDE.md)

Update documentation in Docs/ folder with significant changes

Files:

  • Docs/guides/claude-desktop-integration.md
  • Docs/technical/wfl-mcp-architecture.md
  • Docs/guides/wfl-mcp-api-reference.md
  • Docs/guides/wfl-mcp-guide.md
**/tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Integration tests require cargo build --release and must use the provided scripts (run_integration_tests.ps1|.sh)

Files:

  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/subprocess_security_test.rs
  • tests/analyzer_scope_correctness_test.rs
  • tests/split_functionality.rs
  • tests/analyzer_scope_performance_test.rs
  • tests/zero_arg_action_error_propagation_test.rs
**/{tests,TestPrograms}/**

📄 CodeRabbit inference engine (CLAUDE.md)

**/{tests,TestPrograms}/**: Write failing tests FIRST for any feature or bug fix before implementing the solution
Never modify tests to make them pass - fix the implementation instead

Files:

  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/subprocess_security_test.rs
  • tests/analyzer_scope_correctness_test.rs
  • TestPrograms/unicode_catch_test.wfl
  • tests/split_functionality.rs
  • tests/analyzer_scope_performance_test.rs
  • TestPrograms/complex_expression_catch_test.wfl
  • tests/zero_arg_action_error_propagation_test.rs
tests/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.rs: Always run 'cargo build --release' before running integration tests
Integration tests in Rust must use the release binary (target/release/wfl.exe on Windows, target/release/wfl on Unix)

Files:

  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/subprocess_security_test.rs
  • tests/analyzer_scope_correctness_test.rs
  • tests/split_functionality.rs
  • tests/analyzer_scope_performance_test.rs
  • tests/zero_arg_action_error_propagation_test.rs
**/tests/**/*_test.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write failing tests first (TDD approach); feature-oriented test names (e.g., *_test.rs)

Files:

  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/subprocess_security_test.rs
  • tests/analyzer_scope_correctness_test.rs
  • tests/analyzer_scope_performance_test.rs
  • tests/zero_arg_action_error_propagation_test.rs
TestPrograms/*.wfl

📄 CodeRabbit inference engine (CLAUDE.md)

All TestPrograms/*.wfl files MUST pass after any change

Files:

  • TestPrograms/unicode_catch_test.wfl
  • TestPrograms/complex_expression_catch_test.wfl
wfl-lsp/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Implement LSP server support in wfl-lsp workspace member using tower-lsp

Files:

  • wfl-lsp/src/lib.rs
  • wfl-lsp/src/main.rs
  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/mcp_server.rs
src/interpreter/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

src/interpreter/**/*.rs: Interpreter must be async-capable using Tokio runtime
Interpreter subprocess handling must include security sanitization for commands

Files:

  • src/interpreter/mod.rs
{README.md,readme.md}

📄 CodeRabbit inference engine (.cursor/rules/wfl-rules.mdc)

Make sure we update readme.md with any new information

Files:

  • README.md
README.md

📄 CodeRabbit inference engine (CLAUDE.md)

Update README.md with significant changes to the project

Files:

  • README.md
🧠 Learnings (22)
📓 Common learnings
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to wfl-lsp/**/*.rs : Implement LSP server support in wfl-lsp workspace member using tower-lsp
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to Cargo.toml : Configure workspace with Cargo and support workspace members (wfl-lsp, vscode-extension)

Applied to files:

  • wfl-lsp/Cargo.toml
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: LSP crate development: build with `cargo build -p wfl-lsp` and run with `cargo run -p wfl-lsp`

Applied to files:

  • wfl-lsp/Cargo.toml
  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_security_test.rs
  • tests/split_functionality.rs
  • wfl-lsp/src/lib.rs
  • CLAUDE.md
  • wfl-lsp/src/main.rs
  • wfl-lsp/examples/simple_mcp_client.rs
  • tests/zero_arg_action_error_propagation_test.rs
  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Ensure LSP features integration by building release binary: `cargo build --release` provides `target/release/wfl`

Applied to files:

  • wfl-lsp/Cargo.toml
  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/subprocess_security_test.rs
  • tests/split_functionality.rs
  • CLAUDE.md
  • wfl-lsp/src/main.rs
  • wfl-lsp/examples/simple_mcp_client.rs
  • tests/zero_arg_action_error_propagation_test.rs
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Use Rust 1.75+ as minimum version, currently developing with 1.91.1+

Applied to files:

  • wfl-lsp/Cargo.toml
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to README.md : Update README.md with significant changes to the project

Applied to files:

  • wfl-lsp/examples/README.md
  • README.md
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to wfl-lsp/**/*.rs : Implement LSP server support in wfl-lsp workspace member using tower-lsp

Applied to files:

  • wfl-lsp/examples/README.md
  • Docs/technical/wfl-mcp-architecture.md
  • wfl-lsp/src/lib.rs
  • CLAUDE.md
  • wfl-lsp/src/main.rs
  • Docs/guides/wfl-mcp-api-reference.md
  • wfl-lsp/examples/simple_mcp_client.rs
  • Docs/guides/wfl-mcp-guide.md
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/mcp_server.rs
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to src/stdlib/**/*.rs : Use WFLHASH custom cryptographic hash function for memory and cryptographic operations

Applied to files:

  • generate_hash.wfl
  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/subprocess_security_test.rs
  • tests/split_functionality.rs
  • wflhash/wflhashspec.md
  • src/stdlib/crypto.rs
  • tests/zero_arg_action_error_propagation_test.rs
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to tests/**/*.rs : Integration tests in Rust must use the release binary (target/release/wfl.exe on Windows, target/release/wfl on Unix)

Applied to files:

  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/subprocess_security_test.rs
  • scripts/run_integration_tests.ps1
  • tests/split_functionality.rs
  • src/stdlib/crypto.rs
  • src/interpreter/mod.rs
  • tests/zero_arg_action_error_propagation_test.rs
📚 Learning: 2025-08-12T17:35:32.346Z
Learnt from: logbie
Repo: WebFirstLanguage/wfl PR: 150
File: tests/file_io_modes_test.rs:0-0
Timestamp: 2025-08-12T17:35:32.346Z
Learning: In the WFL project tests, file_io_execution_test.rs contains tests that actually execute WFL code through the interpreter and create real files, while file_io_modes_test.rs contains parser-only tests that don't execute code or create files during parsing.

Applied to files:

  • tests/string_escape_sequences.rs
  • tests/subprocess_cleanup_test.rs
  • tests/subprocess_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • tests/subprocess_security_test.rs
  • tests/split_functionality.rs
  • tests/analyzer_scope_performance_test.rs
  • src/stdlib/crypto.rs
  • src/interpreter/mod.rs
  • tests/zero_arg_action_error_propagation_test.rs
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/mcp_server.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Do not break existing WFL programs; ensure backward compatibility and run all `TestPrograms/` before committing

Applied to files:

  • tests/subprocess_cleanup_test.rs
  • tests/split_functionality.rs
  • TestPrograms/complex_expression_catch_test.wfl
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Applies to **/tests/**/*.rs : Integration tests require `cargo build --release` and must use the provided scripts (`run_integration_tests.ps1|.sh`)

Applied to files:

  • tests/subprocess_test.rs
  • tests/file_io_windows_sync_errors_test.rs
  • tests/modulo_operator_test.rs
  • scripts/run_integration_tests.ps1
  • src/interpreter/mod.rs
  • tests/zero_arg_action_error_propagation_test.rs
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to src/interpreter/**/*.rs : Interpreter must be async-capable using Tokio runtime

Applied to files:

  • tests/subprocess_test.rs
  • src/interpreter/mod.rs
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to tests/**/*.rs : Always run 'cargo build --release' before running integration tests

Applied to files:

  • tests/modulo_operator_test.rs
  • tests/zero_arg_action_error_propagation_test.rs
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to TestPrograms/*.wfl : All TestPrograms/*.wfl files MUST pass after any change

Applied to files:

  • scripts/run_integration_tests.ps1
  • TestPrograms/unicode_catch_test.wfl
  • TestPrograms/complex_expression_catch_test.wfl
📚 Learning: 2025-08-11T05:10:43.202Z
Learnt from: logbie
Repo: WebFirstLanguage/wfl PR: 137
File: TestPrograms/test.wfl:1-2
Timestamp: 2025-08-11T05:10:43.202Z
Learning: Some test scripts in TestPrograms/ are deliberately designed to trigger errors as negative test cases to validate error handling and detection mechanisms. The file TestPrograms/test.wfl specifically tests variable redefinition error detection by attempting to use `store` twice on the same variable.

Applied to files:

  • tests/analyzer_scope_correctness_test.rs
  • TestPrograms/unicode_catch_test.wfl
  • TestPrograms/complex_expression_catch_test.wfl
  • tests/zero_arg_action_error_propagation_test.rs
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to **/*.wfl : Use comprehensive error handling with try/when/otherwise blocks in WFL

Applied to files:

  • TestPrograms/unicode_catch_test.wfl
  • TestPrograms/complex_expression_catch_test.wfl
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Enable LSP trace logs with `RUST_LOG=trace cargo run -p wfl-lsp`

Applied to files:

  • wfl-lsp/src/main.rs
  • wfl-lsp/examples/simple_mcp_client.rs
  • tests/zero_arg_action_error_propagation_test.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Applies to **/*.rs : Review `SECURITY.md`; avoid logging secrets and prefer zeroization for sensitive data in Rust code

Applied to files:

  • src/stdlib/crypto.rs
📚 Learning: 2025-08-12T09:39:16.504Z
Learnt from: logbie
Repo: WebFirstLanguage/wfl PR: 148
File: .claude/settings.local.json:41-44
Timestamp: 2025-08-12T09:39:16.504Z
Learning: The .claude/settings.local.json file is specifically formatted for Claude AI assistant usage and should not be reformatted to standard bash command syntax. The existing formatting is intentional and optimized for Claude's permission system.

Applied to files:

  • .claude/settings.local.json
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to src/interpreter/**/*.rs : Interpreter subprocess handling must include security sanitization for commands

Applied to files:

  • src/interpreter/mod.rs
📚 Learning: 2025-12-08T16:25:57.961Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.961Z
Learning: Applies to src/**/*.rs : Component documentation required for all major modules

Applied to files:

  • wfl-lsp/src/core.rs
🧬 Code graph analysis (8)
src/main.rs (1)
src/stdlib/typechecker.rs (1)
  • register_stdlib_types (4-46)
tests/file_io_windows_sync_errors_test.rs (6)
tests/split_functionality.rs (2)
  • path (21-23)
  • get_wfl_binary_path (28-51)
tests/string_escape_sequences.rs (2)
  • path (21-23)
  • get_wfl_binary_path (26-49)
tests/subprocess_cleanup_test.rs (2)
  • path (21-23)
  • get_wfl_binary_path (26-49)
tests/subprocess_security_test.rs (2)
  • path (21-23)
  • get_wfl_binary_path (26-49)
tests/modulo_operator_test.rs (1)
  • get_wfl_binary_path (9-32)
tests/zero_arg_action_error_propagation_test.rs (1)
  • get_wfl_binary_path (11-34)
tests/analyzer_scope_correctness_test.rs (2)
src/lexer/mod.rs (1)
  • lex_wfl_with_positions (88-226)
src/analyzer/mod.rs (3)
  • new (79-84)
  • new (144-150)
  • new (180-325)
tests/split_functionality.rs (2)
tests/file_io_windows_sync_errors_test.rs (1)
  • get_wfl_binary_path (13-36)
tests/modulo_operator_test.rs (1)
  • get_wfl_binary_path (9-32)
wfl-lsp/src/lib.rs (2)
wfl-lsp/src/core.rs (1)
  • new (40-45)
wfl-lsp/src/mcp_server.rs (1)
  • new (51-58)
wfl-lsp/src/main.rs (3)
wfl-lsp/src/core.rs (1)
  • new (40-45)
wfl-lsp/src/lib.rs (1)
  • new (21-27)
wfl-lsp/src/mcp_server.rs (2)
  • new (51-58)
  • run_server (1171-1231)
wfl-lsp/examples/simple_mcp_client.rs (4)
wfl-lsp/src/main.rs (1)
  • main (5-25)
wfl-lsp/src/lib.rs (1)
  • new (21-27)
wfl-lsp/src/mcp_server.rs (1)
  • new (51-58)
wfl-lsp/examples/test_mcp_server.sh (1)
  • send_request (15-22)
tests/zero_arg_action_error_propagation_test.rs (6)
tests/split_functionality.rs (2)
  • path (21-23)
  • get_wfl_binary_path (28-51)
tests/string_escape_sequences.rs (2)
  • path (21-23)
  • get_wfl_binary_path (26-49)
tests/subprocess_cleanup_test.rs (2)
  • path (21-23)
  • get_wfl_binary_path (26-49)
tests/subprocess_security_test.rs (2)
  • path (21-23)
  • get_wfl_binary_path (26-49)
tests/file_io_windows_sync_errors_test.rs (1)
  • get_wfl_binary_path (13-36)
tests/modulo_operator_test.rs (1)
  • get_wfl_binary_path (9-32)
🪛 GitHub Actions: CI
src/stdlib/core.rs

[error] 75-75: cargo fmt --check detected formatting changes. Run 'cargo fmt' to fix code style issues.

tests/subprocess_security_test.rs

[error] 141-141: cargo fmt --check formatting changes in assertion formatting.


[error] 169-169: cargo fmt --check formatting changes in assertion formatting.

wfl-lsp/examples/simple_mcp_client.rs

[error] 1-1: cargo fmt --check formatting changes: import ordering in example.


[error] 47-47: cargo fmt --check formatting changes: adjusted println! usage formatting.


[error] 82-82: cargo fmt --check formatting changes: adjusted as_str() usage formatting.

src/stdlib/crypto.rs

[error] 377-377: cargo fmt --check formatting changes: multiple lines wrapping the warning string.


[error] 402-402: cargo fmt --check formatting changes: multi-line eprintln! macro formatting.


[error] 421-421: cargo fmt --check formatting changes: multi-line eprintln! macro formatting.


[error] 444-444: cargo fmt --check formatting changes: multi-line eprintln! macro formatting.

src/interpreter/mod.rs

[error] 6123-6123: cargo fmt --check detected formatting changes. Run 'cargo fmt' to fix code style issues.


[error] 6123-6123: Formatting diff detected by cargo fmt --check; apply rustfmt.

wfl-lsp/src/core.rs

[error] 1-1: cargo fmt --check formatting changes: re-export formatting for lsp_types imports.

wfl-lsp/src/mcp_server.rs

[error] 205-205: cargo fmt --check formatting changes: single-line vs multi-line formatting in code.


[error] 635-635: cargo fmt --check formatting changes: indentation/line-wrapping adjustments.


[error] 642-642: cargo fmt --check formatting changes: keyword list formatting adjusted.


[error] 712-712: cargo fmt --check formatting changes: argument formatting in function call.

🪛 LanguageTool
Docs/technical/wfl-mcp-architecture.md

[grammar] ~287-~287: Ensure spelling is correct
Context: ...gn - Performance: Analysis is fast (<100ms typically) - Reliability: No concur...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
Docs/guides/claude-desktop-integration.md

30-30: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


309-309: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

wfl-lsp/MCP_TEST_REPORT.md

247-247: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

Docs/technical/wfl-mcp-architecture.md

30-30: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


309-309: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

wflhash/wflhashspec.md

30-30: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

Docs/guides/wfl-mcp-guide.md

30-30: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


309-309: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

README.md

278-278: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: claude-review
  • GitHub Check: config-lint

Comment on lines +301 to +307
```json
// Good
"cwd": "G:/Projects/my-wfl-app"

// Bad
"cwd": "../my-wfl-app"
```

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.

⚠️ Potential issue | 🟡 Minor

Fix language identifier for JSON with comments.

The code block contains JavaScript-style comments (//) which are not valid in standard JSON. Use jsonc (JSON with Comments) or javascript as the language identifier instead of the missing identifier.

🔎 Proposed fix
+```jsonc
 // Good
 "cwd": "G:/Projects/my-wfl-app"

 // Bad
 "cwd": "../my-wfl-app"
+```

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In Docs/guides/claude-desktop-integration.md around lines 301 to 307, the fenced
code block uses JSON but contains JavaScript-style comments which are invalid in
standard JSON; change the code fence language identifier to "jsonc" (or
"javascript") so comments are allowed and ensure the fenced block has a proper
closing ``` fence; do not alter the snippet content, only update the opening
fence language and verify the block is correctly closed.

Comment thread README.md
Comment on lines +157 to +160
# Get exit code from job result
$result = Receive-Job -Job $job
$exitCode = if ($result -and $result.ExitCode -ne $null) { $result.ExitCode } else { 0 }
Remove-Job -Job $job -Force

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.

⚠️ Potential issue | 🟠 Major

Dangerous fallback: defaulting to success on job failure.

Line 159 defaults $exitCode to 0 (success) when the job result is null or doesn't contain an ExitCode. This could mask critical failures if the job crashes, throws an exception, or fails to return the expected structure. A test that genuinely fails could be reported as passing.

🔎 Proposed fix to treat missing exit codes as failures
                # Get exit code from job result
                $result = Receive-Job -Job $job
-                $exitCode = if ($result -and $result.ExitCode -ne $null) { $result.ExitCode } else { 0 }
+                $exitCode = if ($result -and $result.ExitCode -ne $null) { $result.ExitCode } else { 1 }
                Remove-Job -Job $job -Force

                if ($exitCode -eq 0) {

Alternatively, add explicit error handling:

                # Get exit code from job result
                $result = Receive-Job -Job $job
-                $exitCode = if ($result -and $result.ExitCode -ne $null) { $result.ExitCode } else { 0 }
+                if (-not $result -or $result.ExitCode -eq $null) {
+                    Write-Host "[ERROR] FAIL $($wflFile.Name) (job did not return exit code)" -ForegroundColor Red
+                    $exitCode = 1
+                } else {
+                    $exitCode = $result.ExitCode
+                }
                Remove-Job -Job $job -Force
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Get exit code from job result
$result = Receive-Job -Job $job
$exitCode = if ($result -and $result.ExitCode -ne $null) { $result.ExitCode } else { 0 }
Remove-Job -Job $job -Force
# Get exit code from job result
$result = Receive-Job -Job $job
$exitCode = if ($result -and $result.ExitCode -ne $null) { $result.ExitCode } else { 1 }
Remove-Job -Job $job -Force
🤖 Prompt for AI Agents
In scripts/run_integration_tests.ps1 around lines 157 to 160, the code currently
defaults $exitCode to 0 when the job result is null or missing an ExitCode which
hides failures; update the logic to treat missing or null results as a failure:
if Receive-Job returns null or lacks ExitCode set $exitCode to a non‑zero value
(e.g. 1), and add an explicit error/log message including job state or exception
details before removing the job so failures are visible and the script returns
non‑zero on unexpected job termination.

Comment thread src/analyzer/static_analyzer.rs
Comment thread src/stdlib/core.rs
Comment on lines +19 to +21
let mut stdin = child.stdin.take().expect("Failed to open stdin");
let stdout = child.stdout.take().expect("Failed to open stdout");
let reader = BufReader::new(stdout);

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.

⚠️ Potential issue | 🔴 Critical

Reader needs to be mutable for the closure.

The reader variable needs to be declared as mutable since it's captured by the closure and by_ref() requires a mutable reference.

🔎 Proposed fix
 let mut stdin = child.stdin.take().expect("Failed to open stdin");
 let stdout = child.stdout.take().expect("Failed to open stdout");
-let reader = BufReader::new(stdout);
+let mut reader = BufReader::new(stdout);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let mut stdin = child.stdin.take().expect("Failed to open stdin");
let stdout = child.stdout.take().expect("Failed to open stdout");
let reader = BufReader::new(stdout);
let mut stdin = child.stdin.take().expect("Failed to open stdin");
let stdout = child.stdout.take().expect("Failed to open stdout");
let mut reader = BufReader::new(stdout);
🤖 Prompt for AI Agents
In wfl-lsp/examples/simple_mcp_client.rs around lines 19 to 21, the BufReader
instance is not declared mutable but it's later captured by a closure that calls
by_ref(), which requires a &mut reference; change the declaration to create a
mutable reader (e.g., let mut reader = BufReader::new(stdout);) so the closure
can borrow it mutably, and update any subsequent uses to accept &mut reader as
needed.

Comment on lines +247 to +252
```
timeout_seconds = 60
logging_enabled = false
debug_report_enabled = true
log_level = info
```

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.

⚠️ Potential issue | 🟡 Minor

Fix missing language identifier for configuration block.

The configuration content should have a language identifier. Use ini since this is a .wflcfg configuration file format.

🔎 Proposed fix
-```
+```ini
 timeout_seconds = 60
 logging_enabled = false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
timeout_seconds = 60
logging_enabled = false
debug_report_enabled = true
log_level = info
```
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

247-247: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In wfl-lsp/MCP_TEST_REPORT.md around lines 247 to 252, the fenced code block
containing the .wflcfg configuration lacks a language identifier; update the
opening fence to use ```ini so the block is treated as INI syntax (ensure the
opening fence becomes ```ini and keep the existing closing ``` intact).

Comment thread wfl-lsp/src/core.rs
Comment thread wfl-lsp/src/mcp_server.rs
Comment thread wfl-lsp/src/mcp_server.rs
Comment on lines +912 to +942
/// Handle file:///{path} resource
fn handle_file_resource(&self, id: Option<Value>, uri: &str) -> JsonRpcResponse {
// Extract path from file:/// URI
let path_str = uri.strip_prefix("file:///").unwrap_or(uri);
let path = Path::new(path_str);

match fs::read_to_string(path) {
Ok(content) => JsonRpcResponse {
jsonrpc: "2.0".to_string(),
id,
result: Some(json!({
"contents": [{
"uri": uri,
"mimeType": "text/x-wfl",
"text": content
}]
})),
error: None,
},
Err(e) => JsonRpcResponse {
jsonrpc: "2.0".to_string(),
id,
result: None,
error: Some(JsonRpcError {
code: -32603,
message: format!("Failed to read file: {}", e),
data: None,
}),
},
}
}

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.

⚠️ Potential issue | 🟠 Major

Potential path traversal vulnerability in file resource handler.

The handle_file_resource method strips file:/// from the URI and reads the file directly without validating the path is within the workspace. A malicious client could potentially read arbitrary files (e.g., file:///etc/passwd or file:///C:/Windows/System32/config/SAM).

🔎 Suggested fix: validate path is within workspace
     fn handle_file_resource(&self, id: Option<Value>, uri: &str) -> JsonRpcResponse {
         // Extract path from file:/// URI
         let path_str = uri.strip_prefix("file:///").unwrap_or(uri);
         let path = Path::new(path_str);
 
+        // Security: Validate path is within workspace to prevent path traversal
+        if let Some(workspace_root) = &self.workspace_root {
+            let canonical_path = match path.canonicalize() {
+                Ok(p) => p,
+                Err(e) => {
+                    return JsonRpcResponse {
+                        jsonrpc: "2.0".to_string(),
+                        id,
+                        result: None,
+                        error: Some(JsonRpcError {
+                            code: -32603,
+                            message: format!("Invalid path: {}", e),
+                            data: None,
+                        }),
+                    };
+                }
+            };
+            let canonical_root = workspace_root.canonicalize().unwrap_or(workspace_root.clone());
+            if !canonical_path.starts_with(&canonical_root) {
+                return JsonRpcResponse {
+                    jsonrpc: "2.0".to_string(),
+                    id,
+                    result: None,
+                    error: Some(JsonRpcError {
+                        code: -32603,
+                        message: "Access denied: path outside workspace".to_string(),
+                        data: None,
+                    }),
+                };
+            }
+        }
+
         match fs::read_to_string(path) {

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In wfl-lsp/src/mcp_server.rs around lines 912 to 942, the file:// handler
currently strips the prefix and reads the path directly which allows path
traversal (e.g., file:///etc/passwd); fix by resolving and validating the path
against the workspace root before reading: canonicalize the requested path (and
handle failures), canonicalize the workspace root once, ensure the requested
path starts with the workspace canonical path (taking care with path separators
and Windows drive letters), and if it does not return a JsonRpc error (e.g.,
permission/invalid request) instead of reading the file; only call
fs::read_to_string when validation succeeds.

logbie and others added 2 commits January 2, 2026 05:35
- Add comprehensive Git Workflow with Worktrees section
- Document worktree creation, usage, and cleanup procedures
- Establish mandatory worktree usage for all WFL development
- Include best practices and common commands reference
- Fix minor code fence formatting in README.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Add allowed_bots: '*' to claude-code-review workflow
- Fixes error: "Workflow initiated by non-human actor"
- Enables automated reviews from all GitHub bots including google-labs-jules

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>

@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: 5

♻️ Duplicate comments (9)
src/stdlib/core.rs (1)

62-85: Verify that the formatting issue flagged in a previous review has been resolved.

A prior CI run detected formatting changes at line 75. Please ensure cargo fmt --all has been run and the formatting check now passes.

#!/bin/bash
# Check if formatting is correct for this file
cargo fmt --all -- --check
wfl-lsp/examples/simple_mcp_client.rs (4)

40-93: Consider more robust JSON field access.

Multiple .unwrap() calls (lines 52, 64, 88-90) could panic if the server returns unexpected JSON structure. While acceptable for an example, consider using safer access patterns with ? operator or unwrap_or_default() for better robustness.

For instance, line 52 could use:

init_response.get("result")
    .and_then(|r| r.get("serverInfo"))
    .and_then(|s| s.get("version"))
    .and_then(|v| v.as_str())
    .unwrap_or("unknown")

Note: CI also reports a formatting issue at line 47.


95-173: Examples demonstrate MCP protocol correctly.

The example interactions properly demonstrate the MCP JSON-RPC protocol. The .unwrap() usage follows the same pattern noted earlier. CI reports a formatting issue at line 82 that should be addressed with cargo fmt --all.


1-6: Address cargo fmt pipeline failures.

The CI pipeline reports formatting issues including import ordering at line 1. Run cargo fmt --all to fix these formatting inconsistencies.

As per coding guidelines, all Rust code must be formatted with cargo fmt --all.


19-21: Reader needs to be mutable for the closure.

The reader variable needs to be declared as mutable since it's captured by the closure and by_ref() requires a mutable reference.

🔎 Proposed fix
 let mut stdin = child.stdin.take().expect("Failed to open stdin");
 let stdout = child.stdout.take().expect("Failed to open stdout");
-let reader = BufReader::new(stdout);
+let mut reader = BufReader::new(stdout);
wfl-lsp/src/core.rs (1)

1-11: Formatting appears resolved.

The import formatting in the current code matches rustfmt standards (multi-line imports with proper grouping). If CI is still flagging formatting issues, run cargo fmt --all to ensure consistency, but the current state appears correct.

wfl-lsp/src/mcp_server.rs (3)

1-14: Verify formatting with cargo fmt.

Past review indicated formatting issues at multiple locations. Run cargo fmt --all to ensure all imports and formatting comply with rustfmt standards. As per coding guidelines, all Rust code should be formatted consistently.


1197-1258: Add integration tests for the MCP server entry point.

The run_server() function lacks test coverage. Consider adding integration tests that spawn the server and verify complete request/response flows, including error handling for malformed JSON and stdin/stdout communication.

Example test structure:

  • Mock stdin with test JSON-RPC requests
  • Capture stdout responses
  • Verify correct JSON-RPC protocol handling
  • Test error cases (invalid JSON, unknown methods, etc.)

939-969: CRITICAL: Path traversal vulnerability in file resource handler.

The handle_file_resource method strips file:/// and reads the file directly without validating that the path is within the workspace. A malicious MCP client could read arbitrary files on the system (e.g., file:///etc/passwd, file:///C:/Windows/System32/config/SAM, or any sensitive configuration files).

🔎 Proposed fix: validate path is within workspace
 fn handle_file_resource(&self, id: Option<Value>, uri: &str) -> JsonRpcResponse {
     // Extract path from file:/// URI
     let path_str = uri.strip_prefix("file:///").unwrap_or(uri);
     let path = Path::new(path_str);

+    // Security: Validate path is within workspace to prevent path traversal
+    if let Some(workspace_root) = &self.workspace_root {
+        let canonical_path = match path.canonicalize() {
+            Ok(p) => p,
+            Err(e) => {
+                return JsonRpcResponse {
+                    jsonrpc: "2.0".to_string(),
+                    id,
+                    result: None,
+                    error: Some(JsonRpcError {
+                        code: -32603,
+                        message: format!("Invalid path: {}", e),
+                        data: None,
+                    }),
+                };
+            }
+        };
+        let canonical_root = workspace_root.canonicalize().unwrap_or_else(|_| workspace_root.clone());
+        if !canonical_path.starts_with(&canonical_root) {
+            return JsonRpcResponse {
+                jsonrpc: "2.0".to_string(),
+                id,
+                result: None,
+                error: Some(JsonRpcError {
+                    code: -32603,
+                    message: "Access denied: path outside workspace".to_string(),
+                    data: None,
+                }),
+            };
+        }
+    } else {
+        // If no workspace is configured, deny all file access
+        return JsonRpcResponse {
+            jsonrpc: "2.0".to_string(),
+            id,
+            result: None,
+            error: Some(JsonRpcError {
+                code: -32603,
+                message: "No workspace configured - file access denied".to_string(),
+                data: None,
+            }),
+        };
+    }

     match fs::read_to_string(path) {

Based on learnings, review SECURITY.md for additional guidance on secure file handling.

🧹 Nitpick comments (6)
src/stdlib/core.rs (1)

71-75: Consider moving the import to the top and handling flush failure more explicitly.

The use std::io::Write; inside the if-block is valid but unconventional. Additionally, silently discarding the flush result means the prompt may not appear before blocking on input if flush fails.

🔎 Suggested refactor

Move the import to the module level (top of file) and optionally log or propagate flush errors:

 use crate::interpreter::environment::Environment;
 use crate::interpreter::error::RuntimeError;
 use crate::interpreter::value::Value;
+use std::io::Write;
 use std::rc::Rc;

Then simplify the prompt block:

     if let Some(prompt) = args.first() {
         print!("{}", prompt);
-        use std::io::Write;
-        let _ = std::io::stdout().flush();
+        std::io::stdout().flush().ok(); // or propagate error if desired
     }
wfl-lsp/src/mcp_server.rs (1)

989-1012: Duplicate code pattern for workspace scanning.

The logic for scanning .wfl files in the workspace is duplicated across handle_workspace_symbols (lines 992-1012) and handle_workspace_diagnostics (lines 1095-1120). Both use similar patterns: read directory, filter for .wfl files, read content, parse, and collect results.

🔎 Extract common workspace scanning logic

Create a helper method that scans the workspace and applies a callback:

fn scan_workspace_files<F>(&self, mut callback: F) -> Result<(), String>
where
    F: FnMut(&Path, &str) -> Option<Value>,
{
    let workspace_root = self.workspace_root.as_ref()
        .ok_or("No workspace root configured")?;
    
    for entry in fs::read_dir(workspace_root).map_err(|e| e.to_string())? {
        let entry = entry.map_err(|e| e.to_string())?;
        if entry.file_type().map_err(|e| e.to_string())?.is_file() {
            let path = entry.path();
            if path.extension().and_then(|s| s.to_str()) == Some("wfl") {
                if let Ok(content) = fs::read_to_string(&path) {
                    callback(&path, &content);
                }
            }
        }
    }
    Ok(())
}

Then use it in both handlers to reduce duplication.

src/stdlib/crypto.rs (3)

291-291: Remove meta-commentary that describes PR changes.

This comment describes how the code changed rather than documenting its behavior. Such comments become stale and confusing over time.

🔎 Proposed fix
-// ... Params struct remains mostly the same, ensuring zeroize ...
 #[derive(Clone, Debug)]
 struct WflHashParams {

440-444: Inconsistent error messages: "Invalid arg type" vs "Invalid argument type".

Some functions use the abbreviated "Invalid arg type" while others use "Invalid argument type". Consider standardizing for consistent error reporting.

🔎 Proposed fix: Standardize to full form
-        _ => return Err(RuntimeError::new("Invalid arg type".to_string(), 0, 0)),
+        _ => return Err(RuntimeError::new("Invalid argument type".to_string(), 0, 0)),

Also applies to: 465-469


495-512: Consider logging or handling define failures.

The let _ = env.define(...) pattern silently discards any errors from registration. While failures here are unlikely (and may indicate a bug elsewhere), consider at least debug-logging registration failures for easier troubleshooting.

CLAUDE.md (1)

122-126: Reconsider the mandatory worktree requirement.

While git worktrees are useful for parallel development, declaring them "MANDATORY" for all WFL development may be unnecessarily restrictive. This requirement:

  • Is not mentioned in the PR objectives or commit messages
  • May create barriers for new or occasional contributors
  • May be unnecessary for simple changes (documentation, small bugfixes)
  • Adds workflow complexity without clear justification

Consider softening this to "RECOMMENDED" for complex features or parallel work, while allowing developers flexibility for simpler changes.

🔎 Suggested revision
 ## Git Workflow with Worktrees
 
-**MANDATORY: Always use git worktrees when working on WFL tasks.**
+**RECOMMENDED: Use git worktrees for complex features and parallel development.**
 
 Git worktrees allow you to work on multiple branches simultaneously without switching branches in your main working directory. This is the required workflow for all WFL development.
+This workflow is especially helpful when working on multiple features simultaneously or when you need to maintain build isolation.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ca2884 and 3d12987.

📒 Files selected for processing (10)
  • .github/workflows/claude-code-review.yml
  • CLAUDE.md
  • README.md
  • src/interpreter/mod.rs
  • src/stdlib/core.rs
  • src/stdlib/crypto.rs
  • tests/subprocess_security_test.rs
  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/mcp_server.rs
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/subprocess_security_test.rs
  • src/interpreter/mod.rs
🧰 Additional context used
📓 Path-based instructions (4)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using cargo fmt --all (see .rustfmt.toml)
Lint clean: run cargo clippy --all-targets --all-features -- -D warnings with no warnings
Use snake_case for function and file names in Rust
Use CamelCase for types and traits in Rust
Use SCREAMING_SNAKE_CASE for constants in Rust
Review SECURITY.md; avoid logging secrets and prefer zeroization for sensitive data in Rust code

**/*.rs: Use Rust Edition 2024 for all Rust code in this project
Format all Rust code with 'cargo fmt --all'
Run 'cargo clippy --all-targets --all-features -- -D warnings' to enforce linting rules

Files:

  • src/stdlib/core.rs
  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/src/core.rs
  • src/stdlib/crypto.rs
  • wfl-lsp/src/mcp_server.rs
src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Component documentation required for all major modules

Files:

  • src/stdlib/core.rs
  • src/stdlib/crypto.rs
src/stdlib/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Use WFLHASH custom cryptographic hash function for memory and cryptographic operations

Files:

  • src/stdlib/core.rs
  • src/stdlib/crypto.rs
wfl-lsp/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Implement LSP server support in wfl-lsp workspace member using tower-lsp

Files:

  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/mcp_server.rs
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to wfl-lsp/**/*.rs : Implement LSP server support in wfl-lsp workspace member using tower-lsp
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to wfl-lsp/**/*.rs : Implement LSP server support in wfl-lsp workspace member using tower-lsp

Applied to files:

  • wfl-lsp/examples/simple_mcp_client.rs
  • CLAUDE.md
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/mcp_server.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Enable LSP trace logs with `RUST_LOG=trace cargo run -p wfl-lsp`

Applied to files:

  • wfl-lsp/examples/simple_mcp_client.rs
  • CLAUDE.md
  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: LSP crate development: build with `cargo build -p wfl-lsp` and run with `cargo run -p wfl-lsp`

Applied to files:

  • wfl-lsp/examples/simple_mcp_client.rs
  • CLAUDE.md
  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to **/*.rs : Format all Rust code with 'cargo fmt --all'

Applied to files:

  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/src/core.rs
  • wfl-lsp/src/mcp_server.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Applies to **/*.rs : Format Rust code using `cargo fmt --all` (see `.rustfmt.toml`)

Applied to files:

  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to **/*.rs : Run 'cargo clippy --all-targets --all-features -- -D warnings' to enforce linting rules

Applied to files:

  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Applies to **/*.rs : Lint clean: run `cargo clippy --all-targets --all-features -- -D warnings` with no warnings

Applied to files:

  • wfl-lsp/examples/simple_mcp_client.rs
  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Ensure LSP features integration by building release binary: `cargo build --release` provides `target/release/wfl`

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-08-12T17:35:32.346Z
Learnt from: logbie
Repo: WebFirstLanguage/wfl PR: 150
File: tests/file_io_modes_test.rs:0-0
Timestamp: 2025-08-12T17:35:32.346Z
Learning: In the WFL project tests, file_io_execution_test.rs contains tests that actually execute WFL code through the interpreter and create real files, while file_io_modes_test.rs contains parser-only tests that don't execute code or create files during parsing.

Applied to files:

  • CLAUDE.md
  • wfl-lsp/src/core.rs
  • src/stdlib/crypto.rs
  • wfl-lsp/src/mcp_server.rs
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to **/*.wfl : WFL code must pass linting with 'wfl --lint program.wfl'

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to Cargo.toml : Configure workspace with Cargo and support workspace members (wfl-lsp, vscode-extension)

Applied to files:

  • CLAUDE.md
  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to **/*.rs : Use Rust Edition 2024 for all Rust code in this project

Applied to files:

  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Applies to **/*.rs : Use `CamelCase` for types and traits in Rust

Applied to files:

  • wfl-lsp/src/core.rs
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to src/stdlib/**/*.rs : Use WFLHASH custom cryptographic hash function for memory and cryptographic operations

Applied to files:

  • src/stdlib/crypto.rs
📚 Learning: 2025-12-01T18:28:13.642Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T18:28:13.642Z
Learning: Applies to **/*.rs : Review `SECURITY.md`; avoid logging secrets and prefer zeroization for sensitive data in Rust code

Applied to files:

  • src/stdlib/crypto.rs
  • wfl-lsp/src/mcp_server.rs
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to tests/**/*.rs : Integration tests in Rust must use the release binary (target/release/wfl.exe on Windows, target/release/wfl on Unix)

Applied to files:

  • src/stdlib/crypto.rs
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to src/interpreter/**/*.rs : Interpreter subprocess handling must include security sanitization for commands

Applied to files:

  • wfl-lsp/src/mcp_server.rs
🧬 Code graph analysis (2)
wfl-lsp/examples/simple_mcp_client.rs (4)
wfl-lsp/src/main.rs (1)
  • main (5-25)
wfl-lsp/src/mcp_server.rs (1)
  • new (51-58)
wfl-lsp/src/lib.rs (1)
  • new (21-27)
wfl-lsp/examples/test_mcp_server.sh (1)
  • send_request (15-22)
wfl-lsp/src/core.rs (2)
src/lexer/mod.rs (1)
  • lex_wfl_with_positions (88-226)
src/diagnostics/mod.rs (1)
  • from (18-25)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Integration Tests (windows-latest)
  • GitHub Check: Build, Test, Clippy
🔇 Additional comments (15)
src/stdlib/core.rs (1)

59-60: LGTM!

The registration follows the established pattern used for other native functions in this module.

wfl-lsp/examples/simple_mcp_client.rs (3)

8-17: LGTM!

The process spawning logic is correct, with appropriate stdio configuration for JSON-RPC communication over pipes.


23-38: LGTM with dependency on reader mutability.

The closure correctly implements JSON-RPC request/response handling. Once the reader mutability issue (line 21) is fixed, this will work as intended.


175-179: LGTM!

The completion message and overall example structure effectively demonstrate MCP client usage.

wfl-lsp/src/core.rs (2)

253-315: LGTM! Comprehensive test coverage.

The test suite covers core functionality including creation, workspace handling, document lifecycle, and basic analysis scenarios. Good validation of both valid and invalid code paths.


211-231: The code is correct; offset_to_line_col guarantees 1-based coordinates or None on error.

The function explicitly adds 1 to both line and column (lines 242-243) and only returns Some((line, column)) when both values are ≥ 1. It returns None for invalid inputs or out-of-bounds offsets. Therefore, saturating_sub(1) safely converts from 1-based to 0-based indexing with no risk of 0 remaining as a coordinate.

Likely an incorrect or invalid review comment.

wfl-lsp/src/mcp_server.rs (1)

1260-1335: Good test coverage for core MCP functionality.

The test suite validates server creation, initialization, tools listing, and parse tool behavior for both valid and invalid code. Well-structured tests that cover the main success and error paths.

src/stdlib/crypto.rs (6)

1-70: LGTM: Constants and imports are well-structured.

The DoS protection constant MAX_INPUT_SIZE is appropriately public for external validation, and the cryptographic constants are properly documented with their derivation (cube roots of primes).


72-97: LGTM: State structure with proper zeroization.

The buffered sponge state correctly tracks input length with u128 for large inputs, and the Drop implementation properly zeroizes both state and buffer to prevent sensitive data leakage. Based on learnings, this follows the guideline to prefer zeroization for sensitive data.


99-158: LGTM: Initialization and permutation logic.

The parameter mixing into the IV provides proper domain separation, and the MAC mode correctly absorbs the derived key after the initial permutation. The column-then-row G-function application follows standard sponge permutation patterns.


160-186: LGTM: G-function implementation.

The ARX quarter-round follows ChaCha/BLAKE structure with appropriate 64-bit rotation constants. The sequential mixing step (Feistel-like) maintains invertibility as documented. The #[inline(always)] is appropriate for this performance-critical inner loop.


400-404: Missing experimental warning in native_wflhash256_binary.

Unlike the other native hash functions, this function doesn't emit the experimental crypto warning. If this is intentional (e.g., for internal use), consider adding a brief comment explaining why. Otherwise, add the warning for consistency.


477-493: LGTM: Constant-time MAC verification.

The use of subtle::ConstantTimeEq for MAC comparison correctly prevents timing attacks. Returning Ok(false) for invalid MAC length is reasonable behavior for a verification function.

CLAUDE.md (2)

117-120: No issues found. All referenced MCP documentation files exist with correct paths:

  • Docs/guides/wfl-mcp-guide.md ✓
  • Docs/guides/wfl-mcp-api-reference.md ✓
  • Docs/guides/claude-desktop-integration.md ✓
  • Docs/technical/wfl-mcp-architecture.md ✓

81-86: All referenced files exist in the repository.

Verification confirms:

  • wfl-lsp/examples/test_mcp_server.ps1
  • wfl-lsp/examples/test_mcp_server.sh
  • wfl-lsp/examples/simple_mcp_client.rs

The documentation at lines 81-86 is accurate.

Comment on lines +40 to +41
# Allow all bots to trigger Claude Code reviews
allowed_bots: '*'

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat .github/workflows/claude-code-review.yml

Repository: WebFirstLanguage/wfl

Length of output: 3167


🌐 Web query:

anthropics/claude-code-action allowed_bots parameter

💡 Result:

The Claude Code Action supports an allowed_bots input (env var ALLOWED_BOTS / input name allowed_bots) that controls which GitHub bot accounts may trigger the action. By default it's empty (no bots allowed). You can set a comma-separated list of bot usernames (e.g., "dependabot[bot],renovate[bot]") or "*" to allow all bots. [1][2]

Example (workflow with input):

  • allowed_bots: "dependabot[bot],renovate[bot]"

Sources: Anthropic docs (Claude Code Action config) and action config/readme. [1][2]


Restrict allowed_bots from wildcard to specific trusted bots.

The allowed_bots: '*' parameter allows any bot account to trigger Claude Code reviews, creating unnecessary exposure to unauthorized or malicious bots. Since the default behavior is to allow no bots, using a wildcard significantly increases the security surface and API usage costs. Restrict this to specific trusted bots that legitimately need to trigger reviews:

🔎 Proposed fix
-          # Allow all bots to trigger Claude Code reviews
-          allowed_bots: '*'
+          # Allow specific trusted bots to trigger Claude Code reviews
+          allowed_bots: 'dependabot[bot],renovate[bot]'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Allow all bots to trigger Claude Code reviews
allowed_bots: '*'
# Allow specific trusted bots to trigger Claude Code reviews
allowed_bots: 'dependabot[bot],renovate[bot]'
🤖 Prompt for AI Agents
.github/workflows/claude-code-review.yml around lines 40-41: the workflow
currently uses allowed_bots: '*' which permits any bot to trigger Claude Code
reviews; change this to an explicit list of trusted bot accounts (e.g., CI and
automation bot names) by replacing the wildcard with an array of those bot
usernames or GitHub app identifiers, include only the minimum required bots, and
add a brief comment listing the owners/justification for auditability before
committing.

Comment thread src/stdlib/crypto.rs
Comment on lines 261 to 288
fn squeeze(&mut self, output_bytes: usize) -> Vec<u8> {
let mut output = Vec::new();
let mut output = Vec::with_capacity(output_bytes);

while output.len() < output_bytes {
// Extract rate portion
let rate = self.extract_rate();

// Convert to bytes
for &word in &rate {
let bytes = word.to_le_bytes();
output.extend_from_slice(&bytes);

let rate_words = [
self.state[0][0],
self.state[0][1],
self.state[0][2],
self.state[0][3],
self.state[1][0],
self.state[1][1],
self.state[1][2],
self.state[1][3],
];

for &word in &rate_words {
output.extend_from_slice(&word.to_le_bytes());
if output.len() >= output_bytes {
break;
}
}

// Apply permutation for next block
if output.len() < output_bytes {
self.permute();
}
}

output.truncate(output_bytes);
output
}

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.

⚠️ Potential issue | 🟠 Major

Output length is not truncated to exact output_bytes.

The squeeze function may return more bytes than requested. When breaking from the inner loop after extend_from_slice, the output can contain up to 7 extra bytes beyond output_bytes. This could cause issues for callers expecting exact-length output.

🔎 Proposed fix: Truncate output before returning
         if output.len() < output_bytes {
             self.permute();
         }
     }
+    output.truncate(output_bytes);
     output
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn squeeze(&mut self, output_bytes: usize) -> Vec<u8> {
let mut output = Vec::new();
let mut output = Vec::with_capacity(output_bytes);
while output.len() < output_bytes {
// Extract rate portion
let rate = self.extract_rate();
// Convert to bytes
for &word in &rate {
let bytes = word.to_le_bytes();
output.extend_from_slice(&bytes);
let rate_words = [
self.state[0][0],
self.state[0][1],
self.state[0][2],
self.state[0][3],
self.state[1][0],
self.state[1][1],
self.state[1][2],
self.state[1][3],
];
for &word in &rate_words {
output.extend_from_slice(&word.to_le_bytes());
if output.len() >= output_bytes {
break;
}
}
// Apply permutation for next block
if output.len() < output_bytes {
self.permute();
}
}
output.truncate(output_bytes);
output
}
fn squeeze(&mut self, output_bytes: usize) -> Vec<u8> {
let mut output = Vec::with_capacity(output_bytes);
while output.len() < output_bytes {
let rate_words = [
self.state[0][0],
self.state[0][1],
self.state[0][2],
self.state[0][3],
self.state[1][0],
self.state[1][1],
self.state[1][2],
self.state[1][3],
];
for &word in &rate_words {
output.extend_from_slice(&word.to_le_bytes());
if output.len() >= output_bytes {
break;
}
}
if output.len() < output_bytes {
self.permute();
}
}
output.truncate(output_bytes);
output
}
🤖 Prompt for AI Agents
In src/stdlib/crypto.rs around lines 261 to 288, the squeeze method can append
full 8-byte words and then break, producing up to 7 extra bytes beyond
output_bytes; change the logic to ensure exactly output_bytes are produced by
only appending the needed number of bytes from each word (or continue to append
but truncate the output to output_bytes before returning). Update the inner loop
to compute remaining = output_bytes - output.len() and append only
min(remaining, 8) bytes from word.to_le_bytes(), and as a safe final step always
truncate output.truncate(output_bytes) before returning.

Comment thread wfl-lsp/src/core.rs
Comment on lines +176 to +198
if !wfl_diag.notes.is_empty() {
let related = wfl_diag
.notes
.iter()
.map(|note| DiagnosticRelatedInformation {
location: Location {
uri: Url::parse("file:///document.wfl").unwrap(),
range: Range {
start: Position {
line: 0,
character: 0,
},
end: Position {
line: 0,
character: 0,
},
},
},
message: note.clone(),
})
.collect();
related_information = Some(related);
}

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.

⚠️ Potential issue | 🟡 Minor

Hardcoded file URI in related diagnostic information.

The related diagnostic information uses a hardcoded URI "file:///document.wfl" and zero positions for all notes. This means related information won't correctly link to actual file locations, making it less useful for clients.

🔎 Consider using the actual document URI

If the document URI is available in the context, pass it as a parameter to convert_to_lsp_diagnostic and use it here. Alternatively, if related information lacks proper location data, consider omitting the location field entirely or setting it to point to the main diagnostic's location.

-                    location: Location {
-                        uri: Url::parse("file:///document.wfl").unwrap(),
-                        range: Range {
-                            start: Position {
-                                line: 0,
-                                character: 0,
-                            },
-                            end: Position {
-                                line: 0,
-                                character: 0,
-                            },
-                        },
-                    },
+                    location: Location {
+                        uri: Url::parse("file:///document.wfl").unwrap(), // TODO: use actual document URI
+                        range: range,  // Use the main diagnostic's range
+                    },

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In wfl-lsp/src/core.rs around lines 176 to 198, the related diagnostic
information currently uses a hardcoded URI ("file:///document.wfl") and zeroed
positions; update convert_to_lsp_diagnostic to accept the actual document URI
(or the main diagnostic's Location) and use that URI for related items, and
populate each related item's Range/Position from the note's real location data
if available; if no location data exists for a note, either omit the related
DiagnosticRelatedInformation.location field or set it to the main diagnostic's
location so clients can link correctly.

Comment thread wfl-lsp/src/mcp_server.rs
Comment on lines +902 to +920
let mut wfl_files = Vec::new();
if let Ok(entries) = fs::read_dir(workspace_root) {
for entry in entries.flatten() {
if let Ok(file_type) = entry.file_type() {
if file_type.is_file() {
if let Some(path) = entry.path().to_str() {
if path.ends_with(".wfl") {
let file_name = entry.file_name();
wfl_files.push(json!({
"uri": format!("file:///{}", path.replace("\\", "/")),
"name": file_name.to_string_lossy(),
"mimeType": "text/x-wfl"
}));
}
}
}
}
}
}

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.

⚠️ Potential issue | 🟡 Minor

Non-recursive workspace file listing.

The handle_workspace_files function only scans the top-level workspace directory (fs::read_dir) without recursing into subdirectories. If WFL projects typically organize code in subdirectories, this will miss nested .wfl files.

🔎 Consider recursive directory traversal

Use a recursive directory walker (e.g., walkdir crate) to find all .wfl files:

// Add to Cargo.toml: walkdir = "2"
use walkdir::WalkDir;

// In handle_workspace_files:
for entry in WalkDir::new(workspace_root)
    .into_iter()
    .filter_map(|e| e.ok())
    .filter(|e| e.path().extension().and_then(|s| s.to_str()) == Some("wfl"))
{
    // Process entry...
}
🤖 Prompt for AI Agents
In wfl-lsp/src/mcp_server.rs around lines 902 to 920, the current code only
reads the top-level directory with fs::read_dir so nested .wfl files are missed;
replace the non-recursive loop with a recursive directory walker (add walkdir =
"2" to Cargo.toml), iterate WalkDir::new(workspace_root) filtering out Err
entries and keeping only files whose extension is "wfl", then for each matching
entry build the same JSON object (normalizing path separators and creating the
file:/// URI) and push it to wfl_files; ensure you skip unreadable entries
rather than panicking and preserve the existing name/mimeType fields.

Comment thread wfl-lsp/src/mcp_server.rs
Comment on lines +1049 to +1058
let config_path = workspace_root.join(".wflcfg");
let config_content = if config_path.exists() {
fs::read_to_string(&config_path).unwrap_or_else(|_| "{}".to_string())
} else {
json!({
"message": "No .wflcfg file found in workspace",
"using_defaults": true
})
.to_string()
};

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.

⚠️ Potential issue | 🟡 Minor

Config file read without validation.

The .wflcfg file is read and returned as-is without validating that it contains valid JSON or expected configuration structure. If the file contains malformed JSON, the client will receive invalid data.

🔎 Validate configuration file format
 let config_path = workspace_root.join(".wflcfg");
 let config_content = if config_path.exists() {
-    fs::read_to_string(&config_path).unwrap_or_else(|_| "{}".to_string())
+    match fs::read_to_string(&config_path) {
+        Ok(content) => {
+            // Validate it's valid JSON
+            match serde_json::from_str::<Value>(&content) {
+                Ok(_) => content,
+                Err(e) => {
+                    json!({
+                        "error": format!("Invalid .wflcfg format: {}", e),
+                        "using_defaults": true
+                    }).to_string()
+                }
+            }
+        }
+        Err(e) => json!({
+            "error": format!("Failed to read .wflcfg: {}", e),
+            "using_defaults": true
+        }).to_string()
+    }
 } else {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let config_path = workspace_root.join(".wflcfg");
let config_content = if config_path.exists() {
fs::read_to_string(&config_path).unwrap_or_else(|_| "{}".to_string())
} else {
json!({
"message": "No .wflcfg file found in workspace",
"using_defaults": true
})
.to_string()
};
let config_path = workspace_root.join(".wflcfg");
let config_content = if config_path.exists() {
match fs::read_to_string(&config_path) {
Ok(content) => {
// Validate it's valid JSON
match serde_json::from_str::<Value>(&content) {
Ok(_) => content,
Err(e) => {
json!({
"error": format!("Invalid .wflcfg format: {}", e),
"using_defaults": true
}).to_string()
}
}
}
Err(e) => json!({
"error": format!("Failed to read .wflcfg: {}", e),
"using_defaults": true
}).to_string()
}
} else {
json!({
"message": "No .wflcfg file found in workspace",
"using_defaults": true
})
.to_string()
};

Enhances the static analyzer to recognize and track variables declared in `for each` and `count` loops.

Previously, these loop-specific variables were not registered, preventing accurate unused variable analysis. This change updates the variable collection process to correctly identify these declarations.

This allows the analyzer to properly validate their usage within the loop body and report them as unused when appropriate. Tests are added to confirm the correct behavior.
Copilot AI review requested due to automatic review settings January 2, 2026 13:28

Copilot AI 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.

Pull request overview

Copilot reviewed 42 out of 43 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

logbie added 2 commits January 2, 2026 08:17
Introduces support for the conventional `function(arg1, arg2)` syntax for calling functions, complementing the existing space-separated argument style. This change allows for explicit function calls, including those with zero arguments like `random()`.

The interpreter's evaluation logic is updated to handle this new syntax, ensuring that a function reference is resolved correctly before it's called with the provided arguments. A new test case is added to verify this behavior with a zero-argument native function.
Adjusts code indentation and line breaks across several files to improve readability and maintain a uniform style. This change is purely stylistic and does not alter program logic.

@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: 0

🧹 Nitpick comments (3)
src/parser/expr/primary.rs (1)

1117-1175: Well-implemented function call parsing with parentheses.

The postfix handling correctly parses function calls, handles empty argument lists, supports chained calls (via the while loop), and provides clear error messages. Good use of expect_token for the closing paren.

Minor inconsistency (optional): The expression types matched for line/column extraction (lines 1155-1165) differ from the IntLiteral index access case (lines 990-1004). Consider aligning them for consistency—e.g., adding IndexAccess and MethodCall here if those are valid bases for a call expression:

🔎 Suggested alignment (optional)
                             let (base_line, base_col) = match &expr {
                                 Expression::Variable(_, line, col)
                                 | Expression::FunctionCall {
                                     line, column: col, ..
                                 }
                                 | Expression::PropertyAccess {
                                     line, column: col, ..
                                 }
                                 | Expression::StaticMemberAccess {
                                     line, column: col, ..
                                 }
+                                | Expression::IndexAccess {
+                                    line, column: col, ..
+                                }
+                                | Expression::MethodCall {
+                                    line, column: col, ..
+                                }
                                 => (*line, *col),
                                 _ => (token.line, token.column),
                             };
src/interpreter/mod.rs (2)

6224-6231: Update comment or intent now that spawn_process is argument‑based

This test now always passes explicit args with use_shell = false, so the “no args = shell execution” part of the preceding comment is stale. Either update the comment to describe the argument‑based path, or, if you meant to exercise the shell‑execution branch here, switch to use_shell = true and/or the no‑args form.


6254-6261: Same comment drift in test_wait_for_process_completion

Here too, you’re exercising direct, argument‑based spawn_process on all platforms, but the comment still talks about “no args = shell execution”. Consider aligning the comment with the current behavior (or adjusting the test if shell execution was the original intent).

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 769675a and 206033e.

📒 Files selected for processing (4)
  • .claude/settings.local.json
  • src/interpreter/mod.rs
  • src/interpreter/tests.rs
  • src/parser/expr/primary.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • .claude/settings.local.json
🧰 Additional context used
📓 Path-based instructions (4)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using cargo fmt --all (see .rustfmt.toml)
Lint clean: run cargo clippy --all-targets --all-features -- -D warnings with no warnings
Use snake_case for function and file names in Rust
Use CamelCase for types and traits in Rust
Use SCREAMING_SNAKE_CASE for constants in Rust
Review SECURITY.md; avoid logging secrets and prefer zeroization for sensitive data in Rust code

**/*.rs: Use Rust Edition 2024 for all Rust code in this project
Format all Rust code with 'cargo fmt --all'
Run 'cargo clippy --all-targets --all-features -- -D warnings' to enforce linting rules

Files:

  • src/interpreter/tests.rs
  • src/parser/expr/primary.rs
  • src/interpreter/mod.rs
src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Component documentation required for all major modules

Files:

  • src/interpreter/tests.rs
  • src/parser/expr/primary.rs
  • src/interpreter/mod.rs
src/interpreter/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

src/interpreter/**/*.rs: Interpreter must be async-capable using Tokio runtime
Interpreter subprocess handling must include security sanitization for commands

Files:

  • src/interpreter/tests.rs
  • src/interpreter/mod.rs
src/parser/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

src/parser/**/*.rs: Update bytecode when modifying the parser
Parser must use recursive descent parsing with natural language constructs and error recovery

Files:

  • src/parser/expr/primary.rs
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to wfl-lsp/**/*.rs : Implement LSP server support in wfl-lsp workspace member using tower-lsp
📚 Learning: 2025-12-08T16:25:57.972Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T16:25:57.972Z
Learning: Applies to src/interpreter/**/*.rs : Interpreter must be async-capable using Tokio runtime

Applied to files:

  • src/interpreter/tests.rs
  • src/interpreter/mod.rs
🧬 Code graph analysis (1)
src/interpreter/tests.rs (2)
src/parser/mod.rs (1)
  • new (27-32)
src/lexer/mod.rs (1)
  • lex_wfl_with_positions (88-226)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Integration Tests (windows-latest)
  • GitHub Check: Build, Test, Clippy
🔇 Additional comments (3)
src/interpreter/tests.rs (1)

229-250: LGTM! Well-structured test for zero-argument native function calls.

The test correctly validates the new explicit parentheses syntax for zero-argument native functions (random()). It follows the established testing patterns in the file, uses proper async handling with Tokio, and includes appropriate range assertions and error messages.

src/interpreter/mod.rs (2)

4897-4909: Variable fast‑path in FunctionCall correctly bypasses zero‑arg auto‑call

Directly resolving Expression::Variable via env.borrow().get(name) here cleanly sidesteps the auto‑call behavior of Expression::Variable, so foo() now works for zero‑arg native and user‑defined functions without double invocation, while preserving existing behavior for non‑variable call targets and improving the error message span. Looks good.


6133-6138: Cross‑platform execute_command test setup looks solid

The cfg‑split between "cmd" /C echo hello on Windows and echo hello elsewhere, combined with use_shell = false and explicit args, correctly exercises the argument‑based safe path in IoClient::execute_command across platforms.

Resolved merge conflicts by:
- Using main's disable_auto_call implementation for function calls (prevents state leakage)
- Keeping all test cases from both branches (testing native and user-defined zero-arg functions)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
logbie and others added 3 commits January 2, 2026 08:27
The test was for functionality that doesn't exist in main yet.
Fixes compiler warning about unreachable pattern that resulted from merge.
Fixes issue where builtin functions with multiple signatures (like
'length' for both Text and List) were only seeing the first registered
signature. The type checker now checks if a function is builtin BEFORE
looking up its symbol, and returns Type::Any parameters to accept any
compatible type.

This fixes the split_functionality integration tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 2, 2026 14:38

Copilot AI 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.

Pull request overview

Copilot reviewed 43 out of 45 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wflhash/wflhashspec.md
Comment on lines +1 to +3
The following **frozen specification** for WFLHASH1 incorporates all required corrections: explicit MAC key parameter mixing, derived key absorption into the message length, salt zero-padding, and standard HKDF usage.

Following the specification is the corrected **JSON Test Suite**, where all repeated input patterns have been expanded into valid hex strings for direct conformance testing.

Copilot AI Jan 2, 2026

Copy link

Choose a reason for hiding this comment

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

The opening paragraph mentions 'all required corrections' and 'corrected JSON Test Suite' without explaining what was previously incorrect. For a frozen specification document, this phrasing suggests iterative fixes rather than a canonical reference. Consider removing references to corrections and presenting this as the authoritative specification from the start.

Suggested change
The following **frozen specification** for WFLHASH1 incorporates all required corrections: explicit MAC key parameter mixing, derived key absorption into the message length, salt zero-padding, and standard HKDF usage.
Following the specification is the corrected **JSON Test Suite**, where all repeated input patterns have been expanded into valid hex strings for direct conformance testing.
The following **frozen specification** for WFLHASH1 defines explicit MAC key parameter mixing, derived key absorption into the message length, salt zero-padding, and standard HKDF usage.
Following the specification is the canonical **JSON Test Suite**, where all repeated input patterns have been expanded into valid hex strings for direct conformance testing.

Copilot uses AI. Check for mistakes.
Comment on lines +197 to +198
- [WFL MCP User Guide](../../Docs/guides/wfl-mcp-guide.md)
- [WFL MCP API Reference](../../Docs/guides/wfl-mcp-api-reference.md)

Copilot AI Jan 2, 2026

Copy link

Choose a reason for hiding this comment

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

The relative paths to documentation files use inconsistent casing - 'Docs' with capital 'D'. Verify that this matches the actual directory structure. Some systems are case-sensitive and this could lead to broken links.

Suggested change
- [WFL MCP User Guide](../../Docs/guides/wfl-mcp-guide.md)
- [WFL MCP API Reference](../../Docs/guides/wfl-mcp-api-reference.md)
- [WFL MCP User Guide](../../docs/guides/wfl-mcp-guide.md)
- [WFL MCP API Reference](../../docs/guides/wfl-mcp-api-reference.md)

Copilot uses AI. Check for mistakes.
Removes unnecessary newlines to simplify the assignment of a builtin function's return type.

@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

♻️ Duplicate comments (1)
tests/split_functionality.rs (1)

28-51: Duplicated helper function.

This get_wfl_binary_path() helper is duplicated across at least five test files (file_io_windows_sync_errors_test.rs, modulo_operator_test.rs, zero_arg_action_error_propagation_test.rs, subprocess_cleanup_test.rs, and this file). Extract it to a shared test utility module (e.g., tests/common.rs or tests/utils/mod.rs) to eliminate duplication and simplify maintenance.

🤖 Prompt for AI Agents
Create tests/common.rs with:
pub use std::env;
pub use std::path::PathBuf;

pub fn get_wfl_binary_path() -> PathBuf {
    let current_dir = env::current_dir().unwrap();
    let release_path = if cfg!(target_os = "windows") {
        current_dir.join("target/release/wfl.exe")
    } else {
        current_dir.join("target/release/wfl")
    };
    if release_path.exists() {
        return release_path;
    }
    let debug_path = if cfg!(target_os = "windows") {
        current_dir.join("target/debug/wfl.exe")
    } else {
        current_dir.join("target/debug/wfl")
    };
    if debug_path.exists() {
        return debug_path;
    }
    panic!("WFL binary not found. Run 'cargo build' or 'cargo build --release' first.");
}

Then in each test file (split_functionality.rs, file_io_windows_sync_errors_test.rs, modulo_operator_test.rs, zero_arg_action_error_propagation_test.rs, subprocess_cleanup_test.rs):
- Remove the local get_wfl_binary_path() function
- Add at the top: mod common;
- Replace calls with: common::get_wfl_binary_path()
- Remove std::env and std::path::PathBuf imports if only used for this helper
🧹 Nitpick comments (2)
src/typechecker/mod.rs (1)

2159-2195: Remove redundant builtin function checks.

The early-return path at lines 2166-2168 already handles all builtin functions, so the subsequent checks for builtins at lines 2175 and 2181-2183 are unreachable. This creates dead code and unnecessary complexity.

🔎 Proposed simplification
             Expression::ActionCall {
                 name,
                 arguments,
                 line: _line,
                 column: _column,
             } => {
                 // For builtin functions, use special handling (variadic support, etc.)
                 if Analyzer::is_builtin_function(name) {
                     return self.get_builtin_function_type(name, arguments.len());
                 }
 
                 let symbol_opt = self.analyzer.get_symbol(name);
 
                 if symbol_opt.is_none() {
-                    // Check if this is an action parameter, builtin function, or special function name before reporting it as undefined
+                    // Check if this is an action parameter or special function name before reporting it as undefined
                     if self.analyzer.get_action_parameters().contains(name)
-                        || Analyzer::is_builtin_function(name)
                         || name == "helper_function"
                         || name == "nested_function"
                     {
-                        // It's an action parameter or a special function name, so don't report an error
-                        // For builtin functions, return their proper type
-                        if Analyzer::is_builtin_function(name) {
-                            return self.get_builtin_function_type(name, arguments.len());
-                        }
+                        // It's an action parameter or a special function name, so don't report an error
                         return Type::Unknown;
                     } else {
                         self.type_error(
src/analyzer/mod.rs (1)

500-505: Refactor to avoid unnecessary cloning in scope comparisons.

The pattern Rc::try_unwrap(parent_rc.clone()) will always fail to unwrap because parent_rc.clone() creates a temporary reference, forcing a clone of the inner Scope. Since the outer scope is only used for read-only comparison (calling resolve()), you can avoid this clone by borrowing the Rc directly:

🔎 Proposed refactor
-                // Recover the outer scope Rc for variable tracking
-                let outer_scope = if let Some(parent_rc) = &then_scope.parent {
-                    Rc::try_unwrap(parent_rc.clone()).unwrap_or_else(|rc| (*rc).clone())
-                } else {
-                    Scope::new() // Shouldn't happen, but provide fallback
-                };
-
-                for (name, symbol) in &then_scope.symbols {
-                    if outer_scope.resolve(name).is_none() {
+                // Check symbols against parent scope (read-only)
+                for (name, symbol) in &then_scope.symbols {
+                    if let Some(parent_rc) = &then_scope.parent {
+                        if parent_rc.resolve(name).is_none() {
+                            defined_in_then.push((name.clone(), symbol.clone()));
+                        }
+                    } else {
                         defined_in_then.push((name.clone(), symbol.clone()));
                     }
                 }

Apply the same pattern for the else block on lines 530-535.

Also applies to: 530-535

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 206033e and 2db07cf.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • CLAUDE.md
  • src/analyzer/mod.rs
  • src/interpreter/tests.rs
  • src/typechecker/mod.rs
  • tests/split_functionality.rs
  • tests/subprocess_cleanup_test.rs
✅ Files skipped from review due to trivial changes (1)
  • src/interpreter/tests.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/subprocess_cleanup_test.rs
  • CLAUDE.md
🧰 Additional context used
📓 Path-based instructions (4)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code according to cargo fmt standards
Ensure Rust code passes clippy linter with no warnings (cargo clippy --all-targets --all-features -- -D warnings)

**/*.rs: Lint clean: run cargo clippy --all-targets --all-features -- -D warnings with no violations
Use snake_case for function and file names
Use CamelCase for types and traits
Use SCREAMING_SNAKE_CASE for constants

Files:

  • tests/split_functionality.rs
  • src/analyzer/mod.rs
  • src/typechecker/mod.rs
**/*.{rs,toml}

📄 CodeRabbit inference engine (AGENTS.md)

Format Rust code with cargo fmt --all following Rust 2024 edition conventions (see .rustfmt.toml)

Files:

  • tests/split_functionality.rs
  • src/analyzer/mod.rs
  • src/typechecker/mod.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write failing tests first (TDD is mandatory); place unit/integration tests in tests/ directory

Files:

  • tests/split_functionality.rs
src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.rs: Update bytecode implementation when modifying parser features
Use zeroize and subtle crates for cryptographic security operations
Use hkdf and sha2 crates for key derivation in crypto operations

Files:

  • src/analyzer/mod.rs
  • src/typechecker/mod.rs
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T14:20:06.311Z
Learning: Applies to **/*.wfl : Use comprehensive try/when/otherwise error handling in WFL programs
📚 Learning: 2025-08-12T17:35:32.346Z
Learnt from: logbie
Repo: WebFirstLanguage/wfl PR: 150
File: tests/file_io_modes_test.rs:0-0
Timestamp: 2025-08-12T17:35:32.346Z
Learning: In the WFL project tests, file_io_execution_test.rs contains tests that actually execute WFL code through the interpreter and create real files, while file_io_modes_test.rs contains parser-only tests that don't execute code or create files during parsing.

Applied to files:

  • tests/split_functionality.rs
📚 Learning: 2026-01-02T14:20:06.311Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T14:20:06.311Z
Learning: Applies to src/interpreter/**/*.rs : Utilize Tokio runtime for built-in async/await support in WFL

Applied to files:

  • tests/split_functionality.rs
📚 Learning: 2026-01-02T14:20:28.752Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T14:20:28.752Z
Learning: Maintain backward compatibility: do not break existing WFL programs; run all `TestPrograms/` before merging

Applied to files:

  • tests/split_functionality.rs
📚 Learning: 2026-01-02T14:20:28.752Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T14:20:28.752Z
Learning: Applies to tests/**/*_test.rs : Use feature-oriented test file names following the pattern `*_test.rs`

Applied to files:

  • tests/split_functionality.rs
🧬 Code graph analysis (2)
tests/split_functionality.rs (5)
tests/subprocess_cleanup_test.rs (4)
  • path (21-23)
  • get_wfl_binary_path (26-49)
  • run_wfl (51-69)
  • new (14-19)
tests/pattern_replace_test.rs (3)
  • path (19-21)
  • run_wfl (24-46)
  • new (12-17)
tests/file_io_windows_sync_errors_test.rs (1)
  • get_wfl_binary_path (13-36)
tests/modulo_operator_test.rs (1)
  • get_wfl_binary_path (9-32)
tests/zero_arg_action_error_propagation_test.rs (1)
  • get_wfl_binary_path (11-34)
src/typechecker/mod.rs (2)
src/analyzer/mod.rs (4)
  • is_builtin_function (327-329)
  • new (79-84)
  • new (144-150)
  • new (180-325)
src/builtins.rs (2)
  • is_builtin_function (204-206)
  • get_function_arity (215-312)
🪛 GitHub Actions: CI
src/typechecker/mod.rs

[error] 1526-1529: Cargo fmt check failed. Expected formatting changes: convert multi-line return_type into a single-line expression. Run 'cargo fmt' to fix formatting.

🔇 Additional comments (8)
tests/split_functionality.rs (1)

58-60: Good improvement to use dynamic path resolution.

Replacing the hardcoded binary path with get_wfl_binary_path() makes the test more flexible and robust across debug/release builds. Once the helper is extracted to a shared module (see comment on lines 28-51), this usage will be cleaner with a simple common::get_wfl_binary_path() call.

src/typechecker/mod.rs (1)

1518-1560: LGTM: Centralized builtin function handling.

The refactoring correctly consolidates builtin function type resolution into a dedicated early-return path (lines 1523-1533), preventing conflicts with symbol table lookups and properly handling overloaded builtins like length by using Type::Any for parameters. The special-casing of loopcounter and count (lines 1519-1521) is appropriate and avoids unnecessary symbol lookups.

src/analyzer/mod.rs (6)

4-4: Well-documented performance optimization.

The migration from Box<Scope> to Rc<Scope> is well-motivated and clearly documented. The O(N²) to O(N) complexity improvement for deeply nested scopes is a solid optimization.

Also applies to: 60-70, 86-90


566-598: LGTM: Correct Rc-based scope management.

The scope management in SingleLineIf, ForEachLoop, CountLoop, and WhileLoop correctly uses the Rc pattern: wrap in Rc, create child scope, restore parent via Rc::try_unwrap. The fallback to clone is appropriate for these constructs.

Also applies to: 600-638, 640-687, 689-706


742-793: LGTM: Correct scope propagation in WaitForStatement.

The WaitForStatement correctly creates a child scope, analyzes the inner statement, and propagates symbols (like file handles) back to the parent scope using Rc-based management.


800-863: LGTM: Correct Rc-based scope management in TryStatement.

The try/when/otherwise blocks correctly create isolated child scopes using Rc parents and restore the outer scope appropriately.


1462-1511: LGTM: Correct Rc-based scope management in action bodies.

The action body analysis correctly creates an isolated scope for parameters and body statements, and properly restores the outer scope after analysis.


1606-1615: LGTM: Clean abstraction for scope management.

The push_scope and pop_scope helper methods provide a clean, consistent interface for Rc-based scope management, used by container method analysis.

Comment thread src/typechecker/mod.rs Outdated
Collapse nested if-let statements using && chaining as suggested by clippy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 2, 2026 14:53

Copilot AI 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.

Pull request overview

Copilot reviewed 43 out of 45 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/stdlib/crypto.rs
Comment on lines +380 to +382
eprintln!(
"WARNING: WFL crypto functions are experimental and provide no security guarantees. USE AT OWN RISK."
);

Copilot AI Jan 2, 2026

Copy link

Choose a reason for hiding this comment

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

The warning message is printed to stderr on every call to native_wflhash256. This could spam stderr during normal usage. Consider logging this warning once during initialization, using a static flag, or documenting this behavior in the function's documentation rather than printing on every invocation.

Copilot uses AI. Check for mistakes.
Comment thread wfl-lsp/src/mcp_server.rs
}

/// Run the MCP server on stdin/stdout
pub async fn run_server() -> Result<(), Box<dyn std::error::Error>> {

Copilot AI Jan 2, 2026

Copy link

Choose a reason for hiding this comment

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

The function is marked as async but doesn't perform any async operations. The entire implementation is synchronous (reading from stdin, processing, writing to stdout). Consider removing the async keyword and adjusting the caller in main.rs accordingly to simplify the code.

Suggested change
pub async fn run_server() -> Result<(), Box<dyn std::error::Error>> {
pub fn run_server() -> Result<(), Box<dyn std::error::Error>> {

Copilot uses AI. Check for mistakes.
let reader = BufReader::new(stdout);

// Helper function to send request and read response
let mut send_request = |request: Value| -> Result<Value, Box<dyn std::error::Error>> {

Copilot AI Jan 2, 2026

Copy link

Choose a reason for hiding this comment

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

The closure captures reader by reference but attempts to iterate over it with for line in reader.by_ref().lines(). This will fail because reader is moved into the closure on first call and cannot be reused. Each call to send_request will only work once. Consider refactoring to pass reader as a mutable parameter or restructure the client to handle the response reading differently.

Copilot uses AI. Check for mistakes.
Comment thread src/stdlib/crypto.rs
Comment on lines +407 to +409
eprintln!(
"WARNING: WFL crypto functions are experimental and provide no security guarantees. USE AT OWN RISK."
);

Copilot AI Jan 2, 2026

Copy link

Choose a reason for hiding this comment

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

Similar to Comment 2, this warning is printed on every call to native_wflhash512. Consider consolidating warning emissions or using a once_cell/lazy_static pattern to warn once per session.

Copilot uses AI. Check for mistakes.
# WFL MCP Server Test Report

**Date:** January 2, 2026
**Version:** wfl-lsp v0.1.0

Copilot AI Jan 2, 2026

Copy link

Choose a reason for hiding this comment

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

The version number should be verified to match the actual version in Cargo.toml. Consider using a build-time constant or script to ensure version consistency between documentation and code.

Suggested change
**Version:** wfl-lsp v0.1.0
**Version:** wfl-lsp (see Cargo.toml)

Copilot uses AI. Check for mistakes.
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.

2 participants