Skip to content

fix(library)!: make manifest-declared flows portable across Colang versions#2185

Open
Pouyanpi wants to merge 9 commits into
pouyanpi/rail-library-stack-4-builtinsfrom
pouyanpi/rail-library-stack-4b-flow-gate
Open

fix(library)!: make manifest-declared flows portable across Colang versions#2185
Pouyanpi wants to merge 9 commits into
pouyanpi/rail-library-stack-4-builtinsfrom
pouyanpi/rail-library-stack-4b-flow-gate

Conversation

@Pouyanpi

@Pouyanpi Pouyanpi commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Description

Several packaged library flows either fail to parse under Colang 2 or invoke
action names the runtime cannot resolve. This PR normalizes vendor action
names, repairs the broken Colang 2 flows, adds the missing GCP Colang 1 variant,
and adds a cross-dialect regression gate. Parameterized Colang 2 flows remain
exempt from Colang 1 presence.

It also fixes blocked retrieval rails that re-enter retrieval instead of
terminating, preserves GCP's action-owned fail-closed verdict, and covers
context-bloat allow, block, and transform outcomes.

Compatibility: custom Colang 1 flows using the old space-separated Cleanlab,
Fiddler, or GCP action names must switch to their snake_case names. users enabling the shipped rail flows are unaffected because the bundled flows are updated together.

Impact

  • Built-in manifest-declared rails can load and invoke their actions under both
    packaged Colang dialects instead of failing on invalid syntax or unresolved
    names.
  • The gate detects future drift among manifest action references, flow bodies,
    and registered action names during tests rather than at user runtime.
  • ActiveFence and GCP retain backend-neutral action-owned verdicts while their
    Colang flows remain responsible only for response presentation.
  • GCP moderation remains fail-closed even when detailed violation metadata is
    unavailable.
  • No configuration schema or manifest API is added in this layer.

Stack

Layer Branch Base PR
Stack 3 pouyanpi/rail-library-stack-3-manifest-contract develop #2157
Stack 4 pouyanpi/rail-library-stack-4-builtins Stack 3 #2181
Stack 4b pouyanpi/rail-library-stack-4b-flow-gate Stack 4 #2185
Stack 5 pouyanpi/rail-library-stack-5-lazy-actions Stack 4b #2186

Related Issue(s)

  • Fixes #
  • Internal tracking: NGUARD-855
  • Issue assignee: @

Verification

AI Assistance

  • No AI tools were used.
  • AI tools were used; a human reviewed and can explain every change (tool: Codex).

Codex assisted with implementation analysis, validation, stack restructuring,
and this draft. Check the disclosure box after human review.

Checklist

  • I've read the CONTRIBUTING guidelines.
  • This PR links to a triaged issue assigned to me.
  • My PR title follows the project commit convention.
  • I've updated the documentation if applicable.
  • I've added tests if applicable.
  • I've noted any verification beyond CI and any checks I couldn't run.
  • I did not update generated changelog files manually.
  • I addressed all CodeRabbit, Greptile, and other review comments, or replied with why no change is needed.
  • @mentions of the person or team responsible for reviewing proposed changes.

@github-actions github-actions Bot added status: needs triage New issues that have not yet been reviewed or categorized. size: L labels Jul 17, 2026
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4-builtins branch from 2310548 to f72f3e2 Compare July 17, 2026 11:58
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from c23f5a4 to b05380f Compare July 17, 2026 12:07
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4-builtins branch from abf6536 to be38ebc Compare July 20, 2026 07:18
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from b05380f to 33729cf Compare July 20, 2026 07:18
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4-builtins branch from be38ebc to 938e50e Compare July 20, 2026 12:34
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from 33729cf to 26ce747 Compare July 20, 2026 12:34
@Pouyanpi Pouyanpi changed the title fix(library): make manifest-declared flows portable across Colang versions fix(library)!: make manifest-declared flows portable across Colang versions Jul 20, 2026
@Pouyanpi Pouyanpi added status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile). and removed status: needs triage New issues that have not yet been reviewed or categorized. labels Jul 20, 2026
@Pouyanpi
Pouyanpi marked this pull request as ready for review July 20, 2026 13:53
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR normalizes vendor action names to snake_case, repairs Colang 2 flow files that used invalid syntax (lowercase await calls treated as flow references, old space-separated action names), adds the missing GCP Colang 1 flow file, fixes retrieval rails that re-entered retrieval on block, and adds a cross-dialect regression gate (test_library_flow_files.py).

  • Action renames: call cleanlab apicall_cleanlab_api, call gcpnlp apicall_gcpnlp_api, three Fiddler names, and call activefence api / call gcpnlp api in filters.py are normalized to CallActivefenceApiAction / CallGcpnlpApiAction (the PascalCase form the Colang 2 runtime emits on ActionFinished).
  • Retrieval block fix: Colang 1 retrieval flows for gliner, polygraf, privateai, sensitive_data_detection, and context_bloat_detection now use create event BotMessage(text=...) + $skip_output_rails = True instead of a bot X directive (which caused the retrieval pipeline to re-trigger), while Colang 2 already used abort and is unaffected.
  • New tests: test_library_flow_files.py enforces parse validity, cross-dialect flow presence, and action-resolver consistency at CI time.

