For representative valid and invalid test fixtures demonstrating these rules, see the Fixture Index.
| Rule ID | What it detects |
|---|---|
CELLFENCE_MANIFEST_INVALID |
Invalid manifest or baseline configuration |
CELLFENCE_PATTERN_MATCHES_NOTHING |
Manifest-declared include, exclude, ownership, public path, or non-external artifact pattern matched no repository files |
CELLFENCE_SUSPICIOUS_GLOB_PATTERN |
Manifest pattern contains a glob segment such as *** that is usually a ** typo and changes depth semantics |
CELLFENCE_DUPLICATE_CELL_ID |
Duplicate cell identifiers |
CELLFENCE_OWNERSHIP_OVERLAP |
Overlapping declared ownership paths |
CELLFENCE_OWNERSHIP_COVERAGE_DISABLED |
Strict ownership coverage is disabled, so source outside ownedPaths can escape checks |
CELLFENCE_UNOWNED_SOURCE |
Strict governance found source matched by governance.include that no cell owns |
CELLFENCE_UNOWNED_IMPORT_TARGET |
A cell imports governed source that no cell owns |
CELLFENCE_IMPORT_TARGET_OUTSIDE_ROOT |
A source import resolved to a real file outside the repository root |
CELLFENCE_PUBLIC_ENTRY_OUTSIDE_OWNERSHIP |
A public entry or public path is outside the declaring cell's owned paths |
CELLFENCE_ARTIFACT_OUTSIDE_OWNERSHIP |
A non-external produced artifact lane is outside the producer's owned paths |
CELLFENCE_SYMLINK_TARGET_OUTSIDE_OWNERSHIP |
A governed symlink points outside its owning cell, outside the repository, or cannot be resolved |
CELLFENCE_PRIVATE_IMPORT |
Cross-cell import of private implementation |
CELLFENCE_UNDECLARED_CONSUMER |
Cross-cell dependency missing from the consumer manifest. Walkthrough |
CELLFENCE_PUBLIC_ENTRY_MISSING |
Declared public entry does not exist |
CELLFENCE_PUBLIC_SYMBOL_MISMATCH |
Manifest symbols do not match actual public exports |
CELLFENCE_UNDECLARED_ARTIFACT |
Artifact lane consumption was not declared |
CELLFENCE_UNDECLARED_RESOURCE_ACCESS |
Static file, database, queue, or HTTP resource access was not declared |
CELLFENCE_UNRESOLVED_RESOURCE_ACCESS |
Dynamic or unsafe resource access could not be resolved safely |
CELLFENCE_RESOURCE_EVIDENCE_INVALID |
Runtime resource evidence JSON is invalid or references an unknown cell |
CELLFENCE_RESOURCE_EVIDENCE_TRANSCRIPT_INACTIVE |
Runtime evidence declares an inactive trace transcript, usually because the trace hook was disabled |
CELLFENCE_RESOURCE_EVIDENCE_TRANSCRIPT_INCOMPLETE |
Runtime evidence is missing an active, trustworthy transcript or was capped/truncated before all accesses were observed |
CELLFENCE_EXTERNAL_DEPENDENCY_CLAIM_VIOLATION |
A cell uses an external dependency claimed by another cell or claiming set |
CELLFENCE_RATCHET_EXTERNAL_DEPENDENCY_ADDED |
A cell added a new unclaimed external dependency outside the accepted baseline |
CELLFENCE_LOCKED_EXTERNAL_DEPENDENCY_EXPANSION |
A locked cell expanded its accepted external dependency set |
CELLFENCE_PLUGIN_INVALID |
A programmatic plugin has an unsupported API version, throws, or emits invalid references |
CELLFENCE_REQUIRED_RULE_DISABLED |
A configured governance.requiredRules rule was weakened |
CELLFENCE_IMPORT_ANALYSIS_DISABLED |
Reserved compatibility rule ID; manifest v1 rejects importAnalysis: false as CELLFENCE_MANIFEST_INVALID before repository analysis |
CELLFENCE_RESOURCE_ANALYSIS_DISABLED |
Reserved compatibility rule ID; manifest v1 rejects resourceAnalysis: false as CELLFENCE_MANIFEST_INVALID before repository analysis |
CELLFENCE_CLAIM_INVALID |
Claim store or claim request is malformed, expired metadata is invalid, or a claim references unknown cells |
CELLFENCE_ACTIVE_CLAIM_CONFLICT |
Two active claim leases reserve overlapping cells, paths, symbols, resources, or artifact lanes |
CELLFENCE_UNCLAIMED_CHANGE |
claim check --agent found a changed file outside that agent's active claim |
CELLFENCE_CROSS_CELL_MOVE |
A changed file moved between cells and needs explicit architectural review |
CELLFENCE_GIT_METADATA_UNAVAILABLE |
CellFence could not read required Git metadata for changed-file, commit, or evidence checks |
CELLFENCE_WAIVER_INVALID |
A waiver directive is missing a valid signed attestation, is expired, exceeds the 90-day cap, mismatches repository/source/finding bindings, uses an untrusted approver, or attempts to waive a required rule |
CELLFENCE_WAIVER_UNTRUSTED_APPROVER |
A signed waiver attestation names an approver outside trusted CELLFENCE_APPROVERS |
CELLFENCE_WAIVER_PARSING_DISABLED |
A cell disabled waiver directive parsing with waiverParsing: false; directives in that cell are intentionally ignored |
CELLFENCE_UNRESOLVED_IMPORT |
Static relative import could not be resolved; fails closed |
CELLFENCE_RATCHET_OWNED_PATH_GROWTH |
Owned path pattern count increased |
CELLFENCE_RATCHET_PUBLIC_SYMBOL_GROWTH |
Public symbol count increased |
CELLFENCE_RATCHET_PUBLIC_SURFACE_LINE_GROWTH |
Public entry line count increased |
CELLFENCE_RATCHET_CROSS_CELL_DEPENDENCY_GROWTH |
Cross-cell dependency count increased |
CELLFENCE_RATCHET_CELL_SET_GROWTH |
A cell was added outside the accepted baseline cell set |
CELLFENCE_RATCHET_OWNERSHIP_SCOPE_CHANGE |
An owned path shifted or broadened outside the accepted baseline scope |
CELLFENCE_RATCHET_PUBLIC_SYMBOL_SET_CHANGE |
A new public symbol appeared outside the accepted baseline set |
CELLFENCE_RATCHET_DEPENDENCY_EDGE_CHANGE |
A new dependency edge appeared outside the accepted baseline set |
CELLFENCE_RATCHET_PUBLIC_ENTRY_CHANGE |
A cell's public entry path changed |
CELLFENCE_RATCHET_ARTIFACT_CONTRACT_CHANGE |
A new artifact producer/consumer contract appeared |
CELLFENCE_RATCHET_RESOURCE_ACCESS_CHANGE |
A new static or evidence-backed resource access appeared outside the accepted baseline |
CELLFENCE_RATCHET_PUBLIC_SURFACE_SIGNATURE_CHANGE |
Declaration-derived public surface fingerprint changed beyond formatting/comment noise |
CELLFENCE_BASELINE_SEAL_INVALID |
A baseline seal is missing or does not match when Ed25519 or HMAC baseline verification is configured |
CELLFENCE_LOCKED_BASELINE_EXPANSION |
A locked baseline scope expanded without an accepted ratchet update |
CELLFENCE_UNSUPPORTED_DYNAMIC_REQUIRE |
Computed CommonJS require() cannot be resolved statically; emitted as a fail-closed required-rule finding |
CELLFENCE_UNSUPPORTED_DYNAMIC_IMPORT |
Computed dynamic import cannot be resolved statically; emitted as a fail-closed required-rule finding |
CELLFENCE_UNSUPPORTED_TYPESCRIPT_SYNTAX |
TypeScript or JavaScript source could not be parsed cleanly; emitted as a fail-closed required-rule finding |
CELLFENCE_UNSUPPORTED_PYTHON_SYNTAX |
Python source could not be parsed by the configured Python AST inspector; emitted as a fail-closed required-rule finding |
CELLFENCE_SOURCE_IMPORTS_RUNTIME |
A source-class path imports a runtime-class path in violation of path class policy |
CELLFENCE_MIXED_SOURCE_RUNTIME_CHANGE |
A change mixes source and runtime path classes without an allowed commit policy |
CELLFENCE_GENERATED_PATH_CHANGED |
A generated path changed without the required provenance or separation policy |
CELLFENCE_SERVICE_MANIFEST_DRIFT |
A generated CellFence manifest drifted from declared service manifests |
CELLFENCE_COMMIT_EVIDENCE_MISSING |
Commit-level evidence required by path class policy is missing |
CELLFENCE_COMMIT_TRAILER_MISSING |
A required commit trailer for governed path classes is missing |
CELLFENCE_COMMIT_CHANGED_CELLS_MISMATCH |
Commit metadata does not match the cells changed in the diff |
CELLFENCE_COMMIT_TEST_EVIDENCE_MISMATCH |
Commit test evidence does not cover the changed cell set |
CELLFENCE_COMMIT_TEST_REASON_REQUIRED |
Commit metadata claims weak or missing test evidence without a required reason |
CELLFENCE_COMMIT_TEST_WEAKENING |
Commit metadata weakens required test evidence policy |
CELLFENCE_TASK_INVALID |
A task manifest is malformed or references invalid cells, files, budgets, or allowlists |
CELLFENCE_TASK_WRITE_OUTSIDE_ALLOWLIST |
A task attempted to write outside its declared allowed paths |
CELLFENCE_TASK_FORBIDDEN_PATH |
A task attempted to touch a path explicitly forbidden by its manifest |
CELLFENCE_TASK_CHANGE_BUDGET_EXCEEDED |
A task changed more cells, files, or lines than its declared budget allows |
CELLFENCE_DOC_UNKNOWN_CELL |
A stamped architecture document references a cell that is not in the manifest |
CELLFENCE_DOC_SURFACE_STALE |
A stamped architecture document no longer matches the current cell public surface |
CELLFENCE_MUTATION_SCORE_BELOW_THRESHOLD |
Mutation testing score is below the configured minimum |
The
undeclared-consumer
fixture demonstrates a public cross-cell import that lacks the required
dependency declaration. Its
src/consumer/public.ts
imports producerValue from the producer's declared
src/producer/public.ts
entry. The target is public, so this is not a private-import violation.
The fixture's
cellfence.manifest.json
owns the files with separate consumer and producer cells, but the
consumer's consumes list is empty. CellFence therefore reports
CELLFENCE_UNDECLARED_CONSUMER: using a producer's public entry does not
replace the manifest's explicit cross-cell dependency contract.
Build the CLI and reproduce the finding from the repository root:
npm run build
node packages/cli/dist/index.js check \
--root fixtures/invalid/undeclared-consumer \
--format markdownThe intentionally invalid fixture exits unsuccessfully and reports
CELLFENCE_UNDECLARED_CONSUMER at src/consumer/public.ts:1. Its
expected-result.json
also records the expected CELLFENCE_OWNERSHIP_COVERAGE_DISABLED warning.
CellFence v0.x analyzes:
- ES module imports;
export ... fromdeclarations;- CommonJS
require(...), TypeScriptimport = require(...), selectedmodule.require(...), simplerequirealiases, and selectedcreateRequire(...)aliases; - type-only imports;
- dynamic imports with a static string specifier;
- exact package-name imports declared with
packageName; - tsconfig
compilerOptions.pathsaliases, including aliases inherited throughextends, that resolve to repository files; - Python
.pysource ownership, AST-extractedimportandfrom ... import ...module references, common package roots frompyproject.toml,setup.cfg, and staticsetup.py, and public entries described by literal__all__or top-level declarations. Python module-levelfrom ... import namecreates a public module attribute unless hidden with an underscore alias or constrained by__all__; - selected static string resource access for file, database, queue, and HTTP patterns, including Node
fsread/write/destructive file calls andfetch/requestabsolute, relative, websocket,const, and inlinenew URL(...)string forms; - Prisma model delegate calls when
schema.prismais present; - selected TypeORM entity, repository, and query builder calls;
- selected Drizzle table declarations and
db.select().from(...),db.insert(...),db.update(...), anddb.delete(...)calls; - selected Kysely/Knex-style query builder table calls;
- unsafe or dynamic raw SQL calls, known SQL receiver calls with non-literal arguments, and dynamic HTTP URL calls as fail-closed unresolved resource access;
- selected BullMQ and KafkaJS topic or queue calls;
- selected NestJS controller method decorators;
- selected Fastify route object registrations;
- runtime resource evidence supplied as
cellfence.resource-evidence.v2; - common TypeScript export declarations, named exports, and exported namespaces;
- common Python public symbols from
__all__, top-level functions/classes/assignments, and simple re-export imports.
Computed dynamic imports, computed calls in recognized CommonJS require() forms, TypeScript/JavaScript parser diagnostics, and Python files that the configured Python AST inspector cannot parse are reported as unsupported fail-closed findings rather than silently ignored.
For TypeScript and JavaScript public entries, public surface hashes are based on isolated normalized declaration output when TypeScript can emit it, with a lightweight syntax fingerprint as a fallback. This catches type-facing changes such as generic constraints, inferred changes that appear in declarations, const literal type changes, class member signatures, and namespaces while avoiding method-body churn. It is still a v0.x contract fingerprint, not a full TypeScript semantic-versioning oracle.
NodeNext-style runtime .js, .jsx, .mjs, and .cjs relative specifiers are remapped to TypeScript source candidates such as .ts, .tsx, .mts, and .cts before boundary checks. Python imports are resolved from known source roots such as src/, manifest-derived package roots, and common Python packaging metadata. Relative imports that still cannot be resolved produce CELLFENCE_UNRESOLVED_IMPORT errors instead of being ignored. Relative, absolute, tsconfig alias, and Python source-root imports that resolve to files outside the repository root produce CELLFENCE_IMPORT_TARGET_OUTSIDE_ROOT errors instead of being treated as ungoverned or external.
The repository CI includes a synthetic scale benchmark for 10,000 files / 20 cells, 50,000 files / 100 cells, and 100,000 files / 300 cells. It is a regression tripwire for file discovery, ownership indexing, and low-signal source scanning; it is not a universal performance guarantee for every monorepo shape.
Static resource analysis is intentionally limited. It detects simple string-literal calls, SQL literals, selected Node fs calls, selected fetch/request HTTP calls, selected Prisma delegate calls, selected TypeORM, Drizzle, and query-builder calls, selected BullMQ/KafkaJS calls, selected NestJS/Fastify HTTP route declarations, selected FastAPI route decorators, Django URLConf routes and model manager calls, SQLAlchemy declarative/Table/query/text calls, and Celery task declarations and literal publish calls. When a known HTTP call has a non-static URL, or a receiver already observed as SQL later receives a non-static query argument, CellFence emits unresolved resource access instead of silently dropping the call. It does not infer arbitrary ORM metadata, runtime broker topology, framework plugin behavior, or values assembled through general dataflow.
ORMs, query builders, HTTP frameworks, and broker clients require explicit CellFence adapters. Prisma, TypeORM, Drizzle, BullMQ, KafkaJS, selected string-literal query builders, selected NestJS routes, selected Fastify routes, and selected Django, FastAPI, SQLAlchemy, and Celery Python patterns have built-in coverage; that does not imply support for Sequelize, every Knex/Kysely expression, every Drizzle expression, every NestJS/Fastify plugin, every Python framework extension, or a project-local database wrapper. Each adapter must document:
- the API shapes it recognizes;
- how model, entity, table, topic, or queue names are resolved;
- which unresolved or dynamic forms fail closed;
- which cases remain outside static inference and must be supplied as runtime evidence.
Unsupported adapters are not treated as implicitly safe. If a resource access cannot be resolved by a built-in adapter, an explicit resourceContracts entry, baseline evidence, runtime evidence, or a fail-closed unresolved finding is required depending on the access shape.
Repositories can disable unused built-in resource adapters so CellFence does not infer framework contracts for stacks the repository does not run:
{
"governance": {
"resourceAdapters": {
"prisma": "off",
"typeorm": "off",
"drizzle": "off",
"bullmq": "off",
"kafkajs": "off",
"nestjs": "off",
"fastify": "off",
"django": "off",
"fastapi": "off",
"sqlalchemy": "off",
"celery": "off",
"queue": "off",
"sql-literal": "off"
}
}
}Supported keys are file, http, queue, sql-literal, prisma, typeorm, drizzle, query-builder, bullmq, kafkajs, nestjs, fastify, django, fastapi, sqlalchemy, and celery. Omitted adapters default to on.