Skip to content

feat(rails): add rail manifest contract#2157

Open
Pouyanpi wants to merge 11 commits into
developfrom
pouyanpi/rail-library-stack-3-manifest-contract
Open

feat(rails): add rail manifest contract#2157
Pouyanpi wants to merge 11 commits into
developfrom
pouyanpi/rail-library-stack-3-manifest-contract

Conversation

@Pouyanpi

@Pouyanpi Pouyanpi commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Description

Add the neutral nemoguardrails.manifests package so rail packages can declare
what they contribute without making configuration, runtime, or catalog code
depend on concrete library implementations. The contract covers rail metadata,
configuration schemas, flows, actions, direct execution surfaces, requirements,
privacy, and structured import references.

Keep discovery cheap by representing configuration factories and actions as
lazy module:attribute references. Reading a manifest does not need to import
its action module, configuration models, optional SDKs, or model dependencies.
Descriptive metadata accepts extensions, while executable declarations are
strictly validated so invalid bindings, duplicate ownership, and inconsistent
surface contracts fail at catalog construction.

Executable import edges are typed ActionRef and ConfigSpecRef objects rather
than unrestricted strings. Each reference validates its module:attribute
shape while remaining unresolved during discovery. ActionRef also separates
the public action-registry name from its Python import target, allowing catalog
validation and later lazy dispatch even when the registered name differs from
the underlying symbol. Resolution and conformance checks verify the target only
when that executable layer is needed.

A RailSurface declares a backend-neutral mapping from a configured rail name
and direction to a Python action. Its typed bindings state whether each action
argument comes from a configured surface parameter, runtime context, or a
literal value. The contract is declared rather than inferred from action
decorators or Colang flow bodies.

configured surface references intentionally support only the configuration
syntax used by the manifest layer:

name
name $key=value
name $key=value $other="quoted value"

The parser rejects malformed, adjacent, blank, or duplicate parameters and
does not attempt to parse parenthesized Colang expressions. The catalog indexes
built-in manifests and can extend them with explicitly named plugin entry
points, while the registry provides cached process-wide access.

This PR establishes the contract and discovery primitives only. Built-in
manifest declarations, cross-dialect flow corrections, lazy action dispatch,
and end-to-end plugin activation are reviewed in later stack layers.

Impact

  • Rail packages gain one declarative ownership point for metadata, config
    contributions, actions, flows, and direct execution contracts.
  • Core consumers can discover rail capabilities without importing runtime-heavy
    modules or parsing Colang.
  • Typed bindings give different execution backends enough information to derive
    the same action call from the same configured surface and request context.
  • Catalog-wide collision and contract validation turns silent registry drift
    into deterministic load-time errors.
  • This layer does not change which built-in rails run or how requests are
    processed; those integrations remain isolated in downstream PRs.

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
Stack 6 pouyanpi/rail-library-stack-6-hardening Stack 5 #2187

AI Assistance

  • No AI tools were used.
  • AI tools were used; a human reviewed and can explain every change.

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 documentation if applicable.
  • I’ve added tests where 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 review comments, or replied with why no change is needed.
  • I’ve mentioned the person or team responsible for review.

Summary by CodeRabbit

  • New Features

    • Added structured rail manifests for describing rail metadata, configuration, actions, flows, surfaces, requirements, privacy, and examples.
    • Added catalog discovery for built-in rails and optional plugin-provided rails.
    • Added APIs to browse manifests and filter available rail surfaces by direction and configured flows.
    • Added reusable configuration schema helpers and support for flexible manifest formats.
  • Bug Fixes

    • Added validation for duplicate names, invalid references, malformed imports, and inconsistent rail definitions.
  • Tests

    • Added comprehensive coverage for manifest parsing, catalog discovery, plugin handling, surface selection, and configuration behavior.

@github-actions github-actions Bot added size: XL status: needs triage New issues that have not yet been reviewed or categorized. labels Jul 10, 2026
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-1-outcome branch from ba19362 to ef00c0e Compare July 10, 2026 11:07
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.00748% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
nemoguardrails/manifests/registry.py 80.00% 6 Missing ⚠️
nemoguardrails/manifests/manifest.py 97.80% 4 Missing ⚠️
nemoguardrails/manifests/catalog.py 98.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Pouyanpi Pouyanpi self-assigned this Jul 10, 2026
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-3-manifest-contract branch 2 times, most recently from 42af62e to f7c929e Compare July 13, 2026 09:06
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-1-outcome branch from ef00c0e to 8c1b769 Compare July 13, 2026 10:00
@Pouyanpi
Pouyanpi marked this pull request as ready for review July 13, 2026 10:43
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-3-manifest-contract branch from f7c929e to f4fe58b Compare July 14, 2026 06:42
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-1-outcome branch 2 times, most recently from 55a02d7 to 62d119d Compare July 14, 2026 10:05
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-3-manifest-contract branch from f4fe58b to fdef7b0 Compare July 14, 2026 10:17
@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 14, 2026
@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a versioned manifest contract for rails. The main changes are:

  • New typed manifest models for rail metadata, specs, actions, flows, surfaces, requirements, and privacy.
  • Catalog discovery for built-in rail manifests and optional plugin-provided rails.
  • Public package exports for manifest APIs and configured-surface parsing.
  • Reusable configuration-schema helpers for rail-specific typed settings.
  • Tests for manifest validation, catalog discovery, registry caching, configuration helpers, and surface parsing.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
