RuleContext is the supported interface between a custom rule
and Fensu’s analysis engine. It is passed to every rule check as ctx. Import all
public protocols, handles, locations, facts, and dependency models from fensu,
never from internal package paths.
ast.Module directly when they need unrestricted Python AST access.
ctx.facts
Backend-neutral semantic facts for the current file, computed once and shared by all
rules through a single traversal.
evaluate_rule_calls() supports policy analysis such as FFR707. Custom-rule tests
should use the public testing harness
rather than inspect these facts directly.ctx.project
Cross-file and filesystem queries. Every call records its input for cache
invalidation, so a result stays reusable only while its answers hold. Pass the file
whose result depends on the query as requester, normally ctx.path.
ctx.project.tree
An immutable, deterministic view of the authoritative discovered project. It does
not perform arbitrary filesystem discovery. Every query records its exact answer
against the active file or project-rule requester.
ProjectPath rejects absolute paths, parent traversal, Windows path spellings, and
unsupported path objects. FilePosition includes path, analyzer, source_kind,
scope, scope_root, module, package, domain_parts, role, role_depth,
is_entry_module, and is_main_module.
ctx.graph
For Python, TypeScript, and Svelte targets, an immutable architecture graph
resolved from static imports and authoritative discovered modules. Unresolved
imports remain explicit and dynamic imports are not represented. Web graph
resolution reuses the native analyzer’s static TypeScript, JavaScript, SvelteKit,
and configured alias resolution.
ImportEdge preserves the AuthoredImport, source location, resolved module name,
ImportResolution, and optional target node. Graph identities include analyzer and
source-kind ownership so they remain safe as additional analyzers gain graphs.
ctx.rust
For Rust targets, a versioned immutable workspace fact view transferred from the
native analyzer. It contains no syn or Cargo metadata objects.
RustItemFact uses RustItemKind and RustVisibility, preserves derives and
implementation targets, and carries a stable SourceLocation. RustUseFact
preserves authored parts, source and target modules, optional target file and crate,
and a RustUseResolution of RESOLVED, CRATE, EXTERNAL, or UNRESOLVED.
RustFileFacts.parse_error remains explicit when source cannot be parsed.
Each broad or focused call records its answer for subject-aware cache replay. Use a
focused file() or crate() lookup when unrelated source or Cargo changes should
not invalidate a cached result.
ctx.web
For TypeScript and Svelte targets, a versioned immutable fact view transferred from
the native analyzers. It contains no parser-library nodes and does not require
Node.
WebFileFacts exposes its analyzer, WebSourceKind, WebSourcePurpose, module,
source root, scope, authored source, optional parse error, and immutable imports,
functions, classes, models, bindings, calls, resources, re-exports, and export
counts. WebImportFact.target is a File only when the native analyzer proves a
project-local destination. Use ctx.graph for resolved dependency and dependent
queries.
syntax_handles contains stable Fensu-owned WebSyntaxHandle byte ranges for
imports, declarations, calls, resources, re-exports, Svelte scripts, and runes.
Pass one to WebFileFacts.text(handle) to retrieve its authored text without
receiving an analyzer AST.
On Svelte targets, WebFileFacts.svelte is a SvelteFileFacts extension when the
file is a component or state module. It records script contexts, recognized
top-level runes, component markup, route identity, and state-module identity.
TypeScript-only targets do not require this extension.
Broad files and focused file() calls record their exact answers for
subject-aware cache replay. Tree and graph calls made during the same invocation
record their own query-specific dependencies.
ctx.targets
Repository rules use ctx.targets instead of an unqualified target context.
all() returns every configured RuleTargetFacts handle in target-name order;
named(name) returns one exact handle or None.
Each handle exposes its stable Target identity, target-local tree and graph,
and the typed python, rust, or web workspace facts owned by its analyzer.
repository_path(file_or_path) and repository_location(location) translate
target-local evidence before constructing a repository-relative diagnostic.
Wrong-analyzer access and access to an analyzer omitted from the active rule’s
analyzers fail closed.
Repository contexts have no current file, source, ctx.project, or unqualified
analyzer zones. Their queries use a distinct repository requester for cache replay.
See Repository rules for the complete execution and
cache model.
ctx.text, ctx.syntax, ctx.relations
Source text, opaque syntax identities, and syntax relationships for the current
file.
The zone protocols are
FactAnalysis, ProjectAnalysis, TextAnalysis,
SyntaxAnalysis, and RelationAnalysis, all exported from fensu.
The table above describes the Python analysis zones. Serialized Rust rules use
ctx.rust, ctx.project.tree, ctx.source, and stable locations. Serialized web
rules use ctx.web, ctx.graph, ctx.project.tree, ctx.source, and
WebSyntaxHandle. The generic ctx.syntax and ctx.relations zones are
unavailable because parser implementation objects are not part of native-analyzer
authoring contracts.
Fault construction
Construct diagnostics through the context so the rule’s code, and optionally its declared message and remediation, are wired automatically. Omittedmessage and
remediation use the rule’s envelope values.
During a project-rule invocation there is no current file, source, text, syntax, or
file-fact object.
path_fault() therefore requires an explicit project-relative
path, and fault_for() requires an absolute path confined to the analyzed project.
fault_at() accepts a SourceLocation or SourceRange; a bare SyntaxHandle
cannot be resolved without a current file analysis.
During a repository-rule invocation, path_fault() accepts a repository-relative
path and may omit it to report against the repository subject ".".
fault_at() accepts a repository-relative SourceLocation; translate a
target-local location with target.repository_location(...) first.
Position and roles
Location facts derived from configured roots and scopes, not hardcoded package names.AST helpers
Convenience operations over the current file’s parsed tree.
Prefer
ctx.nodes() over ast.walk(module) for module-wide scans so cooperating
rules share Fensu’s single traversal.
Configuration
Pass the exact
RuleOption[T] declaration from the active rule to preserve the
static return type. Requests for undeclared or cross-rule options are authoring
errors. Values are immutable and already validated before evaluation.
Public models
All models below are exported fromfensu and returned by the calls above. They
are frozen dataclasses; inspect exact fields with your editor’s type information.
Locations and handles
Function and dataflow facts
Annotation facts
Declaration and reference facts
Project and dependency facts
Subjects, project tree, and architecture graph
Rust facts
Python repository facts
Web facts
Test facts
Related
Custom rules
Authoring, loading, testing, and cacheability.
Configuration
Thresholds and contracts the context resolves.

