@prestack/thread 0.0.2 → 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 (183) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/dist/core/{asking.d.ts → answers.d.ts} +6 -14
  3. package/dist/core/{asking.js → answers.js} +13 -332
  4. package/dist/core/{asking.ts → answers.ts} +14 -357
  5. package/dist/core/attach.js +2 -2
  6. package/dist/core/attach.ts +2 -3
  7. package/dist/core/chain.js +4 -11
  8. package/dist/core/chain.ts +4 -3
  9. package/dist/core/client.d.ts +57 -0
  10. package/dist/core/client.js +186 -0
  11. package/dist/core/client.ts +227 -0
  12. package/dist/core/descend.d.ts +2 -0
  13. package/dist/core/descend.js +109 -16
  14. package/dist/core/descend.ts +120 -16
  15. package/dist/core/files.d.ts +45 -0
  16. package/dist/core/files.js +95 -0
  17. package/dist/core/files.ts +137 -0
  18. package/dist/core/init.d.ts +1 -0
  19. package/dist/core/init.js +10 -2
  20. package/dist/core/init.ts +8 -2
  21. package/dist/core/invoked.js +1 -1
  22. package/dist/core/invoked.ts +1 -1
  23. package/dist/core/rows.d.ts +2 -0
  24. package/dist/core/rows.js +65 -0
  25. package/dist/core/rows.ts +58 -0
  26. package/dist/core/tree.js +1 -1
  27. package/dist/core/tree.ts +1 -1
  28. package/dist/derivation/attach.js +0 -12
  29. package/dist/derivation/attach.ts +0 -12
  30. package/dist/derivation/generators/build.js +8 -7
  31. package/dist/derivation/generators/build.ts +8 -7
  32. package/dist/derivation/generators/release.d.ts +1 -1
  33. package/dist/derivation/generators/release.js +15 -23
  34. package/dist/derivation/generators/release.ts +15 -15
  35. package/dist/integrations/attach.js +1 -19
  36. package/dist/integrations/attach.ts +1 -19
  37. package/dist/integrations/generators/read.js +2 -2
  38. package/dist/integrations/generators/read.ts +4 -4
  39. package/dist/integrations/generators/vault.js +4 -12
  40. package/dist/integrations/generators/vault.ts +4 -4
  41. package/dist/integrations/module.js +5 -3
  42. package/dist/integrations/module.ts +5 -3
  43. package/dist/integrations/vault.js +5 -5
  44. package/dist/integrations/vault.ts +5 -5
  45. package/dist/integrity/attach.js +0 -12
  46. package/dist/integrity/attach.ts +0 -12
  47. package/dist/integrity/check-threads.js +1 -1
  48. package/dist/integrity/check-threads.ts +1 -1
  49. package/dist/integrity/constraint.d.ts +11 -2
  50. package/dist/integrity/constraint.js +163 -20
  51. package/dist/integrity/constraint.ts +174 -22
  52. package/dist/integrity/generators/compiler.js +1 -1
  53. package/dist/integrity/generators/compiler.ts +1 -1
  54. package/dist/integrity/generators/gate.js +8 -16
  55. package/dist/integrity/generators/gate.ts +8 -7
  56. package/dist/integrity/generators/publish.js +14 -26
  57. package/dist/integrity/generators/publish.ts +14 -17
  58. package/dist/integrity/generators/trial.d.ts +2 -2
  59. package/dist/integrity/generators/trial.js +108 -50
  60. package/dist/integrity/generators/trial.ts +107 -48
  61. package/dist/integrity/lint.js +3 -3
  62. package/dist/integrity/lint.ts +3 -3
  63. package/dist/integrity/lsp/diagnostics.js +1 -1
  64. package/dist/integrity/lsp/diagnostics.ts +1 -1
  65. package/dist/integrity/lsp/lint.js +1 -1
  66. package/dist/integrity/lsp/lint.ts +1 -1
  67. package/dist/integrity/slopnator.d.ts +1 -14
  68. package/dist/integrity/slopnator.js +8 -40
  69. package/dist/integrity/slopnator.ts +9 -51
  70. package/dist/integrity/slopnators/sl_broken_lineage.js +4 -2
  71. package/dist/integrity/slopnators/sl_broken_lineage.ts +4 -2
  72. package/dist/integrity/slopnators/sl_declared_elsewhere.js +24 -3
  73. package/dist/integrity/slopnators/sl_declared_elsewhere.ts +24 -3
  74. package/dist/integrity/slopnators/sl_derived_drift.js +10 -4
  75. package/dist/integrity/slopnators/sl_derived_drift.ts +10 -4
  76. package/dist/integrity/slopnators/sl_inert_island.js +7 -13
  77. package/dist/integrity/slopnators/sl_inert_island.ts +7 -16
  78. package/dist/integrity/slopnators/sl_inert_slopnator.js +8 -8
  79. package/dist/integrity/slopnators/sl_inert_slopnator.ts +8 -8
  80. package/dist/integrity/slopnators/sl_missing_row.js +14 -9
  81. package/dist/integrity/slopnators/sl_missing_row.ts +14 -10
  82. package/dist/integrity/slopnators/sl_no_child_process.js +8 -8
  83. package/dist/integrity/slopnators/sl_no_child_process.ts +8 -8
  84. package/dist/integrity/slopnators/sl_no_import_cycle.js +1 -1
  85. package/dist/integrity/slopnators/sl_no_import_cycle.ts +1 -1
  86. package/dist/integrity/slopnators/sl_no_such_command.js +20 -5
  87. package/dist/integrity/slopnators/sl_no_such_command.ts +22 -5
  88. package/dist/integrity/slopnators/sl_only_takes_a_literal.js +8 -8
  89. package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +8 -8
  90. package/dist/integrity/slopnators/sl_stale_path.js +91 -18
  91. package/dist/integrity/slopnators/sl_stale_path.ts +97 -18
  92. package/dist/integrity/slopnators/sl_twice_meant.js +25 -2
  93. package/dist/integrity/slopnators/sl_twice_meant.ts +28 -2
  94. package/dist/integrity/slopnators/sl_twice_parented.js +26 -5
  95. package/dist/integrity/slopnators/sl_twice_parented.ts +26 -5
  96. package/dist/integrity/slopnators/sl_undeclared_node.js +18 -2
  97. package/dist/integrity/slopnators/sl_undeclared_node.ts +18 -2
  98. package/dist/integrity/slopnators/sl_undeclared_operation.js +3 -1
  99. package/dist/integrity/slopnators/sl_undeclared_operation.ts +3 -1
  100. package/dist/integrity/slopnators/sl_undeclared_variant.js +6 -2
  101. package/dist/integrity/slopnators/sl_undeclared_variant.ts +6 -2
  102. package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -4
  103. package/dist/integrity/slopnators/sl_ungoverned_island.ts +3 -4
  104. package/dist/integrity/slopnators/sl_unkept_rows.js +1 -1
  105. package/dist/integrity/slopnators/sl_unkept_rows.ts +1 -1
  106. package/dist/integrity/slopnators/sl_unpaired_member.js +13 -8
  107. package/dist/integrity/slopnators/sl_unpaired_member.ts +16 -8
  108. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +16 -3
  109. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +16 -3
  110. package/dist/integrity/slopnators/sl_unthreaded.d.ts +1 -0
  111. package/dist/integrity/slopnators/sl_unthreaded.js +18 -10
  112. package/dist/integrity/slopnators/sl_unthreaded.ts +19 -11
  113. package/dist/integrity/slopnators/sl_untranslated_key.js +1 -1
  114. package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -1
  115. package/dist/integrity/slopnators/sl_unversioned.js +16 -2
  116. package/dist/integrity/slopnators/sl_unversioned.ts +16 -2
  117. package/dist/integrity/sweep.js +17 -3
  118. package/dist/integrity/sweep.ts +20 -3
  119. package/dist/knowledge/attach.js +0 -6
  120. package/dist/knowledge/attach.ts +0 -6
  121. package/dist/knowledge/generators/docsgen.js +12 -3
  122. package/dist/knowledge/generators/docsgen.ts +12 -2
  123. package/dist/knowledge/generators/glossary.js +1 -1
  124. package/dist/knowledge/generators/glossary.ts +1 -1
  125. package/dist/operations/attach.js +2 -26
  126. package/dist/operations/attach.ts +2 -27
  127. package/dist/operations/dispatch.js +2 -3
  128. package/dist/operations/dispatch.ts +2 -3
  129. package/dist/operations/generators/capability.js +4 -7
  130. package/dist/operations/generators/capability.ts +3 -6
  131. package/dist/operations/generators/compile.js +8 -13
  132. package/dist/operations/generators/compile.ts +8 -4
  133. package/dist/operations/generators/permits.js +4 -13
  134. package/dist/operations/generators/permits.ts +3 -3
  135. package/dist/operations/generators/seed.js +5 -2
  136. package/dist/operations/generators/seed.ts +6 -2
  137. package/dist/operations/generators/trial.js +10 -10
  138. package/dist/operations/generators/trial.ts +10 -10
  139. package/dist/operations/http.js +4 -1
  140. package/dist/operations/http.ts +6 -1
  141. package/package.json +2 -2
  142. package/dist/core/cli.d.ts +0 -2
  143. package/dist/core/cli.js +0 -1761
  144. package/dist/core/cli.ts +0 -2004
  145. package/dist/core/generators/meta.d.ts +0 -2
  146. package/dist/core/generators/meta.js +0 -829
  147. package/dist/core/generators/meta.ts +0 -1006
  148. package/dist/derivation/generators/derivation.d.ts +0 -3
  149. package/dist/derivation/generators/derivation.js +0 -273
  150. package/dist/derivation/generators/derivation.ts +0 -347
  151. package/dist/derivation/makers/release.d.ts +0 -1
  152. package/dist/derivation/makers/release.js +0 -107
  153. package/dist/derivation/makers/release.ts +0 -135
  154. package/dist/integrations/generators/secret.d.ts +0 -1
  155. package/dist/integrations/generators/secret.js +0 -233
  156. package/dist/integrations/generators/secret.ts +0 -289
  157. package/dist/integrations/generators/target.d.ts +0 -1
  158. package/dist/integrations/generators/target.js +0 -775
  159. package/dist/integrations/generators/target.ts +0 -944
  160. package/dist/integrity/generators/rule.d.ts +0 -2
  161. package/dist/integrity/generators/rule.js +0 -213
  162. package/dist/integrity/generators/rule.ts +0 -271
  163. package/dist/integrity/generators/seal.d.ts +0 -4
  164. package/dist/integrity/generators/seal.js +0 -101
  165. package/dist/integrity/generators/seal.ts +0 -117
  166. package/dist/integrity/sealed.d.ts +0 -1
  167. package/dist/integrity/sealed.js +0 -56
  168. package/dist/integrity/sealed.ts +0 -56
  169. package/dist/knowledge/generators/skills.d.ts +0 -1
  170. package/dist/knowledge/generators/skills.js +0 -222
  171. package/dist/knowledge/generators/skills.ts +0 -263
  172. package/dist/operations/generators/grant.d.ts +0 -1
  173. package/dist/operations/generators/grant.js +0 -267
  174. package/dist/operations/generators/grant.ts +0 -336
  175. package/dist/operations/generators/operation.d.ts +0 -1
  176. package/dist/operations/generators/operation.js +0 -811
  177. package/dist/operations/generators/operation.ts +0 -972
  178. package/dist/operations/makers/capability.d.ts +0 -1
  179. package/dist/operations/makers/capability.js +0 -117
  180. package/dist/operations/makers/capability.ts +0 -166
  181. package/dist/operations/makers/trial.d.ts +0 -1
  182. package/dist/operations/makers/trial.js +0 -413
  183. package/dist/operations/makers/trial.ts +0 -520
