--- id: 03-b-ast-eslint-rules epic: conformance-system-v1 title: AST-aware ESLint rules (no-undeclared-event-publish, no-undeclared-audit) type: technical-story status: done feature: core-eslint depends-on: [03-a-structural-eslint-rules] blocks: [04-ci-drift-gate] --- ## Goal Ship two AST-aware rules that catch manifest ↔ use-case drift inside factory bodies: - `no-undeclared-event-publish`: `bus.publish("X")` in a factory must match `manifest.useCases[name].publishes` - `no-undeclared-audit`: `auditLog.record({ type: "X" })` must match `manifest.useCases[name].audits` ## Why Boot assertion + structural rules can't see what happens inside a factory body. AST-aware rules catch publish/audit drift the moment a developer (or agent) saves the file. ## Done when - Manifest AST parser extracts per-use-case publishes/audits arrays - Two rules registered in the conformance plugin - Tests cover positive (declared event) and negative (undeclared event) cases for each rule - `pnpm lint` passes (auth's signUp has empty publishes/audits today → no false positives) ## In scope - `_manifest-ast.js` helper using `@typescript-eslint/parser` to extract per-use-case arrays - `_usecase-name.js` helper (file slug → camelCase use-case key) - The two rules + RuleTester tests - Plugin + base.js wiring ## Out of scope - Bus / auditLog parameter detection beyond the conventional names `bus` and `auditLog` - Detection of dynamic event names (`bus.publish(eventVar, payload)` is allowed without warning) - Conditional / nested calls — rules only check top-level CallExpressions in factory bodies ## Tasks - [x] Story 03.b scaffold - [x] Manifest AST parser + tests - [x] Use-case name helper + tests - [x] `no-undeclared-event-publish` rule + tests - [x] `no-undeclared-audit` rule + tests - [x] Plugin update + base.js wiring - [x] Verify `pnpm lint` passes - [x] Final verification + story closeout (tick 03 + 03.b in epic)