Add comprehensive documentation and GitHub Copilot configuration: - docs/knowledge/: 17 deep-dive knowledge files covering value semantics, RVM architecture, builtins, FFI boundary, feature composition, error handling migration, policy evaluation security, Rego semantics, interpreter/compiler architecture, Azure Policy/RBAC, engine API, time builtins, language extension guide, tooling architecture, causality/partial eval, Rego compiler, Azure Policy aliases, and telemetry/diagnostics - .github/agents/: 16 role-specific AI agent definitions (red-teamer, semantics-expert, architect, performance-engineer, test-engineer, verification-engineer, security-auditor, reliability-engineer, support-engineer, ci-engineer, refactorer, api-steward, program-manager, demo-engineer, dx-engineer, tech-lead) - .github/skills/: 6 workflow skill definitions (thorough-review, design-alternatives, add-builtin, opa-conformance, security-review, verification) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
5.3 KiB
Knowledge: Feature Composition
Deep knowledge about regorus's feature flag system and the risks of non-default feature combinations. Read this before adding features or modifying feature-gated code.
Feature Architecture
Default Features
default = ["full-opa", "arc", "rvm"]
full-opa: All OPA-compatible builtins. Impliesstd.arc:Arcinstead ofRcfor thread safety.rvm: Rego Virtual Machine compilation and execution.
Composite Features
full-opa includes: base64, base64url, coverage, glob, graph, hex, http,
jsonschema, net, opa-runtime, regex, cache, semver, std, time, uuid, urlquery,
yaml.
opa-no-std includes: arc, base64, base64url, coverage, graph, hex,
no_std, opa-runtime, regex, semver, lazy_static/spin_no_std. Note this
excludes builtins that require std (glob, time, jsonschema, yaml, etc).
The no_std / std Boundary
The crate is #![no_std] by default with extern crate alloc.
stdfeature: enablesstdlibrary, parking_lot, filesystem, threadingno_stdfeature: enableslazy_static/spin_no_stdfor spinlock-based lazy statics
These are NOT mutually exclusive in Cargo. If both are enabled, std wins.
But no_std should be tested alone:
cargo xtask test-no-std # Builds for thumbv7m-none-eabi
The arc Feature
Controls whether shared data uses Rc or Arc:
// In src/lib.rs (conditional type alias)
#[cfg(feature = "arc")]
type Rc<T> = alloc::sync::Arc<T>;
#[cfg(not(feature = "arc"))]
type Rc<T> = alloc::rc::Rc<T>;
arc is default. Disabling it gives single-threaded performance but breaks
thread safety. The FFI crate's contention detection (contention_checks)
requires arc.
Known Pitfalls
Issue #595 Pattern
Feature combinations that compile individually may fail together. Example:
a feature adds a dependency that conflicts with no_std, or a feature-gated
module uses std types without a feature gate.
Prevention:
- Always test with
--no-default-featuresplus minimal feature sets - CI checks key combinations explicitly
Compilation Verification Matrix
When adding or modifying features, verify these combinations compile:
# Minimal (no_std, no arc, no rvm)
cargo check --no-default-features
# no_std with arc
cargo check --no-default-features --features arc,opa-no-std
# std with arc and rvm (common production config)
cargo check --no-default-features --features std,arc,rvm
# Everything
cargo check --all-features
# The full CI suite checks more combinations
cargo xtask ci-debug
Feature-Gated Code Correctness
Common mistakes:
1. Using std types without gate:
// ✗ Bad — breaks no_std
use std::collections::HashMap;
// ✓ Good — available in no_std via alloc
use alloc::collections::BTreeMap;
// ✓ Good — gated when std is required
#[cfg(feature = "std")]
use std::path::Path;
2. Feature implies another but not declared:
// ✗ Bad — regex module uses std but doesn't declare dependency
[features]
regex = ["dep:regex"] # regex crate needs std!
// ✓ Good — declare the implication
regex = ["dep:regex"] # regex default-features=false works in no_std
3. Conditional compilation in wrong direction:
// ✗ Bad — dead code when feature absent, no compile error
#[cfg(feature = "myfeature")]
fn helper() { ... }
fn caller() {
helper(); // ERROR: `helper` doesn't exist without myfeature
}
// ✓ Good — gate the caller too
#[cfg(feature = "myfeature")]
fn caller() {
helper();
}
docsrs Annotation
Public feature-gated APIs must have the docsrs annotation so docs.rs shows which feature is required:
#[cfg(feature = "myfeature")]
#[cfg_attr(docsrs, doc(cfg(feature = "myfeature")))]
pub fn my_function() -> Result<()> { .. }
Adding a New Feature: Checklist
- Add to
[features]inCargo.tomlwith optional dependency - Gate the module:
#[cfg(feature = "myfeature")] mod myfeature; - Gate registration (builtins, languages, etc.)
- Gate public API with docsrs annotation
- Add to
full-opaif it's an OPA-standard feature - Add to
opa-no-stdif it works without std - Verify compilation with the matrix above
- Run
cargo xtask ci-debugfor the full suite - Consider adding the combination to CI if it's a common configuration
Dependencies and no_std
When adding dependencies:
- Check if the crate supports
no_std(look fordefault-features = false) - Use
default-features = falseand enable only needed features - If the crate requires
std, the feature must implystd - Prefer
core/allocover external crates where feasible
Current dependency pattern:
serde = { version = "1.0", default-features = false, features = ["derive", "rc", "alloc"] }
regex = { version = "1.12", optional = true, default-features = false }
The Rc Type Alias
The crate defines a type alias Rc that maps to either alloc::rc::Rc or
alloc::sync::Arc based on the arc feature. This alias is used throughout
the codebase — in Value, Number, and everywhere shared ownership is needed.
Never use alloc::rc::Rc or alloc::sync::Arc directly in the core crate.
Always use the type alias Rc to ensure the arc feature works correctly.