From df667b40f0029aea749e0989b9db9e5b130353d8 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Sun, 1 Nov 2026 13:54:35 +0000 Subject: [PATCH 1/3] docs(readme): add restrained SQLStack branding Amp-Thread-ID: https://ampcode.com/threads/T-01a1970c-7c44-7042-b987-dc3926e29427 --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 93091018..7317575b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@

- Fensu + + + Fensu + +

+ +

+ by SQLStack

@@ -378,3 +385,11 @@ for the complete API and configuration. The quickstart, architecture model, configuration reference, adoption guide, and CLI reference live at [docs.fensu.dev](https://docs.fensu.dev). + +## Part of SQLStack + + Fensu is part of [SQLStack](https://sqlstack.io), a family of tools for data engineers. + +- [SQLBuild](https://sqlbuild.com) — SQL transformations with compile-time checks, end-to-end tests, and safe renames. +- [SQLClean](https://sqlclean.io) — Fast SQL linting and deterministic formatting. +- [SQLTide](https://docs.streambuild.dev) — Build, replay, and safely deploy ClickHouse streaming pipelines with SQL. From d2f2531e46c3db2516d8a3c5d87f33a04c252f34 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Sun, 1 Nov 2026 14:08:22 +0000 Subject: [PATCH 2/3] docs(readme): focus onboarding and retain reference detail Amp-Thread-ID: https://ampcode.com/threads/T-01a1970c-7c44-7042-b987-dc3926e29427 --- README.md | 432 ++++-------------- website/src/content/docs/docs/cli/index.mdx | 7 + .../docs/docs/concepts/analyzers/rust.mdx | 19 +- .../docs/docs/concepts/architecture-model.mdx | 10 +- .../docs/docs/concepts/configuration.mdx | 14 +- website/src/content/docs/docs/quickstart.mdx | 10 + .../docs/docs/reference/rule-context.mdx | 5 + 7 files changed, 144 insertions(+), 353 deletions(-) diff --git a/README.md b/README.md index 7317575b..628c9f87 100644 --- a/README.md +++ b/README.md @@ -1,390 +1,136 @@

- Fensu - -

- -

+ Fensu +
by SQLStack

-

- Keeping Python, TypeScript, JavaScript, Svelte, and Rust repos from turning into spaghetti. -

- -

Fensu means "fence" in Japanese.

- -**Most linters catch bad code inside files. Fensu catches architectural drift: -code crossing the wrong boundary, living in the wrong module, or growing into the -wrong shape.** - -As a repository grows, code moves, lessons get forgotten, and the mental map -decays. Tests preserve behavior and types preserve interfaces. Fensu makes the -repository's architectural expectations executable. - -Fensu enforces: +Fensu checks repository architecture: **import boundaries, module roles, and function +shape** for Python, Rust, TypeScript, JavaScript, and Svelte. -- which layers may import which; -- what each module or role file may contain; -- whether orchestrator functions stay small; -- whether dataflow and mutation are explicit; -- whether names such as `validate_*` mean what they claim. +- **Boundaries:** stop one domain from importing another domain’s private helpers. +- **Roles:** keep entry points, helpers, models, and types in their owning modules. +- **Function shape:** keep orchestrators small, dataflow explicit, and signatures clear. -It ships a coherent default architecture rather than a blank rule framework, then -lets projects disable, extend, or replace parts deliberately. +Fensu is pre-release and self-hosting. It ships an opinionated default architecture, +not a blank rule framework; tune or replace policies deliberately. -Fensu is functional and self-hosting, but remains pre-release. +## Get started -## Installation +Requires **Python 3.12+**. Install in your project’s Python environment: ```bash pip install fensu ``` -The authoring/API distribution is `fensu`. It installs the lockstep -`fensu-cli` binary package, which exclusively owns the `fensu` command. -Core-only `check`, `dupes`, `init`, `rule`, `map`, `skills`, and `--version` -execution is native. Configured Python custom rules launch one compatible Python -host only for the policy metadata or callbacks they require. - -Built-in commands are available only through the native `fensu` executable; -`python -m fensu` is retired. Installing `fensu-cli` from its source -distribution requires Rust 1.95 or newer. - -Fensu requires Python 3.12+ and includes a compiled analysis core. Prebuilt -wheels cover Linux (x86_64, aarch64), macOS (Intel, Apple silicon), and Windows -(x86_64). On other platforms, `pip` builds from source and requires a Rust -toolchain at version 1.95 or newer. - -## Quick Start - -From the directory containing an existing repository's `pyproject.toml`, detect -the layout, write a validated configuration with the full ruleset enabled, run an -initial check, and install repository-local agent guidance: +From an existing Python repository’s `pyproject.toml` directory: ```bash fensu init --yes -``` - -For an empty repository, provide the package name to scaffold `src/` and `tests/`: - -```bash -fensu init --yes --name my_package -``` - -Pass `--no-skills` only when automation explicitly requires configuration without -repository-local guidance. Do not call onboarding complete until this succeeds: - -```bash fensu skills --check -``` - -Then run: - -```bash fensu check ``` -To configure manually instead, add a minimal `fensu.toml` at the repository root: +`init` detects the layout, writes `fensu.toml`, measures current drift, and installs +repository-local agent guidance. It detects complete SvelteKit projects too; see +[web targets](https://fensu.io/docs/concepts/analyzers/typescript-sveltekit/). +For an empty repository, use `fensu init --yes --name my_package` instead. -```toml -roots = ["src/my_package"] -``` +Already configured? `init` leaves existing configuration unchanged. Run +`fensu skills` to install or refresh guidance, then verify it with `--check`. +Unmanaged skill files are preserved unless you explicitly pass `--force`. +Use `init --no-skills` only for deliberate configuration-only automation. -`tests` defaults to `["tests"]`, `tooling` is optional, caching is enabled by -default, and every rule family is on by default. Install and verify agent guidance -after writing configuration manually: +`check` exits **0** with no blocking faults, **1** when it finds faults, and **2** +for setup/configuration errors. Put `fensu check` in CI to enforce the policy. -```bash -fensu skills -fensu skills --check -fensu check -``` - -Product roots and tooling receive structural rules; tests receive test-convention -and annotation rules. - -### Rust workspaces - -Rust rules run directly in the `fensu-rust` analyzer through the normal Fensu CLI. -Configure a Cargo workspace in `fensu.toml`: - -```toml -[targets.rust] -analyzer = "rust" -roots = ["crates"] -tests = [] -tooling = [] -rule_packs = ["rust"] -select = ["FPRS"] -``` +New and small repositories are the easiest starting point. On established codebases, +expect drift: use [adoption boundaries and explicit exceptions](https://fensu.io/docs/adoption/) +rather than making unsafe structural changes just to reach zero. +Rust projects use [Cargo-aware target configuration](https://fensu.io/docs/concepts/analyzers/rust/). +See [installation details](https://fensu.io/docs/quickstart/#1-install) for wheels and source builds. -Run `fensu check --target rust`. Cargo discovers workspace members, package names, and targets; -use `roots = ["src"]` for a single-package repository. The Rust pack enables all 120 `FPRS*` -rules, covering layout, imports, dependency boundaries, naming, function shape, hygiene, and -test conventions. Existing structural thresholds are the defaults. +## A finding and its fix -Adjust individual rules in the same file: +An order entry point importing inventory’s private helper crosses a domain boundary: -```toml -[targets.rust.rule_options.FPRSS010] -max_arguments = 8 +```python +# src/shop/orders/main/submit.py +from shop.inventory._helpers.reserve import reserve ``` -Selection, warnings, ignores, file exceptions, and caching use the usual Fensu settings. -Cargo manifests, the lockfile when present, Rust sources, and target configuration participate -in cache identity. Analysis does not create or update a lockfile. -See [Rust analyzer configuration](docs/rust.md) for rule options and tooling boundaries. - -Python projects can opt into [production dead-code enforcement](docs/dead-code.md) with -`[dead_code] enabled = true`. Reachability faults cover module-level definitions and modules; -reasoned roots describe dynamic entry mechanisms. Tests and `main/` placement are not roots. - -## Default Structure - -The default architecture follows SQLBuild Compiler Rules v0.101.1. - -Product code uses domain, optional subdomain, then role. Every leaf domain or -subdomain owns meaningful behavior through a direct `main/` containing at least one -entry module. Branch-domain parents do not need their own `main/`; their leaf -subdomains do. Tests mirror the code they cover; tooling uses one ownership level -because `scripts/` already establishes the outer boundary. +Excerpt from a real `fensu check --no-color` run with `FFL102` selected: ```text -src/my_package/ -└── domain/ - └── subdomain/ - ├── main/ - │ └── run.py - ├── _helpers/ - ├── classes/ - ├── models.py - ├── types.py - ├── constants.py - └── exceptions.py -tests/unit/src/my_package/domain/subdomain/ -├── _test_types.py -└── test_run.py -scripts/ -├── run_tool.py -└── tool_name/ - ├── main/ - ├── _helpers/ - └── classes/ +FFL102 import 'shop.inventory._helpers.reserve' reaches into internal structure of 'shop.inventory' + --> src/shop/orders/main/submit.py:1:0 + = help: Import from classes, models, types, constants, exceptions, or a thin main/ entry. ``` -Do not create an empty or initializer-only `main/` to satisfy the layout. If a -package contains only passive models, types, constants, exceptions, or classes, -move those declarations into the closest domain or subdomain whose `main/` behavior -owns and uses them. Fixed role files are siblings of `_helpers/`, never descendants -such as `_helpers/entry/models.py`. - -Direct `scripts/*.py` files are thin command adapters. Supporting logic belongs -under `scripts///`. - -Targets may declare path-scoped ownership roots when domains begin at different physical depths. -The first package below each matched ownership root is a domain; the next non-role package is its -optional subdomain. Without this setting, each Python source root, Cargo source root, or web -`lib/` directory is the ownership root: - -```toml -[targets.app] -analyzer = "python" -roots = ["src/example"] -ownership_roots = [ - "src/example/sources/*", - "src/example/runtime", -] -``` +Publish the operation through inventory’s thin `main/` entry, then import that +public surface instead: -```text -src/example/ -├── sources/ -│ ├── region_a/ -│ │ ├── orders/main/process.py -│ │ └── partners/importing/main/load.py -│ └── region_b/ -│ └── inventory/main/refresh.py -└── runtime/ - ├── scraping/main/collect.py - └── observability/main/report.py +```python +from shop.inventory.main.reserve import reserve ``` -Here each directory matched by `sources/*` and the explicit `runtime/` directory establishes an -ownership root. `orders`, `partners`, `inventory`, `scraping`, and `observability` are domains; -`importing` is a subdomain. The most-specific matching ownership root wins. Structural directories -above and including an ownership root cannot contain role files or role directories directly. -Mirrored tests inherit the production ownership root they cover. Rust, TypeScript, and Svelte use -the same path-scoped model. Declarations must resolve beneath a configured runtime source, select -analyzable files, and own at least one effective path after more-specific matches are applied. +That change clears this boundary finding; it does not disable the rule. Inspect a +diagnostic’s full contract and settings with `fensu rule FFL102`. -## Core Commands +## The default layout -```bash -fensu init -fensu check -fensu rule FFS131 -fensu map run_plan --depth 3 -fensu dupes --since origin/main -``` - -`fensu init` detects and validates an onboarding configuration, `fensu check` -enforces the configured architecture, `fensu rule` explains one rule and its -remediation, `fensu dupes` reports duplicated code as advisory review input, and -`fensu map` renders a conservative project call tree. Downstream -mapping is the default; `--direction upstream` shows proven callers. Mapping -follows project functions and class methods when imports, -annotations, constructors, or return types prove the receiver. Unique protocol -dispatch can resolve to one concrete implementation; ambiguous protocols and -untyped parameters remain visible as unresolved dispatch seams rather than guessed -implementations. Mapping does not require Fensu -configuration or rule adoption. - -`fensu check` stores disposable evaluation results in a repository-local -SQLite database under `.fensu/cache/` -and reuses them only after validating source, configuration, rule, implementation, -and project-query inputs. Caching is enabled by default; set `cache.enabled = false` -in configuration or pass `--no-cache` for an explicit uncached check. `--cache` -overrides a disabled project preference for one invocation. -Deleting `.fensu/cache/` is always safe; ignore that directory rather than the -complete `.fensu/` namespace, which is reserved for other Fensu-owned state. - -## Duplicated Code - -`fensu dupes` reports concrete duplicated code across the configured targets: ranked -clusters of exact, renamed, and near-miss function-level copies in Python, Rust, -TypeScript, JavaScript, and Svelte. It is advisory. It exits 0 whenever analysis -succeeds, whatever it finds, and exits 2 only for usage, configuration, or IO errors. - -```text -$ fensu dupes --since origin/main --diff -fensu dupes: 1 duplicated-code cluster changed since origin/main (advisory; duplicated-code findings to review, not fensu check failures) -analysed python 212 units; 0 allowlisted pairs hidden; 0 contract-exempt members hidden - 1. near-miss sim 0.98, ~111 duplicated tokens, 2 members - src/shop/orders/summary.py:1-15 summarize_orders (113 tokens) - src/shop/reports/summary.py:1-16 summarize_orders (118 tokens) [changed] - diff src/shop/orders/summary.py:1-15 vs src/shop/reports/summary.py:1-16 - + 9: log_progress(count) -``` - -See [duplicated-code detection](docs/dupes.md) for options, `[dupes]` configuration, -and contract exemptions. - -## Enforce It, Then See It - -Because Fensu enforces the structure, it can also render it. `fensu map` -produces a deterministic call tree with clickable `path:line` locations, -class-qualified method names, and explicit protocol seams while marking unresolved -dynamic calls, depth limits, and cycles. Downstream walks follow proven callees; -upstream walks invert those proven edges and omit callers Fensu cannot resolve. +A Python domain owns its behavior and vocabulary: ```text -$ fensu map run_map --depth 4 - -run_map(...) src/fensu/cli/main/map.py:21 -├── _parser(...) src/fensu/cli/main/map.py:53 -├── resolve_mapping_project(...) src/fensu/mapping/main/resolve_project.py:11 -│ └── resolve_mapping_project(...) src/fensu/mapping/_helpers/project.py:15 -│ ├── _find_project_root(...) src/fensu/mapping/_helpers/project.py:73 -│ ├── _explicit_source(...) src/fensu/mapping/_helpers/project.py:65 -│ ├── _optional_config_source(...) src/fensu/mapping/_helpers/project.py:38 -│ │ └── find_config_source(...) src/fensu/config/main/find_config.py:12 (depth limit) -│ └── _configured_project(...) src/fensu/mapping/_helpers/project.py:45 -│ ├── load_config(...) src/fensu/config/main/load_config.py:15 (depth limit) -│ └── _configured_source(...) src/fensu/mapping/_helpers/project.py:57 -└── build_call_map(...) src/fensu/mapping/main/build.py:12 - ├── provider(...) src/fensu/mapping/main/build.py:24 (unresolved parameter call) - └── render_tree(...) src/fensu/mapping/_helpers/render.py:19 - ├── _child_lines(...) src/fensu/mapping/_helpers/render.py:41 - │ └── _child_lines(...) src/fensu/mapping/_helpers/render.py:41 (cycle) - └── _label(...) src/fensu/mapping/_helpers/render.py:88 -``` - -The map is useful precisely because it is not guessing. `fensu check` enforces -layers, roles, and public surfaces first, and `fensu map` then renders the -structure the code is required to expose. - -## Philosophy - -Fensu is strict by default wherever it can make an honest deterministic claim. -Following the rules should remove repeated architectural decisions from everyday -work. Deliberate differences belong in selection, configuration, or custom rules, -where they remain visible, rather than in scattered inline suppressions. - -Unavoidable external calling conventions can use exact symbol-scoped exceptions: - -```toml -[[rule_exceptions]] -rule = "FFS120" -path = "src/my_package/integrations/_helpers/callbacks.py" -symbols = ["ProgressCollector.update"] -reason = "The external API invokes this callback positionally." -``` - -Exceptions accept one exact rule code, repository-relative source file, and optionally one -or more qualified symbols. Python and web symbols use dotted names such as `Class.method`; Rust -symbols use item paths such as `parse`, `Record`, `Record::load`, or `inner::parse` (see -[Rust](docs/rust.md#symbol-scoped-exceptions)). Without `symbols`, an exception covers the whole -file; `Cargo.toml` exceptions are always file-level. Missing or ambiguous symbols are -configuration errors. Globs, directories, line numbers, and inline suppression comments are not -supported. `fensu check` rejects stale exceptions, and each listed symbol must still suppress a -fault. - -For a justified rule/path intersection that is broader than one exact finding, -keep the rules and project context active with `[[rule_ignores]]`: - -```toml -[[rule_ignores]] -rules = ["FFA", "XGENERATED"] -paths = ["src/my_package/generated/**"] -reason = "Generated interfaces are checked by their source schema." -``` - -One declaration must match both the finding's rule code and its reported path. -Unlike exact exceptions, path-scoped ignores are not stale-checked. - -## Agent Skills - -Generate repository-aware guidance from the active ruleset: - -```bash -fensu skills -fensu skills --global -``` - -The generated skill includes Fensu usage, rule-supported architecture examples, -navigation and work-handoff guidance, and every enabled core and custom rule. -Existing user-authored skill files are preserved unless `--force` is supplied. - -## Custom Rules - -Custom checks use `X...` codes and the same `RuleContext` as core rules. Once -configured, they participate in `fensu check`, `fensu rule`, and generated agent -skills. Rules can declare typed `RuleOption` values, repositories can override them -under `[rule_options.]`, and checks read the validated current value through -`ctx.option()`. Rules can also use `ctx.facts`, `ctx.project`, `ctx.text`, `ctx.syntax`, and -`ctx.relations`; these are the same backend-neutral analysis zones used by Fensu's -built-in rules. Project and filesystem reads made through `ctx.project` are tracked -for cache invalidation. Raw `ast.Module` access remains available for checks that need -unrestricted Python syntax traversal. Semantic fact contracts and author-facing models -are public Python APIs, while their production extraction has one native Rust owner; -raw AST, syntax, and relation artifacts remain lazy CPython capabilities. Keep -project-owned checks in the canonical -`scripts/fensu_policy/rules/` tooling role and load them explicitly: - -```toml -tooling = ["scripts"] -rule_paths = ["scripts/fensu_policy/rules"] -``` - -See the [custom-rule guide](https://docs.fensu.dev/concepts/custom-rules) -for the complete API and configuration. +src/shop/ +└── inventory/ + ├── main/ # public entry points and orchestration + │ └── reserve.py + ├── _helpers/ # private implementation phases + ├── classes/ # one class per module + ├── models.py # data models + ├── types.py # type declarations + ├── constants.py + └── exceptions.py +``` + +A leaf needs meaningful `main/` behavior, not an empty placeholder. Domains can +split into named subdomains; tests mirror the code they cover. Tooling has its own +scope. See the [architecture model](https://fensu.io/docs/concepts/architecture-model/) +for complete role contracts, layouts, and defaults. + +## Explore the repository + +| Command | Purpose | +| --- | --- | +| `fensu rule FFL102` | Explain a rule and its effective settings. | +| `fensu map submit --root src --depth 2` | Show proven static Python calls, without running the program. | +| `fensu dupes --since origin/main --diff` | Review changed duplicated-code clusters; advisory, not a blocking check. | +| `fensu skills --check` | Verify installed guidance matches the current policy. | + +Call mapping needs neither Fensu configuration nor rule adoption. It marks +unresolved calls, cycles, and depth limits instead of guessing dynamic targets. +See the [map reference](https://fensu.io/docs/cli/map/) and +[duplicated-code guide](https://fensu.io/docs/concepts/duplicated-code/). ## Documentation -The quickstart, architecture model, configuration reference, adoption guide, and -CLI reference live at [docs.fensu.dev](https://docs.fensu.dev). +[fensu.io/docs](https://fensu.io/docs/) is the full manual; the README is the starting point. + +| Start here | Reference | +| --- | --- | +| [Quickstart](https://fensu.io/docs/quickstart/) | Installation, initialization, and reading diagnostics. | +| [Adoption](https://fensu.io/docs/adoption/) | Roll out enforcement safely on existing code. | +| [Configuration](https://fensu.io/docs/concepts/configuration/) | Targets, ownership roots, selection, thresholds, exceptions, and ignores. | +| [Architecture](https://fensu.io/docs/concepts/architecture-model/) | Roles, domain boundaries, tooling, and test layout. | +| [Rust](https://fensu.io/docs/concepts/analyzers/rust/) · [Web](https://fensu.io/docs/concepts/analyzers/typescript-sveltekit/) | Analyzer-specific setup and rule packs. | +| [CLI](https://fensu.io/docs/cli/) · [Agent guidance](https://fensu.io/docs/cli/skills/) | Commands, execution, and skill update safety. | +| [Caching](https://fensu.io/docs/concepts/caching/) | Cache identities, controls, and safe cleanup. | +| [Custom rules](https://fensu.io/docs/concepts/custom-rules/) · [RuleContext API](https://fensu.io/docs/reference/rule-context/) | Author, configure, and test project-specific policies. | + +[Python dead-code enforcement](docs/dead-code.md) has a separate repository guide +covering reachability, explicit dynamic roots, and adoption caveats. ## Part of SQLStack diff --git a/website/src/content/docs/docs/cli/index.mdx b/website/src/content/docs/docs/cli/index.mdx index 0429c29d..abfbc52c 100644 --- a/website/src/content/docs/docs/cli/index.mdx +++ b/website/src/content/docs/docs/cli/index.mdx @@ -38,6 +38,13 @@ Commands: Run `fensu --help` for command-specific options. +## Execution model + +Core-only `check`, `dupes`, `init`, `rule`, `map`, `skills`, and `--version` +execution is native. Configured Python custom rules launch one compatible Python +host only for the policy metadata or callbacks they require. The native executable +remains the command owner; Python hosting is not a second CLI implementation. + ## Version Both help forms exit `0`: diff --git a/website/src/content/docs/docs/concepts/analyzers/rust.mdx b/website/src/content/docs/docs/concepts/analyzers/rust.mdx index 6950b1d9..622a5c58 100644 --- a/website/src/content/docs/docs/concepts/analyzers/rust.mdx +++ b/website/src/content/docs/docs/concepts/analyzers/rust.mdx @@ -46,7 +46,7 @@ domains begin below additional structural grouping directories. ## What it checks -The `rust` pack exposes all 117 implemented rules under `FPRS`. The rules cover: +The `rust` pack exposes all implemented rules under `FPRS`. The rules cover: - Cargo workspace and dependency policy; - module ownership, visibility, layout, and import boundaries; @@ -62,9 +62,20 @@ warn = [] ignore = ["FPRSH001"] ``` -Exact file exceptions and path-scoped ignores work as they do for other analyzers. -Rust exceptions name a Rust source file or `Cargo.toml`; they do not use Python -definition selectors. Inspect any rule and its effective settings with: +Exact file exceptions and path-scoped ignores use the normal configuration keys. +Rust exceptions name an exact `.rs` file or `Cargo.toml`. An exception without +`symbols` covers the file, including findings owned by items; `Cargo.toml` +exceptions must always be file-level. + +To narrow a Rust exception, use syntactic item paths within the source file: +`parse`, `Record`, `Record::load`, or `inner::parse`, not Python-style dotted +definition selectors. Modules and macro-generated items are not addressable; +missing or ambiguous names are configuration errors. Each listed symbol must +suppress a fault or the exception is stale. The +[repository guide](https://github.com/sqlstack-io/fensu/blob/main/docs/rust.md#symbol-scoped-exceptions) +details item spans, trait and implementation paths, and ambiguity restrictions. + +Inspect any rule and its effective settings with: ```bash fensu rule FPRSS010 --target rust diff --git a/website/src/content/docs/docs/concepts/architecture-model.mdx b/website/src/content/docs/docs/concepts/architecture-model.mdx index ceba160a..b2cba0fb 100644 --- a/website/src/content/docs/docs/concepts/architecture-model.mdx +++ b/website/src/content/docs/docs/concepts/architecture-model.mdx @@ -121,7 +121,7 @@ accidental public surfaces. ## Domains: leaf or branch Fensu's default layout for product code is **domains built from roles**, not a -flat top level. +flat top level. The default architecture follows SQLBuild Compiler Rules v0.101.1. - An ownership root (by default the package root, for example `src/my_package/`) holds only its package protocol modules, deliberate public @@ -140,6 +140,14 @@ parts. There is no mandatory subdomain level and no conventional `core/` ceremony. Loose non-role modules directly at the domain level fault too (`FFR307`). +Every leaf domain or subdomain requires a direct `main/` boundary containing at +least one meaningful entry module. Branch-domain parents do not need their own +`main/`; their leaf subdomains do. An empty or initializer-only `main/` is not a +substitute for behavior. Move passive-only models, types, constants, exceptions, +or classes into the closest domain whose `main/` behavior owns and uses them. +Fixed role files are siblings of `_helpers/`, not descendants such as +`_helpers/entry/models.py`. + ```text src/my_package/ ├── __init__.py # public re-export surface only diff --git a/website/src/content/docs/docs/concepts/configuration.mdx b/website/src/content/docs/docs/concepts/configuration.mdx index 0a1c5e86..df4ee4d4 100644 --- a/website/src/content/docs/docs/concepts/configuration.mdx +++ b/website/src/content/docs/docs/concepts/configuration.mdx @@ -339,7 +339,7 @@ symbols = ["ProgressCollector.update"] reason = "The external API invokes this callback positionally." ``` -Omit `symbols` only for an ownerless file-level finding: +Omit `symbols` to accept matching-rule findings throughout the exact file: ```toml [[rule_exceptions]] @@ -348,14 +348,18 @@ path = "src/my_package/integrations/compatibility.py" reason = "This file remains a direct module while the external integration is supported." ``` -Omitting `symbols` does not suppress findings owned by functions in that file. If -`symbols` is present, it must be non-empty; `symbols = []` is rejected rather than -silently broadening the exception to file scope. +This file-level form also suppresses matching findings owned by functions or +items in that file, for every analyzer. Include `symbols` when only particular +owners should be exempt. If present, it must be non-empty; `symbols = []` is +rejected rather than silently broadening the exception to file scope. The rule, repository-relative analyzer source file, and any qualified symbols are exact: globs, directories, line numbers, and rule prefixes are not accepted. The path and symbols must exist, and `fensu check` fails if either form becomes stale and -suppresses no fault. +suppresses no fault. Each listed symbol must suppress a fault; missing or ambiguous +symbols are configuration errors. Rust uses item paths such as `Record::load`; +`Cargo.toml` exceptions cannot name symbols. See +[Rust exception selectors](/concepts/analyzers/rust#what-it-checks). ## Path-scoped rule ignores diff --git a/website/src/content/docs/docs/quickstart.mdx b/website/src/content/docs/docs/quickstart.mdx index 069a646d..5c5349f0 100644 --- a/website/src/content/docs/docs/quickstart.mdx +++ b/website/src/content/docs/docs/quickstart.mdx @@ -24,6 +24,16 @@ fensu --version Fensu needs Python 3.12 or newer. +The `fensu` distribution provides the Python authoring/API surface and installs the +lockstep `fensu-cli` binary distribution, which owns the `fensu` command. Use that +executable for built-in commands; `python -m fensu` is retired. See the +[CLI execution model](/cli#execution-model) for native commands and custom-rule hosting. + +Fensu includes a compiled analysis core. Prebuilt wheels cover Linux (x86_64 and +aarch64), macOS (Intel and Apple silicon), and Windows (x86_64). Where no compatible +wheel is available, `pip` builds from source; this requires Rust 1.95 or newer, +including when installing `fensu-cli` from its source distribution. + ## 2. Initialize [`fensu init`](/cli/init) is the fastest way to start. It detects your layout, diff --git a/website/src/content/docs/docs/reference/rule-context.mdx b/website/src/content/docs/docs/reference/rule-context.mdx index bbd3e142..6fb0c4e6 100644 --- a/website/src/content/docs/docs/reference/rule-context.mdx +++ b/website/src/content/docs/docs/reference/rule-context.mdx @@ -24,6 +24,11 @@ and configuration. Legacy Python callbacks may ignore the context and walk their Backend-neutral semantic facts for the current file, computed once and shared by all rules through a single traversal. +The semantic fact contracts and author-facing models are public Python APIs; +production fact extraction is owned by the native Rust implementation. Raw Python +AST, syntax, and relation artifacts remain lazy CPython capabilities, materialized +only when a custom rule needs those surfaces. + | Call | Returns | Purpose | | --- | --- | --- | | `annotations()` | `AnnotationFacts` | Missing parameter, return, local, and variable annotations. | From 424d8563ec42c5cd80483b7533ce256bfede8e03 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Sun, 1 Nov 2026 14:17:08 +0000 Subject: [PATCH 3/3] docs(readme): simplify onboarding copy Amp-Thread-ID: https://ampcode.com/threads/T-01a1970c-7c44-7042-b987-dc3926e29427 --- README.md | 26 +++++--------------- website/src/content/docs/docs/quickstart.mdx | 7 ++++++ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 628c9f87..5f743dd5 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,6 @@ shape** for Python, Rust, TypeScript, JavaScript, and Svelte. - **Roles:** keep entry points, helpers, models, and types in their owning modules. - **Function shape:** keep orchestrators small, dataflow explicit, and signatures clear. -Fensu is pre-release and self-hosting. It ships an opinionated default architecture, -not a blank rule framework; tune or replace policies deliberately. - ## Get started Requires **Python 3.12+**. Install in your project’s Python environment: @@ -28,28 +25,17 @@ From an existing Python repository’s `pyproject.toml` directory: ```bash fensu init --yes -fensu skills --check fensu check ``` -`init` detects the layout, writes `fensu.toml`, measures current drift, and installs -repository-local agent guidance. It detects complete SvelteKit projects too; see -[web targets](https://fensu.io/docs/concepts/analyzers/typescript-sveltekit/). -For an empty repository, use `fensu init --yes --name my_package` instead. - -Already configured? `init` leaves existing configuration unchanged. Run -`fensu skills` to install or refresh guidance, then verify it with `--check`. -Unmanaged skill files are preserved unless you explicitly pass `--force`. -Use `init --no-skills` only for deliberate configuration-only automation. +`fensu init --yes` detects your project, creates `fensu.toml`, runs an initial check, +and installs agent guidance. Existing configuration is preserved. -`check` exits **0** with no blocking faults, **1** when it finds faults, and **2** -for setup/configuration errors. Put `fensu check` in CI to enforce the policy. +Run `fensu check` locally and in CI to enforce your policy. For established +repositories, [adopt rules incrementally using explicit boundaries and exceptions](https://fensu.io/docs/adoption/). -New and small repositories are the easiest starting point. On established codebases, -expect drift: use [adoption boundaries and explicit exceptions](https://fensu.io/docs/adoption/) -rather than making unsafe structural changes just to reach zero. -Rust projects use [Cargo-aware target configuration](https://fensu.io/docs/concepts/analyzers/rust/). -See [installation details](https://fensu.io/docs/quickstart/#1-install) for wheels and source builds. +See the [quickstart](https://fensu.io/docs/quickstart/) for empty repositories, +existing configuration, and language-specific setup. ## A finding and its fix diff --git a/website/src/content/docs/docs/quickstart.mdx b/website/src/content/docs/docs/quickstart.mdx index 5c5349f0..06b7042b 100644 --- a/website/src/content/docs/docs/quickstart.mdx +++ b/website/src/content/docs/docs/quickstart.mdx @@ -49,6 +49,13 @@ run `fensu init --yes --name my_package`; init scaffolds a `src/` package and `tests/` directory. Pass `--no-skills` only when automation explicitly needs configuration without repository-local agent guidance. +Existing configuration is preserved: `init` changes nothing when `fensu.toml` +already exists. Use [`fensu skills`](/cli/skills) to install or refresh guidance +for a configured project. See [`fensu init`](/cli/init) for detection and setup +options, or the [Rust](/concepts/analyzers/rust) and +[TypeScript/SvelteKit](/concepts/analyzers/typescript-sveltekit) guides for +language-specific configuration. + Verify that every generated local skill is present and current before calling onboarding complete: