Skip to content

Codex/typechecker contract audit - #652

Merged
logbie merged 4 commits into
mainfrom
codex/typechecker-contract-audit
Jul 27, 2026
Merged

Codex/typechecker contract audit#652
logbie merged 4 commits into
mainfrom
codex/typechecker-contract-audit

Conversation

@logbie

@logbie logbie commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Open in Devin Review

View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

Summary by CodeRabbit

  • New Features

    • Added comprehensive gradual type-system support, including temporal types, optional values, improved built-in contracts, overload selection, and control-flow inference.
    • Added typed container properties, events, static members, inheritance validation, and enhanced action return-type syntax.
    • Improved handling of aliases, mutable lists, runtime-created bindings, scoped values, and concurrent static-method execution.
    • Code fixing now preserves and formats complex type annotations consistently.
  • Bug Fixes

    • Improved diagnostics and validation for invalid operands, stream handling, response contracts, shadowing, and Nothing values.
  • Documentation

    • Added and expanded documentation covering the type-system design, compatibility rules, and runtime parity requirements.
  • Tests

    • Added extensive regression and integration coverage for parsing, inference, runtime behavior, scoping, built-ins, containers, loops, and static members.

Copilot AI review requested due to automatic review settings July 27, 2026 02:39
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

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

Next review available in: 16 minutes

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

How can I continue?

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

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

How do review limits work?

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

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

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 596e4882-8692-4734-a64f-d1085c1aa82d

📥 Commits

Reviewing files that changed from the base of the PR and between f903e8e and b8acbdf.

📒 Files selected for processing (48)
  • Dev diary/2026-07-26-typechecker-gradual-contract-audit.md
  • Docs/development/compiler-internals.md
  • Docs/development/index.md
  • Docs/development/type-system-design.md
  • TestPrograms/docs_examples/keyword_reference/pattern_examples.wfl.ast.txt
  • src/analyzer/mod.rs
  • src/analyzer/static_analyzer.rs
  • src/builtins.rs
  • src/fixer/mod.rs
  • src/fixer/tests.rs
  • src/interpreter/environment.rs
  • src/interpreter/memory_tests.rs
  • src/interpreter/mod.rs
  • src/interpreter/value.rs
  • src/parser/ast.rs
  • src/parser/stmt/actions.rs
  • src/parser/stmt/containers.rs
  • src/stdlib/core.rs
  • src/stdlib/json.rs
  • src/stdlib/list.rs
  • src/stdlib/random.rs
  • src/stdlib/typechecker.rs
  • src/typechecker/mod.rs
  • tests/action_return_type_residuals_test.rs
  • tests/container_parsing_fixes.rs
  • tests/fixer_return_type_roundtrip_test.rs
  • tests/nothing_reassign_widen_test.rs
  • tests/open_file_local_type_test.rs
  • tests/overload_test.rs
  • tests/static_container_member_test.rs
  • tests/stream_handle_type_test.rs
  • tests/typechecker_alias_provenance_residual_test.rs
  • tests/typechecker_builtin_contract_test.rs
  • tests/typechecker_container_contract_test.rs
  • tests/typechecker_definite_binding_test.rs
  • tests/typechecker_expression_coverage_test.rs
  • tests/typechecker_gradual_any_test.rs
  • tests/typechecker_legacy_list_property_test.rs
  • tests/typechecker_loop_runtime_parity_test.rs
  • tests/typechecker_repeat_until_backedge_test.rs
  • tests/typechecker_response_contract_test.rs
  • tests/typechecker_response_stream_join_test.rs
  • tests/typechecker_response_stream_scope_test.rs
  • tests/typechecker_reuse_test.rs
  • tests/typechecker_runtime_binding_test.rs
  • tests/typechecker_statement_completion_parity_test.rs
  • tests/typechecker_statement_operand_contract_test.rs
  • tests/typechecker_try_finally_join_test.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/typechecker-contract-audit

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.

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 is a broad “typechecker contract audit” pass that tightens WFL’s static typing to better match runtime behavior, adds extensive regression coverage, and documents the intended type-system invariants for future contributions.

Changes:

  • Expanded the type system and parser/fixer surface grammar to support richer, parity-driven typing (e.g., Optional<T>, colon-framed action return types, List of T property annotations, date/time keywords).
  • Hardened runtime parity around builtins, Nothing/Null handling, container/static-member behavior, and flow-sensitive joins (try/finally, loops, definite bindings).
  • Added a large suite of new integration/unit tests plus new developer documentation and a dev diary entry capturing the audited contract.

Reviewed changes

Copilot reviewed 46 out of 47 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/typechecker_try_finally_join_test.rs Extends try/when/finally flow-join tests; adds runtime checks and parsing helper.
tests/typechecker_statement_completion_parity_test.rs New: verifies statement “completion” types match runtime expectations.
tests/typechecker_runtime_binding_test.rs New: asserts typechecker preserves concrete types for runtime-created bindings.
tests/typechecker_reuse_test.rs New: ensures analyzer/typechecker state does not leak across runs.
tests/typechecker_response_stream_scope_test.rs Updates response-stream scoping tests to use real request bindings and operand traversal.
tests/typechecker_response_stream_join_test.rs Expands join/backedge tests (including repeat-until semantics and maybe-empty loop behavior).
tests/typechecker_response_contract_test.rs New: checks respond statement operand traversal and runtime-supported content contracts.
tests/typechecker_loop_runtime_parity_test.rs New: validates loop fixed-point/iteration-scope rules against runtime behavior.
tests/typechecker_legacy_list_property_test.rs New: enforces legacy list-property mutation/type contracts and shadowing precedence.
tests/typechecker_expression_coverage_test.rs New: ensures operands are traversed and checked even for fixed-result expressions.
tests/typechecker_definite_binding_test.rs New: definite-binding escape rules for if/single-line-if and mutability joins.
tests/typechecker_container_contract_test.rs New: comprehensive container contract coverage (init, inheritance, methods, events, properties).
tests/typechecker_builtin_contract_test.rs New: validates builtin arity/type contracts, aliasing, and “unimplemented reserved” behavior.
tests/typechecker_alias_provenance_residual_test.rs New: regression tests for alias/provenance and diagnostic residual behavior.
tests/stream_handle_type_test.rs Adds tests for concrete HttpStream field typing and end-of-stream Nothing guarding.
tests/static_container_member_test.rs New: end-to-end + runtime tests for static members, inheritance, and stored method refs.
tests/overload_test.rs Adds overload resolution coverage for temporal/branded types and adjusts describe-nested test expectations.
tests/open_file_local_type_test.rs Updates test scenario for outer binding type preservation across loop-local file handle rebinding.
tests/nothing_reassign_widen_test.rs Adds coverage that change ... to nothing updates flow types (including conditional cases).
tests/fixer_return_type_roundtrip_test.rs New: ensures CodeFixer emits action return types that reparse back to the same AST types.
tests/container_parsing_fixes.rs Extends parsing regression suite for temporal keywords and list property annotations.
tests/action_return_type_residuals_test.rs Expands action return inference tests and adds runtime checks for loop/try/finally return behavior.
TestPrograms/docs_examples/keyword_reference/pattern_examples.wfl.ast.txt Adds AST snapshot output for a keyword-reference docs example.
src/stdlib/random.rs Adds test ensuring random_seed preserves legacy Nothing identity.
src/stdlib/list.rs Strengthens find “not found” behavior tests to assert legacy Nothing identity semantics.
src/stdlib/json.rs Adds test ensuring JSON null maps to legacy Nothing identity.
src/stdlib/core.rs Treats Nothing like Null in isnothing, and adds unit tests for both variants.
src/parser/stmt/containers.rs Implements recursive colon-style property type parsing (notably List / List of T).
src/parser/stmt/actions.rs Adds framed (double-colon) recursive action return type parsing and colon-style type token helpers.
src/parser/ast.rs Extends Type with Date, Time, DateTime, and Optional<T>.
src/interpreter/value.rs Adds static-method runtime context support, shares static properties via Rc<RefCell<_>>, and aligns Null/Nothing equality.
src/interpreter/memory_tests.rs Updates interpreter memory tests for the new function/static-method context fields.
src/interpreter/environment.rs Adds helpers for method-local shadowing behavior and temporary alias binding save/restore.
src/fixer/tests.rs Adds fixer roundtrip tests for temporal types and action return type syntax.
src/fixer/mod.rs Updates parameter formatting, emits framed return types, and adds formatting support for new Type variants.
src/builtins.rs Separates “recognized” vs “implemented” builtin inventories and adds runtime arity-range API.
src/analyzer/static_analyzer.rs Adds analyzer guidance text for inherited-property compatibility warnings.
Docs/development/type-system-design.md New: documents the audited type-system contract and runtime parity expectations.
Docs/development/index.md Links the new type system design document from development index.
Docs/development/compiler-internals.md Cross-references the new type-system contract doc from compiler internals.
Dev diary/2026-07-26-typechecker-gradual-contract-audit.md New: dev diary record of audit scope, findings, and verification steps.

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

