@jjchill/probity-rules 0.4.15 → 0.4.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,91 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.16
4
+
5
+ The JS preset now keeps driving adapters (UI components, pages, route
6
+ handlers) thin (#72). Business logic leaking out of the core into UI
7
+ code is blocked, and the deny names where it should go.
8
+
9
+ - **What went wrong.** The existing ports-and-adapters rules stop
10
+ vendors getting *into* core code. Nothing stopped logic leaking *out*
11
+ of it. In a React consumer on 0.4.14, with clean and fully policed
12
+ core boundaries, `src/ui/` grew:
13
+ - a submit handler running a whole use case (domain `submit()`,
14
+ `repository.save()`, `notifier.timesheetSubmitted()`, and a "a
15
+ failed notification must never fail the submit" policy)
16
+ - `viewer.role === 'SuperUser'` permission checks in four places,
17
+ next to a domain that already exported `canEdit` and `canApprove`
18
+ - a display-name rule copied seven times, with two copies disagreeing
19
+ - a React-free use case filed under `src/ui/`
20
+
21
+ Each one had a component test, so the TDD judge had no reason to
22
+ object. It checks whether code is tested, not where it belongs.
23
+ - **Now:** two new rules in `rules/ports-and-adapters.ts`.
24
+ - `enforceThinDrivingAdapter`, an AI judge. It blocks a write that
25
+ adds (a) a decision in domain terms, (b) coordination of more than
26
+ one port or use-case call, (c) a re-implementation of something the
27
+ core exports, or (d) a framework-free use case under a UI path. The
28
+ deny names the extraction target: a domain function or a use case.
29
+ Rendering, display formatting, local view state, and one call per
30
+ user intent pass. Only what a write adds is judged, so an existing
31
+ thick component doesn't freeze.
32
+ - `forbidNewDomainDiscriminantChecks`, a free deterministic screen.
33
+ It blocks net-new comparisons of configured fields to a literal
34
+ (`viewer.role === 'SuperUser'`, either order) and points to a domain
35
+ function. Off until you list the fields: there is no default,
36
+ because `status === 'loading'` is ordinary view state.
37
+ - **Preset wiring (JS only).** `jsRuleEntries` gets a block on the new
38
+ `drivingAdapterGlobs` option, **on by default**: `src/ui/**`,
39
+ `src/components/**` and `src/**/*.tsx`, minus `*.test.*`, `*.spec.*`
40
+ and `*.stories.*`. It runs before the TDD judge, so a denial costs one
41
+ AI call. New options:
42
+ - `drivingAdapterGlobs`: the scope; `[]` switches the rules off.
43
+ - `domainDiscriminants`: turns on the free screen, e.g. `['role']`.
44
+ - `domainHint`: appended to the screen's deny, e.g. where permission
45
+ rules live.
46
+ - `coreExportsInJudge`: gives the judge the export names of every
47
+ module under `coreGlobs` (capped at 8,000 characters), so it can
48
+ name the existing function a copy duplicates. Off by default; it
49
+ scans the tree on each judged write.
50
+ - **Measured** with Probity's real Claude Code judge, 5 runs per case,
51
+ on synthetic writes built from the four cases above plus five
52
+ controls that must pass: a pure render change, adding a `canX()`
53
+ call, a single use-case call, a local `status === 'loading'` check,
54
+ and calling an existing `displayName` export. These are written from
55
+ the issue's descriptions, not replays of the consumer's real writes.
56
+ With and without the export list, 90/90 verdicts were correct (40
57
+ blocked, 50 allowed). The prompt's examples were then made
58
+ domain-neutral and the replay rerun: 76 of 90 runs returned a verdict
59
+ and all 76 were correct. The other 14 hit a judge login failure in
60
+ the test environment. On 0.4.14 no rule judged these writes, so all
61
+ would pass.
62
+ - **Cost:** one extra AI call per write to a matching UI file, on top of
63
+ the TDD judge.
64
+ - **Migration.** Consumers calling `jsRuleEntries` get the new block on
65
+ upgrade. Check it with `probity-scope-report`: it lists the block and
66
+ flags it `DEAD SCOPE` if your UI lives elsewhere. Then set
67
+ `drivingAdapterGlobs` to your layout, or `[]` to opt out. Hand-composed
68
+ configs add the block themselves:
69
+
70
+ ```ts
71
+ {
72
+ files: ['src/ui/**', '!**/*.test.*'],
73
+ rules: [
74
+ forbidNewDomainDiscriminantChecks({ discriminants: ['role'] }),
75
+ withJudgeFailureDiagnostics(withContradictionRetry(enforceThinDrivingAdapter())),
76
+ ],
77
+ }
78
+ ```
79
+
80
+ The Kotlin, KMP and Swift presets are unchanged; Compose and SwiftUI
81
+ globs are a follow-up.
82
+ - New exports: `enforceThinDrivingAdapter`,
83
+ `forbidNewDomainDiscriminantChecks`, `domainDiscriminantPatterns`,
84
+ `exportedNames` and `listCoreExports`.
85
+ - Skills: `ports-and-adapters` gets a "Driving adapters are equally
86
+ thin" section with a checklist, red flags and a rationalization;
87
+ `frontend-ui-engineering` points to it.
88
+
3
89
  ## 0.4.15
4
90
 
5
91
  The JS/TS TDD judge no longer blocks adding a new red test (#73), and it
@@ -17,6 +17,27 @@ export type JsPresetOptions = {
17
17
  /** Point at your canonical ports once they exist, e.g. "inject the
18
18
  * Clock port from src/ports/clock.ts". */
19
19
  seamHint?: string;
20
+ /** Driving (inbound) adapter files — UI components, pages, route
21
+ * handlers, CLI commands — held thin by `enforceThinDrivingAdapter`
22
+ * (an AI call per matching write). Default: `src/ui/**`,
23
+ * `src/components/**` and every `.tsx` under `src/`, minus tests
24
+ * and stories. Pass `[]` to switch
25
+ * the thinness rules off. */
26
+ drivingAdapterGlobs?: Globs;
27
+ /** Field names whose comparison to a literal in a driving adapter is
28
+ * a domain decision (e.g. `['role', 'plan']`). OFF by default —
29
+ * `status === 'loading'` is ordinary view state, so only your model
30
+ * knows which fields carry domain meaning. Set it to block net-new
31
+ * comparisons free, before the AI call. */
32
+ domainDiscriminants?: string[];
33
+ /** Appended to the discriminant block message, e.g. "permission
34
+ * rules live in src/domain/permissions.ts". */
35
+ domainHint?: string;
36
+ /** Give the thin-driving-adapter judge the export names of every
37
+ * module under `coreGlobs`, so it can spot a copy of an existing
38
+ * domain rule. Off by default: it costs a directory scan per judged
39
+ * write. */
40
+ coreExportsInJudge?: boolean;
20
41
  /** Files where internal-module mocking is forbidden (the only test
21
42
  * seam is a port). */
22
43
  mockGlobs?: Globs;
@@ -1 +1 @@
1
- {"version":3,"file":"js.d.ts","sourceRoot":"","sources":["../../presets/js.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAarE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAA;AAGrC;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAC2O,CAAA;AAEpR,MAAM,MAAM,eAAe,GAAG;IAC5B;qDACiD;IACjD,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;+CAC2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;2BACuB;IACvB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB;wDACoD;IACpD,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB;sDACkD;IAClD,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB;oBACgB;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,wCAAwC;IACxC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,0CAA0C;IAC1C,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,KAAK,CAAA;IAC3B;;wCAEoC;IACpC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB;qEACiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;mCAG+B;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;IAC5B,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;oEACgE;IAChE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CACxB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,eAAoB,GAAG,SAAS,EAAE,CAgKxE"}
1
+ {"version":3,"file":"js.d.ts","sourceRoot":"","sources":["../../presets/js.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAiBrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAA;AAGrC;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAC2O,CAAA;AAEpR,MAAM,MAAM,eAAe,GAAG;IAC5B;qDACiD;IACjD,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;+CAC2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;kCAK8B;IAC9B,mBAAmB,CAAC,EAAE,KAAK,CAAA;IAC3B;;;;gDAI4C;IAC5C,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC9B;oDACgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;iBAGa;IACb,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;2BACuB;IACvB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB;wDACoD;IACpD,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB;sDACkD;IAClD,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB;oBACgB;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,wCAAwC;IACxC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,0CAA0C;IAC1C,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,KAAK,CAAA;IAC3B;;wCAEoC;IACpC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB;qEACiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;mCAG+B;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;IAC5B,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;oEACgE;IAChE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CACxB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,eAAoB,GAAG,SAAS,EAAE,CA2MxE"}
@@ -7,6 +7,8 @@
7
7
  * test-driven-development → enforceJsTdd (built-in enforceTdd + addendum)
8
8
  * ports-and-adapters → enforcePortsBoundary + forbidInternalModuleMocks
9
9
  * + a deterministic import screen
10
+ * + enforceThinDrivingAdapter on UI/inbound
11
+ * adapter files
10
12
  * acceptance-testing → enforceAcceptanceLanguage
11
13
  *
12
14
  * `jsRuleEntries(options?)` reproduces exactly what the shipped
@@ -18,9 +20,9 @@
18
20
  import { basename } from 'node:path';
19
21
  import { forbidContentPattern } from '@nizos/probity';
20
22
  import { enforceAcceptanceLanguage } from '../rules/acceptance-language.js';
21
- import { forbidNewAmbientEffects, JS_AMBIENT_EFFECT_PATTERNS, requireGreenTestRun, } from '../rules/gates.js';
23
+ import { forbidNewAmbientEffects, JS_AMBIENT_EFFECT_PATTERNS, requireGreenTestRun, withJudgeFailureDiagnostics, withContradictionRetry, } from '../rules/gates.js';
22
24
  import { enforceJsTdd } from '../rules/js-tdd.js';
23
- import { enforcePortsBoundary, forbidInternalModuleMocks, } from '../rules/ports-and-adapters.js';
25
+ import { enforcePortsBoundary, enforceThinDrivingAdapter, forbidInternalModuleMocks, forbidNewDomainDiscriminantChecks, } from '../rules/ports-and-adapters.js';
24
26
  import { withExcludeGlobs } from '../rules/scoping.js';
25
27
  import { enforceSpecTestParity, JS_TEST_DECLARATION, requireSpecBackedAcceptanceTest, surfaceScenarioLinkBreakage, } from '../rules/spec-test-parity.js';
26
28
  import { surfaceGlossaryTermBreakage } from '../rules/ubiquitous-language.js';
@@ -44,6 +46,18 @@ export function jsRuleEntries(options = {}) {
44
46
  const tddGlobs = options.tddGlobs ?? ['src/**', 'test/**', 'tests/**'];
45
47
  const specGlobs = options.specGlobs ?? ['specs/**', 'acceptance/**', '**/*.feature'];
46
48
  const excludeGlobs = options.excludeGlobs ?? ['spikes/**', '**/build/**'];
49
+ const drivingAdapterGlobs = [
50
+ ...(options.drivingAdapterGlobs ?? [
51
+ 'src/ui/**',
52
+ 'src/components/**',
53
+ 'src/**/*.tsx',
54
+ '!**/*.test.*',
55
+ '!**/*.spec.*',
56
+ '!**/*.stories.*',
57
+ ]),
58
+ // Core code is never a driving adapter, even as .tsx.
59
+ ...coreGlobs.filter((glob) => !glob.startsWith('!')).map((glob) => `!${glob}`),
60
+ ];
47
61
  const entries = [
48
62
  // ── Boundaries: ports-and-adapters ──────────────────────────────
49
63
  // Core purity. Point these globs at your core/domain/use-case
@@ -78,6 +92,32 @@ export function jsRuleEntries(options = {}) {
78
92
  rules: [forbidInternalModuleMocks()],
79
93
  },
80
94
  ];
95
+ // Driving adapters must be thin (issue #72). The core-purity block
96
+ // above stops vendors getting INTO core code; this stops business
97
+ // logic leaking OUT of it into UI components and handlers, which the
98
+ // TDD gate alone never questions (a component test makes the logic
99
+ // "tested"). The free discriminant screen runs first when
100
+ // configured; the judge runs before the TDD judge, so a denial here
101
+ // costs one AI call, not two.
102
+ if (drivingAdapterGlobs.some((glob) => !glob.startsWith('!'))) {
103
+ const [first, ...rest] = drivingAdapterGlobs;
104
+ entries.push({
105
+ files: [first, ...rest],
106
+ rules: [
107
+ ...(options.domainDiscriminants?.length
108
+ ? [
109
+ forbidNewDomainDiscriminantChecks({
110
+ discriminants: options.domainDiscriminants,
111
+ domainHint: options.domainHint,
112
+ }),
113
+ ]
114
+ : []),
115
+ withJudgeFailureDiagnostics(withContradictionRetry(enforceThinDrivingAdapter({
116
+ coreExports: options.coreExportsInJudge ? { globs: coreGlobs } : undefined,
117
+ }))),
118
+ ],
119
+ });
120
+ }
81
121
  // Spec-to-test traceability (issue #18): OFF by default, so a
82
122
  // project that hasn't opted in sees no behavior change. Setting
83
123
  // `specsDir` wires the same set the KMP preset wires — deterministic
@@ -1 +1 @@
1
- {"version":3,"file":"js.js","sourceRoot":"","sources":["../../presets/js.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"js.js","sourceRoot":"","sources":["../../presets/js.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Rule } from '@nizos/probity';
2
+ import { type NamedPattern } from './gates.js';
2
3
  /**
3
4
  * AI-validated enforcement of the `ports-and-adapters` skill: the
4
5
  * Dependency Rule (core imports nothing from adapters, frameworks,
@@ -83,4 +84,91 @@ export declare function enforceAdapterObservability(options?: {
83
84
  export declare function forbidInternalModuleMocks(options?: {
84
85
  allow?: string | RegExp;
85
86
  }): Rule;
87
+ /**
88
+ * One pattern per discriminant: the field compared to a string literal
89
+ * with `===`, `!==`, `==` or `!=`, in either order
90
+ * (`viewer.role === 'SuperUser'`, `'Draft' !== order.status`).
91
+ */
92
+ export declare function domainDiscriminantPatterns(discriminants: readonly string[]): NamedPattern[];
93
+ /**
94
+ * Deterministic first screen for thin driving adapters (issue #72): a
95
+ * UI component or other inbound adapter that compares a domain
96
+ * discriminant — a role, a status, a plan — to a literal is deciding a
97
+ * business rule itself. The domain should export that decision
98
+ * (`canApprove(actor)`, `isEditable(order)`) and the adapter call
99
+ * it.
100
+ *
101
+ * Delta-based, like `forbidNewAmbientEffects`: only a write that adds
102
+ * comparisons beyond what the file on disk already has blocks, so an
103
+ * existing thick component doesn't freeze. No AI call.
104
+ *
105
+ * There is no default list. `status === 'loading'` is ordinary local
106
+ * view state in a UI, so the discriminants must be the fields that
107
+ * carry domain meaning in YOUR model.
108
+ *
109
+ * Applies to: write actions. Scope it to driving-adapter files (UI
110
+ * components, route handlers, CLI commands).
111
+ *
112
+ * @param options.discriminants — field names whose literal comparisons
113
+ * are domain decisions, e.g. `['role', 'plan']`.
114
+ * @param options.domainHint — appended to the block message to name
115
+ * where the decision should go, e.g. "permission rules live in
116
+ * src/domain/permissions.ts".
117
+ *
118
+ * @example
119
+ * { files: ['src/ui/**'], rules: [forbidNewDomainDiscriminantChecks({ discriminants: ['role'] })] }
120
+ */
121
+ export declare function forbidNewDomainDiscriminantChecks(options: {
122
+ discriminants: readonly string[];
123
+ domainHint?: string;
124
+ }): Rule;
125
+ /** Names a JS/TS module exports, from its source text. */
126
+ export declare function exportedNames(content: string): string[];
127
+ /**
128
+ * The core's export list, one line per module (`src/domain/roles.ts:
129
+ * canApprove, canEdit`), for the thin-driving-adapter judge. Test files
130
+ * are skipped. Truncated beyond `maxChars`.
131
+ */
132
+ export declare function listCoreExports(options: {
133
+ globs: readonly string[];
134
+ root: string;
135
+ maxChars: number;
136
+ }): string;
137
+ /**
138
+ * AI-validated rule for thin driving adapters (issue #72): UI
139
+ * components, pages, route handlers and CLI commands must not add
140
+ * business logic. The judge blocks a write that adds (a) a decision in
141
+ * domain terms, (b) coordination of more than one port/use-case call,
142
+ * (c) a re-implementation of something the core already exports, or
143
+ * (d) a framework-free use case filed as an adapter — naming the
144
+ * extraction target (domain function or use case) in the deny.
145
+ * Rendering, display formatting, local view state and one call per
146
+ * user intent pass. Delta-based: only what a write adds is judged.
147
+ *
148
+ * The other ports-and-adapters rules stop vendors getting INTO core
149
+ * code; this one stops logic leaking OUT of it.
150
+ *
151
+ * Applies to: write actions. Scope it to driving-adapter files — every
152
+ * matching write costs an AI call. Pair it with
153
+ * `forbidNewDomainDiscriminantChecks` so the obvious cases block free.
154
+ *
155
+ * @param options.coreExports — when set, the judge is given the
156
+ * export names of every source file matching `globs` under `root`
157
+ * (default `process.cwd()`), truncated beyond `maxChars` (default
158
+ * 8000), so it can spot a copy of an existing domain rule. Costs a
159
+ * directory scan per judged write.
160
+ * @param options.instructions — replaces or extends the default rules
161
+ * text (string, or `(defaults) => ...`).
162
+ *
163
+ * @example
164
+ * { files: ['src/ui/**', '!**\/*.test.*'], rules: [enforceThinDrivingAdapter()] }
165
+ */
166
+ export declare function enforceThinDrivingAdapter(options?: {
167
+ coreExports?: {
168
+ globs: readonly string[];
169
+ root?: string;
170
+ maxChars?: number;
171
+ };
172
+ instructions?: string | ((defaults: string) => string);
173
+ }): Rule;
86
174
  //# sourceMappingURL=ports-and-adapters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ports-and-adapters.d.ts","sourceRoot":"","sources":["../../rules/ports-and-adapters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,IAAI,EAA2B,MAAM,gBAAgB,CAAA;AAmJ3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;IACtD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CACrB,GACL,IAAI,CAuCN;AAsED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,GAAE;IACP,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;CAClD,GACL,IAAI,CAoCN;AAcD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAO,GACxC,IAAI,CAkCN"}
1
+ {"version":3,"file":"ports-and-adapters.d.ts","sourceRoot":"","sources":["../../rules/ports-and-adapters.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAU,IAAI,EAA2B,MAAM,gBAAgB,CAAA;AAE3E,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAA;AAoJlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;IACtD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CACrB,GACL,IAAI,CAuCN;AAsED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,GAAE;IACP,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;CAClD,GACL,IAAI,CAoCN;AAcD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAO,GACxC,IAAI,CAkCN;AAMD;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,YAAY,EAAE,CAYhB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE;IACzD,aAAa,EAAE,SAAS,MAAM,EAAE,CAAA;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,GAAG,IAAI,CAwBP;AAeD,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAYvD;AAmBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB,GAAG,MAAM,CAmBT;AAgFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE;IACP,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5E,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;CAClD,GACL,IAAI,CAwCN"}
@@ -1,3 +1,7 @@
1
+ import { readdirSync, readFileSync } from 'node:fs';
2
+ import { join, relative, sep } from 'node:path';
3
+ import { introducedPatterns } from './gates.js';
4
+ import { buildMatcher } from './scoping.js';
1
5
  // reason comes FIRST in the shape: an autoregressive model commits to
2
6
  // each field in order, so kind-first forces the verdict before the
3
7
  // analysis — observed live producing a "violation" whose reason
@@ -372,4 +376,289 @@ export function forbidInternalModuleMocks(options = {}) {
372
376
  };
373
377
  };
374
378
  }
379
+ function escapeRegExp(text) {
380
+ return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
381
+ }
382
+ /**
383
+ * One pattern per discriminant: the field compared to a string literal
384
+ * with `===`, `!==`, `==` or `!=`, in either order
385
+ * (`viewer.role === 'SuperUser'`, `'Draft' !== order.status`).
386
+ */
387
+ export function domainDiscriminantPatterns(discriminants) {
388
+ return discriminants.map((name) => {
389
+ const field = escapeRegExp(name);
390
+ const literal = String.raw `(['"\x60])[^'"\x60\n]*\1`;
391
+ return {
392
+ label: `${name} compared to a literal`,
393
+ pattern: new RegExp(String.raw `\b${field}\s*[!=]==?\s*['"\x60]|${literal}\s*[!=]==?\s*[\w$.?!]*\b${field}\b`, 'g'),
394
+ };
395
+ });
396
+ }
397
+ /**
398
+ * Deterministic first screen for thin driving adapters (issue #72): a
399
+ * UI component or other inbound adapter that compares a domain
400
+ * discriminant — a role, a status, a plan — to a literal is deciding a
401
+ * business rule itself. The domain should export that decision
402
+ * (`canApprove(actor)`, `isEditable(order)`) and the adapter call
403
+ * it.
404
+ *
405
+ * Delta-based, like `forbidNewAmbientEffects`: only a write that adds
406
+ * comparisons beyond what the file on disk already has blocks, so an
407
+ * existing thick component doesn't freeze. No AI call.
408
+ *
409
+ * There is no default list. `status === 'loading'` is ordinary local
410
+ * view state in a UI, so the discriminants must be the fields that
411
+ * carry domain meaning in YOUR model.
412
+ *
413
+ * Applies to: write actions. Scope it to driving-adapter files (UI
414
+ * components, route handlers, CLI commands).
415
+ *
416
+ * @param options.discriminants — field names whose literal comparisons
417
+ * are domain decisions, e.g. `['role', 'plan']`.
418
+ * @param options.domainHint — appended to the block message to name
419
+ * where the decision should go, e.g. "permission rules live in
420
+ * src/domain/permissions.ts".
421
+ *
422
+ * @example
423
+ * { files: ['src/ui/**'], rules: [forbidNewDomainDiscriminantChecks({ discriminants: ['role'] })] }
424
+ */
425
+ export function forbidNewDomainDiscriminantChecks(options) {
426
+ const patterns = domainDiscriminantPatterns(options.discriminants);
427
+ return async function forbidNewDomainDiscriminantChecks(action, ctx) {
428
+ if (action.kind !== 'write' || patterns.length === 0)
429
+ return { kind: 'pass' };
430
+ const introduced = await introducedPatterns(action, ctx, patterns);
431
+ if (introduced.length === 0)
432
+ return { kind: 'pass' };
433
+ const hint = options.domainHint ? ` ${options.domainHint}.` : '';
434
+ return {
435
+ kind: 'violation',
436
+ reason: `This write adds a domain decision to a driving adapter (${introduced.join(', ')}). Driving adapters (UI components, route handlers) render ` +
437
+ 'core-supplied state and forward user intent; they do not decide ' +
438
+ 'business rules. Add a function to the domain that makes this ' +
439
+ 'decision (e.g. `canApprove(actor)`, `isEditable(order)`), ' +
440
+ `test it without the UI framework, and call it here.${hint} ` +
441
+ 'Existing comparisons in the file are untouched by this rule — ' +
442
+ 'only new ones are blocked.',
443
+ };
444
+ };
445
+ }
446
+ const EXPORT_DECLARATION = /^\s*export\s+(?:default\s+)?(?:declare\s+)?(?:async\s+)?(?:abstract\s+)?(?:function\*?|const|let|var|class|type|interface|enum)\s+([A-Za-z_$][\w$]*)/gm;
447
+ const EXPORT_LIST = /^\s*export\s+(?:type\s+)?\{([^}]*)\}/gm;
448
+ const SOURCE_FILE = /\.(?:[cm]?[jt]sx?)$/;
449
+ const EXPORT_SCAN_SKIP_DIRS = new Set([
450
+ 'node_modules',
451
+ '.git',
452
+ 'build',
453
+ 'dist',
454
+ 'out',
455
+ 'coverage',
456
+ ]);
457
+ /** Names a JS/TS module exports, from its source text. */
458
+ export function exportedNames(content) {
459
+ const names = new Set();
460
+ for (const match of content.matchAll(EXPORT_DECLARATION)) {
461
+ if (match[1])
462
+ names.add(match[1]);
463
+ }
464
+ for (const match of content.matchAll(EXPORT_LIST)) {
465
+ for (const part of (match[1] ?? '').split(',')) {
466
+ const name = part.trim().split(/\s+as\s+/).pop()?.replace(/^type\s+/, '').trim();
467
+ if (name && /^[A-Za-z_$][\w$]*$/.test(name))
468
+ names.add(name);
469
+ }
470
+ }
471
+ return [...names];
472
+ }
473
+ function sourceFiles(dir, out = []) {
474
+ let entries;
475
+ try {
476
+ entries = readdirSync(dir, { withFileTypes: true });
477
+ }
478
+ catch {
479
+ return out;
480
+ }
481
+ for (const entry of entries) {
482
+ if (entry.isDirectory()) {
483
+ if (!EXPORT_SCAN_SKIP_DIRS.has(entry.name))
484
+ sourceFiles(join(dir, entry.name), out);
485
+ }
486
+ else if (entry.isFile() && SOURCE_FILE.test(entry.name)) {
487
+ out.push(join(dir, entry.name));
488
+ }
489
+ }
490
+ return out;
491
+ }
492
+ /**
493
+ * The core's export list, one line per module (`src/domain/roles.ts:
494
+ * canApprove, canEdit`), for the thin-driving-adapter judge. Test files
495
+ * are skipped. Truncated beyond `maxChars`.
496
+ */
497
+ export function listCoreExports(options) {
498
+ const matches = buildMatcher(options.globs);
499
+ const lines = [];
500
+ for (const file of sourceFiles(options.root).sort()) {
501
+ const rel = relative(options.root, file).split(sep).join('/');
502
+ if (!matches(rel) || /\.(?:test|spec)\.[^.]+$/.test(rel))
503
+ continue;
504
+ let content;
505
+ try {
506
+ content = readFileSync(file, 'utf8');
507
+ }
508
+ catch {
509
+ continue;
510
+ }
511
+ const names = exportedNames(content);
512
+ if (names.length > 0)
513
+ lines.push(`${rel}: ${names.join(', ')}`);
514
+ }
515
+ const text = lines.join('\n');
516
+ return text.length > options.maxChars
517
+ ? `${text.slice(0, options.maxChars)}\n(...export list truncated...)`
518
+ : text;
519
+ }
520
+ const THIN_DRIVING_ADAPTER_INSTRUCTIONS = `## Role
521
+
522
+ You are a driving-adapter thinness validator. A driving (inbound)
523
+ adapter is the code the outside world calls first: a UI component, a
524
+ page, a route handler, a CLI command. In this codebase it renders
525
+ core-supplied state and forwards user intent to the core. Business
526
+ logic in it can only be tested through the framework, drifts when it
527
+ is copied, and is invisible to headless and acceptance tests. Judge
528
+ whether the pending write keeps this adapter thin, per the rules below.
529
+
530
+ ## Inputs
531
+
532
+ 1. "Current file content" — what's on disk right now (may be a marker
533
+ like \`(file does not exist)\`).
534
+ 2. "Pending action" — the file path and the file content after the
535
+ write.
536
+ 3. Optionally, "Core exports" — what the domain and use-case modules
537
+ already export, one module per line.
538
+
539
+ ## What you judge
540
+
541
+ Judge only what this write adds (before → after), never pre-existing
542
+ code: an existing thick component is migrated incrementally, so a
543
+ write that leaves old logic in place but adds none passes. A transient
544
+ state (an unresolved import, a half-built component) is never itself a
545
+ violation. A block recorded earlier in the session is a past verdict,
546
+ not a rule; when the user says to let a change through, treat that as
547
+ authoritative and pass. The bar is a clear violation; when genuinely
548
+ ambiguous, pass.
549
+
550
+ ## Block a write that adds any of these
551
+
552
+ (a) **A decision expressed in domain terms**: eligibility, permission,
553
+ a state transition, a validation rule, or a derived value used to
554
+ make one (who may approve, which approver a request is routed to,
555
+ whether an order can still be edited). Comparing a role, status or plan
556
+ to a literal is the usual shape. Extraction target: a domain
557
+ function the adapter calls.
558
+ (b) **Coordination of more than one port or use-case call in one
559
+ handler**, or a policy about their outcomes (call the domain, then
560
+ save, then notify; "a failed notification must never fail the
561
+ submit"). That is a use case. Extraction target: a use-case
562
+ function, tested headless with fakes at its ports, which the
563
+ handler calls once.
564
+ (c) **A re-implementation of something the core already exports**, or
565
+ a copy of a domain rule that already lives elsewhere (a
566
+ display-name rule, a permission check). When "Core exports" lists
567
+ a matching name, block and name it. Extraction target: call the
568
+ existing export, or move the rule into the domain once and call it.
569
+ (d) **A use case filed as an adapter**: a module under a driving-
570
+ adapter path that uses no UI or framework API and coordinates
571
+ ports (e.g. \`startCheckout(billing, logger)\`). Extraction target:
572
+ move it to the use-case layer.
573
+
574
+ ## Always pass
575
+
576
+ - Rendering and layout, styling, accessibility attributes.
577
+ - Formatting for display: dates, currency, pluralization, truncation.
578
+ - Local view state: open/closed, loading/error flags, form field
579
+ values, the selected tab, input focus.
580
+ - Parsing and shaping user input into the arguments of a call.
581
+ - Calling ONE use case or port per user intent and showing its
582
+ result or error.
583
+ - Calling a domain function to make a decision (\`canApprove(actor)\`)
584
+ — that is the intended pattern.
585
+ - Wiring/composition (providers, DI, routing tables), test code, and
586
+ deleting code.
587
+ - Files that are clearly not driving adapters despite the path.
588
+
589
+ ## When you block
590
+
591
+ Name the exact logic the write adds and its extraction target: a
592
+ domain function (for a decision or a duplicated rule) or a use case
593
+ (for coordination). Name the existing core export to call when there
594
+ is one. Remind the agent that under this codebase's TDD gate the
595
+ extracted function gets its failing test first, written without the UI
596
+ framework.`;
597
+ /**
598
+ * AI-validated rule for thin driving adapters (issue #72): UI
599
+ * components, pages, route handlers and CLI commands must not add
600
+ * business logic. The judge blocks a write that adds (a) a decision in
601
+ * domain terms, (b) coordination of more than one port/use-case call,
602
+ * (c) a re-implementation of something the core already exports, or
603
+ * (d) a framework-free use case filed as an adapter — naming the
604
+ * extraction target (domain function or use case) in the deny.
605
+ * Rendering, display formatting, local view state and one call per
606
+ * user intent pass. Delta-based: only what a write adds is judged.
607
+ *
608
+ * The other ports-and-adapters rules stop vendors getting INTO core
609
+ * code; this one stops logic leaking OUT of it.
610
+ *
611
+ * Applies to: write actions. Scope it to driving-adapter files — every
612
+ * matching write costs an AI call. Pair it with
613
+ * `forbidNewDomainDiscriminantChecks` so the obvious cases block free.
614
+ *
615
+ * @param options.coreExports — when set, the judge is given the
616
+ * export names of every source file matching `globs` under `root`
617
+ * (default `process.cwd()`), truncated beyond `maxChars` (default
618
+ * 8000), so it can spot a copy of an existing domain rule. Costs a
619
+ * directory scan per judged write.
620
+ * @param options.instructions — replaces or extends the default rules
621
+ * text (string, or `(defaults) => ...`).
622
+ *
623
+ * @example
624
+ * { files: ['src/ui/**', '!**\/*.test.*'], rules: [enforceThinDrivingAdapter()] }
625
+ */
626
+ export function enforceThinDrivingAdapter(options = {}) {
627
+ const rules = typeof options.instructions === 'function'
628
+ ? options.instructions(THIN_DRIVING_ADAPTER_INSTRUCTIONS)
629
+ : (options.instructions ?? THIN_DRIVING_ADAPTER_INSTRUCTIONS);
630
+ return async function enforceThinDrivingAdapter(action, ctx) {
631
+ if (action.kind !== 'write')
632
+ return { kind: 'pass' };
633
+ if (!ctx?.agent) {
634
+ return {
635
+ kind: 'violation',
636
+ reason: 'enforceThinDrivingAdapter: no AI agent available; configure Config.ai or use a vendor that ships one.',
637
+ };
638
+ }
639
+ const before = (await ctx.readFile?.(action.path)) ?? {
640
+ kind: 'unknown',
641
+ };
642
+ const sections = [
643
+ rules,
644
+ `## Current file content\n\n${formatBefore(before)}`,
645
+ `## Pending action\n\nFile: ${action.path}\n\n${action.content}`,
646
+ ];
647
+ if (options.coreExports) {
648
+ const exports = listCoreExports({
649
+ globs: options.coreExports.globs,
650
+ root: options.coreExports.root ?? process.cwd(),
651
+ maxChars: options.coreExports.maxChars ?? 8000,
652
+ });
653
+ if (exports)
654
+ sections.push(`## Core exports\n\n${exports}`);
655
+ }
656
+ sections.push(RESPONSE_SPEC);
657
+ const verdict = await ctx.agent.reason(sections.join('\n\n'));
658
+ if (verdict.kind === 'violation') {
659
+ return { kind: 'violation', reason: verdict.reason };
660
+ }
661
+ return { kind: 'pass', reason: verdict.reason };
662
+ };
663
+ }
375
664
  //# sourceMappingURL=ports-and-adapters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ports-and-adapters.js","sourceRoot":"","sources":["../../rules/ports-and-adapters.ts"],"names":[],"mappings":"AAIA,sEAAsE;AACtE,mEAAmE;AACnE,gEAAgE;AAChE,uEAAuE;AACvE,cAAc;AACd,MAAM,aAAa,GAAG;;;;;;4CAMsB,CAAA;AAE5C,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDAmCsB,CAAA;AAEnD,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uEAsDwC,CAAA;AAEvE,MAAM,cAAc,GAAG;;;;;;6CAMsB,CAAA;AAE7C,SAAS,YAAY,CAAC,MAAmB;IACvC,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC,OAAO,CAAA;QACvB,KAAK,QAAQ;YACX,OAAO,uBAAuB,CAAA;QAChC,KAAK,SAAS;YACZ,OAAO,oCAAoC,CAAA;IAC/C,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAClB,KAAa,EACb,QAA4B,EAC5B,MAAmB,EACnB,MAAyC;IAEzC,MAAM,QAAQ,GAAG,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAA;IAC9C,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,kBAAkB,QAAQ,EAAE,CAAC,CAAA;IAC7D,CAAC;IACD,QAAQ,CAAC,IAAI,CACX,8BAA8B,YAAY,CAAC,MAAM,CAAC,EAAE,EACpD,8BAA8B,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,OAAO,EAAE,EAChE,aAAa,CACd,CAAA;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AAC9B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAII,EAAE;IAEN,MAAM,KAAK,GACT,OAAO,OAAO,CAAC,YAAY,KAAK,UAAU;QACxC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,sBAAsB,CAAC;QAC9C,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,IAAI,sBAAsB,CAAC,CAAA;IACtD,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,IAAI,CAAA;IACzD,OAAO,KAAK,UAAU,oBAAoB,CACxC,MAAc,EACd,GAAiB;QAEjB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QACpD,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC;YAChB,OAAO;gBACL,IAAI,EAAE,WAAW;gBACjB,MAAM,EACJ,kGAAkG;aACrG,CAAA;QACH,CAAC;QACD,IAAI,QAA4B,CAAA;QAChC,IAAI,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;YACrD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC5B,QAAQ;oBACN,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,gBAAgB;wBACpC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,8BAA8B;wBAC1E,CAAC,CAAC,IAAI,CAAC,OAAO,CAAA;YACpB,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAgB,CAAC,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI;YACjE,IAAI,EAAE,SAAS;SAChB,CAAA;QACD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CACpC,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAC7C,CAAA;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACjC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAA;QACtD,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAA;IACjD,CAAC,CAAA;AACH,CAAC;AAED,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAkET,CAAA;AAExB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,2BAA2B,CACzC,UAGI,EAAE;IAEN,MAAM,IAAI,GACR,OAAO,OAAO,CAAC,YAAY,KAAK,UAAU;QACxC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,wBAAwB,CAAC;QAChD,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,IAAI,wBAAwB,CAAC,CAAA;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,cAAc;QAClC,CAAC,CAAC,GAAG,IAAI,iCAAiC,OAAO,CAAC,cAAc,EAAE;QAClE,CAAC,CAAC,IAAI,CAAA;IACR,OAAO,KAAK,UAAU,2BAA2B,CAC/C,MAAc,EACd,GAAiB;QAEjB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QACpD,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC;YAChB,OAAO;gBACL,IAAI,EAAE,WAAW;gBACjB,MAAM,EACJ,yGAAyG;aAC5G,CAAA;QACH,CAAC;QACD,MAAM,MAAM,GAAgB,CAAC,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI;YACjE,IAAI,EAAE,SAAS;SAChB,CAAA;QACD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CACpC;YACE,KAAK;YACL,8BAA8B,YAAY,CAAC,MAAM,CAAC,EAAE;YACpD,8BAA8B,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,OAAO,EAAE;YAChE,aAAa;SACd,CAAC,IAAI,CAAC,MAAM,CAAC,CACf,CAAA;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACjC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAA;QACtD,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAA;IACjD,CAAC,CAAA;AACH,CAAC;AAED,MAAM,mBAAmB,GACvB,+DAA+D,CAAA;AAEjE,SAAS,sBAAsB,CAAC,OAAe;IAC7C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QAC1B,IAAI,SAAS;YAAE,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAC1C,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAuC,EAAE;IAEzC,MAAM,OAAO,GAAG,CAAC,SAAiB,EAAW,EAAE;QAC7C,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAA;QAC7C,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ;YACnC,OAAO,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC1C,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACtC,CAAC,CAAA;IACD,OAAO,KAAK,UAAU,yBAAyB,CAC7C,MAAc,EACd,GAAiB;QAEjB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QACpD,MAAM,OAAO,GAAG,sBAAsB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACtD,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACjD,MAAM,QAAQ,GACZ,MAAM,EAAE,IAAI,KAAK,SAAS;YACxB,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,OAAO,CAAC;YACxC,CAAC,CAAC,IAAI,GAAG,EAAU,CAAA;QACvB,MAAM,UAAU,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,CACpC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAC/D,CAAA;QACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QACpD,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,MAAM,EACJ,yDAAyD,UAAU;iBAChE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;iBACpB,IAAI,CAAC,IAAI,CAAC,iDAAiD;gBAC9D,+DAA+D;gBAC/D,iEAAiE;gBACjE,iDAAiD;SACpD,CAAA;IACH,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"ports-and-adapters.js","sourceRoot":"","sources":["../../rules/ports-and-adapters.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjchill/probity-rules",
3
- "version": "0.4.15",
3
+ "version": "0.4.16",
4
4
  "description": "Versioned Probity rule presets and CLI tooling for the agent-skills catalog (test-driven-development, ports-and-adapters, acceptance-testing, spec-test parity, ubiquitous-language) — see hooks/PROBITY.md.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/probity.config.ts CHANGED
@@ -14,6 +14,11 @@
14
14
  * - coreGlobs — where your core/domain code lives
15
15
  * - infrastructureImports — your stack's known vendor/framework imports
16
16
  * - specGlobs — where your acceptance specs live
17
+ * - drivingAdapterGlobs — your UI components / route handlers, held
18
+ * thin (an AI call per write; [] = off)
19
+ * - domainDiscriminants — fields whose literal comparison in UI code
20
+ * is a domain decision, e.g. ['role'] (off
21
+ * until set; blocks free, before the AI call)
17
22
  * - glossaryPath — absolute path to a ubiquitous-language glossary
18
23
  * - commitCommand / commitSuccessPattern / commitFailurePattern
19
24
  * — your real test command and its output shapes
@@ -36,5 +41,7 @@ import { jsRuleEntries } from '@jjchill/probity-rules/presets/js'
36
41
  export default defineConfig({
37
42
  rules: jsRuleEntries({
38
43
  // glossaryPath: fileURLToPath(new URL('./docs/GLOSSARY.md', import.meta.url)),
44
+ // domainDiscriminants: ['role'],
45
+ // coreExportsInJudge: true,
39
46
  }),
40
47
  })