--- id: 03-a-structural-eslint-rules epic: conformance-system-v1 title: Structural ESLint rules (feature-must-have-manifest, usecase-must-have-test-file, required-cores-installed) type: technical-story status: done feature: core-eslint depends-on: [02-boot-assertions] blocks: [03-b-ast-aware-eslint-rules] --- ## Goal Stand up the custom ESLint rule plugin in `@repo/core-eslint` and ship three structural conformance rules that don't require cross-file AST analysis. Editor + CLI feedback fires in <1s. ## Why Boot-time assertion catches drift in bound use cases, but cannot catch: - Features that exist on disk but have no manifest at all - Use-case files lacking a sibling test file - Manifest declaring required cores that aren't in `pnpm-workspace.yaml` Structural ESLint rules surface these in the editor, before code is even saved past lint-on-save. ## Done when - Custom rule plugin exists at `packages/core-eslint/plugin.js` - Three rules registered: `conformance/feature-must-have-manifest`, `conformance/usecase-must-have-test-file`, `conformance/required-cores-installed` - Each rule has RuleTester tests with positive + negative cases - `base.js` registers the plugin and enables the rules - `pnpm lint` passes for the current monorepo state (rules tuned to today's reality — see Out of scope) ## In scope - Custom rule plugin module at `packages/core-eslint/plugin.js` - Rule modules in `packages/core-eslint/rules/*.js` - Manifest text parser (`_manifest-source.js`) — regex-based, sufficient for literal `as const` manifests - Workspace.yaml reader (`_workspace.js`) - Rule integration into `base.js` - Tests for each rule using ESLint's RuleTester ## Out of scope - Cross-file AST analysis rules (`no-undeclared-event-publish`, `no-undeclared-audit`) — milestone iii.b - Enforcement on features that don't yet have a manifest — `feature-must-have-manifest` ships as a WARNING today (only auth has a manifest); flips to ERROR after blog/media/navigation/marketing-pages get manifests - Manifest parser based on TypeScript compiler API — regex is sufficient for literal manifests; the AST path comes in iii.b ## Tasks - [x] Story 03.a scaffold - [x] Manifest source helper (`_manifest-source.js`) - [x] Workspace helper (`_workspace.js`) - [x] `feature-must-have-manifest` rule + tests - [x] `usecase-must-have-test-file` rule + tests - [x] `required-cores-installed` rule + tests - [x] Plugin module + `exports` entry in `package.json` - [x] Wire plugin into `base.js` - [x] Verify `pnpm lint` passes against the monorepo - [x] Final verification + story closeout