Comment thread tests/open_file_local_type_test.rs Outdated
Comment on lines +70 to +72
// The type checker must reconstruct `out` as File while checking the loop,
// then expose the original outer Text binding after leaving that scope.
let source = "store out as \"outer.txt\"\n\
// then expose the original outer Number binding after leaving that scope.
// Text is intentionally accepted as an opaque runtime file-handle ID.

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

Reviewed commit: 1a3a88c04e

ℹ️ 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/interpreter/mod.rs
Comment on lines +8974 to +8977
for prop in static_properties {
let value = match &prop.default_value {
Some(expression) => {
self._evaluate_expression(expression, env.clone()).await?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Document the newly executable static container members

This activates static properties and methods at runtime, but the user-facing container guide and language specification contain no static-member syntax, access, mutation, inheritance, or lifetime semantics; the only new explanation is the contributor-oriented type-system design note. Add validated examples and reference documentation so users can discover and safely use this newly supported behavior.

AGENTS.md reference: AGENTS.md:L195-L200

Useful? React with 👍 / 👎.

@devin-ai-integration devin-ai-integration 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.

Devin Review found 2 potential issues.

Open in Devin Review

Comment thread src/fixer/mod.rs
Type::Pattern => "Pattern".to_string(),
Type::Date => "date".to_string(),
Type::Time => "time".to_string(),
Type::DateTime => "datetime".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.

🔍 Type::DateTime return annotations do not round-trip through the fixer

format_type/format_action_return_type emit "datetime" (lowercase) for Type::DateTime (src/fixer/mod.rs:1176). On reparse, type_from_token/parse_action_return_type only map the keyword tokens date/time to Type::Date/Type::Time; datetime lexes as a plain Identifier and resolves to Type::Custom("datetime") (src/parser/stmt/actions.rs:26-34). So a Type::DateTime would not survive a fix+reparse cycle, silently degrading to Custom("datetime"), which contradicts the runtime-parity checklist item 'formatting or auto-fixing preserves type identity on reparse'. In practice the parser never produces Type::DateTime for a parameter or return annotation (it always yields Custom("datetime")), so the fixer, which operates on the parsed AST, should not encounter it today. The added tests deliberately only cover Type::Custom("datetime"), not Type::DateTime, so this gap is untested. Worth confirming no code path hands the fixer a Type::DateTime.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/stdlib/typechecker.rs
Comment on lines +327 to +345
fn register_json(analyzer: &mut Analyzer) {
register(analyzer, &["parse_json"], vec![Type::Text], Type::Any);

analyzer.register_builtin_function("sha256", param_types, return_type);
let json_values = [
Type::Nothing,
Type::Boolean,
Type::Number,
Type::Text,
list(Type::Any),
map(Type::Text, Type::Any),
];
for value_type in json_values {
register(
analyzer,
&["stringify_json", "stringify_json_pretty"],
vec![value_type],
Type::Text,
);
}

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.

🔍 stringify_json contract narrowed from Any to a fixed set of value kinds

register_json previously registered stringify_json/stringify_json_pretty with a single Type::Unknown parameter (accepting any value), but now registers six explicit overloads over Nothing, Boolean, Number, Text, List<Any>, and Map<Text, Any> (src/stdlib/typechecker.rs:327-345). Any program that statically passes another concrete type (e.g. a Date/temporal value or a container instance) to stringify_json will now be rejected by the type checker where it previously type-checked. Whether this is a backward-compatibility regression depends on whether native_stringify_json actually errors on those inputs at runtime; the audit claims 'a statically rejected concrete type would also fail at runtime', but this pairing should be verified against the runtime implementation before relying on it.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@logbie
logbie force-pushed the codex/typechecker-contract-audit branch from 1a3a88c to 3938edb Compare July 27, 2026 02:59
Copilot AI review requested due to automatic review settings July 27, 2026 02:59
logbie and others added 3 commits July 27, 2026 03:00
Adding the expected syntax tree for the pattern matching reference code. This serves as a "blueprint" that allows automated tests to verify the examples shown in the documentation are valid and remain correct as the language evolves.
The #642 repeat-until backedge regression tests retype `out` by opening a
response stream in the loop body. After rebasing onto main, the gradual
type-checking contract added by this PR requires the streaming target to be a
request object, so the previous text-literal target ("req") is now a type
error that masked the softening behavior under test. Bind `req` via
`wait for request comes in on srv as req` and stream `to req`, matching the
convention this PR already applies to the sibling response-stream tests. The
softening assertions are unchanged and still pass.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

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 47 out of 48 changed files in this pull request and generated 2 comments.

Comment thread src/fixer/mod.rs
Type::Pattern => "Pattern".to_string(),
Type::Date => "date".to_string(),
Type::Time => "time".to_string(),
Type::DateTime => "datetime".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.

The fixer's Type::DateTime arm is unreachable for parsed programs: WFL has no DateTime/datetime keyword, so datetime annotations parse to Type::Custom("datetime") (handled by the Custom arm), and both datetime and DateTime reparse to Custom and bridge back to Type::DateTime via case-insensitive comparison, so identity is preserved either way. Lowercase datetime is the codebase's canonical spelling (analyzer type_to_string, temporal_kind); WFL explicitly has no unambiguous capital DateTime source form, so emitting it would only diverge without improving round-trip.

Comment thread src/parser/ast.rs Outdated
Comment on lines +1074 to +1076
/// An inferred value that may be `Nothing` because an action can fall
/// through without executing a value-returning `return`.
Optional(Box<Type>),
Re-add the test-only `RunState::fresh(call_depth)` constructor that an earlier
rebase dropped. The inline concurrent-handler unit tests reference it, so
`cargo test` failed to compile the lib test target even though a plain
`cargo build` (which never compiles that cfg(test) code) succeeded.

Stop downgrading WebSocket handler event bindings to `Unknown`.
`bind_runtime_value` already recreates the binding in the handler scope with
its concrete runtime map type, shadowing any outer same-named symbol (#642),
so keeping that map type leaves field/index access on the event object
permissive while still rejecting misuse such as arithmetic on it. This
restores the runtime-binding contract test.

Also broaden the `Type::Optional` doc comment to cover every `T | Nothing`
source (find-style lookups, control-flow joins), not just action fall-through,
and correct a stale comment in the open-file local-type test.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
@logbie
logbie force-pushed the codex/typechecker-contract-audit branch from 3938edb to b8acbdf Compare July 27, 2026 03:23
Copilot AI review requested due to automatic review settings July 27, 2026 03:23

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 47 out of 48 changed files in this pull request and generated no new comments.

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