nemoguardrails/manifests/surface_reference.py Adds strict parsing and normalization for configured surface references.
nemoguardrails/manifests/manifest.py Adds the typed rail manifest model and execution-contract validation.
nemoguardrails/manifests/catalog.py Adds rail catalog construction, discovery, plugin loading, and uniqueness checks.
nemoguardrails/manifests/registry.py Adds process-wide catalog caching and plugin-catalog lookup.
tests/manifests/test_surface_reference.py Adds coverage for configured-surface parsing and malformed parameter handling.
tests/manifests/test_manifest.py Adds coverage for manifest validation, import references, and surface bindings.
tests/manifests/test_catalog.py Adds coverage for catalog indexing, duplicate rejection, and plugin handling.

Reviews (15): Last reviewed commit: "fix(manifests): validate surface binding..." | Re-trigger Greptile

Comment thread nemoguardrails/manifests/manifest.py Outdated
Comment thread nemoguardrails/manifests/manifest.py Outdated
@Pouyanpi

Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds typed rail manifest and configuration-schema models, validated built-in/plugin catalog discovery, cached package-level catalog and surface accessors, and comprehensive tests for validation, parsing, discovery, plugins, and cache behavior.

Changes

Rail manifest system

Layer / File(s) Summary
Manifest models and selection utilities
nemoguardrails/manifests/manifest.py, tests/manifests/test_manifest.py
Defines typed manifest structures, import-reference resolution, flat-shape normalization, configured-surface parsing, and surface selection utilities with corresponding tests.
Rail configuration schema primitives
nemoguardrails/manifests/schema.py, tests/manifests/test_schema.py
Adds immutable configuration field specifications, an extra-key-ignoring Pydantic base model, and schema helper exports.
Catalog indexing and plugin discovery
nemoguardrails/manifests/catalog.py, tests/manifests/test_catalog.py
Adds catalog indexing and validation, built-in rail discovery, plugin entry-point loading, provenance metadata, and catalog behavior tests.
Package catalog accessors
nemoguardrails/manifests/__init__.py, tests/manifests/test_init.py, pyproject.toml
Adds cached default and plugin catalogs, manifest/surface accessors, cache reset behavior, public exports, and type-checking coverage.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant default_rail_catalog
  participant RailCatalog
  participant BuiltInRailModules
  Caller->>default_rail_catalog: request default catalog
  default_rail_catalog->>RailCatalog: discover_built_ins()
  RailCatalog->>BuiltInRailModules: import rail.py modules
  BuiltInRailModules-->>RailCatalog: return RAIL manifests
  RailCatalog-->>default_rail_catalog: return validated catalog
  default_rail_catalog-->>Caller: return cached catalog
Loading
🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Test Results For Major Changes ✅ Passed The PR description explicitly mentions package-level manifest tests, which satisfies the testing-info requirement for these major manifest changes.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: introducing the rail manifest contract and related package APIs.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pouyanpi/rail-library-stack-3-manifest-contract

Comment @coderabbitai help to get the list of available commands.

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

🧹 Nitpick comments (2)
nemoguardrails/manifests/schema.py (1)

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

Replace setattr with direct assignment (Ruff B010).

Static analysis flags this call; a direct attribute assignment is equivalent and avoids the lint warning.