Confidence Score: 4/5

Safe to merge once the Colang 1 retrieval flow files that access $config.bot_messages without a local message definition are addressed; otherwise those retrieval rails will throw a KeyError at runtime for configurations that do not co-load a file defining the required bot message.

The action name normalizations, GCP dialect additions, and Colang 2 fixes are all correct and well-tested. The retrieval re-entry fix is sound for the context_bloat case where the message is defined locally. For gliner, polygraf, privateai, and sensitive_data_detection the same pattern reads a bot message key not defined in the respective flows.v1.co files, so the fix works only if the user config happens to load another library that defines the key.

nemoguardrails/library/gliner/flows.v1.co, nemoguardrails/library/polygraf/flows.v1.co, nemoguardrails/library/privateai/flows.v1.co, and nemoguardrails/library/sensitive_data_detection/flows.v1.co — each references a bot message key not defined locally.

Important Files Changed

Filename Overview
nemoguardrails/library/sensitive_data_detection/flows.v1.co Retrieval block now uses $config.bot_messages["inform answer unknown"][0]; this key is NOT defined in this file and must come from user config or another loaded library.
nemoguardrails/library/gliner/flows.v1.co Retrieval block changed to use $config.bot_messages["refuse to respond"][0] + create event BotMessage, but "refuse to respond" is not defined in this file.
nemoguardrails/library/gcp_moderate_text/flows.co Converted from Colang 1 to Colang 2 (flow / await CallGcpnlpApiAction / abort); underscore in abusive_or_harmful flow name matches defined bot flow.
nemoguardrails/library/gcp_moderate_text/flows.v1.co New file: Colang 1 equivalent of the GCP moderation flows using call_gcpnlp_api and stop.
nemoguardrails/llm/filters.py Replaces space-separated old action names with PascalCase forms the Colang 2 runtime emits in ActionFinished events.
nemoguardrails/library/regex/flows.co Renames DetectRegexMatchAction to DetectRegexPatternAction, matching the registered action name detect_regex_pattern.
nemoguardrails/library/autoalign/flows.co Fixes the only remaining lowercase action invocation: autoalign_factcheck_output_api to AutoalignFactcheckOutputApiAction.
tests/rails/llm/test_library_flow_files.py New regression gate: parses flow files in both dialects, checks declared flow names, flags lowercase action invocations, and verifies action resolver consistency.
tests/test_runtime_flow_gate_equivalence.py Extends equivalence test: adds retrieval RailSpecs, context_bloat cases, GCP detailed-moderation block cases, and injection-detection parametrized test.
nemoguardrails/library/injection_detection/flows.co Colang 2 rewrite with correct $ prefixes, $system.config, elif, readable detection joins, and abort at correct indent level.
nemoguardrails/library/context_bloat_detection/flows.v1.co Retrieval block uses direct BotMessage event to avoid re-entry; message key is defined in the same file.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Library Rail Loaded] --> B{Colang Dialect?}
    B -->|Colang 1 - flows.v1.co| C[execute snake_case_action]
    B -->|Colang 2 - flows.co| D[await CamelCaseAction]
    C --> E{Action resolves?}
    D --> F{Action resolves?}
    E -->|YES| G[Outcome: RailOutcome]
    E -->|NO - old space-separated name| H[Runtime Error]
    F -->|YES - dispatcher normalizes PascalCase| G
    F -->|NO - lowercase await is a flow ref| I[Silent wrong flow call]
    G --> J{is_blocked?}
    J -->|YES - Colang 2| K[bot X Y Z + abort]
    J -->|YES - Colang 1 INPUT/OUTPUT| L[bot X Y Z + stop]
    J -->|YES - Colang 1 RETRIEVAL| M[create event BotMessage + stop]
    J -->|NO - is_transform| N[Modify context variable]
    style H fill:#f66
    style I fill:#f66
    style M fill:#6f6
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Library Rail Loaded] --> B{Colang Dialect?}
    B -->|Colang 1 - flows.v1.co| C[execute snake_case_action]
    B -->|Colang 2 - flows.co| D[await CamelCaseAction]
    C --> E{Action resolves?}
    D --> F{Action resolves?}
    E -->|YES| G[Outcome: RailOutcome]
    E -->|NO - old space-separated name| H[Runtime Error]
    F -->|YES - dispatcher normalizes PascalCase| G
    F -->|NO - lowercase await is a flow ref| I[Silent wrong flow call]
    G --> J{is_blocked?}
    J -->|YES - Colang 2| K[bot X Y Z + abort]
    J -->|YES - Colang 1 INPUT/OUTPUT| L[bot X Y Z + stop]
    J -->|YES - Colang 1 RETRIEVAL| M[create event BotMessage + stop]
    J -->|NO - is_transform| N[Modify context variable]
    style H fill:#f66
    style I fill:#f66
    style M fill:#6f6
Loading

Reviews (5): Last reviewed commit: "fix(llm): filter vendor actions from Col..." | Re-trigger Greptile

Comment thread nemoguardrails/library/injection_detection/flows.co Outdated
Comment thread nemoguardrails/library/injection_detection/flows.co Outdated
Comment thread tests/test_runtime_flow_gate_equivalence.py
Comment thread nemoguardrails/llm/filters.py Outdated
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4-builtins branch from 938e50e to 4abf429 Compare July 20, 2026 15:49
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from 26ce747 to cb7c03c Compare July 20, 2026 15:49
@Pouyanpi
Pouyanpi marked this pull request as draft July 20, 2026 15:50
@Pouyanpi Pouyanpi added this to the v0.24.0 milestone Jul 21, 2026
@Pouyanpi Pouyanpi self-assigned this Jul 21, 2026
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from 3c696d7 to 6a88f13 Compare July 21, 2026 08:46
@Pouyanpi

Copy link
Copy Markdown
Collaborator Author

@greptileai any pending issues?

@greptile-apps

greptile-apps Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

All four inline review threads are resolved. The GCP flows.v1.co bot-message mismatch flagged in the summary ("in inappropriate content" vs "with inappropriate content") is also fixed — the current file uses "with" consistently throughout. Codecov is green.

The one loose end: at the end of the filters.py thread, I asked whether to persist a rule about Colang 2 ActionFinished events preserving PascalCase action names. No action needed on your side unless you want that rule saved — just let me know and I'll create it.

Everything else looks good to merge.

@Pouyanpi
Pouyanpi marked this pull request as ready for review July 21, 2026 08:57
@Pouyanpi
Pouyanpi requested a review from tgasser-nv July 21, 2026 08:57
Space-separated action names (call cleanlab api, call fiddler safety on
user message, call fiddler safety on bot message, call fiddler
faithfulness, call gcpnlp api) can never be invoked from Colang 2:
CamelCaseAction invocations normalize to snake_case and the dispatcher
has no alias support. Rename them to the snake_case forms the Colang 2
flows already call, updating v1 flows, docs, log filters, and the
runtime flow gate equivalence fixtures.

Breaking change: custom Colang 1 flows that execute the old spaced
names must switch to the snake_case names.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Pouyanpi added 8 commits July 21, 2026 11:35
None of these had ever been executed under Colang 2:

- injection_detection/flows.co did not parse: variables were missing
  the $ sigil and the file used Colang 1 idioms (else if, {{ }}
  interpolation, $config instead of $system.config). Rewritten to the
  library's Colang 2 idiom, mirroring flows.v1.co semantics.
- regex/flows.co awaited DetectRegexMatchAction, which normalizes to
  the unregistered detect_regex_match; the registered action is
  detect_regex_pattern.
- gcp_moderate_text shipped Colang 1 content in flows.co and had no
  flows.v1.co at all; moved the v1 content to flows.v1.co and authored
  a proper Colang 2 flows.co.
- activefence/flows.v1.co had one flow definition indented by a stray
  space (cosmetic; the parser still registered it).

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Library rail tests run Colang 1 almost exclusively, so broken Colang 2
flow files shipped silently. Gate every manifest-declared rail: both
dialect files must parse, define the declared flow names (a declared
flow whose Colang 2 definition is parameterized is exempt from Colang 1
presence, since Colang 1 has no parameterized flows), and invoke only
actions the dispatcher can resolve.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
flows.co line 44 awaited autoalign_factcheck_output_api by its
registered snake_case name; a lowercase name after await is a flow
reference in Colang 2, so the invocation resolved to a nonexistent flow.
Use the CamelCase Action form like the sibling flows in the same file.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
A lowercase name after await/start parses as a flow reference, so
awaiting an action by its snake_case registered name fails only at
runtime. Flag any awaited lowercase name that matches a registered
action; this caught the autoalign factcheck defect and matches the
mistake pattern seen in inbound rail PRs.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Emit configured terminal BotMessage events when retrieval rails block so their responses do not re-enter retrieval indefinitely. Preserve the predefined-message output-rail bypass and cover each affected retrieval flow end to end.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Exercise allow, block, and transform verdicts for both context-bloat input and retrieval flows using the backend-neutral RailOutcome contract.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Keep GCP detailed moderation and Colang 2 injection detection fail-closed, while preserving readable injection messages.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Match Colang 2 finished-event action names so internal vendor action
results stay out of generated history

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from 6a88f13 to 1e2ca85 Compare July 21, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: L status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant