Development record
Two lint engines under one vocabulary: internal/core/repolint (post-itd-6 rename; Rule/Evaluate/tri-state exit) and internal/core/lint (RuleConfig/Finding stream) are separate engines with separate rule models and config schemas, already entangled (repolint's rule_docs.go wraps docs-lint as a conformance rule). Every new rule author must pick an engine. Consolidating the rule models is a deliberate future intent - deliberately kept out of the itd-123-era rename sweep after adversarial review of merge-now vs rename-only.
Two lint engines under one vocabulary: internal/core/repolint (post-itd-6 rename; Rule/Evaluate/tri-state exit) and internal/core/lint (RuleConfig/Finding stream) are separate engines with separate rule models and config schemas, already entangled (repolint's rule_docs.go wraps docs-lint as a conformance rule). Every new rule author must pick an engine. Consolidating the rule models is a deliberate future intent - deliberately kept out of the itd-123-era rename sweep after adversarial review of merge-now vs rename-only.
Remedy grounds (2026-09-29)
Why: the Finding stream is the richer model and repolint already wraps docs-lint as a rule, so the direction of the merge is set by the entanglement the record names. Rejected: a rename-only sweep, which the record says adversarial review already turned down because it leaves two rule models under one name.
Frontmatter
| id | iss-251 |
|---|---|
| type | issue |
| lifecycle | open |
| severity | minor |
.abcd/work/issues/open/iss-251-two-lint-engines-under-one-vocabulary.md
open on GitHub ↗ · commit history ↗
mentions5
- iss-2608260944055780Brief self-contradiction on abcd lint's exit grammar: 05-internals/06-lint.md:174 states "Exit code follows the standalone grammar (blocker -> 1, warn -> 2, clean -> 0)", which inverts the two non-zero codes. internal/core/repolint/repolint.go:147 exitCode() returns 2 on any blocker, 1 on warnings only, 0 clean, and its own comment names the Conftest tri-state; 04-surfaces/16-lint.md:41 agrees with the code. Observed: this tree at 19 errors and 3 warnings exits 2. The consequence is worse than count drift, because an exit code is a number a CI job branches on: a job written against 06-lint.md would treat 1 as its failure condition and pass green on a tree full of blockers, a gate that runs and never fires. Same class as iss-142 (the iss-37 phantom-enforcement class) and the same file, different line; iss-181 and iss-251 also sit on this file and cover neither. Brief-tier, so under adr-28 it ships in no release artefact and reaches no installed surface, which is the standing disposition for brief drift and the argument for a lower severity. Refines iss-2608261029074763, which records the wider defect this is one symptom of: 06-lint.md section 3 documents an architecture that was never built, verified as internal/core/lint having no package main so the documented invocation cannot run, --codes-filter, --promote-check, --touched-line and --display-path having zero hits across internal/ and cmd/, no .pre-commit-config.yaml, and IntentLinter, _classify_and_filter, _parse_hunk_lines and _detect_location present in no source file. That record cites this one for the exit grammar rather than restating it. Adjacent and distinct: iss-2608231000561060 covers the gates-CI claim and gate-readiness. Detector: enforcement-claims-are-facts sweep over the brief's exit-code and gating claims. Acceptance corpus: the three lines above.
- itd-6RepoPrompt over MCP is one opt-in reviewer route, beside the host's own agents
- itd-123The Intent Audit Says Audit
- itd-124The Conformance Check Calls Itself Lint
- spc-29the-conformance-check-calls-itself-lint-abcd-audit-becomes-a