@jjchill/probity-rules 0.4.15 → 0.4.17
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 +177 -0
- package/dist/presets/driving-adapter.d.ts +39 -0
- package/dist/presets/driving-adapter.d.ts.map +1 -0
- package/dist/presets/driving-adapter.js +33 -0
- package/dist/presets/driving-adapter.js.map +1 -0
- package/dist/presets/js.d.ts +21 -0
- package/dist/presets/js.d.ts.map +1 -1
- package/dist/presets/js.js +27 -0
- package/dist/presets/js.js.map +1 -1
- package/dist/presets/kmp.d.ts +31 -0
- package/dist/presets/kmp.d.ts.map +1 -1
- package/dist/presets/kmp.js +19 -1
- package/dist/presets/kmp.js.map +1 -1
- package/dist/presets/kotlin.d.ts +32 -0
- package/dist/presets/kotlin.d.ts.map +1 -1
- package/dist/presets/kotlin.js +19 -1
- package/dist/presets/kotlin.js.map +1 -1
- package/dist/rules/kotlin.d.ts +39 -0
- package/dist/rules/kotlin.d.ts.map +1 -1
- package/dist/rules/kotlin.js +169 -0
- package/dist/rules/kotlin.js.map +1 -1
- package/dist/rules/ports-and-adapters.d.ts +141 -0
- package/dist/rules/ports-and-adapters.d.ts.map +1 -1
- package/dist/rules/ports-and-adapters.js +381 -0
- package/dist/rules/ports-and-adapters.js.map +1 -1
- package/package.json +1 -1
- package/probity.config.kmp.ts +5 -0
- package/probity.config.kotlin.ts +5 -0
- package/probity.config.ts +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,182 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.17
|
|
4
|
+
|
|
5
|
+
The Kotlin and KMP presets can now keep driving adapters thin (#76):
|
|
6
|
+
Compose screens and CLI commands, in the same repo as the core or in a
|
|
7
|
+
separate app that consumes it as a library. Opt-in.
|
|
8
|
+
|
|
9
|
+
- **What was missing.** 0.4.16 wired `enforceThinDrivingAdapter` and
|
|
10
|
+
`forbidNewDomainDiscriminantChecks` into the JS preset only. Kotlin
|
|
11
|
+
had three more gaps:
|
|
12
|
+
- Its discriminant screen matched only string literals, but Kotlin
|
|
13
|
+
compares to enum entries (`role == Role.SUPER_USER`).
|
|
14
|
+
- The export list only read JS/TS `export` declarations.
|
|
15
|
+
- A UI-only app depending on the core as a library has no core
|
|
16
|
+
source to scan at all.
|
|
17
|
+
- **Opt-in, unlike JS.** `kotlinRuleEntries` and `kmpRuleEntries` get
|
|
18
|
+
a `drivingAdapterGlobs` option with **no default**. A core-only repo
|
|
19
|
+
(mysudo-core has no `@Composable` files) has no UI, so a default glob
|
|
20
|
+
would only show up as `DEAD SCOPE`. Upgrading changes nothing until
|
|
21
|
+
the option is set. When set, the block is listed before the TDD
|
|
22
|
+
judge, and `coreGlobs` are excluded from it (in KMP, that keeps
|
|
23
|
+
`presentation/` ViewModels core). Starting globs per layout are in
|
|
24
|
+
hooks/PROBITY.md, "Driving adapters by project layout".
|
|
25
|
+
- **New options** (both presets):
|
|
26
|
+
- `domainDiscriminants`: turns on the free screen with Kotlin
|
|
27
|
+
patterns. It blocks net-new `role == Role.X` (either order) or
|
|
28
|
+
string-literal comparisons, `when (viewer.role)` subjects, and
|
|
29
|
+
`status is Status.Draft`.
|
|
30
|
+
- `domainHint`: appended to the screen's deny.
|
|
31
|
+
- `coreExportsInJudge`: the judge gets the public names declared in
|
|
32
|
+
`coreGlobs` sources. Capped at `coreExportsMaxChars`, default
|
|
33
|
+
16,000.
|
|
34
|
+
- `coreApiPaths`: for a UI-only app. The judge gets the core's public
|
|
35
|
+
API read from binary-compatibility-validator dumps (`.api` and
|
|
36
|
+
`.klib.api`, as files or directories). Generated members (getters,
|
|
37
|
+
`component1`, `copy`, `equals`…) are dropped; on kotlinx.coroutines'
|
|
38
|
+
real dumps this cuts 125 KB to about 10 KB.
|
|
39
|
+
- **Kotlin judge addendum** (`KOTLIN_DRIVING_ADAPTER_ADDENDUM`). A CLI
|
|
40
|
+
command's options, help text, precondition checks and exhaustive
|
|
41
|
+
`when` over its use case's sealed outcome (to exit code, error code,
|
|
42
|
+
message and JSON) are translation. Branching on domain state,
|
|
43
|
+
retrying, or chaining use cases is not. It also lists Compose view
|
|
44
|
+
state and wiring (`remember`, `collectAsState`, `LaunchedEffect`
|
|
45
|
+
forwarding one intent, `@Preview`) as allowed.
|
|
46
|
+
- **Export scanning (all presets).** Nested worktrees and submodules
|
|
47
|
+
(a directory with a `.git` file, such as `.claude/worktrees/*`) are
|
|
48
|
+
skipped, as the parity rule already does (#55). Paths are printed
|
|
49
|
+
relative to the directory the modules share. On mysudo-core, the
|
|
50
|
+
worktree copies would otherwise have filled the cap several times
|
|
51
|
+
over. Kotlin nested types (mostly sealed-outcome cases) are left out,
|
|
52
|
+
which takes mysudo-core's core list from 29,000 to 13,000 characters.
|
|
53
|
+
- **Shared block.** `presets/driving-adapter.ts` (`drivingAdapterBlock`)
|
|
54
|
+
builds the block for all three presets. The JS preset's wiring is
|
|
55
|
+
unchanged.
|
|
56
|
+
- **Measured** with Probity's real Claude Code judge, wired as the KMP
|
|
57
|
+
preset wires it, 5 runs per case.
|
|
58
|
+
- **mysudo-core's CLI** (`cli/src/main/**/commands/**`, its real
|
|
59
|
+
`coreGlobs`, `coreExportsInJudge: true`):
|
|
60
|
+
- Allowed: four real writes (adding the real `sudos delete`
|
|
61
|
+
command, the real `RegisterCommand` with its extra read for
|
|
62
|
+
display, the real 432-line `PhoneCallsCommand`, and a help-text
|
|
63
|
+
change).
|
|
64
|
+
- Blocked: four splices into real commands (label validation the
|
|
65
|
+
`CreateSudo` use case already does; a last-Sudo rule plus a retry
|
|
66
|
+
in `delete`; a role/status filter in `list`; a locked-account
|
|
67
|
+
sign-out-and-deregister policy in `register`).
|
|
68
|
+
- Result: 40/40 correct. The free screen caught the two enum cases
|
|
69
|
+
before any AI call.
|
|
70
|
+
- **Synthetic Compose versions** of the #72 cases (blocked) and
|
|
71
|
+
controls (allowed: a pure render change, calling `canApprove()`,
|
|
72
|
+
one ViewModel intent, local `remember` state): 40/40 correct.
|
|
73
|
+
- **Addendum check.** Without the Kotlin addendum, the CLI set was
|
|
74
|
+
also correct (39/39 verdicts, 1 run failed on the judge's login).
|
|
75
|
+
So the addendum is guidance these cases didn't need, not a measured
|
|
76
|
+
fix.
|
|
77
|
+
- **Scope.** `probity-scope-report` was run on mysudo-core's tree from
|
|
78
|
+
a scratch copy of its config. Relative globs are anchored to the
|
|
79
|
+
config's own directory, so that copy used the unanchored
|
|
80
|
+
`**/cli/src/main/**/commands/**`. It reported the block with no
|
|
81
|
+
warning but also matched `.claude/worktrees/` copies (123 files). In
|
|
82
|
+
mysudo-core's own config, the anchored `cli/src/main/**/commands/**`
|
|
83
|
+
matches the 31 command files. A scope-report test confirms the block
|
|
84
|
+
leaves out `Composition.kt`.
|
|
85
|
+
- New exports: `drivingAdapterBlock` (`presets/driving-adapter`).
|
|
86
|
+
`ExportLanguage`, `JS_EXPORTS`, `ApiDumpFormat` and
|
|
87
|
+
`listPublishedApi` (`rules/ports-and-adapters`). `kotlinExportedNames`,
|
|
88
|
+
`KOTLIN_EXPORTS`, `readKotlinApiDump`, `KOTLIN_API_DUMP`,
|
|
89
|
+
`kotlinDomainDiscriminantPatterns` and `KOTLIN_DRIVING_ADAPTER_ADDENDUM`
|
|
90
|
+
(`rules/kotlin`). `forbidNewDomainDiscriminantChecks` takes
|
|
91
|
+
`patternsFor`; `enforceThinDrivingAdapter` takes `publishedApi` and a
|
|
92
|
+
`coreExports.language`.
|
|
93
|
+
|
|
94
|
+
## 0.4.16
|
|
95
|
+
|
|
96
|
+
The JS preset now keeps driving adapters (UI components, pages, route
|
|
97
|
+
handlers) thin (#72). Business logic leaking out of the core into UI
|
|
98
|
+
code is blocked, and the deny names where it should go.
|
|
99
|
+
|
|
100
|
+
- **What went wrong.** The existing ports-and-adapters rules stop
|
|
101
|
+
vendors getting *into* core code. Nothing stopped logic leaking *out*
|
|
102
|
+
of it. In a React consumer on 0.4.14, with clean and fully policed
|
|
103
|
+
core boundaries, `src/ui/` grew:
|
|
104
|
+
- a submit handler running a whole use case (domain `submit()`,
|
|
105
|
+
`repository.save()`, `notifier.timesheetSubmitted()`, and a "a
|
|
106
|
+
failed notification must never fail the submit" policy)
|
|
107
|
+
- `viewer.role === 'SuperUser'` permission checks in four places,
|
|
108
|
+
next to a domain that already exported `canEdit` and `canApprove`
|
|
109
|
+
- a display-name rule copied seven times, with two copies disagreeing
|
|
110
|
+
- a React-free use case filed under `src/ui/`
|
|
111
|
+
|
|
112
|
+
Each one had a component test, so the TDD judge had no reason to
|
|
113
|
+
object. It checks whether code is tested, not where it belongs.
|
|
114
|
+
- **Now:** two new rules in `rules/ports-and-adapters.ts`.
|
|
115
|
+
- `enforceThinDrivingAdapter`, an AI judge. It blocks a write that
|
|
116
|
+
adds (a) a decision in domain terms, (b) coordination of more than
|
|
117
|
+
one port or use-case call, (c) a re-implementation of something the
|
|
118
|
+
core exports, or (d) a framework-free use case under a UI path. The
|
|
119
|
+
deny names the extraction target: a domain function or a use case.
|
|
120
|
+
Rendering, display formatting, local view state, and one call per
|
|
121
|
+
user intent pass. Only what a write adds is judged, so an existing
|
|
122
|
+
thick component doesn't freeze.
|
|
123
|
+
- `forbidNewDomainDiscriminantChecks`, a free deterministic screen.
|
|
124
|
+
It blocks net-new comparisons of configured fields to a literal
|
|
125
|
+
(`viewer.role === 'SuperUser'`, either order) and points to a domain
|
|
126
|
+
function. Off until you list the fields: there is no default,
|
|
127
|
+
because `status === 'loading'` is ordinary view state.
|
|
128
|
+
- **Preset wiring (JS only).** `jsRuleEntries` gets a block on the new
|
|
129
|
+
`drivingAdapterGlobs` option, **on by default**: `src/ui/**`,
|
|
130
|
+
`src/components/**` and `src/**/*.tsx`, minus `*.test.*`, `*.spec.*`
|
|
131
|
+
and `*.stories.*`. It runs before the TDD judge, so a denial costs one
|
|
132
|
+
AI call. New options:
|
|
133
|
+
- `drivingAdapterGlobs`: the scope; `[]` switches the rules off.
|
|
134
|
+
- `domainDiscriminants`: turns on the free screen, e.g. `['role']`.
|
|
135
|
+
- `domainHint`: appended to the screen's deny, e.g. where permission
|
|
136
|
+
rules live.
|
|
137
|
+
- `coreExportsInJudge`: gives the judge the export names of every
|
|
138
|
+
module under `coreGlobs` (capped at 8,000 characters), so it can
|
|
139
|
+
name the existing function a copy duplicates. Off by default; it
|
|
140
|
+
scans the tree on each judged write.
|
|
141
|
+
- **Measured** with Probity's real Claude Code judge, 5 runs per case,
|
|
142
|
+
on synthetic writes built from the four cases above plus five
|
|
143
|
+
controls that must pass: a pure render change, adding a `canX()`
|
|
144
|
+
call, a single use-case call, a local `status === 'loading'` check,
|
|
145
|
+
and calling an existing `displayName` export. These are written from
|
|
146
|
+
the issue's descriptions, not replays of the consumer's real writes.
|
|
147
|
+
With and without the export list, 90/90 verdicts were correct (40
|
|
148
|
+
blocked, 50 allowed). The prompt's examples were then made
|
|
149
|
+
domain-neutral and the replay rerun: 76 of 90 runs returned a verdict
|
|
150
|
+
and all 76 were correct. The other 14 hit a judge login failure in
|
|
151
|
+
the test environment. On 0.4.14 no rule judged these writes, so all
|
|
152
|
+
would pass.
|
|
153
|
+
- **Cost:** one extra AI call per write to a matching UI file, on top of
|
|
154
|
+
the TDD judge.
|
|
155
|
+
- **Migration.** Consumers calling `jsRuleEntries` get the new block on
|
|
156
|
+
upgrade. Check it with `probity-scope-report`: it lists the block and
|
|
157
|
+
flags it `DEAD SCOPE` if your UI lives elsewhere. Then set
|
|
158
|
+
`drivingAdapterGlobs` to your layout, or `[]` to opt out. Hand-composed
|
|
159
|
+
configs add the block themselves:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
{
|
|
163
|
+
files: ['src/ui/**', '!**/*.test.*'],
|
|
164
|
+
rules: [
|
|
165
|
+
forbidNewDomainDiscriminantChecks({ discriminants: ['role'] }),
|
|
166
|
+
withJudgeFailureDiagnostics(withContradictionRetry(enforceThinDrivingAdapter())),
|
|
167
|
+
],
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The Kotlin, KMP and Swift presets are unchanged; Compose and SwiftUI
|
|
172
|
+
globs are a follow-up.
|
|
173
|
+
- New exports: `enforceThinDrivingAdapter`,
|
|
174
|
+
`forbidNewDomainDiscriminantChecks`, `domainDiscriminantPatterns`,
|
|
175
|
+
`exportedNames` and `listCoreExports`.
|
|
176
|
+
- Skills: `ports-and-adapters` gets a "Driving adapters are equally
|
|
177
|
+
thin" section with a checklist, red flags and a rationalization;
|
|
178
|
+
`frontend-ui-engineering` points to it.
|
|
179
|
+
|
|
3
180
|
## 0.4.15
|
|
4
181
|
|
|
5
182
|
The JS/TS TDD judge no longer blocks adding a new red test (#73), and it
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The thin-driving-adapter block (issues #72, #76), built once for
|
|
3
|
+
* every preset: the free discriminant screen when discriminants are
|
|
4
|
+
* configured, then the AI judge, wrapped in the same failure
|
|
5
|
+
* diagnostics and contradiction retry as the presets' TDD judges.
|
|
6
|
+
* Presets list it before their TDD block, so a denial costs one AI
|
|
7
|
+
* call, not two.
|
|
8
|
+
*/
|
|
9
|
+
import type { RuleEntry } from '@nizos/probity';
|
|
10
|
+
import type { NamedPattern } from '../rules/gates.js';
|
|
11
|
+
import { type ApiDumpFormat, type ExportLanguage } from '../rules/ports-and-adapters.js';
|
|
12
|
+
export type DrivingAdapterBlockOptions = {
|
|
13
|
+
/** Driving-adapter files. No include glob → no block. */
|
|
14
|
+
globs: readonly string[];
|
|
15
|
+
/** Core scope, excluded: core code is never a driving adapter. */
|
|
16
|
+
coreGlobs: readonly string[];
|
|
17
|
+
/** Fields whose literal comparison is a domain decision. */
|
|
18
|
+
domainDiscriminants?: readonly string[];
|
|
19
|
+
/** Appended to the discriminant screen's deny. */
|
|
20
|
+
domainHint?: string;
|
|
21
|
+
/** Builds the discriminant patterns (default: JS/TS literals). */
|
|
22
|
+
patternsFor?: (discriminants: readonly string[]) => NamedPattern[];
|
|
23
|
+
/** Give the judge the export names of `coreGlobs` sources. */
|
|
24
|
+
coreExports?: {
|
|
25
|
+
root?: string;
|
|
26
|
+
language?: ExportLanguage;
|
|
27
|
+
maxChars?: number;
|
|
28
|
+
};
|
|
29
|
+
/** Give the judge the public API read from published dumps. */
|
|
30
|
+
publishedApi?: {
|
|
31
|
+
paths: readonly string[];
|
|
32
|
+
format: ApiDumpFormat;
|
|
33
|
+
root?: string;
|
|
34
|
+
};
|
|
35
|
+
/** Extends or replaces the judge's rules text. */
|
|
36
|
+
instructions?: string | ((defaults: string) => string);
|
|
37
|
+
};
|
|
38
|
+
export declare function drivingAdapterBlock(options: DrivingAdapterBlockOptions): RuleEntry | undefined;
|
|
39
|
+
//# sourceMappingURL=driving-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driving-adapter.d.ts","sourceRoot":"","sources":["../../presets/driving-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,gCAAgC,CAAA;AAEvC,MAAM,MAAM,0BAA0B,GAAG;IACvC,yDAAyD;IACzD,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB,kEAAkE;IAClE,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,4DAA4D;IAC5D,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,KAAK,YAAY,EAAE,CAAA;IAClE,8DAA8D;IAC9D,WAAW,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7E,+DAA+D;IAC/D,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,aAAa,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACjF,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;CACvD,CAAA;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,SAAS,GAAG,SAAS,CAgC9F"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { withContradictionRetry, withJudgeFailureDiagnostics } from '../rules/gates.js';
|
|
2
|
+
import { enforceThinDrivingAdapter, forbidNewDomainDiscriminantChecks, } from '../rules/ports-and-adapters.js';
|
|
3
|
+
export function drivingAdapterBlock(options) {
|
|
4
|
+
if (!options.globs.some((glob) => !glob.startsWith('!')))
|
|
5
|
+
return undefined;
|
|
6
|
+
const [first, ...rest] = [
|
|
7
|
+
...options.globs,
|
|
8
|
+
...options.coreGlobs.filter((glob) => !glob.startsWith('!')).map((glob) => `!${glob}`),
|
|
9
|
+
];
|
|
10
|
+
return {
|
|
11
|
+
files: [first, ...rest],
|
|
12
|
+
rules: [
|
|
13
|
+
...(options.domainDiscriminants?.length
|
|
14
|
+
? [
|
|
15
|
+
forbidNewDomainDiscriminantChecks({
|
|
16
|
+
discriminants: options.domainDiscriminants,
|
|
17
|
+
domainHint: options.domainHint,
|
|
18
|
+
patternsFor: options.patternsFor,
|
|
19
|
+
}),
|
|
20
|
+
]
|
|
21
|
+
: []),
|
|
22
|
+
withJudgeFailureDiagnostics(withContradictionRetry(enforceThinDrivingAdapter({
|
|
23
|
+
coreExports: options.coreExports && {
|
|
24
|
+
globs: options.coreGlobs,
|
|
25
|
+
...options.coreExports,
|
|
26
|
+
},
|
|
27
|
+
publishedApi: options.publishedApi,
|
|
28
|
+
instructions: options.instructions,
|
|
29
|
+
}))),
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=driving-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driving-adapter.js","sourceRoot":"","sources":["../../presets/driving-adapter.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAA;AACvF,OAAO,EACL,yBAAyB,EACzB,iCAAiC,GAGlC,MAAM,gCAAgC,CAAA;AAqBvC,MAAM,UAAU,mBAAmB,CAAC,OAAmC;IACrE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,SAAS,CAAA;IAC1E,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG;QACvB,GAAG,OAAO,CAAC,KAAK;QAChB,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;KACvF,CAAA;IACD,OAAO;QACL,KAAK,EAAE,CAAC,KAAM,EAAE,GAAG,IAAI,CAAC;QACxB,KAAK,EAAE;YACL,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM;gBACrC,CAAC,CAAC;oBACE,iCAAiC,CAAC;wBAChC,aAAa,EAAE,OAAO,CAAC,mBAAmB;wBAC1C,UAAU,EAAE,OAAO,CAAC,UAAU;wBAC9B,WAAW,EAAE,OAAO,CAAC,WAAW;qBACjC,CAAC;iBACH;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,2BAA2B,CACzB,sBAAsB,CACpB,yBAAyB,CAAC;gBACxB,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI;oBAClC,KAAK,EAAE,OAAO,CAAC,SAAS;oBACxB,GAAG,OAAO,CAAC,WAAW;iBACvB;gBACD,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,YAAY,EAAE,OAAO,CAAC,YAAY;aACnC,CAAC,CACH,CACF;SACF;KACF,CAAA;AACH,CAAC"}
|
package/dist/presets/js.d.ts
CHANGED
|
@@ -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?: readonly string[];
|
|
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;
|
package/dist/presets/js.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"js.d.ts","sourceRoot":"","sources":["../../presets/js.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"js.d.ts","sourceRoot":"","sources":["../../presets/js.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAerE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAGhD,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,SAAS,MAAM,EAAE,CAAA;IACvC;;;;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,CAwLxE"}
|
package/dist/presets/js.js
CHANGED
|
@@ -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
|
|
@@ -22,6 +24,7 @@ import { forbidNewAmbientEffects, JS_AMBIENT_EFFECT_PATTERNS, requireGreenTestRu
|
|
|
22
24
|
import { enforceJsTdd } from '../rules/js-tdd.js';
|
|
23
25
|
import { enforcePortsBoundary, forbidInternalModuleMocks, } from '../rules/ports-and-adapters.js';
|
|
24
26
|
import { withExcludeGlobs } from '../rules/scoping.js';
|
|
27
|
+
import { drivingAdapterBlock } from './driving-adapter.js';
|
|
25
28
|
import { enforceSpecTestParity, JS_TEST_DECLARATION, requireSpecBackedAcceptanceTest, surfaceScenarioLinkBreakage, } from '../rules/spec-test-parity.js';
|
|
26
29
|
import { surfaceGlossaryTermBreakage } from '../rules/ubiquitous-language.js';
|
|
27
30
|
/**
|
|
@@ -44,6 +47,14 @@ export function jsRuleEntries(options = {}) {
|
|
|
44
47
|
const tddGlobs = options.tddGlobs ?? ['src/**', 'test/**', 'tests/**'];
|
|
45
48
|
const specGlobs = options.specGlobs ?? ['specs/**', 'acceptance/**', '**/*.feature'];
|
|
46
49
|
const excludeGlobs = options.excludeGlobs ?? ['spikes/**', '**/build/**'];
|
|
50
|
+
const drivingAdapterGlobs = options.drivingAdapterGlobs ?? [
|
|
51
|
+
'src/ui/**',
|
|
52
|
+
'src/components/**',
|
|
53
|
+
'src/**/*.tsx',
|
|
54
|
+
'!**/*.test.*',
|
|
55
|
+
'!**/*.spec.*',
|
|
56
|
+
'!**/*.stories.*',
|
|
57
|
+
];
|
|
47
58
|
const entries = [
|
|
48
59
|
// ── Boundaries: ports-and-adapters ──────────────────────────────
|
|
49
60
|
// Core purity. Point these globs at your core/domain/use-case
|
|
@@ -78,6 +89,22 @@ export function jsRuleEntries(options = {}) {
|
|
|
78
89
|
rules: [forbidInternalModuleMocks()],
|
|
79
90
|
},
|
|
80
91
|
];
|
|
92
|
+
// Driving adapters must be thin (issue #72). The core-purity block
|
|
93
|
+
// above stops vendors getting INTO core code; this stops business
|
|
94
|
+
// logic leaking OUT of it into UI components and handlers, which the
|
|
95
|
+
// TDD gate alone never questions (a component test makes the logic
|
|
96
|
+
// "tested"). The free discriminant screen runs first when
|
|
97
|
+
// configured; the judge runs before the TDD judge, so a denial here
|
|
98
|
+
// costs one AI call, not two.
|
|
99
|
+
const drivingAdapter = drivingAdapterBlock({
|
|
100
|
+
globs: drivingAdapterGlobs,
|
|
101
|
+
coreGlobs,
|
|
102
|
+
domainDiscriminants: options.domainDiscriminants,
|
|
103
|
+
domainHint: options.domainHint,
|
|
104
|
+
coreExports: options.coreExportsInJudge ? {} : undefined,
|
|
105
|
+
});
|
|
106
|
+
if (drivingAdapter)
|
|
107
|
+
entries.push(drivingAdapter);
|
|
81
108
|
// Spec-to-test traceability (issue #18): OFF by default, so a
|
|
82
109
|
// project that hasn't opted in sees no behavior change. Setting
|
|
83
110
|
// `specsDir` wires the same set the KMP preset wires — deterministic
|
package/dist/presets/js.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"js.js","sourceRoot":"","sources":["../../presets/js.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"js.js","sourceRoot":"","sources":["../../presets/js.ts"],"names":[],"mappings":"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"}
|
package/dist/presets/kmp.d.ts
CHANGED
|
@@ -48,6 +48,37 @@ export type KmpPresetOptions = {
|
|
|
48
48
|
* clock/randomness/env screen's deny text (default: function-typed
|
|
49
49
|
* providers such as `nowEpochMillis: () -> Long`). */
|
|
50
50
|
seamHint?: string;
|
|
51
|
+
/** Driving (inbound) adapter files held thin by
|
|
52
|
+
* `enforceThinDrivingAdapter`: Compose screens, CLI commands, route
|
|
53
|
+
* handlers. OFF unless set — a core-only module has none, so a
|
|
54
|
+
* default glob would only be a dead scope. `coreGlobs` are always
|
|
55
|
+
* excluded (so `presentation/` ViewModels stay core). Starting
|
|
56
|
+
* points:
|
|
57
|
+
* - UI in this repo: `['**\/composeApp/src/**', '**\/src/*Main/**\/ui/**', '!**\/*Preview*.kt']`
|
|
58
|
+
* - a CLI module: `['cli/src/main/**\/commands/**']`
|
|
59
|
+
* - a UI-only app on a core SDK: its `ui/` packages, plus `coreApiPaths`.
|
|
60
|
+
* Every matching write costs an AI call, before the TDD judge. */
|
|
61
|
+
drivingAdapterGlobs?: readonly string[];
|
|
62
|
+
/** Fields whose comparison to a domain value in a driving adapter is
|
|
63
|
+
* a domain decision (e.g. `['role', 'status']`): net-new
|
|
64
|
+
* `role == Role.ADMIN`, `when (viewer.role)` or `status is
|
|
65
|
+
* Status.Draft` block free, before the AI call. No default. */
|
|
66
|
+
domainDiscriminants?: string[];
|
|
67
|
+
/** Appended to the discriminant block message, e.g. where permission
|
|
68
|
+
* rules live. */
|
|
69
|
+
domainHint?: string;
|
|
70
|
+
/** Give the thin-driving-adapter judge the public names declared in
|
|
71
|
+
* `coreGlobs` sources, so it can name the existing function a copy
|
|
72
|
+
* duplicates. Scans the tree on each judged write. */
|
|
73
|
+
coreExportsInJudge?: boolean;
|
|
74
|
+
/** Cap on the export list the judge is given (default 16000
|
|
75
|
+
* characters; the list is truncated beyond it). */
|
|
76
|
+
coreExportsMaxChars?: number;
|
|
77
|
+
/** For a repo that consumes the core as a library: binary-
|
|
78
|
+
* compatibility-validator dumps (`.api`, `.klib.api`), as files or
|
|
79
|
+
* directories relative to the root, whose public API the
|
|
80
|
+
* thin-driving-adapter judge is given. */
|
|
81
|
+
coreApiPaths?: string[];
|
|
51
82
|
/** Names your telemetry convention for the adapter-observability
|
|
52
83
|
* judge — how a boundary event is recorded in this codebase
|
|
53
84
|
* (default: a :foundation `Logger.event` or port-tap convention). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kmp.d.ts","sourceRoot":"","sources":["../../presets/kmp.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAKrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"kmp.d.ts","sourceRoot":"","sources":["../../presets/kmp.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAKrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAQhD,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAA;AA4BrC;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;uEACmE;IACnE,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;6CAEyC;IACzC,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,KAAK,CAAA;IAC3B,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB;qEACiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;gEAC4D;IAC5D,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,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;oEACgE;IAChE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;6BAGyB;IACzB,uBAAuB,CAAC,EAAE,KAAK,CAAA;IAC/B;;2DAEuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;;;uEASmE;IACnE,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC;;;oEAGgE;IAChE,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC9B;sBACkB;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;2DAEuD;IACvD,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;wDACoD;IACpD,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;+CAG2C;IAC3C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;0EAEsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS,EAAE,CAySxF"}
|
package/dist/presets/kmp.js
CHANGED
|
@@ -22,9 +22,10 @@ import { enforceKotlinTdd } from '../internal/kotlin-tdd.js';
|
|
|
22
22
|
import { withExtractionUnderGreen } from '../rules/gates.js';
|
|
23
23
|
import { enforceAcceptanceLanguage, withAcceptanceLanguageFastPath, } from '../rules/acceptance-language.js';
|
|
24
24
|
import { withExcludeGlobs } from '../rules/scoping.js';
|
|
25
|
+
import { drivingAdapterBlock } from './driving-adapter.js';
|
|
25
26
|
import { enforceSpecTestParity, requireSpecBackedAcceptanceTest, surfaceScenarioLinkBreakage, } from '../rules/spec-test-parity.js';
|
|
26
27
|
import { surfaceGlossaryTermBreakage } from '../rules/ubiquitous-language.js';
|
|
27
|
-
import { enforceCharacterizationResolution, enforceProbeReversion, forbidNewAmbientEffects, GRADLE_TEST_COMMAND, KOTLIN_BOUNDARY_ADDENDUM, KOTLIN_INFRASTRUCTURE_IMPORTS, KOTLIN_PRODUCTION_SOURCE_PATTERN, KOTLIN_TEST_SOURCE_PATTERN, kotlinGreenRunOptions, MOCKING_LIBRARY_IMPORTS, requireGreenTestRun, withCharacterizationTest, withKotlinFastPath, withMutationProbe, withTelemetryFastPath, } from '../rules/kotlin.js';
|
|
28
|
+
import { enforceCharacterizationResolution, enforceProbeReversion, forbidNewAmbientEffects, GRADLE_TEST_COMMAND, KOTLIN_API_DUMP, KOTLIN_BOUNDARY_ADDENDUM, KOTLIN_DRIVING_ADAPTER_ADDENDUM, KOTLIN_EXPORTS, kotlinDomainDiscriminantPatterns, KOTLIN_INFRASTRUCTURE_IMPORTS, KOTLIN_PRODUCTION_SOURCE_PATTERN, KOTLIN_TEST_SOURCE_PATTERN, kotlinGreenRunOptions, MOCKING_LIBRARY_IMPORTS, requireGreenTestRun, withCharacterizationTest, withKotlinFastPath, withMutationProbe, withTelemetryFastPath, } from '../rules/kotlin.js';
|
|
28
29
|
import { enforceAdapterObservability, enforcePortsBoundary, } from '../rules/ports-and-adapters.js';
|
|
29
30
|
/**
|
|
30
31
|
* The rule entries, as a factory over the project root. Probity only
|
|
@@ -77,6 +78,22 @@ export function kmpRuleEntries(root, options = {}) {
|
|
|
77
78
|
// listed before any AI-validated rule (a model call per matching
|
|
78
79
|
// write). A write with a vendor import in core code must be
|
|
79
80
|
// rejected by the free import screen, not after a TDD model call.
|
|
81
|
+
// Driving adapters must be thin (issues #72, #76). Opt-in: listed
|
|
82
|
+
// before the TDD block, so a denial costs one AI call, not two.
|
|
83
|
+
const drivingAdapter = drivingAdapterBlock({
|
|
84
|
+
globs: options.drivingAdapterGlobs ?? [],
|
|
85
|
+
coreGlobs,
|
|
86
|
+
domainDiscriminants: options.domainDiscriminants,
|
|
87
|
+
domainHint: options.domainHint,
|
|
88
|
+
patternsFor: kotlinDomainDiscriminantPatterns,
|
|
89
|
+
coreExports: options.coreExportsInJudge
|
|
90
|
+
? { root, language: KOTLIN_EXPORTS, maxChars: options.coreExportsMaxChars ?? 16000 }
|
|
91
|
+
: undefined,
|
|
92
|
+
publishedApi: options.coreApiPaths?.length
|
|
93
|
+
? { paths: options.coreApiPaths, format: KOTLIN_API_DUMP, root }
|
|
94
|
+
: undefined,
|
|
95
|
+
instructions: (defaults) => defaults + KOTLIN_DRIVING_ADAPTER_ADDENDUM,
|
|
96
|
+
});
|
|
80
97
|
const entries = [
|
|
81
98
|
// ── Deterministic wall ───────────────────────────────────────────
|
|
82
99
|
// Core import/effect screens. The import screen also catches Koin
|
|
@@ -162,6 +179,7 @@ export function kmpRuleEntries(root, options = {}) {
|
|
|
162
179
|
// marked `// probity: characterization` passes, and
|
|
163
180
|
// enforceCharacterizationResolution below blocks commits until the
|
|
164
181
|
// marker comes off through a recorded red under a mutation probe.
|
|
182
|
+
...(drivingAdapter ? [drivingAdapter] : []),
|
|
165
183
|
{
|
|
166
184
|
files: [
|
|
167
185
|
'**/src/*Main/kotlin/**',
|
package/dist/presets/kmp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kmp.js","sourceRoot":"","sources":["../../presets/kmp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAE/C,OAAO,EAAE,oBAAoB,EAAkB,MAAM,gBAAgB,CAAA;AAErE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAI5D,OAAO,EACL,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,iCAAiC,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,2BAA2B,GAE5B,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAA;AAC7E,OAAO,EACL,iCAAiC,EACjC,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,6BAA6B,EAC7B,gCAAgC,EAChC,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,GACrB,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"kmp.js","sourceRoot":"","sources":["../../presets/kmp.ts"],"names":[],"mappings":"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"}
|
package/dist/presets/kotlin.d.ts
CHANGED
|
@@ -30,6 +30,38 @@ export type KotlinPresetOptions = {
|
|
|
30
30
|
tddGlobs?: Globs;
|
|
31
31
|
/** Adapter/data packages that must carry boundary observability. */
|
|
32
32
|
adapterGlobs?: Globs;
|
|
33
|
+
/** Driving (inbound) adapter files held thin by
|
|
34
|
+
* `enforceThinDrivingAdapter`: Compose screens, CLI commands, route
|
|
35
|
+
* handlers. OFF unless set — a core-only module has none, so a
|
|
36
|
+
* default glob would only be a dead scope. `coreGlobs` are always
|
|
37
|
+
* excluded, so whether a ViewModel is an adapter or a presenter in
|
|
38
|
+
* the core is decided by which of the two scopes its package
|
|
39
|
+
* matches. Starting points:
|
|
40
|
+
* - UI in this repo: `['**\/composeApp/src/**', '**\/src/*Main/**\/ui/**', '!**\/*Preview*.kt']`
|
|
41
|
+
* - a CLI module: `['cli/src/main/**\/commands/**']`
|
|
42
|
+
* - a UI-only app on a core SDK: its `ui/` packages, plus `coreApiPaths`.
|
|
43
|
+
* Every matching write costs an AI call, before the TDD judge. */
|
|
44
|
+
drivingAdapterGlobs?: readonly string[];
|
|
45
|
+
/** Fields whose comparison to a domain value in a driving adapter is
|
|
46
|
+
* a domain decision (e.g. `['role', 'status']`): net-new
|
|
47
|
+
* `role == Role.ADMIN`, `when (viewer.role)` or `status is
|
|
48
|
+
* Status.Draft` block free, before the AI call. No default. */
|
|
49
|
+
domainDiscriminants?: string[];
|
|
50
|
+
/** Appended to the discriminant block message, e.g. where permission
|
|
51
|
+
* rules live. */
|
|
52
|
+
domainHint?: string;
|
|
53
|
+
/** Give the thin-driving-adapter judge the public names declared in
|
|
54
|
+
* `coreGlobs` sources, so it can name the existing function a copy
|
|
55
|
+
* duplicates. Scans the tree on each judged write. */
|
|
56
|
+
coreExportsInJudge?: boolean;
|
|
57
|
+
/** Cap on the export list the judge is given (default 16000
|
|
58
|
+
* characters; the list is truncated beyond it). */
|
|
59
|
+
coreExportsMaxChars?: number;
|
|
60
|
+
/** For a repo that consumes the core as a library: binary-
|
|
61
|
+
* compatibility-validator dumps (`.api`, `.klib.api`), as files or
|
|
62
|
+
* directories relative to the root, whose public API the
|
|
63
|
+
* thin-driving-adapter judge is given. */
|
|
64
|
+
coreApiPaths?: string[];
|
|
33
65
|
/** The real Gradle test task your commit gate should look for. */
|
|
34
66
|
commitCommand?: RegExp;
|
|
35
67
|
/** Globs excluded (as `!`-negations) from every files-scoped block —
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kotlin.d.ts","sourceRoot":"","sources":["../../presets/kotlin.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"kotlin.d.ts","sourceRoot":"","sources":["../../presets/kotlin.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAmCrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAKhD,MAAM,MAAM,mBAAmB,GAAG;IAChC;;iDAE6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;kEAE8D;IAC9D,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,uEAAuE;IACvE,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;qBAGiB;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;oDACgD;IAChD,eAAe,CAAC,EAAE,KAAK,CAAA;IACvB,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,KAAK,CAAA;IAC3B;sCACkC;IAClC,uBAAuB,CAAC,EAAE,KAAK,CAAA;IAC/B,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,oEAAoE;IACpE,YAAY,CAAC,EAAE,KAAK,CAAA;IACpB;;;;;;;;;;uEAUmE;IACnE,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC;;;oEAGgE;IAChE,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC9B;sBACkB;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;2DAEuD;IACvD,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;wDACoD;IACpD,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;+CAG2C;IAC3C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;oEACgE;IAChE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CACxB,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,SAAS,EAAE,CA8M9F"}
|
package/dist/presets/kotlin.js
CHANGED
|
@@ -18,10 +18,11 @@ import { forbidContentPattern } from '@nizos/probity';
|
|
|
18
18
|
import { enforceKotlinTdd } from '../internal/kotlin-tdd.js';
|
|
19
19
|
import { withExtractionUnderGreen } from '../rules/gates.js';
|
|
20
20
|
import { enforceAcceptanceLanguage, withAcceptanceLanguageFastPath, } from '../rules/acceptance-language.js';
|
|
21
|
-
import { enforceCharacterizationResolution, enforceProbeReversion, forbidNewAmbientEffects, forbidStaticMocks, GRADLE_TEST_COMMAND, KOTLIN_BOUNDARY_ADDENDUM, KOTLIN_INFRASTRUCTURE_IMPORTS, KOTLIN_PRODUCTION_SOURCE_PATTERN, KOTLIN_TEST_SOURCE_PATTERN, kotlinGreenRunOptions, requireGreenTestRun, withCharacterizationTest, withKotlinFastPath, withMutationProbe, withTelemetryFastPath, } from '../rules/kotlin.js';
|
|
21
|
+
import { enforceCharacterizationResolution, enforceProbeReversion, forbidNewAmbientEffects, forbidStaticMocks, GRADLE_TEST_COMMAND, KOTLIN_API_DUMP, KOTLIN_BOUNDARY_ADDENDUM, KOTLIN_DRIVING_ADAPTER_ADDENDUM, KOTLIN_EXPORTS, kotlinDomainDiscriminantPatterns, KOTLIN_INFRASTRUCTURE_IMPORTS, KOTLIN_PRODUCTION_SOURCE_PATTERN, KOTLIN_TEST_SOURCE_PATTERN, kotlinGreenRunOptions, requireGreenTestRun, withCharacterizationTest, withKotlinFastPath, withMutationProbe, withTelemetryFastPath, } from '../rules/kotlin.js';
|
|
22
22
|
import { enforceAdapterObservability, enforcePortsBoundary, } from '../rules/ports-and-adapters.js';
|
|
23
23
|
import { requireSpecBackedAcceptanceTest } from '../rules/spec-test-parity.js';
|
|
24
24
|
import { withExcludeGlobs } from '../rules/scoping.js';
|
|
25
|
+
import { drivingAdapterBlock } from './driving-adapter.js';
|
|
25
26
|
import { surfaceGlossaryTermBreakage } from '../rules/ubiquitous-language.js';
|
|
26
27
|
/**
|
|
27
28
|
* Rule entries for a Kotlin/JVM/Android project, as a factory over the
|
|
@@ -63,6 +64,22 @@ export function kotlinRuleEntries(root, options = {}) {
|
|
|
63
64
|
'**/src/main/**/data/**',
|
|
64
65
|
];
|
|
65
66
|
const excludeGlobs = options.excludeGlobs ?? ['spikes/**', '**/build/**'];
|
|
67
|
+
// Driving adapters must be thin (issues #72, #76). Opt-in: listed
|
|
68
|
+
// before the TDD block, so a denial costs one AI call, not two.
|
|
69
|
+
const drivingAdapter = drivingAdapterBlock({
|
|
70
|
+
globs: options.drivingAdapterGlobs ?? [],
|
|
71
|
+
coreGlobs,
|
|
72
|
+
domainDiscriminants: options.domainDiscriminants,
|
|
73
|
+
domainHint: options.domainHint,
|
|
74
|
+
patternsFor: kotlinDomainDiscriminantPatterns,
|
|
75
|
+
coreExports: options.coreExportsInJudge
|
|
76
|
+
? { root, language: KOTLIN_EXPORTS, maxChars: options.coreExportsMaxChars ?? 16000 }
|
|
77
|
+
: undefined,
|
|
78
|
+
publishedApi: options.coreApiPaths?.length
|
|
79
|
+
? { paths: options.coreApiPaths, format: KOTLIN_API_DUMP, root }
|
|
80
|
+
: undefined,
|
|
81
|
+
instructions: (defaults) => defaults + KOTLIN_DRIVING_ADAPTER_ADDENDUM,
|
|
82
|
+
});
|
|
66
83
|
const entries = [
|
|
67
84
|
// ── Deterministic wall ───────────────────────────────────────────
|
|
68
85
|
// Core import/effect screens.
|
|
@@ -125,6 +142,7 @@ export function kotlinRuleEntries(root, options = {}) {
|
|
|
125
142
|
// production already has (born green): a test-source write marked
|
|
126
143
|
// `// probity: characterization` passes, and the commit gate below
|
|
127
144
|
// holds the marker until a mutation probe shows that test failing.
|
|
145
|
+
...(drivingAdapter ? [drivingAdapter] : []),
|
|
128
146
|
{
|
|
129
147
|
files: tddGlobs,
|
|
130
148
|
// Telemetry-only additions pass deterministically — see the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kotlin.js","sourceRoot":"","sources":["../../presets/kotlin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,oBAAoB,EAAkB,MAAM,gBAAgB,CAAA;AAErE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAE5D,OAAO,EACL,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,iCAAiC,CAAA;AACxC,OAAO,EACL,iCAAiC,EACjC,qBAAqB,EACrB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,6BAA6B,EAC7B,gCAAgC,EAChC,0BAA0B,EAC1B,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,GACrB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,+BAA+B,EAAE,MAAM,8BAA8B,CAAA;AAE9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"kotlin.js","sourceRoot":"","sources":["../../presets/kotlin.ts"],"names":[],"mappings":"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"}
|