Issue 224: Oxlint Configuration Authority
Issue 224: Oxlint Configuration Authority
The user subsequently accepted all proposals in this report. The managed lint grill is now the decision record, including delegated lifecycle defaults. Research-time candidate labels and open questions below are historical; compiled grill confirmation is pending. No implementation result is implied.
Boundary and decision status
The user accepted the settings-based software-scope model from the
scope brainstorm, then requested
investigation of conflicting lint entrypoints in ~/Desktop/repos/dp-ai and
comparison with previous release fixes. This report proposes the next part of
that model; migration details are not yet accepted implementation requirements.
The operator is an agent or developer selecting a file or package to lint. The system includes settings, package-local technology evidence, inherited project policy, generated config, commands, hooks, update validation, and drift feedback. Application/business behavior is outside scope. CI matters as a caller of lint commands; API, auth, database, and deployment changes have no evidenced need.
The Mac checkout is not mounted on this Linux host. Research used a separate
checkout of wearedevpunks/devpunks-intelligence, branch
team/manuel/massive-lint-fixes, latest remote commit
b326ba1a350db5feb071db3ef822228b807bfc5c at research time. No tracked consumer files
were changed. Its settings record CLI 5.1.1 and baseline
2026.09.15-1ee7f8b7, matching the latest published baseline returned by GitHub at
research time. The Mac's installed binaries and uncommitted state remain unknown.
Confirmed authority split
All consumer links below are pinned to that commit.
| Entrypoint | Selected policy / execution | Evidence |
|---|---|---|
Root pnpm lint | Recursive workspace scripts, then oxlint --config oxlint.base.json with residual root paths. | Root package. |
| Backend package script | oxlint --config ../.oxlintrc.json .; parent JSON extends the root base. | Backend package, parent policy. |
| Frontend script and CI | Package script explicitly selects parent JSON; CI runs that script from the frontend workspace. | Frontend package, CI. |
| Edited-file hook | Finds nearest package and invokes Oxlint without explicit config. | Hook. |
| Lefthook | Matching package and root contracts execute their scripts; root and package work overlap. | Contracts, installed runner. |
The root JSON has no-debugger plus ignores; the backend JSON adds intentional
rule severities including typescript/no-explicit-any: off. Generated
backend TS config
extends Ultracite core, Next, React, TanStack, and Vitest presets plus local plugins.
It does not explicitly incorporate that parent JSON policy. These are two policy
definitions for the same files, not merely two equivalent config formats.
The consumer maintenance runbook
documents renaming root JSON to oxlint.base.json to avoid same-directory
JSON/TypeScript collisions while retaining explicit JSON script routing. Its
platform-specific explanation was not independently verified. Renaming a file
can remove a discovery collision without reconciling executable authority.
Runtime witness
A separate temporary tool installation used direct lint package versions from the
consumer lockfile: Oxlint 1.80.0, Ultracite 7.10.7, @oxlint/plugins 1.83.0,
eslint-plugin-react-you-might-not-need-an-effect 1.0.2, ESLint 10.5.0, and
Oxfmt 0.66.0. Lifecycle scripts were disabled. Only this lint toolchain was
installed; this was not a full application installation or full CI reproduction.
From app/backend/core, with the same binary and unchanged
src/abstractions/embeddings.ts:
| Command | Exit | Diagnostics |
|---|---|---|
oxlint --config ../.oxlintrc.json --format json src/abstractions/embeddings.ts | 0 | 0 |
oxlint --format json src/abstractions/embeddings.ts | 1 | 25 errors |
oxlint --config oxlint.config.ts --format json src/abstractions/embeddings.ts | 1 | 25 errors |
The latter two normalized diagnostic arrays were identical. --print-config
showed typescript/no-explicit-any as allow for legacy JSON and deny for
generated/default TS. The file contains Record<string, any> at lines 5, 13,
20, 30, and 43. This proves the entrypoint split independently of source changes.
The issue's full-repository 41,955 diagnostic count was not rerun.
A separate Oxlint 1.80.0 probe with an explicitly selected root JSON allowing
no-debugger and a nested config rejecting it produced zero findings for a nested
debugger file, both with and without --disable-nested-config. Do not assume
that an explicit config argument still discovers child configs or add that flag
without a need demonstrated against the supported toolchain.
What the earlier releases fixed
- 4.0.3 / issue 181: normalized edit-hook diagnostics, file-scoped fixes,
nearest-config resolution, and workspace typed settings. The issue-181 spec
excluded rewriting arbitrary project-owned configs. See
CHANGELOG.md:112–121andapps/wiki/content/docs/project/specs/cli/issue-181-lint-feedback-adoption/SPEC.md:29–49. - 5.1.0 / issue 203: plugin alias loading and retaining JSON policy in both
planning and materialization. Initial fix
7357f43b686f4866e45925f875e458e8c29ef6f3removed plan-only generation's empty-policy shortcut; release commit1ee7f8b72f8fe116ad74aa15923238d3b985c751shipped the issue fixes. SeeCHANGELOG.md:36and the issue-203 spec atSPEC.md:33–46. - The existing regression test,
apps/cli/src/scaffold/output-root-materialization.test.ts:57–105, asserts preservation of a same-directory.oxlintrc.jsonrule/ignore and byte convergence on the next plan. It does not compare diagnostics across commands. - Current
apps/cli/src/scaffold/output.ts:1655–1679reads recognized JSON names directly inside the scope. It does not resolve a script's arbitrary--configtarget, its parent policy, or the renamedoxlint.base.jsonas the owning input. - Current
features/commit-gate/quality.ts:140–154preserves existing scripts;data/hooks/format-edited-file.mjs:553–575,1050independently invokes Oxlint without--config. The earlier fixes remain present but did not eliminate this authority split.
Classification: a confirmed recurring symptom through an uncovered contract. It is not evidence that the exact #203 planning/materialization fix was reverted.
Framework selection is a separate proven contributor
The backend manifest contains React and React DOM for email rendering, along with
NestJS and Jest. Thus React is locally evidenced, contrary to the issue's shorthand
claim of no React usage. Next, TanStack, and Vitest are not declared there.
Actual email rendering imports appear in
app/backend/core/src/tools/catalog/hr/developer-cv-sharing/action.ts:14 and
src/messaging/email/hr-notifications/sharing-developer-cv/cv-sharing-email.tsx:1.
In CLI 5.1.1 and the current branch, features/context-planning/compiler.ts:94–114
uses any React dependency as a frontend signal. Lines 156–159 then add selected
Next and TanStack packs to every frontend scope. The quality pack is also selected
generally. The consumer's recorded lint selection contains those unrelated assets.
Fixing config routing alone would consistently apply the wrong generated rules.
Lint-asset applicability needs concrete local evidence, separate from broad agent
guidance pack eligibility; generic quality guidance is not proof of Vitest usage.
Recommended smallest coherent change
settings: selected software scopes and exclusions
+ local framework evidence + explicit project policy inputs
-> one effective Oxlint config per owner
-> one resolved owner/config/toolchain route
-> package script / root aggregate / CI / Lefthook / edit hook / previewOne authoritative config per owner does not require one giant repository config. Shared project policy and Harness presets may be inputs, but should not remain independent execution targets for the same scope.
| Candidate | Evidence / consequence | Tradeoff and design change |
|---|---|---|
| Keep explicit software scopes in settings, derive owner-to-config routing once using existing selection/contracts. | Accepted scope model plus proven divergent consumers; runtime callers stop rediscovering owners/config independently. | Exact schema and root-only app behavior remain to be specified. Avoid adding a second hand-maintained route registry. |
| Generate a canonical scope config that explicitly composes supported Harness presets and project-owned policy, with deliberate precedence. | Backend parent JSON relaxations vanish from the effective generated policy today. | Preserve explicit project choices; enumerate inherited rules, ignores, overrides, environments, globals, and path-relative references before migration. Moving raw JSON without rebasing paths is unsafe. |
| Keep project-owned override inputs outside automatic config discovery. | Consumer renamed JSON to avoid coexistence while scripts still targeted it. | A separate non-discovered override file is the recommended ownership seam; existing policy files may remain inputs if equivalence is proven. Do not silently delete unowned config. |
| Route every managed command to the canonical config and the same supported toolchain explicitly. | The exact same file gives 0 versus 25 errors based only on config route. | A small shared resolver/runner is justified by multiple existing consumers; it must preserve warning severity, typed settings, exclusions, file sets, and staged rename/delete behavior. Root aggregates dispatch to selected owners rather than a second broad lint pass. |
| Make adoption a reconciled transition across config, script, hook, selection, and receipt. | Existing preservation does not prove executable parity; arbitrary custom commands may escape the proposed route. | Inspectable migration preview, preserve/rebase project policy, and verify before activation. Keep custom incompatible commands intact but report unresolved adoption; do not declare convergence while their policy differs. No automatic bulk source fixing as a migration side effect. |
| Report resolved policy and test actual entrypoints. | Byte/digest integrity can pass while commands select different configs. | Expose owner, config, tool version, and unresolved route in existing check/selection output; include scope, transitive config inputs, plugins/presets, and lockfile in relevant validation/cache identity. Do not run whole-repository lint on every lightweight drift check. |
The agent's intake becomes an explicit scope and policy inventory. Saved settings hold scope decisions; the compiled route holds reproducible derived state. CLI generation and the shared runtime own control. Diagnostics identify the owner and policy actually used. Recovery follows existing managed-file ownership rules and retains user policy. Handoff names the exact unresolved command or override rather than asking an agent to guess which configuration is authoritative.
Required specification, plan, and verification changes
If accepted, the issue-224 spec must define a policy-parity invariant: for the same owner, source bytes, file set, toolchain, and check mode, every managed entrypoint uses the same effective rules and exclusions. Different check/fix phases need not emit identical post-fix findings; compare equivalent verification stages.
The execution plan should settle settings and policy ownership first, then allow
disjoint producer and runtime work against that contract, followed by migration
and end-to-end parity proof. Update the scaffold lint baseline, managed format
hook, issue-181 feedback, issue-203 convergence, and commit-gate authority where
the new contract supersedes earlier nearest-config/preservation behavior. Keep
historical evidence intact. Update docs/runbooks/hi-cli-scaffolding.md and
docs/README.md when the behavior is implemented; current research links alone do
not change implemented-operation claims.
Tests should model this consumer's inherited/renamed JSON inputs, not only a same-directory legacy file. Retain project overrides, prove workspace-local framework applicability, and exercise script/root aggregate/hook/CI command parity through real subprocesses. Cover wiki and embedded fixture exclusion, ordinary tests, staged rename/delete, overlapping root/owner routing, legacy custom-command conflicts, and repeated update convergence without user-file loss. The single-file reproduction above is a useful witness, not complete acceptance.
Unresolved decisions: final settings/override representation; which existing custom commands can be migrated mechanically; how policy conflicts are presented for explicit resolution; new/moved-scope maintenance and legacy-settings migration. These remain candidates until accepted. No product code or consumer config changed.
Research and work log
- Readonly history lane examined 4.0.3, 5.1.0, issue 203, current implementation, and existing regression coverage. Readonly consumer lane mapped scripts, CI, hooks, config inputs, and installed contract behavior. Coordinator reproduced policy divergence and synthesized this single report.
HI-CLI-001,HI-CLI-003,HI-CLI-004: pass for readonly ownership inspection; production/managed-asset validation is not applicable to this documentation diff.HI-WIKI-001,HI-WIKI-003: existing research route, registered metadata, frontmatter and pinned evidence; content check passed and public wiki contract passed all 3 tests after authoring.HI-DOCS-001: pass; proposed design and research remain private wiki material; implemented runbook claims are not rewritten prematurely.- Consumer rule registry was consulted; no consumer code or durable documents were edited, so behavior-change documentation and application-specific rules were not activated. Mac-specific state and full application CI remain unverified.
- Neither changelog changes; this research selects no product release. The earlier authorized one-time hook exception was used for PR #225's initial draft only; this follow-up research remains local pending normal publication validation.