@openagentsy/hooks 0.0.0-stage → 0.2.1

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 (307) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +32 -2
  3. package/dist/accountability.d.ts +29 -0
  4. package/dist/accountability.d.ts.map +1 -0
  5. package/dist/accountability.js +21 -0
  6. package/dist/accountability.js.map +1 -0
  7. package/dist/accountability.test.d.ts +2 -0
  8. package/dist/accountability.test.d.ts.map +1 -0
  9. package/dist/accountability.test.js +42 -0
  10. package/dist/accountability.test.js.map +1 -0
  11. package/dist/approvals.d.ts +110 -0
  12. package/dist/approvals.d.ts.map +1 -0
  13. package/dist/approvals.js +464 -0
  14. package/dist/approvals.js.map +1 -0
  15. package/dist/approvals.test.d.ts +2 -0
  16. package/dist/approvals.test.d.ts.map +1 -0
  17. package/dist/approvals.test.js +307 -0
  18. package/dist/approvals.test.js.map +1 -0
  19. package/dist/base-tool.d.ts +26 -0
  20. package/dist/base-tool.d.ts.map +1 -0
  21. package/dist/base-tool.js +37 -0
  22. package/dist/base-tool.js.map +1 -0
  23. package/dist/base-tool.test.d.ts +2 -0
  24. package/dist/base-tool.test.d.ts.map +1 -0
  25. package/dist/base-tool.test.js +34 -0
  26. package/dist/base-tool.test.js.map +1 -0
  27. package/dist/eval/index.d.ts +3 -0
  28. package/dist/eval/index.d.ts.map +1 -0
  29. package/dist/eval/index.js +3 -0
  30. package/dist/eval/index.js.map +1 -0
  31. package/dist/eval/runner.d.ts +179 -0
  32. package/dist/eval/runner.d.ts.map +1 -0
  33. package/dist/eval/runner.js +616 -0
  34. package/dist/eval/runner.js.map +1 -0
  35. package/dist/eval/runner.test.d.ts +2 -0
  36. package/dist/eval/runner.test.d.ts.map +1 -0
  37. package/dist/eval/runner.test.js +431 -0
  38. package/dist/eval/runner.test.js.map +1 -0
  39. package/dist/eval/types.d.ts +173 -0
  40. package/dist/eval/types.d.ts.map +1 -0
  41. package/dist/eval/types.js +104 -0
  42. package/dist/eval/types.js.map +1 -0
  43. package/dist/event.d.ts +59 -0
  44. package/dist/event.d.ts.map +1 -0
  45. package/dist/event.js +178 -0
  46. package/dist/event.js.map +1 -0
  47. package/dist/event.test.d.ts +2 -0
  48. package/dist/event.test.d.ts.map +1 -0
  49. package/dist/event.test.js +49 -0
  50. package/dist/event.test.js.map +1 -0
  51. package/dist/index.d.ts +30 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +29 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/lessons/capture.d.ts +66 -0
  56. package/dist/lessons/capture.d.ts.map +1 -0
  57. package/dist/lessons/capture.js +166 -0
  58. package/dist/lessons/capture.js.map +1 -0
  59. package/dist/lessons/capture.test.d.ts +2 -0
  60. package/dist/lessons/capture.test.d.ts.map +1 -0
  61. package/dist/lessons/capture.test.js +200 -0
  62. package/dist/lessons/capture.test.js.map +1 -0
  63. package/dist/lessons/decide.d.ts +90 -0
  64. package/dist/lessons/decide.d.ts.map +1 -0
  65. package/dist/lessons/decide.js +334 -0
  66. package/dist/lessons/decide.js.map +1 -0
  67. package/dist/lessons/decide.test.d.ts +2 -0
  68. package/dist/lessons/decide.test.d.ts.map +1 -0
  69. package/dist/lessons/decide.test.js +527 -0
  70. package/dist/lessons/decide.test.js.map +1 -0
  71. package/dist/lessons/id.d.ts +5 -0
  72. package/dist/lessons/id.d.ts.map +1 -0
  73. package/dist/lessons/id.js +20 -0
  74. package/dist/lessons/id.js.map +1 -0
  75. package/dist/lessons/index.d.ts +5 -0
  76. package/dist/lessons/index.d.ts.map +1 -0
  77. package/dist/lessons/index.js +5 -0
  78. package/dist/lessons/index.js.map +1 -0
  79. package/dist/lessons/model.d.ts +163 -0
  80. package/dist/lessons/model.d.ts.map +1 -0
  81. package/dist/lessons/model.js +181 -0
  82. package/dist/lessons/model.js.map +1 -0
  83. package/dist/lessons/model.test.d.ts +2 -0
  84. package/dist/lessons/model.test.d.ts.map +1 -0
  85. package/dist/lessons/model.test.js +178 -0
  86. package/dist/lessons/model.test.js.map +1 -0
  87. package/dist/lessons/permissions.test.d.ts +2 -0
  88. package/dist/lessons/permissions.test.d.ts.map +1 -0
  89. package/dist/lessons/permissions.test.js +88 -0
  90. package/dist/lessons/permissions.test.js.map +1 -0
  91. package/dist/lessons/store.d.ts +74 -0
  92. package/dist/lessons/store.d.ts.map +1 -0
  93. package/dist/lessons/store.js +231 -0
  94. package/dist/lessons/store.js.map +1 -0
  95. package/dist/output-checks.d.ts +64 -0
  96. package/dist/output-checks.d.ts.map +1 -0
  97. package/dist/output-checks.js +248 -0
  98. package/dist/output-checks.js.map +1 -0
  99. package/dist/output-checks.test.d.ts +2 -0
  100. package/dist/output-checks.test.d.ts.map +1 -0
  101. package/dist/output-checks.test.js +58 -0
  102. package/dist/output-checks.test.js.map +1 -0
  103. package/dist/paths.d.ts +37 -0
  104. package/dist/paths.d.ts.map +1 -0
  105. package/dist/paths.js +70 -0
  106. package/dist/paths.js.map +1 -0
  107. package/dist/paths.test.d.ts +2 -0
  108. package/dist/paths.test.d.ts.map +1 -0
  109. package/dist/paths.test.js +36 -0
  110. package/dist/paths.test.js.map +1 -0
  111. package/dist/policies/agi-framing.d.ts +12 -0
  112. package/dist/policies/agi-framing.d.ts.map +1 -0
  113. package/dist/policies/agi-framing.js +33 -0
  114. package/dist/policies/agi-framing.js.map +1 -0
  115. package/dist/policies/anti-anthropomorphism.d.ts +13 -0
  116. package/dist/policies/anti-anthropomorphism.d.ts.map +1 -0
  117. package/dist/policies/anti-anthropomorphism.js +34 -0
  118. package/dist/policies/anti-anthropomorphism.js.map +1 -0
  119. package/dist/policies/anti-dependence.d.ts +12 -0
  120. package/dist/policies/anti-dependence.d.ts.map +1 -0
  121. package/dist/policies/anti-dependence.js +33 -0
  122. package/dist/policies/anti-dependence.js.map +1 -0
  123. package/dist/policies/anti-sycophancy.d.ts +13 -0
  124. package/dist/policies/anti-sycophancy.d.ts.map +1 -0
  125. package/dist/policies/anti-sycophancy.js +34 -0
  126. package/dist/policies/anti-sycophancy.js.map +1 -0
  127. package/dist/policies/dark-pattern.d.ts +14 -0
  128. package/dist/policies/dark-pattern.d.ts.map +1 -0
  129. package/dist/policies/dark-pattern.js +44 -0
  130. package/dist/policies/dark-pattern.js.map +1 -0
  131. package/dist/policies/destructive-needs-approval.d.ts +14 -0
  132. package/dist/policies/destructive-needs-approval.d.ts.map +1 -0
  133. package/dist/policies/destructive-needs-approval.js +31 -0
  134. package/dist/policies/destructive-needs-approval.js.map +1 -0
  135. package/dist/policies/discovery.d.ts +12 -0
  136. package/dist/policies/discovery.d.ts.map +1 -0
  137. package/dist/policies/discovery.js +130 -0
  138. package/dist/policies/discovery.js.map +1 -0
  139. package/dist/policies/high-risk.d.ts +25 -0
  140. package/dist/policies/high-risk.d.ts.map +1 -0
  141. package/dist/policies/high-risk.js +105 -0
  142. package/dist/policies/high-risk.js.map +1 -0
  143. package/dist/policies/human-only-decisions.d.ts +14 -0
  144. package/dist/policies/human-only-decisions.d.ts.map +1 -0
  145. package/dist/policies/human-only-decisions.js +33 -0
  146. package/dist/policies/human-only-decisions.js.map +1 -0
  147. package/dist/policies/index.d.ts +29 -0
  148. package/dist/policies/index.d.ts.map +1 -0
  149. package/dist/policies/index.js +82 -0
  150. package/dist/policies/index.js.map +1 -0
  151. package/dist/policies/no-skip-git-hooks.d.ts +14 -0
  152. package/dist/policies/no-skip-git-hooks.d.ts.map +1 -0
  153. package/dist/policies/no-skip-git-hooks.js +31 -0
  154. package/dist/policies/no-skip-git-hooks.js.map +1 -0
  155. package/dist/policies/package-manager.d.ts +12 -0
  156. package/dist/policies/package-manager.d.ts.map +1 -0
  157. package/dist/policies/package-manager.js +29 -0
  158. package/dist/policies/package-manager.js.map +1 -0
  159. package/dist/policies/patterns.d.ts +17 -0
  160. package/dist/policies/patterns.d.ts.map +1 -0
  161. package/dist/policies/patterns.js +30 -0
  162. package/dist/policies/patterns.js.map +1 -0
  163. package/dist/policies/policies.test.d.ts +2 -0
  164. package/dist/policies/policies.test.d.ts.map +1 -0
  165. package/dist/policies/policies.test.js +210 -0
  166. package/dist/policies/policies.test.js.map +1 -0
  167. package/dist/policies/privacy-transparency.d.ts +14 -0
  168. package/dist/policies/privacy-transparency.d.ts.map +1 -0
  169. package/dist/policies/privacy-transparency.js +50 -0
  170. package/dist/policies/privacy-transparency.js.map +1 -0
  171. package/dist/policies/professional-displacement.d.ts +15 -0
  172. package/dist/policies/professional-displacement.d.ts.map +1 -0
  173. package/dist/policies/professional-displacement.js +45 -0
  174. package/dist/policies/professional-displacement.js.map +1 -0
  175. package/dist/policies/protect-policy.d.ts +14 -0
  176. package/dist/policies/protect-policy.d.ts.map +1 -0
  177. package/dist/policies/protect-policy.js +35 -0
  178. package/dist/policies/protect-policy.js.map +1 -0
  179. package/dist/policies/scope-enforcement.d.ts +14 -0
  180. package/dist/policies/scope-enforcement.d.ts.map +1 -0
  181. package/dist/policies/scope-enforcement.js +34 -0
  182. package/dist/policies/scope-enforcement.js.map +1 -0
  183. package/dist/policies/secret-scan-writes.d.ts +13 -0
  184. package/dist/policies/secret-scan-writes.d.ts.map +1 -0
  185. package/dist/policies/secret-scan-writes.js +38 -0
  186. package/dist/policies/secret-scan-writes.js.map +1 -0
  187. package/dist/policies/selection.d.ts +20 -0
  188. package/dist/policies/selection.d.ts.map +1 -0
  189. package/dist/policies/selection.js +93 -0
  190. package/dist/policies/selection.js.map +1 -0
  191. package/dist/policies/structural-bias.d.ts +14 -0
  192. package/dist/policies/structural-bias.d.ts.map +1 -0
  193. package/dist/policies/structural-bias.js +41 -0
  194. package/dist/policies/structural-bias.js.map +1 -0
  195. package/dist/policies/third-party-impact.d.ts +13 -0
  196. package/dist/policies/third-party-impact.d.ts.map +1 -0
  197. package/dist/policies/third-party-impact.js +38 -0
  198. package/dist/policies/third-party-impact.js.map +1 -0
  199. package/dist/policies/tool-call.d.ts +38 -0
  200. package/dist/policies/tool-call.d.ts.map +1 -0
  201. package/dist/policies/tool-call.js +53 -0
  202. package/dist/policies/tool-call.js.map +1 -0
  203. package/dist/policies/truthfulness-uncertainty.d.ts +13 -0
  204. package/dist/policies/truthfulness-uncertainty.d.ts.map +1 -0
  205. package/dist/policies/truthfulness-uncertainty.js +45 -0
  206. package/dist/policies/truthfulness-uncertainty.js.map +1 -0
  207. package/dist/policies/workspace-writes-only.d.ts +25 -0
  208. package/dist/policies/workspace-writes-only.d.ts.map +1 -0
  209. package/dist/policies/workspace-writes-only.js +54 -0
  210. package/dist/policies/workspace-writes-only.js.map +1 -0
  211. package/dist/policy-engine.d.ts +69 -0
  212. package/dist/policy-engine.d.ts.map +1 -0
  213. package/dist/policy-engine.js +145 -0
  214. package/dist/policy-engine.js.map +1 -0
  215. package/dist/policy-registry.d.ts +62 -0
  216. package/dist/policy-registry.d.ts.map +1 -0
  217. package/dist/policy-registry.js +63 -0
  218. package/dist/policy-registry.js.map +1 -0
  219. package/dist/policy-registry.test.d.ts +2 -0
  220. package/dist/policy-registry.test.d.ts.map +1 -0
  221. package/dist/policy-registry.test.js +79 -0
  222. package/dist/policy-registry.test.js.map +1 -0
  223. package/dist/policy-release.d.ts +44 -0
  224. package/dist/policy-release.d.ts.map +1 -0
  225. package/dist/policy-release.js +65 -0
  226. package/dist/policy-release.js.map +1 -0
  227. package/dist/policy.d.ts +141 -0
  228. package/dist/policy.d.ts.map +1 -0
  229. package/dist/policy.js +22 -0
  230. package/dist/policy.js.map +1 -0
  231. package/dist/quality/audit.d.ts +56 -0
  232. package/dist/quality/audit.d.ts.map +1 -0
  233. package/dist/quality/audit.js +52 -0
  234. package/dist/quality/audit.js.map +1 -0
  235. package/dist/quality/findings.d.ts +34 -0
  236. package/dist/quality/findings.d.ts.map +1 -0
  237. package/dist/quality/findings.js +121 -0
  238. package/dist/quality/findings.js.map +1 -0
  239. package/dist/quality/findings.test.d.ts +2 -0
  240. package/dist/quality/findings.test.d.ts.map +1 -0
  241. package/dist/quality/findings.test.js +79 -0
  242. package/dist/quality/findings.test.js.map +1 -0
  243. package/dist/quality/index.d.ts +20 -0
  244. package/dist/quality/index.d.ts.map +1 -0
  245. package/dist/quality/index.js +20 -0
  246. package/dist/quality/index.js.map +1 -0
  247. package/dist/quality/rule.d.ts +43 -0
  248. package/dist/quality/rule.d.ts.map +1 -0
  249. package/dist/quality/rule.js +162 -0
  250. package/dist/quality/rule.js.map +1 -0
  251. package/dist/quality/rule.test.d.ts +2 -0
  252. package/dist/quality/rule.test.d.ts.map +1 -0
  253. package/dist/quality/rule.test.js +187 -0
  254. package/dist/quality/rule.test.js.map +1 -0
  255. package/dist/quality/tools.d.ts +30 -0
  256. package/dist/quality/tools.d.ts.map +1 -0
  257. package/dist/quality/tools.js +33 -0
  258. package/dist/quality/tools.js.map +1 -0
  259. package/dist/quality/tools.test.d.ts +2 -0
  260. package/dist/quality/tools.test.d.ts.map +1 -0
  261. package/dist/quality/tools.test.js +41 -0
  262. package/dist/quality/tools.test.js.map +1 -0
  263. package/dist/quality/waive.d.ts +37 -0
  264. package/dist/quality/waive.d.ts.map +1 -0
  265. package/dist/quality/waive.js +39 -0
  266. package/dist/quality/waive.js.map +1 -0
  267. package/dist/quality/waivers.d.ts +63 -0
  268. package/dist/quality/waivers.d.ts.map +1 -0
  269. package/dist/quality/waivers.js +132 -0
  270. package/dist/quality/waivers.js.map +1 -0
  271. package/dist/quality/waivers.test.d.ts +2 -0
  272. package/dist/quality/waivers.test.d.ts.map +1 -0
  273. package/dist/quality/waivers.test.js +138 -0
  274. package/dist/quality/waivers.test.js.map +1 -0
  275. package/dist/registry.d.ts +86 -0
  276. package/dist/registry.d.ts.map +1 -0
  277. package/dist/registry.js +92 -0
  278. package/dist/registry.js.map +1 -0
  279. package/dist/registry.test.d.ts +2 -0
  280. package/dist/registry.test.d.ts.map +1 -0
  281. package/dist/registry.test.js +117 -0
  282. package/dist/registry.test.js.map +1 -0
  283. package/dist/rules.d.ts +107 -0
  284. package/dist/rules.d.ts.map +1 -0
  285. package/dist/rules.js +632 -0
  286. package/dist/rules.js.map +1 -0
  287. package/dist/rules.test.d.ts +2 -0
  288. package/dist/rules.test.d.ts.map +1 -0
  289. package/dist/rules.test.js +488 -0
  290. package/dist/rules.test.js.map +1 -0
  291. package/dist/secrets.d.ts +17 -0
  292. package/dist/secrets.d.ts.map +1 -0
  293. package/dist/secrets.js +17 -0
  294. package/dist/secrets.js.map +1 -0
  295. package/dist/secrets.test.d.ts +2 -0
  296. package/dist/secrets.test.d.ts.map +1 -0
  297. package/dist/secrets.test.js +20 -0
  298. package/dist/secrets.test.js.map +1 -0
  299. package/dist/shell-env.d.ts +23 -0
  300. package/dist/shell-env.d.ts.map +1 -0
  301. package/dist/shell-env.js +34 -0
  302. package/dist/shell-env.js.map +1 -0
  303. package/dist/shell-env.test.d.ts +2 -0
  304. package/dist/shell-env.test.d.ts.map +1 -0
  305. package/dist/shell-env.test.js +45 -0
  306. package/dist/shell-env.test.js.map +1 -0
  307. package/package.json +49 -4
