@jjchill/probity-rules 0.1.0

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/GLOSSARY.template.md +33 -0
  3. package/README.md +96 -0
  4. package/dist/index.d.ts +20 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +20 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/presets/js.d.ts +63 -0
  9. package/dist/presets/js.d.ts.map +1 -0
  10. package/dist/presets/js.js +112 -0
  11. package/dist/presets/js.js.map +1 -0
  12. package/dist/presets/kmp.d.ts +27 -0
  13. package/dist/presets/kmp.d.ts.map +1 -0
  14. package/dist/presets/kmp.js +253 -0
  15. package/dist/presets/kmp.js.map +1 -0
  16. package/dist/presets/kotlin.d.ts +40 -0
  17. package/dist/presets/kotlin.d.ts.map +1 -0
  18. package/dist/presets/kotlin.js +172 -0
  19. package/dist/presets/kotlin.js.map +1 -0
  20. package/dist/presets/swift.d.ts +10 -0
  21. package/dist/presets/swift.d.ts.map +1 -0
  22. package/dist/presets/swift.js +285 -0
  23. package/dist/presets/swift.js.map +1 -0
  24. package/dist/rules/acceptance-language.d.ts +95 -0
  25. package/dist/rules/acceptance-language.d.ts.map +1 -0
  26. package/dist/rules/acceptance-language.js +443 -0
  27. package/dist/rules/acceptance-language.js.map +1 -0
  28. package/dist/rules/gates.d.ts +125 -0
  29. package/dist/rules/gates.d.ts.map +1 -0
  30. package/dist/rules/gates.js +285 -0
  31. package/dist/rules/gates.js.map +1 -0
  32. package/dist/rules/kotlin.d.ts +323 -0
  33. package/dist/rules/kotlin.d.ts.map +1 -0
  34. package/dist/rules/kotlin.js +722 -0
  35. package/dist/rules/kotlin.js.map +1 -0
  36. package/dist/rules/ports-and-adapters.d.ts +86 -0
  37. package/dist/rules/ports-and-adapters.d.ts.map +1 -0
  38. package/dist/rules/ports-and-adapters.js +366 -0
  39. package/dist/rules/ports-and-adapters.js.map +1 -0
  40. package/dist/rules/scoping.d.ts +68 -0
  41. package/dist/rules/scoping.d.ts.map +1 -0
  42. package/dist/rules/scoping.js +93 -0
  43. package/dist/rules/scoping.js.map +1 -0
  44. package/dist/rules/spec-test-parity.d.ts +164 -0
  45. package/dist/rules/spec-test-parity.d.ts.map +1 -0
  46. package/dist/rules/spec-test-parity.js +456 -0
  47. package/dist/rules/spec-test-parity.js.map +1 -0
  48. package/dist/rules/swift.d.ts +50 -0
  49. package/dist/rules/swift.d.ts.map +1 -0
  50. package/dist/rules/swift.js +50 -0
  51. package/dist/rules/swift.js.map +1 -0
  52. package/dist/rules/ubiquitous-language.d.ts +36 -0
  53. package/dist/rules/ubiquitous-language.d.ts.map +1 -0
  54. package/dist/rules/ubiquitous-language.js +140 -0
  55. package/dist/rules/ubiquitous-language.js.map +1 -0
  56. package/dist/scripts/scope-report.d.ts +3 -0
  57. package/dist/scripts/scope-report.d.ts.map +1 -0
  58. package/dist/scripts/scope-report.js +184 -0
  59. package/dist/scripts/scope-report.js.map +1 -0
  60. package/kiro/README.md +20 -0
  61. package/kiro/kiro-agent.template.json +45 -0
  62. package/kiro/kiro-transcript-to-claude.py +183 -0
  63. package/kiro/probity-kiro-translate.py +132 -0
  64. package/kiro/probity-kiro.sh +87 -0
  65. package/kiro/skill-activation-forced-eval.sh +45 -0
  66. package/package.json +68 -0
  67. package/probity.config.kmp.ts +40 -0
  68. package/probity.config.kotlin.ts +37 -0
  69. package/probity.config.swift.ts +38 -0
  70. package/probity.config.ts +43 -0
  71. package/scripts/spec-parity.mjs +345 -0
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Probity rule-entry factory — Kotlin Multiplatform preset.
3
+ *
4
+ * Same enforcement as the Kotlin preset, recalibrated for a KMP
5
+ * codebase with ports-and-adapters codified per feature module:
6
+ * source sets (`commonMain`/`androidMain`/`desktopMain`/`iosMain`,
7
+ * tests in `commonTest`/`androidHostTest`/…), core vs adapter split
8
+ * by package (`domain`/`port`/`usecase`/`presentation` vs
9
+ * `adapter`/`di`/`ui`), kotlin.test + hand-written fakes with NO
10
+ * mocking library, Koin at the composition root only, and
11
+ * acceptance tests driven through a Robot DSL at the ViewModel
12
+ * boundary with Markdown Given/When/Then specs in docs/specs/.
13
+ * Adjust globs and package names to your layout.
14
+ *
15
+ * Probity still runs on Node: `npm install -D @nizos/probity`
16
+ * (plus optionally @ast-grep/napi @ast-grep/lang-kotlin for the TDD
17
+ * fast-path) next to gradlew.
18
+ */
19
+ import { join } from 'node:path';
20
+ import { enforceTdd, forbidContentPattern } from '@nizos/probity';
21
+ import { enforceAcceptanceLanguage, withAcceptanceLanguageFastPath, } from '../rules/acceptance-language.js';
22
+ import { enforceSpecTestParity, requireSpecBackedAcceptanceTest, surfaceScenarioLinkBreakage, } from '../rules/spec-test-parity.js';
23
+ import { surfaceGlossaryTermBreakage } from '../rules/ubiquitous-language.js';
24
+ import { enforceProbeReversion, forbidNewAmbientEffects, GRADLE_TEST_COMMAND, KOTLIN_BOUNDARY_ADDENDUM, KOTLIN_INFRASTRUCTURE_IMPORTS, MOCKING_LIBRARY_IMPORTS, requireGreenTestRun, withKotlinFastPath, withMutationProbe, withTelemetryFastPath, } from '../rules/kotlin.js';
25
+ import { enforceAdapterObservability, enforcePortsBoundary, } from '../rules/ports-and-adapters.js';
26
+ /**
27
+ * The rule entries, as a factory over the project root. Probity only
28
+ * reads the default export below; the factory exists so tooling can
29
+ * instantiate the exact same blocks against a different root — the
30
+ * workflow eval runs them in a temp directory, and
31
+ * `scripts/scope-report.ts` resolves their `files` scopes against the
32
+ * real tree. Keeping the entries in one place is what lets the eval's
33
+ * scoping stay derived from this config instead of hand-mirrored.
34
+ *
35
+ * Relative globs (`docs/...`) are NOT anchored here: Probity's
36
+ * `loadConfig` anchors them against this file's directory at load
37
+ * time, and the tooling replicates that via `rules/scoping.ts`.
38
+ *
39
+ * `parity` optionally switches on the per-scenario driver mapping
40
+ * (`driverScopes`/`defaultScopes` on the commit-time parity gate) —
41
+ * projects normally enable it by uncommenting the block in the
42
+ * `enforceSpecTestParity` call below; the parameter exists so the
43
+ * workflow eval can exercise the scope checks without changing the
44
+ * template's default-off posture.
45
+ */
46
+ export function kmpRuleEntries(root, parity) {
47
+ // Ubiquitous-language glossary (copy GLOSSARY.template.md here).
48
+ // The glossary-aware rules degrade gracefully while the file
49
+ // doesn't exist yet — wiring it up front costs nothing.
50
+ const glossary = join(root, 'docs/GLOSSARY.md');
51
+ // Core purity scope — the inside of the hexagon: domain, ports,
52
+ // use cases, and MVI presentation in commonMain. Adapter, DI, and
53
+ // Compose ui packages import vendors by design — excluded.
54
+ const CORE_GLOBS = [
55
+ '**/src/commonMain/**/domain/**',
56
+ '**/src/commonMain/**/port/**',
57
+ '**/src/commonMain/**/usecase/**',
58
+ '**/src/commonMain/**/presentation/**',
59
+ ];
60
+ // Rule ordering principle: Probity stops at the first violation, so
61
+ // every deterministic screen (pattern match, free, instant) is
62
+ // listed before any AI-validated rule (a model call per matching
63
+ // write). A write with a vendor import in core code must be
64
+ // rejected by the free import screen, not after a TDD model call.
65
+ return [
66
+ // ── Deterministic wall ───────────────────────────────────────────
67
+ // Core import/effect screens. The import screen also catches Koin
68
+ // here: DI stays at the composition root, never in domain code.
69
+ {
70
+ files: CORE_GLOBS,
71
+ rules: [
72
+ forbidContentPattern({
73
+ match: KOTLIN_INFRASTRUCTURE_IMPORTS,
74
+ reason: 'Core code imports an infrastructure/vendor package (this ' +
75
+ 'screen includes Koin — DI belongs at the composition ' +
76
+ 'root). The Dependency Rule: core imports nothing from ' +
77
+ 'frameworks, vendors, or OS I/O — define a port and reach ' +
78
+ 'the dependency through an adapter (see the ' +
79
+ 'ports-and-adapters skill).',
80
+ }),
81
+ forbidNewAmbientEffects({
82
+ seamHint: 'This codebase injects function-typed providers (e.g. ' +
83
+ 'nowEpochMillis: () -> Long) with real defaults supplied ' +
84
+ 'only in platform adapters or DI modules',
85
+ }),
86
+ ],
87
+ },
88
+ // No mocking library at all: this convention is hand-written
89
+ // fakes substituted at ports (shared via testfixtures modules).
90
+ {
91
+ files: ['**/src/*Test/kotlin/**', '**/src/test/kotlin/**'],
92
+ rules: [
93
+ forbidContentPattern({
94
+ match: MOCKING_LIBRARY_IMPORTS,
95
+ reason: 'This codebase uses no mocking library: substitute a ' +
96
+ 'hand-written fake at the port (see the shared test ' +
97
+ 'fixtures), never mock an SDK or framework type. Ports ' +
98
+ 'are the only test seam.',
99
+ }),
100
+ ],
101
+ },
102
+ // Spec↔test traceability. Editing a spec must not silently break
103
+ // the tests that claim its scenarios: removing or renaming a
104
+ // `## Scenario:` heading still covered by a test blocks with the
105
+ // list of affected tests, so the rename updates its Covers: tags
106
+ // in the same change.
107
+ {
108
+ files: ['docs/specs/**/*.feature.md'],
109
+ rules: [surfaceScenarioLinkBreakage({ testRoots: [root] })],
110
+ },
111
+ // Spec-first, at write time: adding a new acceptance test case
112
+ // requires a new Covers: tag resolving to a scenario that already
113
+ // exists in docs/specs — the feature file is written before the
114
+ // test that claims it. Scoped to the test-case layer only
115
+ // (*Spec.kt); drivers/DSL/scenario bodies add no @Test functions.
116
+ {
117
+ files: ['**/acceptance/**/*Spec.kt', '**/acceptance/**/*Test.kt'],
118
+ rules: [
119
+ requireSpecBackedAcceptanceTest({ specsDir: join(root, 'docs/specs') }),
120
+ ],
121
+ },
122
+ // Ubiquitous-language drift: renaming or removing a glossary term
123
+ // that specs, tests, or code still use blocks the glossary edit
124
+ // with the list of users.
125
+ {
126
+ files: ['docs/GLOSSARY.md'],
127
+ rules: [surfaceGlossaryTermBreakage({ searchRoots: [root] })],
128
+ },
129
+ // ── AI-validated judgment layer ──────────────────────────────────
130
+ // Inner loop: test-driven-development. `src/*Main` / `src/*Test`
131
+ // cover every KMP source set (commonMain, androidMain, commonTest,
132
+ // androidHostTest, …); main/test cover classic Android app modules
133
+ // alongside them. The Kotlin fast-path keeps the most common write
134
+ // (a single new @Test) deterministic. The mutation-probe wrapper
135
+ // lets a write marked `// probity: mutation-probe` (a deliberate
136
+ // break proving a retrofitted test bites) through without a
137
+ // red-before-green demand — enforceProbeReversion below blocks
138
+ // commits until the probe is reverted.
139
+ {
140
+ files: [
141
+ '**/src/*Main/kotlin/**',
142
+ '**/src/*Test/kotlin/**',
143
+ '**/src/main/kotlin/**',
144
+ '**/src/test/kotlin/**',
145
+ ],
146
+ // Telemetry-only additions (a complete logger.event/breadcrumb
147
+ // line) pass deterministically — instrumentation demanded by the
148
+ // adapter-observability rule must not be judged as unasserted
149
+ // behavior by the TDD gate.
150
+ rules: [
151
+ withMutationProbe(withTelemetryFastPath(withKotlinFastPath(enforceTdd()))),
152
+ ],
153
+ },
154
+ // Boundaries: ports-and-adapters. The Dependency Rule judgments
155
+ // the import screen can't make — thin adapters, vendor types in
156
+ // port signatures, glossary-conflicting names.
157
+ {
158
+ files: CORE_GLOBS,
159
+ rules: [
160
+ enforcePortsBoundary({
161
+ instructions: (defaults) => defaults + KOTLIN_BOUNDARY_ADDENDUM,
162
+ glossaryPath: glossary,
163
+ }),
164
+ ],
165
+ },
166
+ // Adapters must be thin, but not blind: a new adapter path doing
167
+ // external I/O carries boundary observability (structured event,
168
+ // port tap, or span). Delta-based — legacy uninstrumented paths
169
+ // migrate incrementally.
170
+ {
171
+ files: ['**/src/*Main/kotlin/**/adapter/**'],
172
+ rules: [
173
+ withTelemetryFastPath(enforceAdapterObservability({
174
+ conventionHint: 'This codebase uses structured Logger.event(tag, event, ' +
175
+ 'level, fields) from :foundation (one greppable line: ' +
176
+ 'event=<name> k=v), and/or a recording port-tap decorator ' +
177
+ 'wired at the Koin composition root.',
178
+ })),
179
+ ],
180
+ },
181
+ // Outer loop: acceptance-testing. The Language Test on the spec
182
+ // layer: Markdown Given/When/Then specs and the acceptance test
183
+ // cases. Robot/DSL/driver classes are layers 2-3 (they know about
184
+ // UiState and MVI intents) — excluded, whichever of the two
185
+ // layouts a feature uses (merged *Robot.kt, or split *Dsl.kt +
186
+ // *Driver.kt per the four-layer model). Shared scenario-body
187
+ // files (*Scenarios.kt — the bodies both drivers run) are layer 1
188
+ // and stay INCLUDED by design: they must read as pure domain
189
+ // language.
190
+ {
191
+ files: [
192
+ 'docs/specs/**/*.feature.md',
193
+ '**/acceptance/**',
194
+ '!**/*Robot.kt',
195
+ '!**/*Dsl.kt',
196
+ '!**/*Driver.kt',
197
+ ],
198
+ // requireGlossaryEntry: true is the strict "glossary
199
+ // conversation happens first" mode — turn it on once the
200
+ // glossary has real coverage, not on day one. The fast-path
201
+ // wrapper keeps a single-@Test write that only reuses existing
202
+ // DSL vocabulary free of AI calls (Markdown specs always go to
203
+ // the validator).
204
+ rules: [
205
+ withAcceptanceLanguageFastPath(enforceAcceptanceLanguage({ glossaryPath: glossary })),
206
+ ],
207
+ },
208
+ // ── Ship gates ───────────────────────────────────────────────────
209
+ // Definition of done, made mechanical: every non-wip scenario in
210
+ // docs/specs is claimed by an acceptance test (Covers: tag), and
211
+ // every tag resolves to a real scenario. Mark in-progress specs
212
+ // `## Scenario (wip):`. CI mirror for human commits:
213
+ // scripts/spec-parity.mjs.
214
+ //
215
+ // Brownfield adoption: a spec suite that predates the gate would
216
+ // block every commit. Generate a baseline once —
217
+ // node scripts/spec-parity.mjs --specs docs/specs \
218
+ // --baseline docs/specs/.parity-baseline --write-baseline
219
+ // — and commit it: baselined scenarios are exempt while new ones
220
+ // are enforced from day one; burn the file down by deleting lines
221
+ // as coverage lands. No baseline file → full enforcement.
222
+ //
223
+ // Per-scenario driver mapping (optional): declare named driver
224
+ // scopes and tag scenarios that need more than the default suite —
225
+ // `## Scenario [system]: …` then requires a covering test whose
226
+ // path matches that scope. Tags are floors, not ceilings; with
227
+ // shared scenario bodies (*Scenarios.kt) the extra covering test
228
+ // is a thin spec class calling the existing body. CALIBRATE THE
229
+ // PATTERNS TO YOUR LAYOUT before uncommenting — a pattern matching
230
+ // zero files makes every tagged scenario fail, loudly.
231
+ enforceSpecTestParity({
232
+ specsDir: join(root, 'docs/specs'),
233
+ testRoots: [root],
234
+ baselinePath: join(root, 'docs/specs/.parity-baseline'),
235
+ // driverScopes: [
236
+ // { name: 'view-model', filePattern: /[/\\]acceptance[/\\]viewmodel[/\\]/ },
237
+ // { name: 'system', filePattern: /[/\\]acceptance[/\\]ui[/\\]/ },
238
+ // ],
239
+ // defaultScopes: ['view-model'],
240
+ ...parity,
241
+ }),
242
+ // The commit half of the mutation-probe round-trip: no commit
243
+ // while a `probity: mutation-probe` marker is still on disk —
244
+ // reverting the mutation removes the marker with it.
245
+ enforceProbeReversion({ roots: [root] }),
246
+ // Matches testAndroidHostTest, :feature:x:testAndroidHostTest,
247
+ // :desktop:jvmTest, allTests, :app:testDevDebugUnitTest. Stricter
248
+ // than Probity's requireCommand: the recorded run's output must
249
+ // actually be green, not merely exist.
250
+ requireGreenTestRun({ command: GRADLE_TEST_COMMAND }),
251
+ ];
252
+ }
253
+ //# sourceMappingURL=kmp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kmp.js","sourceRoot":"","sources":["../../presets/kmp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { type RuleEntry } from '@nizos/probity';
2
+ import type { Globs } from '../rules/scoping.js';
3
+ export type KotlinPresetOptions = {
4
+ /** Absolute path to the ubiquitous-language glossary. Defaults to
5
+ * `<root>/docs/GLOSSARY.md`; glossary-aware rules degrade
6
+ * gracefully while it doesn't exist yet. */
7
+ glossaryPath?: string;
8
+ /** Core purity scope — point at your core modules (e.g. the
9
+ * `*-core` modules of a core/ui split); DI wiring and adapter
10
+ * packages import vendors by design and must be excluded. */
11
+ coreGlobs?: Globs;
12
+ /** Deterministic infrastructure/vendor import screen for core code. */
13
+ infrastructureImports?: RegExp;
14
+ /** Point at the project's canonical ambient-effect port(s). */
15
+ seamHint?: string;
16
+ /** Test source sets where static/object/constructor mocking is
17
+ * forbidden — ports are the only test seam. */
18
+ staticMockGlobs?: Globs;
19
+ /** Test-case files that must carry a spec-backed Covers: tag. */
20
+ acceptanceTestGlobs?: Globs;
21
+ /** Files the Language Test applies to (acceptance test globs plus
22
+ * any Gherkin feature files). */
23
+ acceptanceLanguageGlobs?: Globs;
24
+ /** Source sets the TDD gate applies to. */
25
+ tddGlobs?: Globs;
26
+ /** Adapter/data packages that must carry boundary observability. */
27
+ adapterGlobs?: Globs;
28
+ /** The real Gradle test task your commit gate should look for. */
29
+ commitCommand?: RegExp;
30
+ };
31
+ /**
32
+ * Rule entries for a Kotlin/JVM/Android project, as a factory over the
33
+ * project root. Rule ordering principle: Probity stops at the first
34
+ * violation, so every deterministic screen (pattern match, free,
35
+ * instant) is listed before any AI-validated rule (a model call per
36
+ * matching write). A write with a vendor import in core code must be
37
+ * rejected by the free import screen, not after a TDD model call.
38
+ */
39
+ export declare function kotlinRuleEntries(root: string, options?: KotlinPresetOptions): RuleEntry[];
40
+ //# sourceMappingURL=kotlin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kotlin.d.ts","sourceRoot":"","sources":["../../presets/kotlin.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAuBjF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAGhD,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;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,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,SAAS,EAAE,CAgK9F"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Probity rule-entry factory — Kotlin/JVM/Android preset.
3
+ *
4
+ * Same enforcement as the JS preset (see hooks/PROBITY.md) with the
5
+ * deterministic layer swapped to Kotlin-shaped rules from
6
+ * '../rules/kotlin.js'. Calibrated against a multi-module Android
7
+ * codebase (Gradle per project, `<module>-core` / `<module>-ui`
8
+ * split, Mockito-kotlin + JUnit 4, AWS/Amplify/Apollo/OkHttp/
9
+ * Retrofit/Room vendor stack) — every option below defaults to that
10
+ * calibration; a consuming project overrides what its layout needs.
11
+ *
12
+ * Note Probity itself still runs on Node: the consuming Kotlin
13
+ * project needs `npm install -D @nizos/probity` (a one-dependency
14
+ * package.json next to gradlew is fine).
15
+ */
16
+ import { join } from 'node:path';
17
+ import { enforceTdd, forbidContentPattern } from '@nizos/probity';
18
+ import { enforceAcceptanceLanguage, withAcceptanceLanguageFastPath, } from '../rules/acceptance-language.js';
19
+ import { enforceProbeReversion, forbidNewAmbientEffects, forbidStaticMocks, GRADLE_TEST_COMMAND, KOTLIN_BOUNDARY_ADDENDUM, KOTLIN_INFRASTRUCTURE_IMPORTS, requireGreenTestRun, withKotlinFastPath, withMutationProbe, withTelemetryFastPath, } from '../rules/kotlin.js';
20
+ import { enforceAdapterObservability, enforcePortsBoundary, } from '../rules/ports-and-adapters.js';
21
+ import { requireSpecBackedAcceptanceTest } from '../rules/spec-test-parity.js';
22
+ import { surfaceGlossaryTermBreakage } from '../rules/ubiquitous-language.js';
23
+ /**
24
+ * Rule entries for a Kotlin/JVM/Android project, as a factory over the
25
+ * project root. Rule ordering principle: Probity stops at the first
26
+ * violation, so every deterministic screen (pattern match, free,
27
+ * instant) is listed before any AI-validated rule (a model call per
28
+ * matching write). A write with a vendor import in core code must be
29
+ * rejected by the free import screen, not after a TDD model call.
30
+ */
31
+ export function kotlinRuleEntries(root, options = {}) {
32
+ const glossary = options.glossaryPath ?? join(root, 'docs/GLOSSARY.md');
33
+ const coreGlobs = options.coreGlobs ?? [
34
+ '**/*-core/src/main/**',
35
+ '!**/*-core/src/main/**/di/**',
36
+ '!**/*-core/src/main/**/data/**',
37
+ ];
38
+ const staticMockGlobs = options.staticMockGlobs ?? [
39
+ '**/src/test/**',
40
+ '**/src/androidTest/**',
41
+ '**/src/sharedTest/**',
42
+ ];
43
+ const acceptanceTestGlobs = options.acceptanceTestGlobs ?? [
44
+ '**/acceptance/**/*Spec.kt',
45
+ '**/acceptance/**/*Test.kt',
46
+ ];
47
+ const acceptanceLanguageGlobs = options.acceptanceLanguageGlobs ?? [
48
+ ...acceptanceTestGlobs,
49
+ '**/*.feature',
50
+ ];
51
+ const tddGlobs = options.tddGlobs ?? [
52
+ '**/src/main/java/**',
53
+ '**/src/main/kotlin/**',
54
+ '**/src/test/**',
55
+ '**/src/sharedTest/**',
56
+ ];
57
+ const adapterGlobs = options.adapterGlobs ?? [
58
+ '**/src/main/**/adapter/**',
59
+ '**/src/main/**/adapters/**',
60
+ '**/src/main/**/data/**',
61
+ ];
62
+ return [
63
+ // ── Deterministic wall ───────────────────────────────────────────
64
+ // Core import/effect screens.
65
+ {
66
+ files: coreGlobs,
67
+ rules: [
68
+ forbidContentPattern({
69
+ match: options.infrastructureImports ?? KOTLIN_INFRASTRUCTURE_IMPORTS,
70
+ reason: 'Core code imports an infrastructure package. The ' +
71
+ 'Dependency Rule: core imports nothing from frameworks, ' +
72
+ 'vendors, or OS I/O — define a port in the core and reach ' +
73
+ 'the dependency through an adapter (see the ' +
74
+ 'ports-and-adapters skill).',
75
+ }),
76
+ // Delta-based: only NEW ambient calls block, so the existing
77
+ // Instant.now()/UUID.randomUUID() sites in a brownfield
78
+ // codebase don't freeze their files. Point seamHint at your
79
+ // canonical port(s).
80
+ forbidNewAmbientEffects({
81
+ seamHint: options.seamHint ??
82
+ 'This codebase has a TimeProvider port (sudocommons-core) — inject it rather than reading the OS clock',
83
+ }),
84
+ ],
85
+ },
86
+ // Ports are the only test seam: no new static/object/constructor
87
+ // mocking anywhere in the suite.
88
+ {
89
+ files: staticMockGlobs,
90
+ rules: [forbidStaticMocks()],
91
+ },
92
+ // Ubiquitous-language drift: renaming or removing a glossary term
93
+ // that specs, tests, or code still use blocks the glossary edit
94
+ // with the list of users.
95
+ {
96
+ files: ['docs/GLOSSARY.md'],
97
+ rules: [surfaceGlossaryTermBreakage({ searchRoots: [root] })],
98
+ },
99
+ // Spec-first, at write time: adding a new acceptance test case
100
+ // requires a new Covers: tag resolving to a `## Scenario:` that
101
+ // already exists in docs/specs — the feature file is written
102
+ // before the test that claims it. Deterministic; the pattern also
103
+ // matches Swift XCTest (`func test…`), so an XCUITest acceptance
104
+ // glob works here unchanged.
105
+ {
106
+ files: acceptanceTestGlobs,
107
+ rules: [
108
+ requireSpecBackedAcceptanceTest({ specsDir: join(root, 'docs/specs') }),
109
+ ],
110
+ },
111
+ // ── AI-validated judgment layer ──────────────────────────────────
112
+ // Inner loop: test-driven-development. Android source sets
113
+ // commonly keep .kt under src/main/java, so match both. Probity
114
+ // has no built-in Kotlin fast-path; withKotlinFastPath supplies
115
+ // one — a write adding exactly one @Test function passes without
116
+ // an AI call. It needs the optional packages
117
+ // (`npm install -D @ast-grep/napi @ast-grep/lang-kotlin`) and
118
+ // falls through to plain enforceTdd when they're absent.
119
+ {
120
+ files: tddGlobs,
121
+ // Telemetry-only additions pass deterministically — see the
122
+ // KMP preset's note on the TDD/observability tension.
123
+ rules: [
124
+ withMutationProbe(withTelemetryFastPath(withKotlinFastPath(enforceTdd()))),
125
+ ],
126
+ },
127
+ // Boundaries: ports-and-adapters. The Dependency Rule judgments
128
+ // the import screen can't make — thin adapters, vendor types in
129
+ // port signatures, glossary-conflicting names.
130
+ {
131
+ files: coreGlobs,
132
+ rules: [
133
+ enforcePortsBoundary({
134
+ instructions: (defaults) => defaults + KOTLIN_BOUNDARY_ADDENDUM,
135
+ glossaryPath: glossary,
136
+ }),
137
+ ],
138
+ },
139
+ // Adapters must be thin, but not blind: a new adapter path doing
140
+ // external I/O carries boundary observability (structured event,
141
+ // port tap, or span). Point the globs at your adapter/data
142
+ // packages. Delta-based — legacy paths migrate incrementally.
143
+ {
144
+ files: adapterGlobs,
145
+ rules: [withTelemetryFastPath(enforceAdapterObservability())],
146
+ },
147
+ // Outer loop: acceptance-testing. The Language Test on the spec
148
+ // layer only. Point at wherever your executable specifications
149
+ // live (e.g. an acceptance package under androidTest, or Gherkin
150
+ // features); protocol drivers and test infrastructure must NOT
151
+ // match.
152
+ {
153
+ files: acceptanceLanguageGlobs,
154
+ rules: [
155
+ withAcceptanceLanguageFastPath(enforceAcceptanceLanguage({ glossaryPath: glossary })),
156
+ ],
157
+ },
158
+ // ── Ship gates ───────────────────────────────────────────────────
159
+ // The commit half of the mutation-probe round-trip: no commit
160
+ // while a `probity: mutation-probe` marker is still on disk —
161
+ // reverting the mutation removes the marker with it.
162
+ enforceProbeReversion({ roots: [root] }),
163
+ // No commit on an unverified tree. GRADLE_TEST_COMMAND matches
164
+ // plain and flavored test tasks (`./gradlew test`,
165
+ // `./gradlew :app:testDevDebugUnitTest`); tighten it to your
166
+ // module's real task if you want the gate strict about which
167
+ // suite counts. Stricter than Probity's requireCommand: the
168
+ // recorded run's output must actually be green, not merely exist.
169
+ requireGreenTestRun({ command: options.commitCommand ?? GRADLE_TEST_COMMAND }),
170
+ ];
171
+ }
172
+ //# sourceMappingURL=kotlin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kotlin.js","sourceRoot":"","sources":["../../presets/kotlin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type RuleEntry } from '@nizos/probity';
2
+ /**
3
+ * Rule entries as a factory over the project root, mirroring the KMP
4
+ * preset: Probity reads the default export; tooling (scope reports,
5
+ * workflow evals) can instantiate the same blocks against another
6
+ * root. Relative globs are anchored by Probity's loadConfig against
7
+ * this file's directory.
8
+ */
9
+ export declare function swiftRuleEntries(root: string): RuleEntry[];
10
+ //# sourceMappingURL=swift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swift.d.ts","sourceRoot":"","sources":["../../presets/swift.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AA6CjF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAmR1D"}