@erclx/aitk 3.8.0 → 3.10.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.
@@ -14,6 +14,15 @@ import {
14
14
  mergeExtraRules,
15
15
  resolveRules,
16
16
  } from '@/gov/stacks'
17
+ import {
18
+ INSTRUCTIONS_REL,
19
+ type RestatedEntry,
20
+ type RestatedRefusal,
21
+ type RestatedReport,
22
+ readRestated,
23
+ SEED_REL,
24
+ SHIPPED_SKILLS_REL,
25
+ } from '@/gov/restated'
17
26
  import {
18
27
  readSuperseded,
19
28
  SUPERSEDED_MARKER,
@@ -68,6 +77,17 @@ interface SupersededOptions {
68
77
  readonly json?: boolean
69
78
  }
70
79
 
80
+ interface RestatedOptions {
81
+ readonly root?: string
82
+ readonly json?: boolean
83
+ }
84
+
85
+ /** What a reader does about each way the sweep produced no reading. */
86
+ const RESTATED_REFUSALS: Record<RestatedRefusal, string> = {
87
+ 'no-instructions': `No ${INSTRUCTIONS_REL} here, or it carries no bullet, so there is no instruction corpus to sweep.`,
88
+ 'no-surfaces': `Neither ${SEED_REL} nor ${SHIPPED_SKILLS_REL}/ is here, so no second surface exists to match against.`,
89
+ }
90
+
71
91
  export function register(program: Command): void {
72
92
  const gov = program
73
93
  .command('gov')
@@ -245,6 +265,146 @@ export function register(program: Command): void {
245
265
  process.exitCode = await runSuperseded(superseded, replacement, opts)
246
266
  },
247
267
  )
268
+
269
+ gov
270
+ .command('restated')
271
+ .description(
272
+ 'Report every instruction the always-loaded file states that a second surface states too',
273
+ )
274
+ .helpOption('-h, --help', 'Show this help message')
275
+ .option('--root <path>', 'Tree to read, defaulting to the cwd')
276
+ .option('--json', 'Add a machine-readable record on stdout')
277
+ .addHelpText(
278
+ 'after',
279
+ [
280
+ '',
281
+ `Matches every bullet in ${INSTRUCTIONS_REL} against ${SEED_REL}`,
282
+ `and every ${SHIPPED_SKILLS_REL}/*/SKILL.md body. Matching is recall-first,`,
283
+ 'keyed on distinctive tokens two statements share rather than on a phrase',
284
+ 'they spell the same way, because the case this exists for was one rule',
285
+ 'written three different ways.',
286
+ '',
287
+ 'What it separates:',
288
+ ' mirror a declared authoring-to-consumed pair, where repeating is the design',
289
+ ' repetition two surfaces state one rule and neither is declared a copy',
290
+ ' contradiction the prohibition falls on one surface alone, on a strong match',
291
+ '',
292
+ 'The contradiction class is a polarity reading rather than a judgment',
293
+ 'about meaning, so weigh each against the surfaces it names.',
294
+ '',
295
+ 'What it does not measure:',
296
+ ' a rule stated in two skill bodies and never in the always-loaded file,',
297
+ ' since the bullets there are the subjects and the bodies are searched',
298
+ '',
299
+ 'Exit codes:',
300
+ ' 0 no instruction is restated outside a declared mirror',
301
+ ' 1 refused, with the reason on stderr or in the JSON record',
302
+ ' 2 at least one instruction is restated outside a declared mirror',
303
+ '',
304
+ 'Examples:',
305
+ ' aitk gov restated',
306
+ ' aitk gov restated --json',
307
+ '',
308
+ ].join('\n'),
309
+ )
310
+ .action((opts: RestatedOptions) => {
311
+ process.exitCode = runRestated(opts)
312
+ })
313
+ }
314
+
315
+ /**
316
+ * Reports and never gates, matching the two sweeps above. A restatement is
317
+ * legitimate more often than not, so failing a push on one would fail on the
318
+ * ordinary case and teach contributors to route around the stage.
319
+ */
320
+ function runRestated(opts: RestatedOptions): number {
321
+ const root = resolve(opts.root ?? process.cwd())
322
+ const report = readRestated(root)
323
+ const emitJson = opts.json ?? false
324
+
325
+ if (report.kind === 'unreadable') {
326
+ intro('aitk gov restated')
327
+ logStep('Refused')
328
+ logWarn(RESTATED_REFUSALS[report.reason])
329
+ outro()
330
+
331
+ if (emitJson) {
332
+ process.stdout.write(
333
+ `${JSON.stringify({
334
+ root,
335
+ reason: report.reason,
336
+ message: RESTATED_REFUSALS[report.reason],
337
+ })}\n`,
338
+ )
339
+ }
340
+
341
+ return 1
342
+ }
343
+
344
+ reportRestated(report, root)
345
+
346
+ if (emitJson) {
347
+ process.stdout.write(`${JSON.stringify({ root, ...report })}\n`)
348
+ }
349
+
350
+ const findings = report.counts.contradictions + report.counts.repetitions
351
+ return findings > 0 ? 2 : 0
352
+ }
353
+
354
+ function describeEntry(entry: RestatedEntry): string[] {
355
+ const lines = [`${entry.subject.file}:${entry.subject.line}`]
356
+
357
+ for (const surface of entry.surfaces) {
358
+ lines.push(
359
+ ` [${surface.restatement}] ${surface.file}:${surface.line} via ${surface.anchors.join(', ')}`,
360
+ )
361
+ }
362
+
363
+ return lines
364
+ }
365
+
366
+ function reportRestated(
367
+ report: Extract<RestatedReport, { kind: 'measured' }>,
368
+ root: string,
369
+ ): void {
370
+ intro('aitk gov restated')
371
+
372
+ // A count of what matched reads as a verdict on the repository unless the run
373
+ // also says how wide the corpus behind it was.
374
+ logStep('Corpus')
375
+ logInfo(
376
+ `${report.corpus.instructions} instruction(s) against ${report.corpus.candidates} statement(s) from the seed and ${report.corpus.bodies} shipped body/bodies in ${root}`,
377
+ )
378
+ logInfo(
379
+ `matched on ${report.matcher.anchors} weighted anchor(s), dropping any token in more than ${report.matcher.common} statements`,
380
+ )
381
+
382
+ // Named rather than counted. A polarity split is the only class claiming a
383
+ // defect, and a reader weighing one has to reach both surfaces.
384
+ logStep(
385
+ report.counts.contradictions === 0 ? 'No contradiction' : 'Contradictions',
386
+ )
387
+ if (report.counts.contradictions === 0) {
388
+ logInfo('no restatement puts a prohibition on one surface alone')
389
+ } else {
390
+ for (const entry of report.restatements) {
391
+ const carries = entry.surfaces.some(
392
+ (surface) => surface.restatement === 'contradiction',
393
+ )
394
+ if (!carries) continue
395
+ for (const line of describeEntry(entry)) logWarn(line)
396
+ }
397
+ }
398
+
399
+ logStep('Restated')
400
+ logInfo(
401
+ `${report.counts.repetitions} repetition(s) outside a declared mirror, and ${report.counts.mirrors} on one`,
402
+ )
403
+ logInfo(
404
+ `${report.counts.threeSurface} instruction(s) reach three surfaces or more`,
405
+ )
406
+
407
+ outro()
248
408
  }
249
409
 
250
410
  /**