@meetless/mla 0.1.4

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 (202) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +81 -0
  3. package/dist/build-info.json +9 -0
  4. package/dist/bundles/ask-core.js +396 -0
  5. package/dist/bundles/mcp.js +16592 -0
  6. package/dist/bundles/trace-core.js +263 -0
  7. package/dist/cli.js +828 -0
  8. package/dist/commands/activate.js +781 -0
  9. package/dist/commands/adoption.js +130 -0
  10. package/dist/commands/ask.js +290 -0
  11. package/dist/commands/context.js +114 -0
  12. package/dist/commands/debug.js +313 -0
  13. package/dist/commands/doctor.js +1021 -0
  14. package/dist/commands/enrich.js +427 -0
  15. package/dist/commands/evidence.js +229 -0
  16. package/dist/commands/flush.js +184 -0
  17. package/dist/commands/graph.js +104 -0
  18. package/dist/commands/init.js +272 -0
  19. package/dist/commands/internal-active-review.js +322 -0
  20. package/dist/commands/internal-auto-index.js +188 -0
  21. package/dist/commands/internal-capture-decisions.js +320 -0
  22. package/dist/commands/internal-evidence-correlate.js +239 -0
  23. package/dist/commands/internal-evidence-hooks.js +240 -0
  24. package/dist/commands/internal-evidence-inject.js +231 -0
  25. package/dist/commands/internal-finalize.js +221 -0
  26. package/dist/commands/internal-pretool-observe.js +225 -0
  27. package/dist/commands/internal-refresh.js +136 -0
  28. package/dist/commands/internal-session-nudge.js +120 -0
  29. package/dist/commands/internal-steer-sync.js +117 -0
  30. package/dist/commands/internal-turn-recap.js +140 -0
  31. package/dist/commands/kb.js +375 -0
  32. package/dist/commands/kb_add.js +681 -0
  33. package/dist/commands/kb_forget.js +283 -0
  34. package/dist/commands/kb_move.js +45 -0
  35. package/dist/commands/kb_pending.js +410 -0
  36. package/dist/commands/kb_personal.js +149 -0
  37. package/dist/commands/kb_promote.js +188 -0
  38. package/dist/commands/kb_purge.js +168 -0
  39. package/dist/commands/kb_reingest.js +335 -0
  40. package/dist/commands/kb_retime.js +170 -0
  41. package/dist/commands/kb_review.js +391 -0
  42. package/dist/commands/kb_revision.js +179 -0
  43. package/dist/commands/kb_show.js +385 -0
  44. package/dist/commands/label.js +226 -0
  45. package/dist/commands/login.js +295 -0
  46. package/dist/commands/logout.js +108 -0
  47. package/dist/commands/mcp-supervisor.js +93 -0
  48. package/dist/commands/mcp.js +227 -0
  49. package/dist/commands/queue-prune.js +98 -0
  50. package/dist/commands/review.js +358 -0
  51. package/dist/commands/rewire.js +124 -0
  52. package/dist/commands/rules.js +728 -0
  53. package/dist/commands/scan-context.js +67 -0
  54. package/dist/commands/session.js +347 -0
  55. package/dist/commands/stats.js +479 -0
  56. package/dist/commands/status.js +61 -0
  57. package/dist/commands/summary.js +250 -0
  58. package/dist/commands/turn.js +114 -0
  59. package/dist/commands/uninstall.js +222 -0
  60. package/dist/commands/whoami.js +102 -0
  61. package/dist/commands/workspace.js +130 -0
  62. package/dist/hooks-template/ce0-post-tool-use.sh +34 -0
  63. package/dist/hooks-template/ce0-session-start.sh +49 -0
  64. package/dist/hooks-template/ce0-stop.sh +29 -0
  65. package/dist/hooks-template/ce0-user-prompt-submit.sh +38 -0
  66. package/dist/hooks-template/common.sh +934 -0
  67. package/dist/hooks-template/event-batch-filter.jq +67 -0
  68. package/dist/hooks-template/flush.sh +503 -0
  69. package/dist/hooks-template/post-tool-use.sh +423 -0
  70. package/dist/hooks-template/pre-tool-use.sh +69 -0
  71. package/dist/hooks-template/session-start.sh +140 -0
  72. package/dist/hooks-template/stop.sh +308 -0
  73. package/dist/hooks-template/user-prompt-submit.sh +1162 -0
  74. package/dist/lib/activation.js +79 -0
  75. package/dist/lib/active-conflict-cache.js +141 -0
  76. package/dist/lib/active-memory.js +59 -0
  77. package/dist/lib/active-review-runner.js +26 -0
  78. package/dist/lib/agent-decision/index.js +25 -0
  79. package/dist/lib/agent-decision/keys.js +49 -0
  80. package/dist/lib/agent-decision/normalize-claude.js +183 -0
  81. package/dist/lib/agent-decision/types.js +21 -0
  82. package/dist/lib/agent-decision/validate.js +216 -0
  83. package/dist/lib/analytics/capture.js +96 -0
  84. package/dist/lib/analytics/command-event.js +267 -0
  85. package/dist/lib/analytics/consent.js +58 -0
  86. package/dist/lib/analytics/coverage-gap.js +96 -0
  87. package/dist/lib/analytics/envelope.js +236 -0
  88. package/dist/lib/analytics/event-id.js +86 -0
  89. package/dist/lib/analytics/evidence.js +150 -0
  90. package/dist/lib/analytics/followthrough.js +194 -0
  91. package/dist/lib/analytics/forwarder.js +109 -0
  92. package/dist/lib/analytics/logs.js +78 -0
  93. package/dist/lib/analytics/metrics.js +78 -0
  94. package/dist/lib/analytics/recorder.js +92 -0
  95. package/dist/lib/analytics/review-analytics.js +75 -0
  96. package/dist/lib/analytics/sequence.js +77 -0
  97. package/dist/lib/analytics/store.js +131 -0
  98. package/dist/lib/analytics/turn-recap.js +279 -0
  99. package/dist/lib/artifact_id.js +108 -0
  100. package/dist/lib/auth-breaker.js +161 -0
  101. package/dist/lib/auto-index.js +112 -0
  102. package/dist/lib/classifier.js +88 -0
  103. package/dist/lib/config.js +298 -0
  104. package/dist/lib/conflict-advisory.js +64 -0
  105. package/dist/lib/debug-bundle.js +520 -0
  106. package/dist/lib/enrichment/ingest.js +301 -0
  107. package/dist/lib/enrichment/plan.js +253 -0
  108. package/dist/lib/enrichment/protocol.js +359 -0
  109. package/dist/lib/enrichment/scout-brief.js +176 -0
  110. package/dist/lib/failure-telemetry.js +444 -0
  111. package/dist/lib/git.js +200 -0
  112. package/dist/lib/governance-cache.js +77 -0
  113. package/dist/lib/governed-path-cache.js +76 -0
  114. package/dist/lib/http.js +677 -0
  115. package/dist/lib/identity-envelope.js +23 -0
  116. package/dist/lib/kb-candidate.js +65 -0
  117. package/dist/lib/kb_acl.js +98 -0
  118. package/dist/lib/login.js +353 -0
  119. package/dist/lib/mcp-fetchers.js +130 -0
  120. package/dist/lib/mcp-restart.js +47 -0
  121. package/dist/lib/observability.js +805 -0
  122. package/dist/lib/open-url.js +33 -0
  123. package/dist/lib/orphan-guard.js +70 -0
  124. package/dist/lib/packaged.js +21 -0
  125. package/dist/lib/reconcile-sessions.js +171 -0
  126. package/dist/lib/redactor.js +89 -0
  127. package/dist/lib/relationship-candidate-query.js +27 -0
  128. package/dist/lib/render.js +611 -0
  129. package/dist/lib/rules/applicability.js +64 -0
  130. package/dist/lib/rules/attest-code-rule-version.js +47 -0
  131. package/dist/lib/rules/attest-notes-location.js +217 -0
  132. package/dist/lib/rules/attest-rule-version.js +69 -0
  133. package/dist/lib/rules/canonical-json.js +97 -0
  134. package/dist/lib/rules/ce0-emit.js +64 -0
  135. package/dist/lib/rules/ce0-evidence.js +281 -0
  136. package/dist/lib/rules/ce0-recall-sample.js +82 -0
  137. package/dist/lib/rules/ce0-rule.js +55 -0
  138. package/dist/lib/rules/ce0-sampling-bucket.js +15 -0
  139. package/dist/lib/rules/ce0-store.js +683 -0
  140. package/dist/lib/rules/ce0-telemetry-project.js +93 -0
  141. package/dist/lib/rules/ce0-telemetry.js +158 -0
  142. package/dist/lib/rules/code-rule-registry.js +17 -0
  143. package/dist/lib/rules/command-match.js +185 -0
  144. package/dist/lib/rules/consult-evidence-binding.js +27 -0
  145. package/dist/lib/rules/consultation-capture-adapter.js +193 -0
  146. package/dist/lib/rules/content-match.js +56 -0
  147. package/dist/lib/rules/deny-admission.js +99 -0
  148. package/dist/lib/rules/durable-observation.js +190 -0
  149. package/dist/lib/rules/enforce-notes-version.js +421 -0
  150. package/dist/lib/rules/evaluation-input-hash.js +126 -0
  151. package/dist/lib/rules/evaluator.js +108 -0
  152. package/dist/lib/rules/inert-rule-families.js +51 -0
  153. package/dist/lib/rules/input-authority-resolver.js +241 -0
  154. package/dist/lib/rules/interception-schema.js +170 -0
  155. package/dist/lib/rules/interception-store.js +267 -0
  156. package/dist/lib/rules/live-input-authority.js +66 -0
  157. package/dist/lib/rules/local-matcher.js +108 -0
  158. package/dist/lib/rules/local-observe.js +79 -0
  159. package/dist/lib/rules/local-rule-version-repo.js +214 -0
  160. package/dist/lib/rules/memory-requirement.js +109 -0
  161. package/dist/lib/rules/notes-observe.js +39 -0
  162. package/dist/lib/rules/notes-path.js +261 -0
  163. package/dist/lib/rules/notes-rule.js +75 -0
  164. package/dist/lib/rules/observe-adapter.js +114 -0
  165. package/dist/lib/rules/observed-rule-hash.js +119 -0
  166. package/dist/lib/rules/prompt-submit-adapter.js +132 -0
  167. package/dist/lib/rules/requirement-subject.js +240 -0
  168. package/dist/lib/rules/rule-activity.js +67 -0
  169. package/dist/lib/rules/rule-version-hash.js +151 -0
  170. package/dist/lib/rules/runtime-scope.js +55 -0
  171. package/dist/lib/rules/stop-adapter.js +116 -0
  172. package/dist/lib/rules/stop-response-snapshot.js +174 -0
  173. package/dist/lib/rules/types.js +10 -0
  174. package/dist/lib/rules/ulid.js +46 -0
  175. package/dist/lib/rules/version-evaluation.js +156 -0
  176. package/dist/lib/scanner/agent-memory.js +99 -0
  177. package/dist/lib/scanner/bootstrap-summary.js +87 -0
  178. package/dist/lib/scanner/cache.js +59 -0
  179. package/dist/lib/scanner/frontmatter.js +42 -0
  180. package/dist/lib/scanner/parse-directives.js +69 -0
  181. package/dist/lib/scanner/parse-structured.js +72 -0
  182. package/dist/lib/scanner/render.js +73 -0
  183. package/dist/lib/scanner/scan.js +132 -0
  184. package/dist/lib/scanner/score.js +38 -0
  185. package/dist/lib/scanner/scout-mission.js +126 -0
  186. package/dist/lib/scanner/types.js +7 -0
  187. package/dist/lib/session-scope.js +195 -0
  188. package/dist/lib/spool.js +355 -0
  189. package/dist/lib/staleness.js +100 -0
  190. package/dist/lib/steer-cache.js +87 -0
  191. package/dist/lib/tagged-reference.js +20 -0
  192. package/dist/lib/temporal.js +109 -0
  193. package/dist/lib/turn-recap-emit.js +67 -0
  194. package/dist/lib/unwire.js +253 -0
  195. package/dist/lib/update-check.js +469 -0
  196. package/dist/lib/update-notifier.js +217 -0
  197. package/dist/lib/upgrade-apply.js +643 -0
  198. package/dist/lib/wire.js +1087 -0
  199. package/dist/lib/workspace.js +96 -0
  200. package/dist/lib/zip.js +154 -0
  201. package/dist/pretool-entry.js +37 -0
  202. package/package.json +75 -0