🧹 Proposed fix
-setattr(RailConfigSpec, "__hash__", None)
+RailConfigSpec.__hash__ = None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nemoguardrails/manifests/schema.py` at line 41, Replace the setattr call
configuring RailConfigSpec.__hash__ with direct class attribute assignment,
preserving the value None and behavior while resolving Ruff B010.

Source: Linters/SAST tools

nemoguardrails/manifests/manifest.py (1)

100-133: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Tighten import-target validation to reject embedded colons in the attribute path.

_validate_import_target only checks that module_name/separator/attribute_path are non-empty, so a target like "pkg:sub:attr" passes validation (attribute_path = "sub:attr"), but resolve_import_ref (Lines 362-368) splits only on ".", so it will call getattr(obj, "sub:attr") and fail with a confusing AttributeError rather than the clear ValueError this validator is meant to produce. This undercuts the module's own stated goal that "the executable spec is strict so misconfiguration fails loudly at load time."

🛠️ Proposed tightened validation
+_IMPORT_TARGET = re.compile(r"^[A-Za-z_][A-Za-z0-9_.]*:[A-Za-z_][A-Za-z0-9_.]*$")
+
+
 def _validate_import_target(target: str) -> str:
-    module_name, separator, attribute_path = target.partition(":")
-    if not separator or not module_name or not attribute_path:
+    if not _IMPORT_TARGET.match(target):
         raise ValueError(f"Invalid import reference {target!r}; expected 'module:attribute'.")
     return target
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nemoguardrails/manifests/manifest.py` around lines 100 - 133, Update
_validate_import_target to reject any import target whose attribute_path
contains a colon, while preserving the existing non-empty module, separator, and
attribute checks. Ensure targets such as “pkg:sub:attr” raise the validator’s
clear ValueError before resolve_import_ref processes them.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/manifests/test_init.py`:
- Line 25: Remove the newly added inline comments near the second-call cache
assertion and the related assertion at the referenced locations in the test,
leaving the test logic unchanged.
- Around line 20-36: Ensure test_package_accessors_with_no_built_in_rails always
resets the rail manifest cache by wrapping its setup and assertions in
try/finally, or using a fixture finalizer. Keep _reset_rail_manifest_cache as
the cleanup action so _catalog and _plugin_catalogs are cleared even when an
assertion fails.

---

Nitpick comments:
In `@nemoguardrails/manifests/manifest.py`:
- Around line 100-133: Update _validate_import_target to reject any import
target whose attribute_path contains a colon, while preserving the existing
non-empty module, separator, and attribute checks. Ensure targets such as
“pkg:sub:attr” raise the validator’s clear ValueError before resolve_import_ref
processes them.

In `@nemoguardrails/manifests/schema.py`:
- Line 41: Replace the setattr call configuring RailConfigSpec.__hash__ with
direct class attribute assignment, preserving the value None and behavior while
resolving Ruff B010.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 81ba4bba-252c-4e48-9ca3-7a4fcb131a75

📥 Commits

Reviewing files that changed from the base of the PR and between 62d119d and fdef7b0.

📒 Files selected for processing (9)
  • nemoguardrails/manifests/__init__.py
  • nemoguardrails/manifests/catalog.py
  • nemoguardrails/manifests/manifest.py
  • nemoguardrails/manifests/schema.py
  • pyproject.toml
  • tests/manifests/test_catalog.py
  • tests/manifests/test_init.py
  • tests/manifests/test_manifest.py
  • tests/manifests/test_schema.py

Comment thread tests/manifests/test_init.py Outdated
Comment thread tests/manifests/test_init.py Outdated
Base automatically changed from pouyanpi/rail-library-stack-1-outcome to develop July 15, 2026 06:45
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-3-manifest-contract branch from 9bfe7a9 to 0f29e2d Compare July 15, 2026 07:28
Comment thread nemoguardrails/manifests/manifest.py Outdated
Comment thread nemoguardrails/manifests/manifest.py Outdated
Comment thread nemoguardrails/manifests/manifest.py Outdated
Pouyanpi added 11 commits July 17, 2026 13:56
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Mirror the manifests package layout under tests/manifests/ (test_manifest,
test_catalog, test_schema, test_init) and refocus the rails/llm shim tests on
re-export identity and the discovery helpers. Adds coverage for RailCatalog
discovery and plugin entry-point loading, the config schema primitives, and the
package-level accessors, which were previously untested.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
The parser now supports only:

name
name $key=value
name $key=value $other="quoted value"

Changes include:

- No parenthesized parameter parsing.
- Exact $name=value; spaces around = rejected.
- No bare-value escaping or shell quote concatenation.
- Parenthesized custom flows remain uninterpreted and ignored by manifest discovery.
- Linear parsing, control rejection, duplicate detection, quote fidelity, and value-free errors retained.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Remove unused compatibility aliases and convenience APIs before the manifest contract is published. Document the retained public models, catalog accessors, import helpers, and configured-surface grammar.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-3-manifest-contract branch from 4e1f759 to 49f9f7f Compare July 17, 2026 11:58
@Pouyanpi Pouyanpi changed the title feat(rails): add versioned rail manifest contract feat(rails): add rail manifest contract Jul 17, 2026
@Pouyanpi Pouyanpi added this to the v0.24.0 milestone Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: XL 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