diff --git a/scripts/check-architecture-guardrails.mjs b/scripts/check-architecture-guardrails.mjs index 1c3008b..c0512f6 100644 --- a/scripts/check-architecture-guardrails.mjs +++ b/scripts/check-architecture-guardrails.mjs @@ -100,6 +100,40 @@ export const rules = [ ], forbidden: [], }, + { + file: "apps/web/src/hooks/timelineLivePreview.ts", + maxLines: 140, + required: [ + { + pattern: /\bexport function scheduleLivePreview\b/, + message: "timeline live preview helpers must keep frame scheduling centralized", + }, + { + pattern: /\bexport function clearLivePreview\b/, + message: "timeline live preview helpers must keep preview reset logic centralized", + }, + { + pattern: /\bexport function preserveLivePreview\b/, + message: "timeline live preview helpers must keep snapshot preservation centralized", + }, + ], + forbidden: [], + }, + { + file: "apps/web/src/hooks/useTimelineDrag.ts", + required: [ + { + pattern: /from "\.\/timelineLivePreview\.js"/, + message: "timeline drag must keep live preview behavior delegated to the extracted helper module", + }, + ], + forbidden: [ + { + pattern: /\bfunction (?:toPxValue|joinTransforms|captureLivePreviewTargets|renderLivePreview|scheduleLivePreview|clearLivePreview|datesMatch|preserveLivePreview)\b/, + message: "timeline drag must not re-inline live preview helper implementations", + }, + ], + }, { file: "docker-compose.prod.yml", required: [ diff --git a/scripts/check-architecture-guardrails.test.mjs b/scripts/check-architecture-guardrails.test.mjs index 235de3f..cd13cd1 100644 --- a/scripts/check-architecture-guardrails.test.mjs +++ b/scripts/check-architecture-guardrails.test.mjs @@ -4,6 +4,7 @@ import { collectArchitectureGuardrailViolations, countLines, evaluateRule, + rules, } from "./check-architecture-guardrails.mjs"; describe("architecture guardrails", () => { @@ -66,4 +67,22 @@ describe("architecture guardrails", () => { "apps/web/src/example.ts: file grew to 4 lines and exceeds maxLines=2; split the ownership surface before expanding it further", ]); }); + + it("guards the extracted timeline live preview ownership boundary", () => { + const dragRule = rules.find((rule) => rule.file === "apps/web/src/hooks/useTimelineDrag.ts"); + const livePreviewRule = rules.find((rule) => rule.file === "apps/web/src/hooks/timelineLivePreview.ts"); + + assert.ok(dragRule); + assert.ok(livePreviewRule); + + assert.deepEqual(evaluateRule(dragRule, "function clearLivePreview() {}\n"), [ + "apps/web/src/hooks/useTimelineDrag.ts: missing guardrail anchor: timeline drag must keep live preview behavior delegated to the extracted helper module", + "apps/web/src/hooks/useTimelineDrag.ts: forbidden pattern matched: timeline drag must not re-inline live preview helper implementations", + ]); + + assert.deepEqual(evaluateRule(livePreviewRule, "export function scheduleLivePreview() {}\n"), [ + "apps/web/src/hooks/timelineLivePreview.ts: missing guardrail anchor: timeline live preview helpers must keep preview reset logic centralized", + "apps/web/src/hooks/timelineLivePreview.ts: missing guardrail anchor: timeline live preview helpers must keep snapshot preservation centralized", + ]); + }); });