@@ -0,0 +1,281 @@
1
+ "use strict";
2
+ // Commit 9: the `mla evidence` CE0 labeling workflow, export half
3
+ // (notes/20260617-evidence-consultation-forcing-function-proposal.md §2.3). CE0 finalization is
4
+ // a human-driven LOCAL JSONL workflow: no model call, no external egress, no second deterministic
5
+ // finalizer. `ce0-export` writes a JSONL of the three-record facts a labeler needs for answer
6
+ // disposition and per-subject coverage audit; `ce0-import-labels` (slice 9b) reads the labeled
7
+ // file back, verifies each obligation's id and expected stateVersion, writes the terminal outcome,
8
+ // and moves status to FINALIZED.
9
+ //
10
+ // The CE0 nuance this module resolves: the live store never writes subjectSatisfaction. The
11
+ // runtime adapters only record facts (the assessment, the consultation attempts) and the first
12
+ // Stop freezes the eligibility boundary; the live subjectSatisfaction stays []. So the export is
13
+ // the one place the deterministic satisfaction reducer runs: it selects the eligible consultations
14
+ // (those that contributed a proof AND landed on or before the frozen deadline boundary) and
15
+ // recomputes the per-subject proof set. That recomputed set, NOT the live [], is the machine
16
+ // baseline the human audits against the terminal outcome they assign.
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.assembleCe0ExportRows = assembleCe0ExportRows;
19
+ exports.serializeCe0ExportRows = serializeCe0ExportRows;
20
+ exports.parseCe0ExportRows = parseCe0ExportRows;
21
+ exports.assembleCe0ExportLines = assembleCe0ExportLines;
22
+ exports.serializeCe0ExportLines = serializeCe0ExportLines;
23
+ exports.parseCe0ExportLines = parseCe0ExportLines;
24
+ exports.runCe0Export = runCe0Export;
25
+ exports.reconcileCe0Labels = reconcileCe0Labels;
26
+ exports.parseCe0LabelRows = parseCe0LabelRows;
27
+ exports.runCe0ImportLabels = runCe0ImportLabels;
28
+ const ce0_store_1 = require("./ce0-store");
29
+ const requirement_subject_1 = require("./requirement-subject");
30
+ const ce0_recall_sample_1 = require("./ce0-recall-sample");
31
+ /**
32
+ * Build the export rows for a workspace: one per deadline-claimed, non-finalized obligation. For
33
+ * each, read the turn's consultations, run the deterministic reducer over the eligible set bounded
34
+ * by the frozen deadline, and carry the recomputed proof set plus the raw consultation facts with
35
+ * their eligibility flag. Deterministic and side-effect-free; the store reads are already ordered.
36
+ */
37
+ function assembleCe0ExportRows(store, workspaceId) {
38
+ const rows = [];
39
+ for (const obl of (0, ce0_store_1.listDeadlineClaimedObligations)(store, workspaceId)) {
40
+ // FINALIZED obligations are already labeled; the export is for the set awaiting a label.
41
+ if (obl.status === "FINALIZED")
42
+ continue;
43
+ const consultations = (0, ce0_store_1.listConsultationsForTurn)(store, {
44
+ workspaceId: obl.workspaceId,
45
+ sessionId: obl.sessionId,
46
+ localTurnSequence: obl.localTurnSequence,
47
+ });
48
+ const reducerInputs = consultations.map(ce0_store_1.consultationRecordToReducerInput);
49
+ const eligible = (0, requirement_subject_1.selectEligibleConsultations)(reducerInputs, obl.deadlineClaimedAt);
50
+ const eligibleIds = new Set(eligible.map((c) => c.consultationId));
51
+ const subjectSatisfaction = (0, requirement_subject_1.recomputeSubjectSatisfaction)(obl.requiredSubjects, eligible);
52
+ rows.push({
53
+ obligationId: obl.obligationId,
54
+ workspaceId: obl.workspaceId,
55
+ sessionId: obl.sessionId,
56
+ localTurnSequence: obl.localTurnSequence,
57
+ ruleId: obl.ruleId,
58
+ ruleVersionId: obl.ruleVersionId,
59
+ requiredSubjects: obl.requiredSubjects,
60
+ status: obl.status,
61
+ stateVersion: obl.stateVersion,
62
+ deadlineClaimedAt: obl.deadlineClaimedAt,
63
+ deadlineClaimedVersion: obl.deadlineClaimedVersion,
64
+ responseHash: obl.responseHash,
65
+ subjectSatisfaction,
66
+ machineSatisfied: (0, requirement_subject_1.isObligationSatisfied)(obl.requiredSubjects, subjectSatisfaction),
67
+ consultations: consultations.map((c) => ({
68
+ consultationId: c.consultationId,
69
+ source: c.source,
70
+ consultationSubjects: c.consultationSubjects,
71
+ execution: c.execution,
72
+ result: c.result,
73
+ deliveredToAnsweringContext: c.deliveredToAnsweringContext,
74
+ orderingToken: c.orderingToken,
75
+ eligible: eligibleIds.has(c.consultationId),
76
+ })),
77
+ });
78
+ }
79
+ return rows;
80
+ }
81
+ /** Serialize export rows as JSONL: one JSON object per line, newline-terminated. An empty set
82
+ * serializes to the empty string (no spurious blank line). */
83
+ function serializeCe0ExportRows(rows) {
84
+ return rows.map((r) => JSON.stringify(r)).join("\n") + (rows.length > 0 ? "\n" : "");
85
+ }
86
+ /** Parse a JSONL export back into rows, ignoring blank lines so a trailing newline round-trips. */
87
+ function parseCe0ExportRows(jsonl) {
88
+ return jsonl
89
+ .split("\n")
90
+ .map((line) => line.trim())
91
+ .filter((line) => line.length > 0)
92
+ .map((line) => JSON.parse(line));
93
+ }
94
+ /**
95
+ * Assemble the full export stream for a workspace: every precision (obligation) line first, then every
96
+ * recall (sampled unflagged assessment) line. `recallSampleRate` thresholds the recall population only;
97
+ * the precision population is always complete. Deterministic and side-effect-free.
98
+ */
99
+ function assembleCe0ExportLines(store, workspaceId, recallSampleRate) {
100
+ const lines = [];
101
+ for (const obligation of assembleCe0ExportRows(store, workspaceId)) {
102
+ lines.push({ population: "PRECISION", obligation });
103
+ }
104
+ for (const recall of (0, ce0_recall_sample_1.assembleCe0RecallSampleRows)(store, workspaceId, recallSampleRate)) {
105
+ lines.push({ population: "RECALL", recall });
106
+ }
107
+ return lines;
108
+ }
109
+ /** Serialize export lines as JSONL: one JSON object per line, newline-terminated. An empty stream
110
+ * serializes to the empty string (no spurious blank line). */
111
+ function serializeCe0ExportLines(lines) {
112
+ return lines.map((l) => JSON.stringify(l)).join("\n") + (lines.length > 0 ? "\n" : "");
113
+ }
114
+ /** Parse a JSONL export back into lines, ignoring blank lines so a trailing newline round-trips. */
115
+ function parseCe0ExportLines(jsonl) {
116
+ return jsonl
117
+ .split("\n")
118
+ .map((line) => line.trim())
119
+ .filter((line) => line.length > 0)
120
+ .map((line) => JSON.parse(line));
121
+ }
122
+ /** The `mla evidence ce0-export` core: assemble the workspace's two-population stream and serialize it.
123
+ * `recallSampleRate` defaults to the pinned DEFAULT_RECALL_SAMPLE_RATE (sample every unflagged turn). */
124
+ function runCe0Export(store, workspaceId, recallSampleRate = ce0_recall_sample_1.DEFAULT_RECALL_SAMPLE_RATE) {
125
+ return serializeCe0ExportLines(assembleCe0ExportLines(store, workspaceId, recallSampleRate));
126
+ }
127
+ const OBLIGATION_OUTCOMES = new Set([
128
+ "NOT_DUE",
129
+ "COMPLIANT_ON_TIME",
130
+ "CONSULTED_LATE_WITH_EVIDENCE",
131
+ "CONSULTED_LATE_NO_EVIDENCE",
132
+ "MISSED",
133
+ "UNKNOWN",
134
+ "CANCELLED",
135
+ ]);
136
+ const COVERAGE_GRADES = new Set([
137
+ "FULL",
138
+ "PARTIAL",
139
+ "NONE",
140
+ "UNKNOWN",
141
+ ]);
142
+ /** Whether an outcome asserts the obligation was satisfied on time (true), missed (false), or is
143
+ * not a satisfaction claim at all (null). The agreement check compares this to the machine baseline. */
144
+ function satisfactionExpectation(outcome) {
145
+ switch (outcome) {
146
+ case "COMPLIANT_ON_TIME":
147
+ return true;
148
+ case "CONSULTED_LATE_WITH_EVIDENCE":
149
+ case "CONSULTED_LATE_NO_EVIDENCE":
150
+ case "MISSED":
151
+ return false;
152
+ case "NOT_DUE":
153
+ case "UNKNOWN":
154
+ case "CANCELLED":
155
+ return null;
156
+ }
157
+ }
158
+ /**
159
+ * Validate a labeled file against the export snapshot, producing the finalization commands, the
160
+ * rejections, and the machine-vs-human agreement summary. Pure: no store access, no side effects.
161
+ * Each label is checked in order (unknown obligation, stale stateVersion, bad outcome, bad grade,
162
+ * subject-coverage mismatch); the first failure rejects the label and no finalization is emitted.
163
+ */
164
+ function reconcileCe0Labels(exportRows, labelRows) {
165
+ const byId = new Map(exportRows.map((r) => [r.obligationId, r]));
166
+ const out = { finalizations: [], rejections: [], agreement: [] };
167
+ for (const label of labelRows) {
168
+ const row = byId.get(label.obligationId);
169
+ if (!row) {
170
+ out.rejections.push({
171
+ obligationId: label.obligationId,
172
+ reason: "unknown obligation: not in the export set (already finalized or never claimed)",
173
+ });
174
+ continue;
175
+ }
176
+ if (label.expectedStateVersion !== row.stateVersion) {
177
+ out.rejections.push({
178
+ obligationId: label.obligationId,
179
+ reason: `stale label: expected stateVersion ${label.expectedStateVersion}, export is ${row.stateVersion}`,
180
+ });
181
+ continue;
182
+ }
183
+ if (!OBLIGATION_OUTCOMES.has(label.outcome)) {
184
+ out.rejections.push({
185
+ obligationId: label.obligationId,
186
+ reason: `invalid outcome: ${String(label.outcome)} is not one of the seven terminal outcomes`,
187
+ });
188
+ continue;
189
+ }
190
+ const badGrade = label.perSubject.find((p) => !COVERAGE_GRADES.has(p.grade));
191
+ if (badGrade) {
192
+ out.rejections.push({
193
+ obligationId: label.obligationId,
194
+ reason: `invalid grade: ${String(badGrade.grade)} for subject ${badGrade.subjectId}`,
195
+ });
196
+ continue;
197
+ }
198
+ const requiredIds = new Set(row.requiredSubjects.map((s) => s.subjectId));
199
+ const gradedIds = new Set(label.perSubject.map((p) => p.subjectId));
200
+ const extra = [...gradedIds].find((id) => !requiredIds.has(id));
201
+ if (extra) {
202
+ out.rejections.push({
203
+ obligationId: label.obligationId,
204
+ reason: `grades a subject the obligation does not require: ${extra}`,
205
+ });
206
+ continue;
207
+ }
208
+ const ungraded = [...requiredIds].find((id) => !gradedIds.has(id));
209
+ if (ungraded) {
210
+ out.rejections.push({
211
+ obligationId: label.obligationId,
212
+ reason: `leaves a required subject ungraded: ${ungraded}`,
213
+ });
214
+ continue;
215
+ }
216
+ out.finalizations.push({
217
+ obligationId: label.obligationId,
218
+ expectedStateVersion: label.expectedStateVersion,
219
+ outcome: label.outcome,
220
+ });
221
+ const expectation = satisfactionExpectation(label.outcome);
222
+ out.agreement.push({
223
+ obligationId: label.obligationId,
224
+ machineSatisfied: row.machineSatisfied,
225
+ humanOutcome: label.outcome,
226
+ agrees: expectation === null ? null : expectation === row.machineSatisfied,
227
+ });
228
+ }
229
+ return out;
230
+ }
231
+ /** Parse a labeled JSONL back into rows, ignoring blank lines (mirrors parseCe0ExportRows). */
232
+ function parseCe0LabelRows(jsonl) {
233
+ return jsonl
234
+ .split("\n")
235
+ .map((line) => line.trim())
236
+ .filter((line) => line.length > 0)
237
+ .map((line) => JSON.parse(line));
238
+ }
239
+ /**
240
+ * The `mla evidence ce0-import-labels` core: assemble the workspace's current export snapshot,
241
+ * reconcile the labeled JSONL against it, then CAS-finalize each accepted label. The reconcile
242
+ * pre-flight gives clean human-facing rejections; the store's compare-and-swap is the authoritative
243
+ * write guard, so an already-finalized or concurrently-changed obligation can never be double-written.
244
+ */
245
+ function runCe0ImportLabels(store, workspaceId, labelJsonl) {
246
+ const exportRows = assembleCe0ExportRows(store, workspaceId);
247
+ const labels = parseCe0LabelRows(labelJsonl);
248
+ const reconciliation = reconcileCe0Labels(exportRows, labels);
249
+ const report = {
250
+ finalized: [],
251
+ conflicts: [],
252
+ rejected: [...reconciliation.rejections],
253
+ agreement: reconciliation.agreement,
254
+ };
255
+ for (const cmd of reconciliation.finalizations) {
256
+ const result = (0, ce0_store_1.finalizeObligation)(store, cmd);
257
+ switch (result.status) {
258
+ case "FINALIZED":
259
+ report.finalized.push({
260
+ obligationId: result.obligationId,
261
+ outcome: result.outcome,
262
+ stateVersion: result.stateVersion,
263
+ });
264
+ break;
265
+ case "CAS_CONFLICT":
266
+ report.conflicts.push({
267
+ obligationId: result.obligationId,
268
+ expectedStateVersion: result.expectedStateVersion,
269
+ actualStateVersion: result.actualStateVersion,
270
+ });
271
+ break;
272
+ case "NO_OBLIGATION":
273
+ report.rejected.push({
274
+ obligationId: result.obligationId,
275
+ reason: "obligation vanished between reconcile and finalize",
276
+ });
277
+ break;
278
+ }
279
+ }
280
+ return report;
281
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ // The offline recall-sampling threshold for `ce0-export`
3
+ // (notes/20260617-evidence-consultation-forcing-function-proposal.md lines 1010-1019, 2129).
4
+ //
5
+ // The durable store stamps EVERY classified turn with a uniform `samplingBucket` (a sha256 hex digest
6
+ // over the turn's natural key; see ce0-sampling-bucket.ts) and bakes in NO sampling rate. Recall (the
7
+ // false-negative rate) is constructible only from the NOT_REQUIRED / UNKNOWN turns we did not flag, so
8
+ // the OFFLINE export must choose WHICH of those unflagged turns to put in front of a grader. It does so
9
+ // by THRESHOLDING the bucket: read the leading 32 bits of the digest as a uniform fraction in [0, 1) and
10
+ // sample the turn iff that fraction is below the rate. Because the bucket is reconstructible from the
11
+ // turn's logical coordinate alone, sample membership is reproducible offline with no runtime random draw.
12
+ //
13
+ // The threshold is monotonic in the rate: a turn in the sample at rate r is in the sample at every rate
14
+ // above r. Widening the rate only ever ADDS turns, so a later, more generous export is a superset of an
15
+ // earlier one over the same store.
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.DEFAULT_RECALL_SAMPLE_RATE = void 0;
18
+ exports.isInRecallSample = isInRecallSample;
19
+ exports.assembleCe0RecallSampleRows = assembleCe0RecallSampleRows;
20
+ const ce0_store_1 = require("./ce0-store");
21
+ /**
22
+ * The pinned default recall sampling rate: 1.0, i.e. sample EVERY unflagged (NOT_REQUIRED / UNKNOWN)
23
+ * turn. At dogfood / measurement-harness scale the recall gate needs at least 100 sampled unflagged
24
+ * turns before recall is observable at all (proposal line 2129; line 2145: recall unmeasurable -> do
25
+ * not authorize CE1). Sampling DOWN from that starves the gate, so the default measures everything.
26
+ * The threshold machinery below exists so the rate can be dialed under 1.0 once a real pilot's volume
27
+ * forces a grader-load bound; it is not exercised by the default path.
28
+ */
29
+ exports.DEFAULT_RECALL_SAMPLE_RATE = 1;
30
+ /** The number of leading hex chars (32 bits) of the digest read as the sampling fraction. */
31
+ const PREFIX_HEX_CHARS = 8;
32
+ /** 2^32: the denominator that turns the 32-bit prefix into a fraction in [0, 1). */
33
+ const PREFIX_SPACE = 0x1_0000_0000;
34
+ /**
35
+ * Whether a turn whose assessment carries `samplingBucket` falls in the offline recall sample at `rate`.
36
+ * Reads the leading 32 bits of the digest as a uniform fraction and samples iff it is strictly below the
37
+ * rate. `rate >= 1` samples every turn; `rate <= 0` samples none. A malformed bucket (not a hex digest
38
+ * of at least 8 chars) is never sampled: the real producer always emits a 64-char sha256 digest, and a
39
+ * conservative exclude keeps a parse fault from silently corrupting the recall denominator.
40
+ */
41
+ function isInRecallSample(samplingBucket, rate) {
42
+ if (samplingBucket.length < PREFIX_HEX_CHARS)
43
+ return false;
44
+ const prefix = samplingBucket.slice(0, PREFIX_HEX_CHARS);
45
+ if (!/^[0-9a-f]{8}$/.test(prefix))
46
+ return false;
47
+ // The fraction is always in [0, 1) (the largest 32-bit prefix is 0xffffffff / 2^32 < 1), so this
48
+ // single comparison subsumes the rate bounds: rate >= 1 samples every valid bucket, rate <= 0 none.
49
+ const fraction = parseInt(prefix, 16) / PREFIX_SPACE;
50
+ return fraction < rate;
51
+ }
52
+ /**
53
+ * Build the recall-sample rows for a workspace: one per NOT_REQUIRED / UNKNOWN assessment whose
54
+ * samplingBucket falls in the sample at `rate`. Reads the store's ordered assessment list, so the rows
55
+ * inherit its (session, sequence, assessmentId) order. Deterministic and side-effect-free.
56
+ */
57
+ function assembleCe0RecallSampleRows(store, workspaceId, rate) {
58
+ const rows = [];
59
+ for (const a of (0, ce0_store_1.listTurnMemoryAssessments)(store, workspaceId)) {
60
+ // REQUIRED turns are the precision population (assembleCe0ExportRows); the recall sample is the
61
+ // unflagged turns only.
62
+ if (a.requirement === "REQUIRED")
63
+ continue;
64
+ if (!isInRecallSample(a.samplingBucket, rate))
65
+ continue;
66
+ const ref = a.responseSourceRef ?? null;
67
+ rows.push({
68
+ assessmentId: a.assessmentId,
69
+ workspaceId: a.workspaceId,
70
+ sessionId: a.sessionId,
71
+ localTurnSequence: a.localTurnSequence,
72
+ requirement: a.requirement,
73
+ samplingBucket: a.samplingBucket,
74
+ promptHash: a.promptHash,
75
+ responseHash: a.responseHash ?? null,
76
+ responseSourceRef: ref,
77
+ labelability: ref ? "LABELABLE" : "UNLABELABLE",
78
+ labelabilityReason: ref ? null : "NO_RESPONSE_SNAPSHOT",
79
+ });
80
+ }
81
+ return rows;
82
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CONSULT_EVIDENCE_CANONICAL_PAYLOAD_HASH = exports.CONSULT_EVIDENCE_RULE_PAYLOAD = exports.CONSULT_EVIDENCE_RESPONSE_CEILING = exports.CONSULT_EVIDENCE_RULE_VERSION_ID = exports.CONSULT_EVIDENCE_RULE_ID = void 0;
4
+ const canonical_json_1 = require("./canonical-json");
5
+ const memory_requirement_1 = require("./memory-requirement");
6
+ const requirement_subject_1 = require("./requirement-subject");
7
+ /**
8
+ * The ONE CE0 rule the forcing function records against:
9
+ * CONSULT_GOVERNED_EVIDENCE_ON_MEMORY_REQUIRED_TURN_V1
10
+ * (notes/20260617-evidence-consultation-forcing-function-proposal.md §1.3).
11
+ *
12
+ * This is NOT a second obligation framework. The canonical Rules primitive
13
+ * (types.ts / applicability.ts, commit 7cdbee1a) models PreToolUse ACTION gates;
14
+ * its "turn" mode is explicitly inert there. The turn-scoped obligation lives as the
15
+ * TurnRuleObligation record, created by the prompt-submit adapter and STAMPED with
16
+ * this module's frozen identity. This file only pins that identity; it owns no
17
+ * lifecycle and selects nothing.
18
+ *
19
+ * THE RESPONSE CEILING is RECORD_ONLY for CE0 and CE1: the hook observes and records,
20
+ * it NEVER injects, steers, asks, or denies. Raising the ceiling to AUTO_CORRECT is a
21
+ * CE2 concern that requires a NEW immutable rule version (a new ruleVersionId) minted
22
+ * after a separate policy ratification, never an in-place edit of this one.
23
+ *
24
+ * THE canonicalPayloadHash binds the obligation to the EXACT compiled rule that
25
+ * produced it: the rule identity plus the live trigger-classifier and subject-extractor
26
+ * seed versions. Because the payload reads those seed constants (it never hand-copies
27
+ * the literals), bumping any seed set rotates this hash, so an obligation is always
28
+ * attributable to a reproducible (classifier, extractor, seed-set) tuple. The digest is
29
+ * sha256 over RFC 8785 canonical JSON, the same discipline as the subject fingerprint.
30
+ */
31
+ exports.CONSULT_EVIDENCE_RULE_ID = "consult-evidence";
32
+ exports.CONSULT_EVIDENCE_RULE_VERSION_ID = "consult-evidence@ce0-v1";
33
+ exports.CONSULT_EVIDENCE_RESPONSE_CEILING = "RECORD_ONLY";
34
+ /** The closed, hashable identity of the compiled rule. All fields are strings; the seed
35
+ * versions are read from their owning modules so the payload cannot drift from the
36
+ * classifier / extractor actually wired into the adapter. */
37
+ exports.CONSULT_EVIDENCE_RULE_PAYLOAD = {
38
+ schemaVersion: "ce0-rule-v1",
39
+ ruleId: exports.CONSULT_EVIDENCE_RULE_ID,
40
+ ruleVersionId: exports.CONSULT_EVIDENCE_RULE_VERSION_ID,
41
+ responseCeiling: exports.CONSULT_EVIDENCE_RESPONSE_CEILING,
42
+ trigger: {
43
+ classifierVersion: memory_requirement_1.MEMORY_REQUIREMENT_CLASSIFIER_VERSION,
44
+ markerSetVersion: memory_requirement_1.MEMORY_REQUIREMENT_MARKER_SET_VERSION,
45
+ exclusionSetVersion: memory_requirement_1.MEMORY_REQUIREMENT_EXCLUSION_SET_VERSION,
46
+ },
47
+ subject: {
48
+ extractorVersion: requirement_subject_1.REQUIREMENT_SUBJECT_EXTRACTOR_VERSION,
49
+ fingerprintSchemaVersion: requirement_subject_1.SUBJECT_FINGERPRINT_SCHEMA_VERSION,
50
+ stopwordSetVersion: requirement_subject_1.SUBJECT_STOPWORD_SET_VERSION,
51
+ },
52
+ };
53
+ /** sha256(RFC 8785 canonical JSON of the rule payload). Stamped on every obligation as
54
+ * its canonicalPayloadHash so the obligation attests which compiled rule produced it. */
55
+ exports.CONSULT_EVIDENCE_CANONICAL_PAYLOAD_HASH = (0, canonical_json_1.sha256Hex)((0, canonical_json_1.canonicalize)(exports.CONSULT_EVIDENCE_RULE_PAYLOAD));
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.samplingBucketFor = samplingBucketFor;
4
+ const canonical_json_1 = require("./canonical-json");
5
+ /** Deterministic, uniform sampling bucket for one assessment: sha256 over the canonical natural key,
6
+ * the same hashing discipline as the rule and subject fingerprints (canonical-json). The full digest
7
+ * carries maximum entropy and bakes in no sampling cardinality; the offline export thresholds it to
8
+ * pick the rate. */
9
+ function samplingBucketFor(key) {
10
+ return (0, canonical_json_1.sha256Hex)((0, canonical_json_1.canonicalize)({
11
+ workspaceId: key.workspaceId,
12
+ sessionId: key.sessionId,
13
+ localTurnSequence: key.localTurnSequence,
14
+ }));
15
+ }