@@ -1,6 +1,7 @@
1
- import { existsSync, readFileSync, readdirSync } from 'node:fs'
1
+ import { existsSync, readFileSync, readdirSync } from '../../core/files.ts'
2
2
  import { resolve } from 'node:path'
3
3
 
4
+ import type { Sourced } from '../constraint.ts'
4
5
  import type { Slopnator } from '../slopnator.ts'
5
6
  import { foldersGoverned, here, islandsDeclared, rowsIn, type Declared } from './sl_unthreaded.ts'
6
7
  import { findTree } from '../../core/tree.ts'
@@ -60,6 +61,15 @@ function declaredNames(one: Seeding): readonly string[] {
60
61
  }
61
62
  }
62
63
 
64
+ const ISLAND: readonly Sourced[] = [
65
+ {
66
+ at: 'threads/thread.ts',
67
+ source:
68
+ "export const THREAD: Threaded = {\n declares: [\n { id: 'operations', at: 'src/islands/operations.ts', governs: ['operations/'] },\n { id: 'operation', at: 'threads/operations.ts' },\n ],\n}\n",
69
+ },
70
+ { at: 'src/islands/operations.ts', source: 'export const OperationsIslandSchema = {}\n' },
71
+ ]
72
+
63
73
  export const slopnator: Slopnator = {
64
74
  holds: (_node, at) => {
65
75
  const path = here(at.filename)
@@ -105,25 +115,23 @@ export const slopnator: Slopnator = {
105
115
  wrong: [
106
116
  {
107
117
  files: [
108
- {
109
- at: 'threads/_member_probe.ts',
110
- source: "export const OPERATIONS: readonly Member[] = [\n {\n id: 'wf_unseeded_probe',\n at: 'threads/operations.ts',\n },\n]\n",
111
- },
118
+ ...ISLAND,
119
+ { at: 'threads/_member_probe.ts', source: "export const OPERATIONS: readonly Threaded[] = [\n {\n id: 'wf_unseeded_probe',\n },\n]\n" },
112
120
  ],
113
121
  at: 'threads/_member_probe.ts',
114
122
  },
115
123
  {
116
- files: [{ at: 'operations/wf_undeclared_probe.ts', source: 'export const operation = { id: 1 }\n' }],
124
+ files: [...ISLAND, { at: 'operations/wf_undeclared_probe.ts', source: 'export const operation = { id: 1 }\n' }],
117
125
  at: 'operations/wf_undeclared_probe.ts',
118
126
  },
119
127
  ],
120
128
  right: [
121
129
  {
122
- files: [{ at: 'threads/_member_probe.ts', source: 'export const OPERATIONS: readonly Member[] = []\n' }],
130
+ files: [...ISLAND, { at: 'threads/_member_probe.ts', source: 'export const OPERATIONS: readonly Threaded[] = []\n' }],
123
131
  at: 'threads/_member_probe.ts',
124
132
  },
125
133
  {
126
- files: [{ at: 'threads/_member_quiet.ts', source: 'export const NOTHING = []\n' }],
134
+ files: [...ISLAND, { at: 'threads/_member_quiet.ts', source: 'export const NOTHING = []\n' }],
127
135
  at: 'threads/_member_quiet.ts',
128
136
  },
129
137
  ],
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync } from 'node:fs';
1
+ import { existsSync, readFileSync } from "../../core/files.js";
2
2
  import { join, resolve } from 'node:path';
3
3
  import { SEEDED, SHIPPED, slopnatorName } from "../slopnator.js";
4
4
  import { here } from "./sl_unthreaded.js";
@@ -48,8 +48,21 @@ export const slopnator = {
48
48
  },
49
49
  ],
50
50
  right: [
51
- "const CONSTRAINTS = [\n {\n id: 'no-comment',\n },\n]",
52
- "const CONSTRAINTS = [\n {\n id: 'no-comment',\n },\n {\n id: 'unthreaded',\n },\n]",
51
+ {
52
+ files: [
53
+ { at: 'threads/_probe_paired.ts', source: "const CONSTRAINTS = [\n {\n id: 'no-comment',\n },\n]\n" },
54
+ { at: 'threads/slopnators/sl_no_comment.ts', source: 'export const slopnator = { on: [], holds: () => false }\n' },
55
+ ],
56
+ at: 'threads/_probe_paired.ts',
57
+ },
58
+ {
59
+ files: [
60
+ { at: 'threads/_probe_paired.ts', source: "const CONSTRAINTS = [\n {\n id: 'no-comment',\n },\n {\n id: 'unthreaded',\n },\n]\n" },
61
+ { at: 'threads/slopnators/sl_no_comment.ts', source: 'export const slopnator = { on: [], holds: () => false }\n' },
62
+ { at: 'threads/slopnators/sl_unthreaded.ts', source: 'export const slopnator = { on: [], holds: () => false }\n' },
63
+ ],
64
+ at: 'threads/_probe_paired.ts',
65
+ },
53
66
  'export const PLAIN = 1',
54
67
  {
55
68
  files: [{ at: 'threads/slopnators/not_a_walk.ts', source: 'export const HELPER = 1\n' }],
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync } from '../../core/files.ts'
2
2
  import { join, resolve } from 'node:path'
3
3
 
4
4
  import { SEEDED, SHIPPED, slopnatorName, type Slopnator } from '../slopnator.ts'
@@ -46,8 +46,21 @@ export const slopnator: Slopnator = {
46
46
  },
47
47
  ],
48
48
  right: [
49
- "const CONSTRAINTS = [\n {\n id: 'no-comment',\n },\n]",
50
- "const CONSTRAINTS = [\n {\n id: 'no-comment',\n },\n {\n id: 'unthreaded',\n },\n]",
49
+ {
50
+ files: [
51
+ { at: 'threads/_probe_paired.ts', source: "const CONSTRAINTS = [\n {\n id: 'no-comment',\n },\n]\n" },
52
+ { at: 'threads/slopnators/sl_no_comment.ts', source: 'export const slopnator = { on: [], holds: () => false }\n' },
53
+ ],
54
+ at: 'threads/_probe_paired.ts',
55
+ },
56
+ {
57
+ files: [
58
+ { at: 'threads/_probe_paired.ts', source: "const CONSTRAINTS = [\n {\n id: 'no-comment',\n },\n {\n id: 'unthreaded',\n },\n]\n" },
59
+ { at: 'threads/slopnators/sl_no_comment.ts', source: 'export const slopnator = { on: [], holds: () => false }\n' },
60
+ { at: 'threads/slopnators/sl_unthreaded.ts', source: 'export const slopnator = { on: [], holds: () => false }\n' },
61
+ ],
62
+ at: 'threads/_probe_paired.ts',
63
+ },
51
64
  'export const PLAIN = 1',
52
65
  {
53
66
  files: [{ at: 'threads/slopnators/not_a_walk.ts', source: 'export const HELPER = 1\n' }],
@@ -39,6 +39,7 @@ export interface Declared {
39
39
  readonly tree?: string;
40
40
  readonly member?: string;
41
41
  }
42
+ export declare const canonical: (at: string) => string;
42
43
  export declare function islandsDeclared(): readonly Declared[];
43
44
  export declare const declaresIsland: (text: string) => string | undefined;
44
45
  export declare function meaningsIn(text: string): readonly Meaning[];
@@ -1,12 +1,12 @@
1
1
  import { parser } from 'typescript-eslint';
2
- import { descend, forget as forgetDescent, read, reached as fromThread, threading } from "../../core/descend.js";
2
+ import { LISTS as LINEAGE, descend, forget as forgetDescent, read, reached as fromThread, threading } from "../../core/descend.js";
3
3
  import { findTree } from "../../core/tree.js";
4
4
  const TREE_AT = findTree();
5
5
  const ROOT = `${TREE_AT.at.split('\\').join('/')}/`;
6
6
  const TREE = TREE_AT.name;
7
7
  const THREAD_AT = `${TREE_AT.name}/thread.ts`;
8
8
  const FOLLOWABLE = /\.(ts|tsx|mts|cts|mjs|cjs|js)$/;
9
- const LISTS = new Set(['declares', 'derives', 'seeds']);
9
+ const LISTS = new Set(LINEAGE);
10
10
  let threaders;
11
11
  let tree;
12
12
  const parsed = new Map();
@@ -164,6 +164,7 @@ export function governs(all, path) {
164
164
  return rest !== undefined && tail.every((part) => rest.includes(part));
165
165
  });
166
166
  }
167
+ export const canonical = (at) => at.replace(/^threads\//, `${TREE}/`);
167
168
  export function islandsDeclared() {
168
169
  const found = [];
169
170
  const seen = new Set();
@@ -177,17 +178,20 @@ export function islandsDeclared() {
177
178
  all.push(...reaching(held));
178
179
  }
179
180
  for (const row of all) {
180
- if (row.id === undefined || row.at === undefined || seen.has(row.at))
181
+ if (row.id === undefined || row.at === undefined)
181
182
  continue;
182
- const source = read(row.at);
183
+ const at = canonical(row.at);
184
+ if (seen.has(at))
185
+ continue;
186
+ const source = read(at);
183
187
  if (source === undefined || !SCHEMA.test(source))
184
188
  continue;
185
- seen.add(row.at);
189
+ seen.add(at);
186
190
  const tree = `${TREE}/${row.id}.ts`;
187
- const named = all.find((one) => one.at === tree)?.id;
191
+ const named = all.find((one) => one.at !== undefined && canonical(one.at) === tree)?.id;
188
192
  found.push({
189
193
  id: row.id,
190
- at: row.at,
194
+ at,
191
195
  describes: row.describes ?? '',
192
196
  governs: row.governs ?? [],
193
197
  define: DEFINE.exec(source)?.[1],
@@ -334,15 +338,19 @@ export const slopnator = {
334
338
  "export const HELD: Threaded = {\n declares: [\n {\n at: 'threads/probe.tsx',\n },\n ],\n}",
335
339
  {
336
340
  files: [
337
- { at: 'threads/_names_it.ts', source: "export const OWNER: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_child.ts',\n },\n ],\n}\n" },
341
+ { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
342
+ { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_names_it.ts',\n },\n ],\n}\n" },
343
+ { at: 'threads/_names_it.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const OWNER: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_child.ts',\n },\n ],\n}\n" },
338
344
  { at: 'scripts/_probe_child.ts', source: 'export const CHILD = 1\n' },
339
345
  ],
340
346
  at: 'scripts/_probe_child.ts',
341
347
  },
342
348
  {
343
349
  files: [
344
- { at: 'threads/_names_it.ts', source: "export const OWNER: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_parent.ts',\n },\n ],\n}\n" },
345
- { at: 'scripts/_probe_parent.ts', source: "export const MID: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_leaf.ts',\n },\n ],\n}\n" },
350
+ { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
351
+ { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_names_it.ts',\n },\n ],\n}\n" },
352
+ { at: 'threads/_names_it.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const OWNER: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_parent.ts',\n },\n ],\n}\n" },
353
+ { at: 'scripts/_probe_parent.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const MID: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_leaf.ts',\n },\n ],\n}\n" },
346
354
  { at: 'scripts/_probe_leaf.ts', source: 'export const LEAF = 1\n' },
347
355
  ],
348
356
  at: 'scripts/_probe_leaf.ts',
@@ -1,11 +1,11 @@
1
- import { readFileSync } from 'node:fs'
1
+ import { readFileSync } from '../../core/files.ts'
2
2
  import { resolve } from 'node:path'
3
3
 
4
4
  import { parser } from 'typescript-eslint'
5
5
 
6
6
  import type { Slopnator } from '../slopnator.ts'
7
7
 
8
- import { descend, forget as forgetDescent, read, reached as fromThread, threading } from '../../core/descend.ts'
8
+ import { LISTS as LINEAGE, descend, forget as forgetDescent, read, reached as fromThread, threading } from '../../core/descend.ts'
9
9
  import { findTree } from '../../core/tree.ts'
10
10
 
11
11
  const TREE_AT = findTree()
@@ -13,7 +13,7 @@ const ROOT = `${TREE_AT.at.split('\\').join('/')}/`
13
13
  const TREE = TREE_AT.name
14
14
  const THREAD_AT = `${TREE_AT.name}/thread.ts`
15
15
  const FOLLOWABLE = /\.(ts|tsx|mts|cts|mjs|cjs|js)$/
16
- const LISTS = new Set(['declares', 'derives', 'seeds'])
16
+ const LISTS: ReadonlySet<string> = new Set(LINEAGE)
17
17
 
18
18
  let threaders: ReadonlySet<string> | undefined
19
19
  let tree: Index | undefined
@@ -221,6 +221,8 @@ export interface Declared {
221
221
  readonly member?: string
222
222
  }
223
223
 
224
+ export const canonical = (at: string): string => at.replace(/^threads\//, `${TREE}/`)
225
+
224
226
  export function islandsDeclared(): readonly Declared[] {
225
227
  const found: Declared[] = []
226
228
  const seen = new Set<string>()
@@ -234,17 +236,19 @@ export function islandsDeclared(): readonly Declared[] {
234
236
  }
235
237
 
236
238
  for (const row of all) {
237
- if (row.id === undefined || row.at === undefined || seen.has(row.at)) continue
238
- const source = read(row.at)
239
+ if (row.id === undefined || row.at === undefined) continue
240
+ const at = canonical(row.at)
241
+ if (seen.has(at)) continue
242
+ const source = read(at)
239
243
  if (source === undefined || !SCHEMA.test(source)) continue
240
- seen.add(row.at)
244
+ seen.add(at)
241
245
 
242
246
  const tree = `${TREE}/${row.id}.ts`
243
- const named = all.find((one) => one.at === tree)?.id
247
+ const named = all.find((one) => one.at !== undefined && canonical(one.at) === tree)?.id
244
248
 
245
249
  found.push({
246
250
  id: row.id,
247
- at: row.at,
251
+ at,
248
252
  describes: row.describes ?? '',
249
253
  governs: row.governs ?? [],
250
254
  define: DEFINE.exec(source)?.[1],
@@ -401,15 +405,19 @@ export const slopnator: Slopnator = {
401
405
  "export const HELD: Threaded = {\n declares: [\n {\n at: 'threads/probe.tsx',\n },\n ],\n}",
402
406
  {
403
407
  files: [
404
- { at: 'threads/_names_it.ts', source: "export const OWNER: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_child.ts',\n },\n ],\n}\n" },
408
+ { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
409
+ { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_names_it.ts',\n },\n ],\n}\n" },
410
+ { at: 'threads/_names_it.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const OWNER: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_child.ts',\n },\n ],\n}\n" },
405
411
  { at: 'scripts/_probe_child.ts', source: 'export const CHILD = 1\n' },
406
412
  ],
407
413
  at: 'scripts/_probe_child.ts',
408
414
  },
409
415
  {
410
416
  files: [
411
- { at: 'threads/_names_it.ts', source: "export const OWNER: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_parent.ts',\n },\n ],\n}\n" },
412
- { at: 'scripts/_probe_parent.ts', source: "export const MID: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_leaf.ts',\n },\n ],\n}\n" },
417
+ { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
418
+ { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_names_it.ts',\n },\n ],\n}\n" },
419
+ { at: 'threads/_names_it.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const OWNER: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_parent.ts',\n },\n ],\n}\n" },
420
+ { at: 'scripts/_probe_parent.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const MID: Threaded = {\n declares: [\n {\n at: 'scripts/_probe_leaf.ts',\n },\n ],\n}\n" },
413
421
  { at: 'scripts/_probe_leaf.ts', source: 'export const LEAF = 1\n' },
414
422
  ],
415
423
  at: 'scripts/_probe_leaf.ts',
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, readdirSync } from 'node:fs';
1
+ import { existsSync, readFileSync, readdirSync } from "../../core/files.js";
2
2
  import { join } from 'node:path';
3
3
  import { named as packageOf } from "../../core/scope.js";
4
4
  /*
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, readdirSync } from 'node:fs'
1
+ import { existsSync, readFileSync, readdirSync } from '../../core/files.ts'
2
2
  import { join } from 'node:path'
3
3
 
4
4
  import type { Slopnator } from '../slopnator.ts'
@@ -21,10 +21,24 @@ export const slopnator = {
21
21
  },
22
22
  proves: {
23
23
  wrong: [
24
- "export const L: Constraint = {\n id: 'a-law',\n at: 'packages/core/integrity/src/constraint.ts',\n describes: 'A rule that must be enforced.',\n}",
24
+ {
25
+ files: [
26
+ { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
27
+ { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_unversioned_probe.ts',\n },\n ],\n}\n" },
28
+ { at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: 'packages/core/integrity/src/constraint.ts',\n describes: 'A rule that must be enforced.',\n}\n" },
29
+ ],
30
+ at: 'threads/_unversioned_probe.ts',
31
+ },
25
32
  ],
26
33
  right: [
27
- "export const L: Constraint = {\n id: 'a-law',\n at: 'packages/core/integrity/src/constraint.ts',\n describes: 'A rule that must be enforced.',\n version: 3,\n}",
34
+ {
35
+ files: [
36
+ { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
37
+ { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_unversioned_probe.ts',\n },\n ],\n}\n" },
38
+ { at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: 'packages/core/integrity/src/constraint.ts',\n describes: 'A rule that must be enforced.',\n version: 3,\n}\n" },
39
+ ],
40
+ at: 'threads/_unversioned_probe.ts',
41
+ },
28
42
  "export const HELPER = {\n id: 'a-helper',\n at: 'threads/meta.ts',\n describes: 'Nothing conforms to this.',\n}",
29
43
  ],
30
44
  },
@@ -26,10 +26,24 @@ export const slopnator: Slopnator = {
26
26
  },
27
27
  proves: {
28
28
  wrong: [
29
- "export const L: Constraint = {\n id: 'a-law',\n at: 'packages/core/integrity/src/constraint.ts',\n describes: 'A rule that must be enforced.',\n}",
29
+ {
30
+ files: [
31
+ { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
32
+ { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_unversioned_probe.ts',\n },\n ],\n}\n" },
33
+ { at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: 'packages/core/integrity/src/constraint.ts',\n describes: 'A rule that must be enforced.',\n}\n" },
34
+ ],
35
+ at: 'threads/_unversioned_probe.ts',
36
+ },
30
37
  ],
31
38
  right: [
32
- "export const L: Constraint = {\n id: 'a-law',\n at: 'packages/core/integrity/src/constraint.ts',\n describes: 'A rule that must be enforced.',\n version: 3,\n}",
39
+ {
40
+ files: [
41
+ { at: 'thread/core/thread.ts', source: "export interface Threaded {\n readonly id?: string\n readonly at?: string\n readonly describes?: string\n readonly declares?: readonly Threaded[]\n readonly derives?: readonly Threaded[]\n readonly seeds?: readonly Threaded[]\n}\n" },
42
+ { at: 'threads/thread.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const THREAD: Threaded = {\n declares: [\n {\n at: 'threads/_unversioned_probe.ts',\n },\n ],\n}\n" },
43
+ { at: 'threads/_unversioned_probe.ts', source: "import type { Threaded } from '../thread/core/thread.ts'\n\nexport const L: Threaded = {\n id: 'a-law',\n at: 'packages/core/integrity/src/constraint.ts',\n describes: 'A rule that must be enforced.',\n version: 3,\n}\n" },
44
+ ],
45
+ at: 'threads/_unversioned_probe.ts',
46
+ },
33
47
  "export const HELPER = {\n id: 'a-helper',\n at: 'threads/meta.ts',\n describes: 'Nothing conforms to this.',\n}",
34
48
  ],
35
49
  },
@@ -1,5 +1,5 @@
1
1
  import { execFileSync } from 'node:child_process';
2
- import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
+ import { attached, existsSync, readFileSync, readdirSync } from "../core/files.js";
3
3
  import { join } from 'node:path';
4
4
  import { stdout } from 'node:process';
5
5
  import { descend } from "../core/descend.js";
@@ -8,6 +8,7 @@ import { exit, invoked } from "../core/invoked.js";
8
8
  import { parser } from 'typescript-eslint';
9
9
  import { CONSTRAINTS } from "./constraint.js";
10
10
  import { NOT_WRITTEN, ROOT, governs, load, reads, rules, slopnatorName, sweeps, visits } from "./slopnator.js";
11
+ import { deriveTrials, runTrials } from "./generators/trial.js";
11
12
  const PARSEABLE = /\.(ts|tsx|mts|cts|mjs|cjs|js|jsx)$/;
12
13
  function tree(text) {
13
14
  const read = (jsx) => parser.parseForESLint(text, {
@@ -89,7 +90,7 @@ export function tracked(root) {
89
90
  })
90
91
  .split('\n')
91
92
  .filter(Boolean);
92
- if (listed.length > 0) {
93
+ if (!attached() && listed.length > 0) {
93
94
  return [...new Set(listed)].filter((one) => existsSync(join(root, one)) && mine(one)).sort();
94
95
  }
95
96
  }
@@ -219,6 +220,15 @@ if (invoked(import.meta.url)) {
219
220
  const slopnators = await load(ROOT, governing);
220
221
  const named = new Map(governing.map((rule) => [rule.id, rule]));
221
222
  const run = sweep(ROOT, governing, slopnators, tracked(ROOT));
223
+ const { default: plugin } = await import("./lint.js");
224
+ const proving = runTrials(deriveTrials(governing, slopnators).trials, governing, plugin.rules, parser, slopnators);
225
+ const unproven = proving.outcomes.filter((one) => !one.passed);
226
+ const failing = new Map();
227
+ for (const one of unproven) {
228
+ const held = failing.get(one.rule) ?? [];
229
+ held.push(` ${one.failures.join('; ')}`);
230
+ failing.set(one.rule, held);
231
+ }
222
232
  const warned = new Set();
223
233
  const grouped = new Map();
224
234
  const files = new Map();
@@ -244,6 +254,10 @@ if (invoked(import.meta.url)) {
244
254
  ...(rule?.severity === 'warning' ? { severity: 'warning' } : {}),
245
255
  };
246
256
  }),
257
+ ...[...failing.entries()].map(([id, why]) => ({
258
+ detail: `${id} — ${String(why.length)} of its own trial(s) did not pass:\n${[...new Set(why)].sort().join('\n')}`,
259
+ instead: 'make the rule refuse the `wrong` it declares and accept the `right`, or correct the pair — a rule that has never fired on its own example is a rule nobody has seen work',
260
+ })),
247
261
  ...run.unrun.map((rule) => ({
248
262
  detail: `${rule} DID NOT RUN — no slopnator is on disk for it, so this sweep measured nothing for that rule and a green result here says nothing about it`,
249
263
  instead: 'write the walk the rule names, or delete the rule and its row together — half a rule reads as a whole one from every direction',
@@ -251,7 +265,7 @@ if (invoked(import.meta.url)) {
251
265
  ];
252
266
  runChecker('sweep', findings, `each naming one rule and the files it refuses — ${String(run.findings.length)} refusal(s) across ${String(refused.size)} file(s), ` +
253
267
  `over ${String(run.rules)} rule(s) run across ${String(run.swept)} of ${String(run.tracked)} file(s) in this tree, ` +
254
- `${String(run.linted.length)} of them reading a syntax tree` +
268
+ `${String(run.linted.length)} of them reading a syntax tree, and ${String(proving.passed)} of ${String(proving.outcomes.length)} rule trial(s) passed, ${String(proving.measured)} measured` +
255
269
  `${run.unrun.length === 0 ? '' : `, ${String(run.unrun.length)} that DID NOT RUN AT ALL`}` +
256
270
  `${run.unmet.length === 0 ? '' : `, and ${String(run.unmet.length)} that governed no file here and so measured nothing: ${run.unmet.join(', ')}`}`);
257
271
  const forbidding = findings.length - run.findings.filter((one) => named.get(one.rule)?.severity === 'warning').length;
@@ -1,5 +1,5 @@
1
1
  import { execFileSync } from 'node:child_process'
2
- import { existsSync, readFileSync, readdirSync } from 'node:fs'
2
+ import { attached, existsSync, readFileSync, readdirSync } from '../core/files.ts'
3
3
  import { join } from 'node:path'
4
4
  import { stdout } from 'node:process'
5
5
  import { pathToFileURL } from 'node:url'
@@ -13,6 +13,7 @@ import { parser } from 'typescript-eslint'
13
13
  import { CONSTRAINTS, type Constraint } from './constraint.ts'
14
14
  import { NOT_WRITTEN, ROOT, governs, load, reads, rules, slopnatorName, sweeps, visits, type Reading, type Slopnator, type Spoken, type Visiting } from './slopnator.ts'
15
15
  import { ruleMessage } from './lint.ts'
16
+ import { deriveTrials, runTrials } from './generators/trial.ts'
16
17
 
17
18
  const PARSEABLE = /\.(ts|tsx|mts|cts|mjs|cjs|js|jsx)$/
18
19
 
@@ -108,7 +109,7 @@ export function tracked(root: string): readonly string[] {
108
109
  })
109
110
  .split('\n')
110
111
  .filter(Boolean)
111
- if (listed.length > 0) {
112
+ if (!attached() && listed.length > 0) {
112
113
  return [...new Set(listed)].filter((one) => existsSync(join(root, one)) && mine(one)).sort()
113
114
  }
114
115
  } catch {
@@ -258,6 +259,17 @@ if (invoked(import.meta.url)) {
258
259
  const named = new Map(governing.map((rule) => [rule.id, rule]))
259
260
  const run = sweep(ROOT, governing, slopnators, tracked(ROOT))
260
261
 
262
+ const { default: plugin } = await import('./lint.ts')
263
+ const proving = runTrials(deriveTrials(governing, slopnators).trials, governing, plugin.rules, parser, slopnators)
264
+ const unproven = proving.outcomes.filter((one) => !one.passed)
265
+
266
+ const failing = new Map<string, string[]>()
267
+ for (const one of unproven) {
268
+ const held = failing.get(one.rule) ?? []
269
+ held.push(` ${one.failures.join('; ')}`)
270
+ failing.set(one.rule, held)
271
+ }
272
+
261
273
  const warned = new Set<string>()
262
274
  const grouped = new Map<string, string[]>()
263
275
  const files = new Map<string, Set<string>>()
@@ -283,6 +295,11 @@ if (invoked(import.meta.url)) {
283
295
  ...(rule?.severity === 'warning' ? { severity: 'warning' as const } : {}),
284
296
  }
285
297
  }),
298
+ ...[...failing.entries()].map(([id, why]): Finding => ({
299
+ detail: `${id} — ${String(why.length)} of its own trial(s) did not pass:\n${[...new Set(why)].sort().join('\n')}`,
300
+ instead:
301
+ 'make the rule refuse the `wrong` it declares and accept the `right`, or correct the pair — a rule that has never fired on its own example is a rule nobody has seen work',
302
+ })),
286
303
  ...run.unrun.map((rule): Finding => ({
287
304
  detail: `${rule} DID NOT RUN — no slopnator is on disk for it, so this sweep measured nothing for that rule and a green result here says nothing about it`,
288
305
  instead: 'write the walk the rule names, or delete the rule and its row together — half a rule reads as a whole one from every direction',
@@ -294,7 +311,7 @@ if (invoked(import.meta.url)) {
294
311
  findings,
295
312
  `each naming one rule and the files it refuses — ${String(run.findings.length)} refusal(s) across ${String(refused.size)} file(s), ` +
296
313
  `over ${String(run.rules)} rule(s) run across ${String(run.swept)} of ${String(run.tracked)} file(s) in this tree, ` +
297
- `${String(run.linted.length)} of them reading a syntax tree` +
314
+ `${String(run.linted.length)} of them reading a syntax tree, and ${String(proving.passed)} of ${String(proving.outcomes.length)} rule trial(s) passed, ${String(proving.measured)} measured` +
298
315
  `${run.unrun.length === 0 ? '' : `, ${String(run.unrun.length)} that DID NOT RUN AT ALL`}` +
299
316
  `${run.unmet.length === 0 ? '' : `, and ${String(run.unmet.length)} that governed no file here and so measured nothing: ${run.unmet.join(', ')}`}`,
300
317
  )
@@ -279,12 +279,6 @@ const SHIPPED = [
279
279
  id: 'docs-generator',
280
280
  source: " {\n id: 'docs-generator',\n at: 'node_modules/@prestack/thread/dist/knowledge/generators/docsgen.js',\n describes: 'The writer of the page stating what this app declares — it descends the tree once and writes every node, everything each one declares and derives, and the command that writes each of those, with the sentence the row itself states. It moved here from the package that had operations in it, where it could only ever have documented operations: a package stating what another package declares would be one package authoring another\\'s. Where an operation has been run, the count of recorded runs is taken from the trials file by path if that file is there, so what proves an operation survives without anything here depending on the package that produces it.',\n version: 1,\n by: 'thread docs',\n runs: 'thread docs --check',\n },",
281
281
  },
282
- {
283
- into: 'derivation.ts',
284
- list: 'GENERATORS',
285
- id: 'skills-generator',
286
- source: " {\n id: 'skills-generator',\n at: 'node_modules/@prestack/thread/dist/knowledge/generators/skills.js',\n describes: 'The writer of one skill per `create` this tree has — it runs each maker bare, keeps what that command prints about itself, and writes one file per noun into `thread/knowledge`. What a skill teaches is what the command states, so the two cannot disagree, and a skill naming a `create` the tree no longer declares is removed rather than left teaching a command that refuses.',\n version: 1,\n by: 'thread skills',\n runs: 'thread skills --check',\n },",
287
- },
288
282
  ];
289
283
  export const ATTACH = {
290
284
  attaches: SEEDED.attaches,
@@ -289,12 +289,6 @@ const SHIPPED: readonly { readonly into: string; readonly list: string; readonly
289
289
  id: 'docs-generator',
290
290
  source: " {\n id: 'docs-generator',\n at: 'node_modules/@prestack/thread/dist/knowledge/generators/docsgen.js',\n describes: 'The writer of the page stating what this app declares — it descends the tree once and writes every node, everything each one declares and derives, and the command that writes each of those, with the sentence the row itself states. It moved here from the package that had operations in it, where it could only ever have documented operations: a package stating what another package declares would be one package authoring another\\'s. Where an operation has been run, the count of recorded runs is taken from the trials file by path if that file is there, so what proves an operation survives without anything here depending on the package that produces it.',\n version: 1,\n by: 'thread docs',\n runs: 'thread docs --check',\n },",
291
291
  },
292
- {
293
- into: 'derivation.ts',
294
- list: 'GENERATORS',
295
- id: 'skills-generator',
296
- source: " {\n id: 'skills-generator',\n at: 'node_modules/@prestack/thread/dist/knowledge/generators/skills.js',\n describes: 'The writer of one skill per `create` this tree has — it runs each maker bare, keeps what that command prints about itself, and writes one file per noun into `thread/knowledge`. What a skill teaches is what the command states, so the two cannot disagree, and a skill naming a `create` the tree no longer declares is removed rather than left teaching a command that refuses.',\n version: 1,\n by: 'thread skills',\n runs: 'thread skills --check',\n },",
297
- },
298
292
  ]
299
293
  export const ATTACH: Attaching = {
300
294
  attaches: SEEDED.attaches,
@@ -1,9 +1,10 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { dirname, resolve } from 'node:path';
1
+ import { existsSync, readFileSync, writeFileSync } from "../../core/files.js";
2
+ import { resolve } from 'node:path';
3
3
  import { argv, stderr, stdout } from 'node:process';
4
4
  import { exit } from "../../core/invoked.js";
5
5
  import { ROOT, descend } from "../../core/descend.js";
6
6
  import { forbids, runChecker } from "../../core/finding.js";
7
+ import { agentInstructions } from "../../integrity/lint.js";
7
8
  const AT = 'docs.md';
8
9
  const CHECKING = argv.includes('--check');
9
10
  const SHOWING = argv.includes('--show');
@@ -74,6 +75,7 @@ const commands = [...pass.derived.values(), ...[...under.values()].flat().map((o
74
75
  .filter((one) => text(one.by)?.startsWith('thread ') === true)
75
76
  .reduce((found, one) => found.set(text(one.by), one), new Map());
76
77
  const sections = [...under.keys()].sort();
78
+ const refused = agentInstructions();
77
79
  const page = [
78
80
  '<!-- GENERATED by `thread docs` from what this app declares — do not edit by hand.',
79
81
  ' Every sentence here is the `describes` on a row. To change one, change the row. -->',
@@ -92,6 +94,14 @@ const page = [
92
94
  .sort(([one], [two]) => (one < two ? -1 : 1))
93
95
  .map(([word, one]) => `- \`${word}\` — ${said(one)}`)),
94
96
  '',
97
+ '## What the build refuses',
98
+ '',
99
+ 'Every rule below stops a build outright. Each line pairs the code it rejects with the code it requires instead.',
100
+ '',
101
+ ...(refused.length === 0
102
+ ? ['_nothing here refuses anything yet._']
103
+ : refused.map((rule) => `- ${rule}`)),
104
+ '',
95
105
  ...sections.flatMap((node) => {
96
106
  const own = pass.stated.get(node) ?? pass.derived.get(node);
97
107
  const kept = under.get(node) ?? [];
@@ -140,6 +150,5 @@ if (CHECKING) {
140
150
  runChecker('docs', findings, `${AT} states every row this app declares, ${String(pass.rows)} of them`);
141
151
  exit(findings.length === 0 ? 0 : 1);
142
152
  }
143
- mkdirSync(dirname(PATH), { recursive: true });
144
153
  writeFileSync(PATH, page, 'utf8');
145
154
  stdout.write(`docs: wrote ${AT} — ${String(sections.length)} node(s), ${String(commands.size)} command(s), ${String(words.length)} word(s).\n`);
@@ -1,10 +1,11 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync, writeFileSync } from '../../core/files.ts'
2
2
  import { dirname, resolve } from 'node:path'
3
3
  import { argv, stderr, stdout } from 'node:process'
4
4
 
5
5
  import { exit } from '../../core/invoked.ts'
6
6
  import { ROOT, descend, type Pass, type Row } from '../../core/descend.ts'
7
7
  import { forbids, runChecker, type Finding } from '../../core/finding.ts'
8
+ import { agentInstructions } from '../../integrity/lint.ts'
8
9
 
9
10
  const AT = 'docs.md'
10
11
 
@@ -101,6 +102,8 @@ const commands = [...pass.derived.values(), ...[...under.values()].flat().map((o
101
102
 
102
103
  const sections = [...under.keys()].sort()
103
104
 
105
+ const refused = agentInstructions()
106
+
104
107
  const page = [
105
108
  '<!-- GENERATED by `thread docs` from what this app declares — do not edit by hand.',
106
109
  ' Every sentence here is the `describes` on a row. To change one, change the row. -->',
@@ -119,6 +122,14 @@ const page = [
119
122
  .sort(([one], [two]) => (one < two ? -1 : 1))
120
123
  .map(([word, one]) => `- \`${word}\` — ${said(one)}`)),
121
124
  '',
125
+ '## What the build refuses',
126
+ '',
127
+ 'Every rule below stops a build outright. Each line pairs the code it rejects with the code it requires instead.',
128
+ '',
129
+ ...(refused.length === 0
130
+ ? ['_nothing here refuses anything yet._']
131
+ : refused.map((rule) => `- ${rule}`)),
132
+ '',
122
133
  ...sections.flatMap((node) => {
123
134
  const own = pass.stated.get(node) ?? pass.derived.get(node)
124
135
  const kept = under.get(node) ?? []
@@ -169,6 +180,5 @@ if (CHECKING) {
169
180
  exit(findings.length === 0 ? 0 : 1)
170
181
  }
171
182
 
172
- mkdirSync(dirname(PATH), { recursive: true })
173
183
  writeFileSync(PATH, page, 'utf8')
174
184
  stdout.write(`docs: wrote ${AT} — ${String(sections.length)} node(s), ${String(commands.size)} command(s), ${String(words.length)} word(s).\n`)
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, writeFileSync } from 'node:fs';
1
+ import { existsSync, readFileSync, writeFileSync } from "../../core/files.js";
2
2
  import { dirname, relative, resolve } from 'node:path';
3
3
  import { argv, stderr, stdout } from 'node:process';
4
4
  import { fileURLToPath } from 'node:url';
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, writeFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync, writeFileSync } from '../../core/files.ts'
2
2
  import { dirname, relative, resolve } from 'node:path'
3
3
  import { argv, stderr, stdout } from 'node:process'
4
4
  import { fileURLToPath } from 'node:url'