Skip to content

fix: stop rules from quietly taking the wrong branch - #202

Merged
Pama-Lee merged 3 commits into
mainfrom
fix/silent-wrong-decisions
Oct 18, 2026
Merged

Pama-Lee merged 3 commits into
mainfrom
fix/silent-wrong-decisions

Conversation

@Pama-Lee

@Pama-Lee Pama-Lee commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Before: several ordinary rules returned a confident, wrong decision with no error. Checked against the released 0.9.0 CLI and server:

  • applicant.age < 18 || blacklisted == true with blacklisted: true and no age returned APPROVED. The missing field made the whole condition false, so a blacklisted applicant went through.
  • In jev-routing, renaming jev.intent.confidence to jev.intent.confidense passed ordo validate and ordo lint. At run time the field is always missing, so every "not a refund" message falls into the refund path.
  • An input field called data or item couldn't be read: data.x == 1 was always false.
  • max(scores) == 100 was always false, because max/min given one array returned the array itself.
  • "a\sb" turned into asb, so regexes like "\d+" silently matched the wrong thing.
  • ordo impact ... | head panicked (exit 101).

After:

  • A missing field makes only its own comparison unknown. A true side of || still matches, a false side of && still fails, and anything still unknown stays false as before. This only runs after a missing-field error, so the normal path costs nothing extra.
  • With an input schema, ordo validate / ordo lint report each field the rules read that the schema does not declare ([intent] jev.intent.confidense is not in the input schema). Variables ($x) and external data ($data.x) are skipped. An object with no listed fields accepts any sub-path.
  • data.x and item.x read the input field when it exists (otherwise they behave as before).
  • max(arr) / min(arr) return the largest/smallest element (null for an empty array).
  • Unknown escapes keep their backslash. \n \t \r \\ \" \' are unchanged.
  • The CLI exits quietly on a closed pipe.
  • Docs (en + zh): missing-field wording in expression syntax, rule structure and guard; a short Strings section on escapes; max(arr) in built-in functions.

How: Kleene-style evaluation in RuleExecutor on the lenient missing-field path; undeclared_fields() in rule/input_schema.rs, called by the CLI validator; prefix fallback in Context::get; a shared extreme() for min/max; one parser match arm; SIGPIPE reset in the CLI main.

Tested on the merged tree: cargo fmt --check, cargo clippy --all-targets --all-features -D warnings and cargo test --all-features --workspace all pass, with new tests for each case. All four rule packs validate and all their tests pass. Earlier, 6000 concurrent execute calls against the built server all returned 200.

Not covered: the binary .ordo executor still treats a missing field as making the whole condition false.

- A missing field now makes only its own comparison unknown, so
  `age < 18 || blacklisted` still matches a blacklisted applicant
  who sent no age (it used to fall through to the default branch).
- `ordo validate` / `ordo lint` report a field the input schema
  does not declare (a typo like `confidense` used to pass and never match).
- Input fields named `data` or `item` can be read (`data.x` used to
  miss the field).
- `max(scores)` / `min(scores)` work on one array (they returned the array,
  so `max(scores) == 100` was always false).
- Unknown string escapes keep their backslash, so regexes like "\d+" work.
- `ordo trace ... | head` exits quietly instead of panicking.
- Docs: contains_str, array elements as path segments, map_extract,
  no implicit string/number conversion.
@vercel

vercel Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ordo_docs Ready Ready Preview Oct 18, 2026 6:04am UTC

# Conflicts:
#	crates/ordo-core/src/context/store.rs
#	ordo-editor/apps/docs/en/guide/builtin-functions.md
#	ordo-editor/apps/docs/en/guide/expression-syntax.md
#	ordo-editor/apps/docs/en/guide/rule-structure.md
#	ordo-editor/apps/docs/en/platform/guard.md
#	ordo-editor/apps/docs/zh/guide/builtin-functions.md
#	ordo-editor/apps/docs/zh/guide/expression-syntax.md
#	ordo-editor/apps/docs/zh/guide/rule-structure.md
#	ordo-editor/apps/docs/zh/platform/guard.md

Pama-Lee commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator Author

Dependency audit failed on RUSTSEC-2026-0349, a rustls 0.23.45 advisory published after main last ran CI. It isn't caused by this PR's changes, and main would fail the same check. b57b65b bumps rustls to 0.23.46 in Cargo.lock. Clippy and all workspace tests still pass with it.

Pama-Lee commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator Author

After the 0.23.46 bump, Dependency audit still fails on rustls 0.21.12 (RUSTSEC-2026-0346 and RUSTSEC-2026-0349). That version comes in through tonic 0.10's TLS stack (ordo-grpc / ordo-server), and main has exactly the same lock entry, so this PR doesn't cause it. The fixes only exist in rustls 0.23.46+, which means migrating to tonic/hyper 1.x. That's the same migration deny.toml already tracks for RUSTSEC-2026-0258.

Neither advisory looks reachable here. 0346 only affects Debug output of a custom ClientSessionStore, and Ordo has none. 0349 can drop post-quantum key exchange on resumed client connections, but classical TLS is not weakened. I haven't added them to the deny.toml ignore list: the owner needs to decide that.

@Pama-Lee
Pama-Lee merged commit 7402a4a into main Oct 18, 2026
14 of 15 checks passed
@Pama-Lee Pama-Lee mentioned this pull request Oct 19, 2026
Pama-Lee added a commit that referenced this pull request Oct 19, 2026
* chore: release 0.9.1

Bump crates and the npm wrapper to 0.9.1 to ship #202.

* chore: upgrade tonic to 0.12 to drop rustls 0.21

tonic 0.10's TLS stack pulled in rustls 0.21.12, which has RUSTSEC-2026-0346
and RUSTSEC-2026-0349 and no fixed 0.21 release. tonic 0.12 uses rustls 0.23,
so cargo deny passes again.

- tonic 0.10 -> 0.12, prost 0.12 -> 0.13, tonic-build 0.10 -> 0.12; generated
  gRPC code regenerated.
- UDS test client wraps UnixStream in hyper_util's TokioIo (hyper 1 IO traits).

This branch was successfully deployed

1 active deployment
Preview – ordo_docs — b57b65ba Deployed Oct 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant