Harness Intelligence Wiki
Research

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.

EntrypointSelected policy / executionEvidence
Root pnpm lintRecursive workspace scripts, then oxlint --config oxlint.base.json with residual root paths.Root package.
Backend package scriptoxlint --config ../.oxlintrc.json .; parent JSON extends the root base.Backend package, parent policy.
Frontend script and CIPackage script explicitly selects parent JSON; CI runs that script from the frontend workspace.Frontend package, CI.
Edited-file hookFinds nearest package and invokes Oxlint without explicit config.Hook.
LefthookMatching 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:

CommandExitDiagnostics
oxlint --config ../.oxlintrc.json --format json src/abstractions/embeddings.ts00
oxlint --format json src/abstractions/embeddings.ts125 errors
oxlint --config oxlint.config.ts --format json src/abstractions/embeddings.ts125 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–121 and apps/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 7357f43b686f4866e45925f875e458e8c29ef6f3 removed plan-only generation's empty-policy shortcut; release commit 1ee7f8b72f8fe116ad74aa15923238d3b985c751 shipped the issue fixes. See CHANGELOG.md:36 and the issue-203 spec at SPEC.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.json rule/ignore and byte convergence on the next plan. It does not compare diagnostics across commands.
  • Current apps/cli/src/scaffold/output.ts:1655–1679 reads recognized JSON names directly inside the scope. It does not resolve a script's arbitrary --config target, its parent policy, or the renamed oxlint.base.json as the owning input.
  • Current features/commit-gate/quality.ts:140–154 preserves existing scripts; data/hooks/format-edited-file.mjs:553–575,1050 independently 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.

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 / preview

One 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.

CandidateEvidence / consequenceTradeoff 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.

On this page