@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,285 @@
1
+ /**
2
+ * Probity rule-entry factory — Swift/iOS preset.
3
+ *
4
+ * Same enforcement stack as the Kotlin presets (see hooks/PROBITY.md),
5
+ * recalibrated for a native iOS app: an Xcode workspace with the
6
+ * acceptance suite in AcceptanceTests/ following the four-layer model
7
+ * (Specs + Component test glue / Scenarios / DSL / Drivers), XCUITest
8
+ * plus an app-hosted component-test target, MVVM view models over
9
+ * use-case ports, and Markdown Given/When/Then specs in docs/specs/.
10
+ * Calibrated against a production CocoaPods + SwiftPM app — adjust
11
+ * globs and package names to your layout.
12
+ *
13
+ * Probity runs on Node: `npm install -D @nizos/probity` (a
14
+ * one-dependency package.json with `"type": "module"` next to the
15
+ * xcworkspace is fine).
16
+ */
17
+ import { join } from 'node:path';
18
+ import { enforceTdd, forbidContentPattern } from '@nizos/probity';
19
+ import { enforceAcceptanceLanguage, enforceControlledPreconditions, } from '../rules/acceptance-language.js';
20
+ import { enforceCharacterizationResolution, enforceProbeReversion, requireGreenTestRun, withCharacterizationTest, withInverseScenarioGuidance, withMutationProbe, withTelemetryFastPath, } from '../rules/kotlin.js';
21
+ import { enforceAdapterObservability, enforcePortsBoundary, } from '../rules/ports-and-adapters.js';
22
+ import { enforceSpecTestParity, requireSpecBackedAcceptanceTest, surfaceScenarioLinkBreakage, } from '../rules/spec-test-parity.js';
23
+ import { SWIFT_FIXED_SLEEPS, SWIFT_PROBE_FILE_PATTERN, XCODEBUILD_TEST_COMMAND, XCODEBUILD_TEST_FAILED, XCODEBUILD_TEST_SUCCEEDED, XCUITEST_MECHANICS, } from '../rules/swift.js';
24
+ import { surfaceGlossaryTermBreakage } from '../rules/ubiquitous-language.js';
25
+ // Acceptance test files live under AcceptanceTests/ (capital A) — the
26
+ // parity scanners' default pattern expects a lowercase `acceptance/`
27
+ // segment, so every spec-traceability rule below overrides it.
28
+ const ACCEPTANCE_TEST_FILES = /AcceptanceTests[/\\]/;
29
+ // Swift telemetry lines the fast-path recognizes as complete
30
+ // single-line instrumentation (SudoLogging-style logger calls).
31
+ const SWIFT_TELEMETRY_LINES = [
32
+ /^[\w.]*logger\.(?:event|info|debug|error|warning)\(.*\)$/i,
33
+ ];
34
+ /**
35
+ * Rule entries as a factory over the project root, mirroring the KMP
36
+ * preset: Probity reads the default export; tooling (scope reports,
37
+ * workflow evals) can instantiate the same blocks against another
38
+ * root. Relative globs are anchored by Probity's loadConfig against
39
+ * this file's directory.
40
+ */
41
+ export function swiftRuleEntries(root) {
42
+ const glossary = join(root, 'docs/GLOSSARY.md');
43
+ // Rule ordering principle: Probity stops at the first violation, so
44
+ // every deterministic screen (pattern match, free, instant) is
45
+ // listed before any AI-validated rule (a model call per matching
46
+ // write).
47
+ return [
48
+ // ── Deterministic wall ───────────────────────────────────────────
49
+ // No fixed waits anywhere in the acceptance suite: synchronize
50
+ // with XCTest expectations, predicates, or
51
+ // waitForExistence(timeout:) — never sleep.
52
+ {
53
+ files: ['AcceptanceTests/**'],
54
+ rules: [
55
+ forbidContentPattern({
56
+ match: SWIFT_FIXED_SLEEPS,
57
+ reason: 'Fixed waits are races: XCUITest flakiness starts here. ' +
58
+ 'Wait for the concluding observable state with XCTest ' +
59
+ 'expectations, predicate expectations, or ' +
60
+ 'waitForExistence(timeout:) (see the acceptance-testing ' +
61
+ 'and ios-development skills).',
62
+ }),
63
+ ],
64
+ },
65
+ // XCUITest mechanics belong only in the driver that owns the
66
+ // deployed-app scope. Specs, scenario bodies, the DSL, and the
67
+ // app-hosted component tests must stay implementation-neutral.
68
+ {
69
+ files: [
70
+ 'AcceptanceTests/Specs/**',
71
+ 'AcceptanceTests/Scenarios/**',
72
+ 'AcceptanceTests/DSL/**',
73
+ 'AcceptanceTests/Component/**',
74
+ ],
75
+ rules: [
76
+ forbidContentPattern({
77
+ match: XCUITEST_MECHANICS,
78
+ reason: 'XCUIApplication/XCUIElement outside AcceptanceTests/Drivers: ' +
79
+ 'only protocol drivers know how to reach the SUT. Move the ' +
80
+ 'mechanics into the XCUITest driver and express this layer ' +
81
+ 'in domain language (four-layer model, acceptance-testing ' +
82
+ 'skill).',
83
+ }),
84
+ ],
85
+ },
86
+ // Spec-first, at write time: adding a new acceptance test case
87
+ // (func test…) requires a Covers: tag resolving to a
88
+ // `## Scenario:` heading that already exists in docs/specs — the
89
+ // feature file is written before the test that claims it. A file
90
+ // whose existing tag already resolves may gain further driver
91
+ // tests for the same scenario (one scenario, many drivers).
92
+ // Scoped to the whole suite directory, not *Tests.swift: XCTest
93
+ // only discovers `func test…` methods, so the declaration pattern
94
+ // is the real detector and a creative filename can't dodge the
95
+ // rule. NOTE the directory itself is the boundary — acceptance
96
+ // tests added outside it (e.g. a new App/Tests/ target) are
97
+ // invisible to every rule here until the globs learn the path.
98
+ {
99
+ files: ['AcceptanceTests/**'],
100
+ rules: [
101
+ requireSpecBackedAcceptanceTest({ specsDir: join(root, 'docs/specs') }),
102
+ ],
103
+ },
104
+ // Editing a spec must not silently break the tests that claim its
105
+ // scenarios: removing or renaming a covered `## Scenario:` heading
106
+ // blocks with the list of affected tests.
107
+ {
108
+ files: ['docs/specs/**/*.feature.md'],
109
+ rules: [
110
+ surfaceScenarioLinkBreakage({
111
+ testRoots: [root],
112
+ testFilePattern: ACCEPTANCE_TEST_FILES,
113
+ }),
114
+ ],
115
+ },
116
+ // Ubiquitous-language drift: renaming or removing a glossary term
117
+ // that specs, tests, or code still use blocks the glossary edit
118
+ // with the list of users.
119
+ {
120
+ files: ['docs/GLOSSARY.md'],
121
+ rules: [surfaceGlossaryTermBreakage({ searchRoots: [root] })],
122
+ },
123
+ // ── AI-validated judgment layer ──────────────────────────────────
124
+ // Inner loop: test-driven-development over app sources and the
125
+ // acceptance suite. On a project whose only suite is the
126
+ // acceptance scheme, the observed red comes from
127
+ // `xcodebuild … test` — the outside-in loop, not an exemption.
128
+ // The mutation-probe wrapper lets a deliberate break marked
129
+ // `// probity: mutation-probe` through without a red-before-green
130
+ // demand; enforceProbeReversion below holds the commit hostage
131
+ // until it is reverted. Telemetry-only additions pass
132
+ // deterministically so the observability rule and the TDD gate
133
+ // never contradict each other.
134
+ // App/*.swift catches root-level sources (AppDelegate.swift lives
135
+ // beside App/Sources, not inside it) — audit these globs against
136
+ // your tree with scripts/scope-report.ts; a write no rule matches
137
+ // is a silent free pass.
138
+ {
139
+ files: [
140
+ 'App/*.swift',
141
+ 'App/Sources/**',
142
+ 'AcceptanceTests/**',
143
+ 'VPNNetworkExtension/**',
144
+ ],
145
+ rules: [
146
+ // The inverse-scenario wrapper changes only the DENY TEXT, and
147
+ // only on the test-control layer (the acceptance composition
148
+ // root): when a fixture has no red demanding it because the
149
+ // environment already satisfies the scenario's Given, the
150
+ // correct move — write the inverse scenario and let its red
151
+ // drive the fixture — is stated at the decision point instead
152
+ // of leaving "observe a red first" to read as "delete the
153
+ // control".
154
+ // The characterization wrapper sanctions the FIRST test for
155
+ // behavior that predates it (born green, so no red can be
156
+ // observed before it exists): a test-layer write carrying
157
+ // `// probity: characterization` passes, and the marker only
158
+ // comes off through a proof-checked removal (a recorded run
159
+ // where that test failed under a mutation probe). The
160
+ // resolution gate below blocks commits while a marker is on
161
+ // disk, so the bypass is a round-trip, not an exemption.
162
+ withInverseScenarioGuidance(withCharacterizationTest(withMutationProbe(withTelemetryFastPath(enforceTdd(), {
163
+ patterns: SWIFT_TELEMETRY_LINES,
164
+ filePattern: /\.swift$/,
165
+ })), { filePattern: /AcceptanceTests[/\\]/ }), { filePattern: /App[/\\]Sources[/\\]Acceptance[/\\]/ }),
166
+ ],
167
+ },
168
+ // Preconditions are controlled, not observed: a driver method
169
+ // named for a Given must establish it (fixture key, launch
170
+ // environment, programmed fake), and control wiring is never
171
+ // deleted just because the scenario passes without it — on a
172
+ // brownfield system the environment produces the sad path for
173
+ // free, which is exactly when the seam matters most (the success
174
+ // path is unreachable until the port is controlled).
175
+ {
176
+ files: ['AcceptanceTests/Drivers/**', 'App/Sources/Acceptance/**'],
177
+ rules: [enforceControlledPreconditions()],
178
+ },
179
+ // Boundaries: ports-and-adapters judgments the screens can't make
180
+ // — thin adapters, vendor types in port signatures, names
181
+ // conflicting with the glossary. Point at wherever your ports and
182
+ // core behavior live (here: module view-models/use-cases and the
183
+ // application-owned provider ports).
184
+ {
185
+ files: ['App/Sources/Modules/**', 'App/Sources/Utilities/Providers/**'],
186
+ rules: [enforcePortsBoundary({ glossaryPath: glossary })],
187
+ },
188
+ // Adapters must be thin, but not blind: a new adapter path doing
189
+ // external I/O carries boundary observability (structured event,
190
+ // port tap, or span). Delta-based — legacy paths migrate
191
+ // incrementally.
192
+ {
193
+ files: [
194
+ 'App/Sources/**/Adapters/**',
195
+ 'App/Sources/**/Services/**',
196
+ 'App/Sources/**/Analytics/**',
197
+ ],
198
+ rules: [
199
+ withTelemetryFastPath(enforceAdapterObservability({
200
+ conventionHint: 'This codebase uses SudoLogging (a Logger built by the ' +
201
+ 'MySudoVpn logger factories — one structured, greppable ' +
202
+ 'line per boundary call/outcome), and/or a recording ' +
203
+ 'port-tap decorator wired where the app composes its ' +
204
+ 'dependencies.',
205
+ }), { patterns: SWIFT_TELEMETRY_LINES, filePattern: /\.swift$/ }),
206
+ ],
207
+ },
208
+ // Outer loop: acceptance-testing. The Language Test on the spec
209
+ // layer: Markdown specs, test-case glue, scenario bodies, and the
210
+ // DSL — everything above the drivers must read as pure domain
211
+ // language. Drivers are layer 3 (they know accessibility
212
+ // identifiers, hosted views, view-model ports) — excluded.
213
+ {
214
+ files: [
215
+ 'docs/specs/**/*.feature.md',
216
+ 'AcceptanceTests/Specs/**',
217
+ 'AcceptanceTests/Component/**',
218
+ 'AcceptanceTests/Scenarios/**',
219
+ 'AcceptanceTests/DSL/**',
220
+ ],
221
+ rules: [enforceAcceptanceLanguage({ glossaryPath: glossary })],
222
+ },
223
+ // ── Ship gates ───────────────────────────────────────────────────
224
+ // Definition of done, made mechanical: every non-wip scenario in
225
+ // docs/specs is claimed by an acceptance test (Covers: tag), and
226
+ // every tag resolves to a real scenario. Brownfield adoption:
227
+ // generate a baseline once with scripts/spec-parity.mjs
228
+ // --write-baseline and burn it down (see hooks/PROBITY.md).
229
+ // Per-scenario driver mapping (optional): declare named driver
230
+ // scopes and tag scenarios that need more than the default suite —
231
+ // `## Scenario [system]: …` then requires a covering test whose
232
+ // path matches that scope. Tags are floors, not ceilings; with a
233
+ // shared scenario layer (AcceptanceTests/Scenarios/) the extra
234
+ // covering test is a thin spec class calling the existing body.
235
+ // The example scopes match the calibration app's layout — the
236
+ // XCUITest target under Specs/, the app-hosted component target
237
+ // under Component/. CALIBRATE TO YOUR LAYOUT before uncommenting.
238
+ enforceSpecTestParity({
239
+ specsDir: join(root, 'docs/specs'),
240
+ testRoots: [root],
241
+ testFilePattern: ACCEPTANCE_TEST_FILES,
242
+ baselinePath: join(root, 'docs/specs/.parity-baseline'),
243
+ // driverScopes: [
244
+ // { name: 'system', filePattern: /AcceptanceTests[/\\]Specs[/\\]/ },
245
+ // { name: 'hosted-ui', filePattern: /AcceptanceTests[/\\]Component[/\\]/ },
246
+ // ],
247
+ // defaultScopes: ['hosted-ui'],
248
+ }),
249
+ // The commit half of the mutation-probe round-trip: no commit
250
+ // while a `probity: mutation-probe` marker is still on disk.
251
+ enforceProbeReversion({
252
+ roots: [root],
253
+ filePattern: SWIFT_PROBE_FILE_PATTERN,
254
+ }),
255
+ // The commit half of the characterization round-trip: no commit
256
+ // while a `probity: characterization` marker is still on disk —
257
+ // the marker only comes off once the transcript records the
258
+ // marked test failing under a mutation probe.
259
+ enforceCharacterizationResolution({
260
+ roots: [root],
261
+ filePattern: SWIFT_PROBE_FILE_PATTERN,
262
+ }),
263
+ // No commit on an unverified tree. Matches `xcodebuild … test`
264
+ // and xcresulttool summary readbacks; the recorded output must
265
+ // actually be green (** TEST SUCCEEDED ** or "result": "Passed"),
266
+ // not merely exist. CALIBRATE AGAINST YOUR REAL COMMAND: a
267
+ // `-quiet` run suppresses the verdict banner entirely (verified
268
+ // live), so a runbook that mandates -quiet must also mandate the
269
+ // `xcrun xcresulttool get test-results summary` readback — that
270
+ // readback is the output this gate accepts. Run your documented
271
+ // test command once and confirm successPattern matches what it
272
+ // actually prints before trusting the gate.
273
+ // Scope the commit-on-green gate to code the acceptance suite
274
+ // actually validates; infra/docs/tooling-only commits (CI config,
275
+ // lint config, Markdown, probity.config.ts, rules/**) aren't gated
276
+ // on a fresh xcodebuild run. Adjust the paths to your layout.
277
+ requireGreenTestRun({
278
+ command: XCODEBUILD_TEST_COMMAND,
279
+ successPattern: XCODEBUILD_TEST_SUCCEEDED,
280
+ failurePattern: XCODEBUILD_TEST_FAILED,
281
+ enforceForPaths: /^(?:App|AcceptanceTests|VPNNetworkExtension)\//,
282
+ }),
283
+ ];
284
+ }
285
+ //# sourceMappingURL=swift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swift.js","sourceRoot":"","sources":["../../presets/swift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ import type { Rule } from '@nizos/probity';
2
+ /**
3
+ * Wraps `enforceAcceptanceLanguage` so the most common spec-layer
4
+ * write — a Kotlin test file gaining exactly one new `@Test` whose
5
+ * added lines only call vocabulary that already exists in the
6
+ * suite's DSL/Robot/driver files — passes deterministically, with no
7
+ * model call. Rationale: when two rule scopes overlap (the TDD rule's
8
+ * Kotlin fast-path plus this rule on `acceptance/**`), a single-test
9
+ * write otherwise still pays one AI call despite being advertised as
10
+ * free.
11
+ *
12
+ * The fast-path is conservative on three axes; failing any one falls
13
+ * through to the wrapped AI rule (it can only skip work, never
14
+ * block):
15
+ * 1. the write must add exactly one `@Test`;
16
+ * 2. no added line may contain mechanism vocabulary
17
+ * (backend/server/database/url/click/... — the deterministic
18
+ * screen errs broad);
19
+ * 3. every identifier the added lines call must already be declared
20
+ * in this file or a sibling `.kt` file in the same directory —
21
+ * a brand-new DSL step name is exactly what the validator should
22
+ * judge.
23
+ *
24
+ * Markdown/Gherkin spec writes never fast-path — prose is where the
25
+ * Language Test earns its keep.
26
+ */
27
+ export declare function withAcceptanceLanguageFastPath(rule: Rule): Rule;
28
+ /**
29
+ * AI-validated enforcement of the `acceptance-testing` skill's
30
+ * Language Test: executable specifications stay in domain language —
31
+ * no UI mechanics, protocols, or persistence details — assert a
32
+ * single outcome, and (when a glossary is supplied) use the
33
+ * ubiquitous language verbatim.
34
+ *
35
+ * Applies to: write actions. Scope it with a `{ files, rules }` block
36
+ * to the spec layer only (e.g. `specs/**`, `**\/*.feature`) — the DSL
37
+ * and protocol-driver layers are supposed to contain the mechanics
38
+ * this rule blocks, and every matching write costs an AI call.
39
+ *
40
+ * @param options.glossaryPath — absolute path to the project's
41
+ * ubiquitous-language glossary (see the `ubiquitous-language`
42
+ * skill). Resolve it in the config file, e.g.
43
+ * `fileURLToPath(new URL('./docs/GLOSSARY.md', import.meta.url))`.
44
+ * When set and readable, the glossary is included in the
45
+ * validator's prompt and vocabulary conflicts become violations.
46
+ * @param options.requireGlossaryEntry — strict vocabulary mode: when
47
+ * true (and a glossary is supplied and readable), a domain concept
48
+ * in spec content with no glossary entry becomes a violation —
49
+ * "the glossary conversation happens first" (ubiquitous-language
50
+ * skill). Default false: only conflicts with existing entries
51
+ * violate, so an empty or young glossary doesn't block everything.
52
+ * @param options.instructions — overrides or extends the default
53
+ * language rules text. Pass a string to replace it, or a function
54
+ * `(defaults) => ...` to extend it.
55
+ * @param options.maxGlossaryChars — truncate the glossary beyond this
56
+ * length when building the prompt (default 8000).
57
+ *
58
+ * @example
59
+ * { files: ['specs/**', 'acceptance/**', '**\/*.feature'], rules: [enforceAcceptanceLanguage()] }
60
+ */
61
+ export declare function enforceAcceptanceLanguage(options?: {
62
+ glossaryPath?: string;
63
+ requireGlossaryEntry?: boolean;
64
+ instructions?: string | ((defaults: string) => string);
65
+ maxGlossaryChars?: number;
66
+ }): Rule;
67
+ /**
68
+ * AI-validated enforcement of the `acceptance-testing` skill's
69
+ * controlled-precondition principle: a scenario's Given is established
70
+ * by the test (fixture, programmed stub, substituted port), never
71
+ * inherited from the ambient environment. Catches the two moves that
72
+ * silently hand a Given to the environment:
73
+ *
74
+ * 1. a driver method whose name states a precondition but whose body
75
+ * sets no fixture/stub/launch state (the no-op precondition
76
+ * driver), and
77
+ * 2. removing control fixtures because the scenario passes without
78
+ * them — the brownfield trap where the environment produces the
79
+ * sad path for free, and the deleted fixture leaves the success
80
+ * path unspecifiable.
81
+ *
82
+ * Applies to: write actions. Scope it with a `{ files, rules }` block
83
+ * to the driver and test-control layers (e.g.
84
+ * `AcceptanceTests/Drivers/**` plus the acceptance composition root) —
85
+ * the opposite scoping from `enforceAcceptanceLanguage`, which
86
+ * excludes those layers. Every matching write costs an AI call.
87
+ *
88
+ * @param options.instructions — overrides or extends the default
89
+ * precondition rules text. Pass a string to replace it, or a
90
+ * function `(defaults) => ...` to extend it.
91
+ */
92
+ export declare function enforceControlledPreconditions(options?: {
93
+ instructions?: string | ((defaults: string) => string);
94
+ }): Rule;
95
+ //# sourceMappingURL=acceptance-language.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acceptance-language.d.ts","sourceRoot":"","sources":["../../rules/acceptance-language.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAU,IAAI,EAA2B,MAAM,gBAAgB,CAAA;AA8Q3E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAmD/D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAA;CACrB,GACL,IAAI,CAyCN;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;CAClD,GACL,IAAI,CAiCN"}