@@ -0,0 +1,166 @@
1
+ import { redactForStorage } from '../secrets.js';
2
+ import { normalizeText } from './model.js';
3
+ import { createLessonId, listLessons, readObservations, writeLesson, writeObservations, } from './store.js';
4
+ /**
5
+ * The capture.
6
+ *
7
+ * The archivist watches for the same kind of waste again and again, and it
8
+ * turns that into a candidate. It does so in two cases only:
9
+ *
10
+ * - the same waste kind with a similar detail shows up in three or more
11
+ * sessions, which is a pattern rather than an accident;
12
+ * - a person corrects the agent outright, which is a lesson whatever the
13
+ * count is.
14
+ *
15
+ * The observations are kept before there is a candidate, because the rule is
16
+ * about sessions: the third session is only a pattern if the first two are
17
+ * remembered. A candidate is deduplicated by its normalised summary, and
18
+ * every sighting of the same summary raises the count. The count is a
19
+ * priority, not evidence: a lesson that happened often is still only a claim
20
+ * until a person has decided it.
21
+ */
22
+ /** How many sessions make a pattern. */
23
+ export const SESSION_THRESHOLD = 3;
24
+ /**
25
+ * Redact every text field of a packet.
26
+ *
27
+ * The packet is read by a person, and it is written to disk, so it goes
28
+ * through the same door as everything else that is stored.
29
+ */
30
+ function redactPacket(packet) {
31
+ let count = 0;
32
+ const text = (value) => {
33
+ const redacted = redactForStorage(value);
34
+ count += redacted.count;
35
+ return redacted.text;
36
+ };
37
+ const list = (values) => values.map((value) => {
38
+ const redacted = redactForStorage(value);
39
+ count += redacted.count;
40
+ return redacted.text;
41
+ });
42
+ const owner = packet.owner;
43
+ const redactedOwner = owner === undefined ? undefined : text(owner);
44
+ return {
45
+ packet: {
46
+ ...(packet.futureBehavior === undefined
47
+ ? {}
48
+ : { futureBehavior: text(packet.futureBehavior) }),
49
+ ...(packet.representativeTask === undefined
50
+ ? {}
51
+ : { representativeTask: text(packet.representativeTask) }),
52
+ ...(packet.evidence === undefined ? {} : { evidence: list(packet.evidence) }),
53
+ ...(redactedOwner === undefined ? {} : { owner: redactedOwner }),
54
+ ...(packet.ownerJustification === undefined
55
+ ? {}
56
+ : { ownerJustification: text(packet.ownerJustification) }),
57
+ ...(packet.writeBoundary === undefined ? {} : { writeBoundary: list(packet.writeBoundary) }),
58
+ ...(packet.proof === undefined ? {} : { proof: text(packet.proof) }),
59
+ },
60
+ count,
61
+ };
62
+ }
63
+ /**
64
+ * The key a waste is counted under.
65
+ *
66
+ * The kind and the normalised detail make the key, so a waste that says the
67
+ * same thing twice is one waste, and a waste of another kind is another one.
68
+ */
69
+ function groupKey(observation) {
70
+ return `${observation.kind} ${normalizeText(observation.detail)}`;
71
+ }
72
+ /**
73
+ * The groups of waste, and the sessions each was seen in.
74
+ */
75
+ function groupsOf(observations) {
76
+ const groups = new Map();
77
+ for (const observation of observations) {
78
+ const key = groupKey(observation);
79
+ const group = groups.get(key) ?? {
80
+ kind: observation.kind,
81
+ detail: observation.detail,
82
+ sessions: new Set(),
83
+ };
84
+ group.sessions.add(observation.session);
85
+ groups.set(key, group);
86
+ }
87
+ return groups;
88
+ }
89
+ /**
90
+ * Capture a lesson.
91
+ *
92
+ * Nothing is written to the lesson store until there is something to write:
93
+ * a waste that has been seen once is not a pattern, and the archivist says
94
+ * so instead of filling the store with candidates nobody will read. The
95
+ * observations are kept either way, because the third session is only a
96
+ * pattern if the first two are remembered.
97
+ */
98
+ export async function captureCandidate(root, input, now = () => new Date()) {
99
+ const summary = redactForStorage(input.summary);
100
+ // The evidence the caller names is the evidence of the lesson: it goes
101
+ // into the packet, so the person reads it with the rest of the claim.
102
+ const evidence = [...(input.packet?.evidence ?? []), ...(input.evidence ?? [])];
103
+ const packet = redactPacket({
104
+ ...input.packet,
105
+ ...(evidence.length > 0 ? { evidence } : {}),
106
+ });
107
+ let redactions = summary.count + packet.count;
108
+ const observations = input.observations.map((observation) => {
109
+ const kind = redactForStorage(observation.kind);
110
+ const detail = redactForStorage(observation.detail);
111
+ redactions += kind.count + detail.count;
112
+ return { kind: kind.text, detail: detail.text, session: observation.session };
113
+ });
114
+ const history = await readObservations(root);
115
+ const all = [...history, ...observations];
116
+ await writeObservations(root, all);
117
+ let best = { kind: '', detail: '', sessions: new Set() };
118
+ const incoming = new Set(observations.map(groupKey));
119
+ for (const [key, group] of groupsOf(all)) {
120
+ // Only the waste that was just seen decides: an older pattern does not
121
+ // make a new sighting a candidate.
122
+ if (!incoming.has(key))
123
+ continue;
124
+ if (group.sessions.size > best.sessions.size)
125
+ best = group;
126
+ }
127
+ const stamp = now().toISOString();
128
+ const key = normalizeText(summary.text);
129
+ const existing = (await listLessons(root)).find((lesson) => normalizeText(lesson.summary) === key);
130
+ if (existing !== undefined) {
131
+ const lesson = {
132
+ ...existing,
133
+ occurrences: existing.occurrences + 1,
134
+ sessions: [...new Set([...existing.sessions, ...best.sessions])],
135
+ packet: { ...existing.packet, ...packet.packet },
136
+ updated_at: stamp,
137
+ };
138
+ await writeLesson(root, lesson);
139
+ return { ok: true, lesson, created: false, redactions };
140
+ }
141
+ const explicit = input.explicitCorrection === true;
142
+ if (!explicit && best.sessions.size < SESSION_THRESHOLD) {
143
+ return {
144
+ ok: false,
145
+ reason: 'not_enough_sessions',
146
+ redactions,
147
+ sessions: best.sessions.size,
148
+ };
149
+ }
150
+ const lesson = {
151
+ id: createLessonId(),
152
+ state: 'candidate',
153
+ summary: summary.text,
154
+ occurrences: 1,
155
+ packet: packet.packet,
156
+ history: [],
157
+ kind: best.kind,
158
+ detail: best.detail,
159
+ sessions: [...best.sessions],
160
+ created_at: stamp,
161
+ updated_at: stamp,
162
+ };
163
+ await writeLesson(root, lesson);
164
+ return { ok: true, lesson, created: true, redactions };
165
+ }
166
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/lessons/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAe,aAAa,EAAgC,MAAM,YAAY,CAAC;AACtF,OAAO,EACL,cAAc,EACd,WAAW,EAEX,gBAAgB,EAChB,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;GAiBG;AAEH,wCAAwC;AACxC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AA+BnC;;;;;GAKG;AACH,SAAS,YAAY,CAAC,MAA4B;IAIhD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,IAAI,GAAG,CAAC,KAAa,EAAU,EAAE;QACrC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACzC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC;QACxB,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,MAAgB,EAAY,EAAE,CAC1C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACnB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACzC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC;QACxB,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC,CAAC,CAAC;IACL,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,MAAM,aAAa,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpE,OAAO;QACL,MAAM,EAAE;YACN,GAAG,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS;gBACrC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,MAAM,CAAC,kBAAkB,KAAK,SAAS;gBACzC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC5D,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7E,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,aAAsB,EAAE,CAAC;YACzE,GAAG,CAAC,MAAM,CAAC,kBAAkB,KAAK,SAAS;gBACzC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC5D,GAAG,CAAC,MAAM,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAC5F,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;SACrE;QACD,KAAK;KACN,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,WAAwB;IACxC,OAAO,GAAG,WAAW,CAAC,IAAI,IAAI,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;AACpE,CAAC;AASD;;GAEG;AACH,SAAS,QAAQ,CAAC,YAA2B;IAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;IACxC,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;YAC/B,IAAI,EAAE,WAAW,CAAC,IAAI;YACtB,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,QAAQ,EAAE,IAAI,GAAG,EAAU;SAC5B,CAAC;QACF,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAY,EACZ,KAAmB,EACnB,MAAkB,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE;IAElC,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChD,uEAAuE;IACvE,sEAAsE;IACtE,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,YAAY,CAAC;QAC1B,GAAG,KAAK,CAAC,MAAM;QACf,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAC;IAEH,IAAI,UAAU,GAAG,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC9C,MAAM,YAAY,GAAkB,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE;QACzE,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,gBAAgB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACpD,UAAU,IAAI,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QACxC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;IAChF,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,YAAY,CAAC,CAAC;IAC1C,MAAM,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAEnC,IAAI,IAAI,GAAU,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,GAAG,EAAU,EAAE,CAAC;IACxE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,uEAAuE;QACvE,mCAAmC;QACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACjC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI;YAAE,IAAI,GAAG,KAAK,CAAC;IAC7D,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAC7C,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,CAClD,CAAC;IAEF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAW;YACrB,GAAG,QAAQ;YACX,WAAW,EAAE,QAAQ,CAAC,WAAW,GAAG,CAAC;YACrC,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAChE,MAAM,EAAE,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;YAChD,UAAU,EAAE,KAAK;SAClB,CAAC;QACF,MAAM,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,kBAAkB,KAAK,IAAI,CAAC;IACnD,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,iBAAiB,EAAE,CAAC;QACxD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,qBAAqB;YAC7B,UAAU;YACV,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;SAC7B,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAW;QACrB,EAAE,EAAE,cAAc,EAAE;QACpB,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,OAAO,CAAC,IAAI;QACrB,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5B,UAAU,EAAE,KAAK;QACjB,UAAU,EAAE,KAAK;KAClB,CAAC;IACF,MAAM,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AACzD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=capture.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.test.d.ts","sourceRoot":"","sources":["../../src/lessons/capture.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,200 @@
1
+ import { mkdtemp, readFile, rm } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { describe, expect, it } from 'vitest';
5
+ import { captureCandidate, SESSION_THRESHOLD } from './capture.js';
6
+ import { listLessons, readObservations } from './store.js';
7
+ /**
8
+ * A temporary state root.
9
+ */
10
+ async function temporaryRoot() {
11
+ const root = await mkdtemp(join(tmpdir(), 'openagentsy-lessons-'));
12
+ return { root, remove: () => rm(root, { recursive: true, force: true }) };
13
+ }
14
+ /**
15
+ * A secret with the shape of a real one, assembled from segments.
16
+ *
17
+ * The shape is what the redaction looks for, and the segments are what keeps
18
+ * the fixture out of the push protection.
19
+ */
20
+ const SECRET = ['gh', 'p_', 'abcdefghijklmnopqrstuvwxyz0123456789'].join('');
21
+ /** One sighting of a waste. */
22
+ function sighting(session, kind = 'missing-file', detail = 'the file was missing') {
23
+ return { kind, detail, session };
24
+ }
25
+ describe('the capture', () => {
26
+ it('creates no candidate for a waste that has been seen once', async () => {
27
+ const { root, remove } = await temporaryRoot();
28
+ try {
29
+ const outcome = await captureCandidate(root, {
30
+ summary: 'the agent wrote to a file that does not exist',
31
+ observations: [sighting('session-1')],
32
+ });
33
+ expect(outcome.ok).toBe(false);
34
+ expect(await listLessons(root)).toHaveLength(0);
35
+ }
36
+ finally {
37
+ await remove();
38
+ }
39
+ });
40
+ it('creates a candidate when the same waste shows up in three sessions', async () => {
41
+ const { root, remove } = await temporaryRoot();
42
+ try {
43
+ for (const session of ['session-1', 'session-2']) {
44
+ const outcome = await captureCandidate(root, {
45
+ summary: 'the agent wrote to a file that does not exist',
46
+ observations: [sighting(session)],
47
+ });
48
+ expect(outcome.ok).toBe(false);
49
+ }
50
+ const outcome = await captureCandidate(root, {
51
+ summary: 'the agent wrote to a file that does not exist',
52
+ observations: [sighting('session-3')],
53
+ });
54
+ expect(outcome.ok).toBe(true);
55
+ if (outcome.ok) {
56
+ expect(outcome.created).toBe(true);
57
+ expect(outcome.lesson.state).toBe('candidate');
58
+ expect(outcome.lesson.sessions).toHaveLength(SESSION_THRESHOLD);
59
+ }
60
+ expect(await listLessons(root)).toHaveLength(1);
61
+ }
62
+ finally {
63
+ await remove();
64
+ }
65
+ });
66
+ it('counts a waste of another kind as another waste', async () => {
67
+ const { root, remove } = await temporaryRoot();
68
+ try {
69
+ for (const session of ['session-1', 'session-2', 'session-3']) {
70
+ await captureCandidate(root, {
71
+ summary: 'the agent wrote to a file that does not exist',
72
+ observations: [sighting(session)],
73
+ });
74
+ }
75
+ const outcome = await captureCandidate(root, {
76
+ summary: 'the test suite took a minute',
77
+ observations: [sighting('session-4', 'slow-test', 'the test took a minute')],
78
+ });
79
+ expect(outcome.ok).toBe(false);
80
+ expect(await listLessons(root)).toHaveLength(1);
81
+ }
82
+ finally {
83
+ await remove();
84
+ }
85
+ });
86
+ it('creates a candidate at once for an explicit correction', async () => {
87
+ const { root, remove } = await temporaryRoot();
88
+ try {
89
+ const outcome = await captureCandidate(root, {
90
+ summary: 'the person said the agent must read the file first',
91
+ observations: [sighting('session-1')],
92
+ explicitCorrection: true,
93
+ });
94
+ expect(outcome.ok).toBe(true);
95
+ if (outcome.ok)
96
+ expect(outcome.created).toBe(true);
97
+ }
98
+ finally {
99
+ await remove();
100
+ }
101
+ });
102
+ it('deduplicates by the normalised summary and raises the count', async () => {
103
+ const { root, remove } = await temporaryRoot();
104
+ try {
105
+ const first = await captureCandidate(root, {
106
+ summary: 'The agent wrote to a file that does not exist.',
107
+ observations: [sighting('session-1')],
108
+ explicitCorrection: true,
109
+ });
110
+ expect(first.ok).toBe(true);
111
+ const second = await captureCandidate(root, {
112
+ summary: 'the agent wrote to a file that does not exist',
113
+ observations: [sighting('session-2')],
114
+ explicitCorrection: true,
115
+ });
116
+ expect(second.ok).toBe(true);
117
+ if (first.ok && second.ok) {
118
+ expect(second.created).toBe(false);
119
+ expect(second.lesson.id).toBe(first.lesson.id);
120
+ expect(second.lesson.occurrences).toBe(2);
121
+ }
122
+ expect(await listLessons(root)).toHaveLength(1);
123
+ }
124
+ finally {
125
+ await remove();
126
+ }
127
+ });
128
+ it('keeps the observations, so the third session can be a pattern', async () => {
129
+ const { root, remove } = await temporaryRoot();
130
+ try {
131
+ await captureCandidate(root, {
132
+ summary: 'the agent wrote to a file that does not exist',
133
+ observations: [sighting('session-1')],
134
+ });
135
+ expect(await readObservations(root)).toHaveLength(1);
136
+ }
137
+ finally {
138
+ await remove();
139
+ }
140
+ });
141
+ it('keeps a secret out of the store, in the summary and in the detail', async () => {
142
+ const { root, remove } = await temporaryRoot();
143
+ try {
144
+ const outcome = await captureCandidate(root, {
145
+ summary: `the token ${SECRET} was pasted into the file`,
146
+ observations: [sighting('session-1', 'secret', `the token was ${SECRET}`)],
147
+ explicitCorrection: true,
148
+ evidence: [`the run used ${SECRET}`],
149
+ });
150
+ expect(outcome.ok).toBe(true);
151
+ const stored = await readFile(join(root, '.openagentsy', 'lessons', `${outcome.ok ? outcome.lesson.id : ''}.json`), 'utf8');
152
+ expect(stored).not.toContain(SECRET);
153
+ expect(stored).toContain('redacted:github-token');
154
+ const observations = await readFile(join(root, '.openagentsy', 'lessons', 'observations.json'), 'utf8');
155
+ expect(observations).not.toContain(SECRET);
156
+ }
157
+ finally {
158
+ await remove();
159
+ }
160
+ });
161
+ });
162
+ describe('the evidence of a candidate', () => {
163
+ it('merges the evidence the caller names into the packet', async () => {
164
+ const { root, remove } = await temporaryRoot();
165
+ try {
166
+ const outcome = await captureCandidate(root, {
167
+ summary: 'the person corrected the agent',
168
+ observations: [sighting('session-1')],
169
+ explicitCorrection: true,
170
+ evidence: ['ledger-42'],
171
+ });
172
+ expect(outcome.ok).toBe(true);
173
+ if (outcome.ok)
174
+ expect(outcome.lesson.packet.evidence).toEqual(['ledger-42']);
175
+ }
176
+ finally {
177
+ await remove();
178
+ }
179
+ });
180
+ it('keeps a secret out of a session id', async () => {
181
+ const { root, remove } = await temporaryRoot();
182
+ try {
183
+ const secret = ['gh', 'p_', 'c'.repeat(36)].join('');
184
+ const outcome = await captureCandidate(root, {
185
+ summary: 'the person corrected the agent',
186
+ observations: [{ kind: 'missing-file', detail: 'the file', session: `session-${secret}` }],
187
+ explicitCorrection: true,
188
+ });
189
+ expect(outcome.ok).toBe(true);
190
+ const observations = await readFile(join(root, '.openagentsy', 'lessons', 'observations.json'), 'utf8');
191
+ expect(observations).not.toContain(secret);
192
+ const lesson = await readFile(join(root, '.openagentsy', 'lessons', `${outcome.ok ? outcome.lesson.id : ''}.json`), 'utf8');
193
+ expect(lesson).not.toContain(secret);
194
+ }
195
+ finally {
196
+ await remove();
197
+ }
198
+ });
199
+ });
200
+ //# sourceMappingURL=capture.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.test.js","sourceRoot":"","sources":["../../src/lessons/capture.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ import { type EvalResult } from '../eval/types.js';
2
+ import { type Lesson, type LessonState } from './model.js';
3
+ /**
4
+ * The decision.
5
+ *
6
+ * A person decides what happens to a lesson: it is validated, applied,
7
+ * rejected, or observed. The tool that carries the decision is denied to
8
+ * every agent role by the permission map, and the command that runs this
9
+ * code is the one a person uses, so `decidedBy` is the human.
10
+ */
11
+ /** What a person can do to a lesson. */
12
+ export declare const LESSON_ACTIONS: readonly ["validate", "apply", "reject", "observe"];
13
+ export type LessonAction = (typeof LESSON_ACTIONS)[number];
14
+ /**
15
+ * The states an observation can land a lesson in.
16
+ *
17
+ * An observation is what a person saw: the behaviour did not change, a newer
18
+ * lesson took over, or the claim needs an answer before it can go on.
19
+ */
20
+ export declare const OBSERVE_OUTCOMES: readonly ["rolled_back", "superseded", "open_question"];
21
+ export type ObserveOutcome = (typeof OBSERVE_OUTCOMES)[number];
22
+ /** How many runs a suite proof needs. */
23
+ export declare const SUITE_RUNS = 3;
24
+ /** What a person decided. */
25
+ export type DecideInput = {
26
+ /** The lesson the decision is about. */
27
+ id: string;
28
+ /** What was decided. */
29
+ action: LessonAction;
30
+ /** Who decided. The human. */
31
+ decidedBy: string;
32
+ /** Why. */
33
+ reason: string;
34
+ /** The proof, when the decision rests on one. */
35
+ evalResult?: EvalResult;
36
+ /** The change the decision names, when it applies one. */
37
+ changeRef?: string;
38
+ /** The state an observation lands in, when the default is not wanted. */
39
+ outcome?: ObserveOutcome;
40
+ };
41
+ /** What the decision did. */
42
+ export type DecideOutcome = {
43
+ ok: true;
44
+ lesson: Lesson;
45
+ } | {
46
+ ok: false;
47
+ reason: string;
48
+ hint: string;
49
+ };
50
+ /**
51
+ * The state an observation of a lesson in this state lands in.
52
+ *
53
+ * An applied lesson is observed after the fact: the behaviour either changed
54
+ * or it did not, and a behaviour that did not change is a rollback. A
55
+ * candidate is observed while it is being considered: an observation that
56
+ * raises a question leaves it as a question, and an answered question goes
57
+ * back to being a candidate.
58
+ */
59
+ export declare function observeTarget(state: LessonState): LessonState | undefined;
60
+ /**
61
+ * The state a decision moves the lesson to.
62
+ */
63
+ export declare function targetState(lesson: Lesson, input: DecideInput): LessonState | undefined;
64
+ /**
65
+ * The path of the proof of a lesson.
66
+ *
67
+ * The proof is a file in the project the lesson is about, so the resolved
68
+ * path has to stay inside the project: a proof that names a directory above
69
+ * it, or a file somewhere else on the machine, is not a proof of this lesson.
70
+ */
71
+ export declare function proofPath(root: string, proof: string): string;
72
+ /**
73
+ * Record a decision.
74
+ *
75
+ * The move itself is the model's: this only finds the lesson, works out
76
+ * where the decision lands it, and writes the result. A decision that the
77
+ * lifecycle refuses is refused here too, with the reason the model gives.
78
+ */
79
+ export declare function decideLesson(root: string, input: DecideInput, now?: () => Date): Promise<DecideOutcome>;
80
+ /**
81
+ * The result of a proof, read from a file.
82
+ *
83
+ * A file that cannot be read is an error and not an absent result: the
84
+ * person who asked has to know which of the two it was.
85
+ */
86
+ export declare function readEvalResult(root: string, path: string): Promise<{
87
+ result?: EvalResult;
88
+ error?: string;
89
+ }>;
90
+ //# sourceMappingURL=decide.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decide.d.ts","sourceRoot":"","sources":["../../src/lessons/decide.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,UAAU,EAA+B,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAGL,KAAK,MAAM,EAEX,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AAGpB;;;;;;;GAOG;AAEH,wCAAwC;AACxC,eAAO,MAAM,cAAc,qDAAsD,CAAC;AAElF,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,yDAA0D,CAAC;AAExF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,yCAAyC;AACzC,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,6BAA6B;AAC7B,MAAM,MAAM,WAAW,GAAG;IACxB,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,wBAAwB;IACxB,MAAM,EAAE,YAAY,CAAC;IACrB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,6BAA6B;AAC7B,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS,CAWzE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS,CAevF;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS7D;AAmMD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,EAClB,GAAG,GAAE,MAAM,IAAuB,GACjC,OAAO,CAAC,aAAa,CAAC,CA4CxB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBlD"}