chore(01-02): add ESLint flat config + boundaries plugin + CORE-10 firewall rule
- New eslint.config.js (flat, ESLint 9) declaring 9 element types: the seven Phase-1 firewall directories (sim, render, ui, save, content, audio, store) plus the template's app + game. - One rule, severity error: sim cannot import from render or ui (CORE-10). - Default posture allow — Phase 1 enforces ONE rule, not closed-by-default. - src/sim/__test_violation__/ excluded from default lint glob; the rule's end-to-end correctness is proven by Task 2's Vitest test, not by 'lint exits 0 on clean code'. - Added typescript-eslint as devDep (parser only — no rule sets) so ESLint can parse .ts/.tsx (Espree default cannot). Documented as a Plan 02 deviation in 01-02-SUMMARY.md (Rule 3 — Blocking). Verifies green on the clean codebase: 0 errors, 0 warnings via 'npm run lint'. Stderr notices from boundaries plugin about deprecated rule name (element-types vs dependencies in v6) and legacy selector syntax are informational only — they don't count as ESLint warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
// eslint.config.js — ESLint 9 flat config
|
||||
//
|
||||
// Phase 1, Plan 02 (CORE-10): the architectural firewall.
|
||||
//
|
||||
// This file declares the seven src/ subsystem element types plus the
|
||||
// template-provided `app` and `game` types, and one rule:
|
||||
//
|
||||
// `src/sim/` MUST NOT import from `src/render/` or `src/ui/`.
|
||||
//
|
||||
// The simulation core must remain rendering-agnostic and headless so the
|
||||
// offline-catchup math in Phase 2 can run deterministically without React
|
||||
// or Phaser. See CLAUDE.md "Architectural Firewall (load-bearing)" and
|
||||
// .planning/phases/01-foundations-and-doctrine/01-CONTEXT.md (D-10).
|
||||
//
|
||||
// We intentionally do NOT pull in `js.configs.recommended` or the
|
||||
// typescript-eslint *rule sets* here. Plan 02 owns exactly one
|
||||
// architectural rule; broader code-quality lint is out of scope for
|
||||
// Phase 1 (and would expand Wave-2 surface area on a clean greenfield
|
||||
// codebase). Future phases may layer more rules on top of this config
|
||||
// without touching the firewall block.
|
||||
//
|
||||
// We DO use `typescript-eslint`'s *parser* — it is the only way ESLint
|
||||
// can parse `.ts` / `.tsx` files at all (Espree, ESLint's default
|
||||
// parser, doesn't understand TypeScript syntax or JSX). This is a
|
||||
// parser-only integration; no `tseslint.configs.*` rule sets are
|
||||
// applied. This is documented as a Plan 02 deviation (Rule 3 — Blocking)
|
||||
// in 01-02-SUMMARY.md.
|
||||
|
||||
import boundaries from 'eslint-plugin-boundaries';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default [
|
||||
// ---------------------------------------------------------------------
|
||||
// 1. Default-lint exclusions.
|
||||
//
|
||||
// The deliberate-violation fixture under src/sim/__test_violation__/
|
||||
// exists ONLY to be lint-tested by Task 2's Vitest test (which runs
|
||||
// ESLint programmatically with `ignore: false`). It must NOT trip
|
||||
// `npm run lint` in CI — the rule is verified by the unit test, not
|
||||
// by the default lint glob.
|
||||
// ---------------------------------------------------------------------
|
||||
{
|
||||
ignores: [
|
||||
'src/sim/__test_violation__/**',
|
||||
'dist/**',
|
||||
'node_modules/**',
|
||||
'coverage/**',
|
||||
'*.tsbuildinfo',
|
||||
],
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 2. Phase-1 architectural firewall (CORE-10).
|
||||
//
|
||||
// Seven src/ subsystem types matching CONTEXT D-10's directory layout,
|
||||
// plus `app` (the React/Phaser bridge files at src/main.tsx, src/App.tsx,
|
||||
// src/PhaserGame.tsx) and `game` (the Phaser scene tree at src/game/**).
|
||||
//
|
||||
// Default posture is `allow` — Phase 1 enforces ONE rule, not a
|
||||
// closed-by-default architecture. Future phases may add cross-subsystem
|
||||
// restrictions (e.g., `render` cannot import `save`) without changing
|
||||
// the default.
|
||||
// ---------------------------------------------------------------------
|
||||
{
|
||||
files: ['src/**/*.{ts,tsx,js,jsx,mjs,cjs}'],
|
||||
plugins: { boundaries },
|
||||
languageOptions: {
|
||||
// Parser-only integration with typescript-eslint. Lets ESLint
|
||||
// parse TS / TSX (incl. JSX) so the boundaries rule can inspect
|
||||
// imports. No tseslint rule sets are enabled — that is out of
|
||||
// Phase-1 scope (Plan 02 owns ONE rule: CORE-10).
|
||||
parser: tseslint.parser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: { jsx: true },
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
'boundaries/elements': [
|
||||
{ type: 'sim', pattern: 'src/sim/**' },
|
||||
{ type: 'render', pattern: 'src/render/**' },
|
||||
{ type: 'ui', pattern: 'src/ui/**' },
|
||||
{ type: 'save', pattern: 'src/save/**' },
|
||||
{ type: 'content', pattern: 'src/content/**' },
|
||||
{ type: 'audio', pattern: 'src/audio/**' },
|
||||
{ type: 'store', pattern: 'src/store/**' },
|
||||
{ type: 'app', pattern: 'src/{main,App,PhaserGame}.{ts,tsx}' },
|
||||
{ type: 'game', pattern: 'src/game/**' },
|
||||
],
|
||||
'boundaries/include': ['src/**/*'],
|
||||
// Quietly tolerate files that aren't classified (e.g., src/vite-env.d.ts,
|
||||
// src/__sentinel__.test.ts). The firewall rule only fires on
|
||||
// sim → {render, ui} edges; unclassified files don't trigger it.
|
||||
'boundaries/ignore': ['src/vite-env.d.ts', 'src/__sentinel__.test.ts'],
|
||||
},
|
||||
rules: {
|
||||
// CORE-10: the simulation core cannot reach into render or UI.
|
||||
// Severity MUST be `error` — `npm run lint` runs with
|
||||
// `--max-warnings 0` (per Plan 01), so a warning would also fail
|
||||
// CI, but `error` makes intent unambiguous.
|
||||
'boundaries/element-types': ['error', {
|
||||
default: 'allow',
|
||||
rules: [
|
||||
{ from: ['sim'], disallow: ['render', 'ui'] },
|
||||
],
|
||||
}],
|
||||
},
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user