Known limitations
Source-verified boundaries of Signalint 1.2.1, including hook coverage, snapshot identity, live-buffer semantics and source-writing transactions.
These are verified boundaries of Signalint 1.2.1, not a roadmap or a certificate that every native configuration or editor version works.
Native JS/TS versus supplied external diagnostics
Section titled “Native JS/TS versus supplied external diagnostics”The native MCP check safety gate requires recognized JS/TS ecosystem markers. The four registered subprocess engines are Oxlint, TypeScript, Biome and ESLint. Oxlint, TypeScript and Biome are optional peers, not guaranteed bundled engines. Biome can additionally contribute JSON/JSONC, CSS and GraphQL diagnostics in that ecosystem.
Caller-supplied LSP reports and Python/Rust/Go report normalizers are new, but do not launch additional language toolchains. There is no built-in editor subscription/extension or watcher. See live diagnostics.
Explicit patches, not automatic repairs or a sandbox
Section titled “Explicit patches, not automatic repairs or a sandbox”Native checks do not request automatic fix/write modes. fixable is inferred metadata, not a patch or proof a change is safe. The new preview tool accepts caller-provided full-file content; apply explicitly writes source with confirm: true.
Apply now revalidates paths and original-content SHA-256, then uses sequential adjacent temp-file replacements with an in-memory journal. It is not filesystem-atomic across files or persistent crash recovery. Rollback remains best-effort and post-check failure does not revert successful writes. A supplied unknown/expired baseline is refused before writes; omitting the baseline requests no delta. The boolean does not prove human approval. Review transaction limits and security before enabling it.
Plugins, native config and compiler artifacts operate with the user’s permissions. The tool-argument boundary is not an OS sandbox.
Project scan coverage and path limits
Section titled “Project scan coverage and path limits”- Input path arrays are limited to 512 paths. Oversized MCP arrays fail validation.
- Expanded snapshots use the same 512-path resolver:
["."]can fail withtoo_many_pathsafter discovering more than 512 candidates. Non-JS candidates count before relevance filtering. - The walker skips
node_modules,.git,.signalintanddistindependently of ignore settings. Unreadable directories can be skipped. - Its 2,000-candidate directory-entry guard is not a complete-walk guarantee or a strict universal file cap.
truncated describes summary overflow, not repository coverage. Use narrower explicit scopes and native tools when the walk cannot provide required coverage. An all-disabled native check reports nothing_checked; a check with failed engines is not clean just because it has no issue records.
Workspace planning is opt-in and narrow
Section titled “Workspace planning is opt-in and narrow”monorepoMode defaults to off. Auto/strict discovery now uses the yaml parser and common *, ?, **/negative-exclusion patterns. It is not a complete package-manager glob or semver implementation: brace/classes, wildcard prefixes before recursive **, ordered re-inclusion and full dependency resolution have limits. Strict rejects missing/malformed YAML and graph cycles; other root/empty-scope fallbacks remain.
Project planning can include transitive dependents. check_files uses its first file for the TypeScript hash/fingerprint probe and workspace dependency directories, while the default compiler runner still uses the root config; it does not independently typecheck every package represented in a multi-package list. See monorepos.
Normal TypeScript project mode defaults --skipLibCheck when omitted and partitions build info under .signalint/cache/tsc/<project-id>/. Native build mode can write elsewhere. Do not assume equivalence with an arbitrary bare compiler command.
Cache reuse can miss context
Section titled “Cache reuse can miss context”Requested-file keys omit filename and includeFormatter. Identical-content files under different path-based rules can share results; formatter-mode changes can preserve old behavior. The TypeScript metadata fingerprint does not hash source contents or implement the full compiler dependency graph. Same-size/restored-mtime edits, unsupported config inheritance, skipped/symlinked sources and external inputs can leave stale state.
Project-ID partitioning, bounded config/reference hashing, root lockfile hashing and explicit dependency-directory fingerprints improve tracking; they do not prove there are no false hits. There is no force-refresh tool flag. See caching.
Bounded checks versus full live arrays
Section titled “Bounded checks versus full live arrays”Native check summaries emit at most 10 multi-issue clusters and 100 flat records. Only clusters with more than 2 issues include up to 2 distinct sample IDs. Overflow groups are demoted; omitted flat IDs are not listed by that summary. Record caps do not enforce a constant byte size.
get_live_diagnostics returns the full newest retained non-LSP-snapshot plus buffered normalized array, so it can enumerate currently omitted IDs. It is not historical snapshot pagination and is not bounded to 100 issues. get_diagnostic_snapshot returns metadata and bounded summaries, not its full normalized array. Detail requires a known issue/cluster reference.
Clustering groups rule strings, including across engines. Repetition is not semantic proof of a common cause or one-edit resolution.
Snapshot identity and delta are not absolute guarantees
Section titled “Snapshot identity and delta are not absolute guarantees”Snapshots default to 50 / 30 minutes, in memory only. Content-derived checkId can repeat and overwrite an entry. Stored snapshots are deep-cloned/frozen; lookups return detached copies, not necessarily frozen objects. Detail requires checkId; latest-result lookup has been removed.
Issue IDs omit engine and column. Exact/prefix lookup can return multiple matches; prefix extension distinguishes different hashes, not equal full IDs. Detail returns bounded normalized messages, not original compiler output.
Delta matches exact IDs, then file/rule/normalized-message/severity with nearest-line pairing. Error counters exclude warnings and do not establish engine coverage. A narrow/failed current check can make unobserved baseline errors look resolved; “Clean check” advice is not a safety certificate. See snapshot verification.
Live-buffer lifecycle
Section titled “Live-buffer lifecycle”Batches accumulate; empty ingestion does not clear old file diagnostics. Buffer dedup ignores engine and message, and the merged internal/external view has no cross-source dedup. Batch snapshots and accumulated live state are different views. MCP has no clear-buffer tool; richer timestamped provenance is not wired into every ingestion result.
Hooks are not a clean-project gate
Section titled “Hooks are not a clean-project gate”The threshold policy inspects flat remaining records only, not clusters. Grouped priority-1 errors can yield an approve action. All-disabled stop checks and no-relevant-file post-edit calls can report clean without useful engine coverage.
Post-edit bypasses the configured file-check wrapper. Host emitters/decision formats vary; install may replace targeted existing hooks, and non-TTY install does not enforce --confirm. The launcher communicates decisions in JSON and normally exits 0. See hooks.
Transport, state and concurrency
Section titled “Transport, state and concurrency”Text mode omits structured data/schemas. In both/structured, the first JSON text mirrors the structured object; structured adds a summary block and is not the lower-byte mode. Compact mode’s second summary can incorrectly say zero because it reads totalIssues, not total. Compact snapshot construction can also omit normal-key totals/remaining records, and advertised structured check schemas do not declare compact aliases. Prefer normal keys for those integrations. See payload modes.
SQLite waits up to 5 seconds for locks, not indefinitely. Session updates are serialized per process, not across every agent. SIGNALINT_STATE_DIR redirects supported state; use separate destinations where project isolation matters. Check cancellation and coarse token-based progress are not equivalent guarantees for apply or every new tool.
MCP initialize version now follows the package; the old 0.4.2 metadata mismatch is fixed.
Setup, historical warnings and CLI thresholds
Section titled “Setup, historical warnings and CLI thresholds”initautomatically updates.gitignorewhen needed. Its JSON merger does not parse arbitrary JSONC and replaces the selected Signalint entry. Back up client settings.- Doctor can swallow config parse errors;
PASSEDdoes not prove all config, engines or an MCP handshake work. - Registry and hook paths verify emitted configuration, not every external client version/platform.
- Oscillation/churn history is bounded and scope-sensitive. Narrow absence is not proof of repair; replay can reset churn differently from live project checks.
- Thresholded CLI exits inspect returned clusters and flat records, not omitted records. An engine error without a qualifying diagnostic can exit 0. Inspect JSON status or retain native validation commands.
See CLI and loop detection.
Hardened is not universally validated
Section titled “Hardened is not universally validated”Thrown check-provider failures now carry classified code, engine, message, retryable and nextStep with isError: true; normal settled engine failures still use diagnostic status data. The wire-message sanitizer is pattern-based, stderr logs original failures, and not every input/transaction error uses it. Do not treat it as universal secret redaction.
Inputs are Zod-validated and outputs advertise schemas. Upstream Ajv tests/validating clients do not imply every server return is Ajv-validated; compact aliases and thrown post-apply delta.error remain shape gaps. Per-file replacement also does not guarantee preservation of inode/permission/ownership metadata or every rename-fallback failure path. Runtime evidence outranks the upstream risk register’s broad “closed” labels.