@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.
- package/LICENSE +201 -0
- package/README.md +81 -0
- package/dist/build-info.json +9 -0
- package/dist/bundles/ask-core.js +396 -0
- package/dist/bundles/mcp.js +16592 -0
- package/dist/bundles/trace-core.js +263 -0
- package/dist/cli.js +828 -0
- package/dist/commands/activate.js +781 -0
- package/dist/commands/adoption.js +130 -0
- package/dist/commands/ask.js +290 -0
- package/dist/commands/context.js +114 -0
- package/dist/commands/debug.js +313 -0
- package/dist/commands/doctor.js +1021 -0
- package/dist/commands/enrich.js +427 -0
- package/dist/commands/evidence.js +229 -0
- package/dist/commands/flush.js +184 -0
- package/dist/commands/graph.js +104 -0
- package/dist/commands/init.js +272 -0
- package/dist/commands/internal-active-review.js +322 -0
- package/dist/commands/internal-auto-index.js +188 -0
- package/dist/commands/internal-capture-decisions.js +320 -0
- package/dist/commands/internal-evidence-correlate.js +239 -0
- package/dist/commands/internal-evidence-hooks.js +240 -0
- package/dist/commands/internal-evidence-inject.js +231 -0
- package/dist/commands/internal-finalize.js +221 -0
- package/dist/commands/internal-pretool-observe.js +225 -0
- package/dist/commands/internal-refresh.js +136 -0
- package/dist/commands/internal-session-nudge.js +120 -0
- package/dist/commands/internal-steer-sync.js +117 -0
- package/dist/commands/internal-turn-recap.js +140 -0
- package/dist/commands/kb.js +375 -0
- package/dist/commands/kb_add.js +681 -0
- package/dist/commands/kb_forget.js +283 -0
- package/dist/commands/kb_move.js +45 -0
- package/dist/commands/kb_pending.js +410 -0
- package/dist/commands/kb_personal.js +149 -0
- package/dist/commands/kb_promote.js +188 -0
- package/dist/commands/kb_purge.js +168 -0
- package/dist/commands/kb_reingest.js +335 -0
- package/dist/commands/kb_retime.js +170 -0
- package/dist/commands/kb_review.js +391 -0
- package/dist/commands/kb_revision.js +179 -0
- package/dist/commands/kb_show.js +385 -0
- package/dist/commands/label.js +226 -0
- package/dist/commands/login.js +295 -0
- package/dist/commands/logout.js +108 -0
- package/dist/commands/mcp-supervisor.js +93 -0
- package/dist/commands/mcp.js +227 -0
- package/dist/commands/queue-prune.js +98 -0
- package/dist/commands/review.js +358 -0
- package/dist/commands/rewire.js +124 -0
- package/dist/commands/rules.js +728 -0
- package/dist/commands/scan-context.js +67 -0
- package/dist/commands/session.js +347 -0
- package/dist/commands/stats.js +479 -0
- package/dist/commands/status.js +61 -0
- package/dist/commands/summary.js +250 -0
- package/dist/commands/turn.js +114 -0
- package/dist/commands/uninstall.js +222 -0
- package/dist/commands/whoami.js +102 -0
- package/dist/commands/workspace.js +130 -0
- package/dist/hooks-template/ce0-post-tool-use.sh +34 -0
- package/dist/hooks-template/ce0-session-start.sh +49 -0
- package/dist/hooks-template/ce0-stop.sh +29 -0
- package/dist/hooks-template/ce0-user-prompt-submit.sh +38 -0
- package/dist/hooks-template/common.sh +934 -0
- package/dist/hooks-template/event-batch-filter.jq +67 -0
- package/dist/hooks-template/flush.sh +503 -0
- package/dist/hooks-template/post-tool-use.sh +423 -0
- package/dist/hooks-template/pre-tool-use.sh +69 -0
- package/dist/hooks-template/session-start.sh +140 -0
- package/dist/hooks-template/stop.sh +308 -0
- package/dist/hooks-template/user-prompt-submit.sh +1162 -0
- package/dist/lib/activation.js +79 -0
- package/dist/lib/active-conflict-cache.js +141 -0
- package/dist/lib/active-memory.js +59 -0
- package/dist/lib/active-review-runner.js +26 -0
- package/dist/lib/agent-decision/index.js +25 -0
- package/dist/lib/agent-decision/keys.js +49 -0
- package/dist/lib/agent-decision/normalize-claude.js +183 -0
- package/dist/lib/agent-decision/types.js +21 -0
- package/dist/lib/agent-decision/validate.js +216 -0
- package/dist/lib/analytics/capture.js +96 -0
- package/dist/lib/analytics/command-event.js +267 -0
- package/dist/lib/analytics/consent.js +58 -0
- package/dist/lib/analytics/coverage-gap.js +96 -0
- package/dist/lib/analytics/envelope.js +236 -0
- package/dist/lib/analytics/event-id.js +86 -0
- package/dist/lib/analytics/evidence.js +150 -0
- package/dist/lib/analytics/followthrough.js +194 -0
- package/dist/lib/analytics/forwarder.js +109 -0
- package/dist/lib/analytics/logs.js +78 -0
- package/dist/lib/analytics/metrics.js +78 -0
- package/dist/lib/analytics/recorder.js +92 -0
- package/dist/lib/analytics/review-analytics.js +75 -0
- package/dist/lib/analytics/sequence.js +77 -0
- package/dist/lib/analytics/store.js +131 -0
- package/dist/lib/analytics/turn-recap.js +279 -0
- package/dist/lib/artifact_id.js +108 -0
- package/dist/lib/auth-breaker.js +161 -0
- package/dist/lib/auto-index.js +112 -0
- package/dist/lib/classifier.js +88 -0
- package/dist/lib/config.js +298 -0
- package/dist/lib/conflict-advisory.js +64 -0
- package/dist/lib/debug-bundle.js +520 -0
- package/dist/lib/enrichment/ingest.js +301 -0
- package/dist/lib/enrichment/plan.js +253 -0
- package/dist/lib/enrichment/protocol.js +359 -0
- package/dist/lib/enrichment/scout-brief.js +176 -0
- package/dist/lib/failure-telemetry.js +444 -0
- package/dist/lib/git.js +200 -0
- package/dist/lib/governance-cache.js +77 -0
- package/dist/lib/governed-path-cache.js +76 -0
- package/dist/lib/http.js +677 -0
- package/dist/lib/identity-envelope.js +23 -0
- package/dist/lib/kb-candidate.js +65 -0
- package/dist/lib/kb_acl.js +98 -0
- package/dist/lib/login.js +353 -0
- package/dist/lib/mcp-fetchers.js +130 -0
- package/dist/lib/mcp-restart.js +47 -0
- package/dist/lib/observability.js +805 -0
- package/dist/lib/open-url.js +33 -0
- package/dist/lib/orphan-guard.js +70 -0
- package/dist/lib/packaged.js +21 -0
- package/dist/lib/reconcile-sessions.js +171 -0
- package/dist/lib/redactor.js +89 -0
- package/dist/lib/relationship-candidate-query.js +27 -0
- package/dist/lib/render.js +611 -0
- package/dist/lib/rules/applicability.js +64 -0
- package/dist/lib/rules/attest-code-rule-version.js +47 -0
- package/dist/lib/rules/attest-notes-location.js +217 -0
- package/dist/lib/rules/attest-rule-version.js +69 -0
- package/dist/lib/rules/canonical-json.js +97 -0
- package/dist/lib/rules/ce0-emit.js +64 -0
- package/dist/lib/rules/ce0-evidence.js +281 -0
- package/dist/lib/rules/ce0-recall-sample.js +82 -0
- package/dist/lib/rules/ce0-rule.js +55 -0
- package/dist/lib/rules/ce0-sampling-bucket.js +15 -0
- package/dist/lib/rules/ce0-store.js +683 -0
- package/dist/lib/rules/ce0-telemetry-project.js +93 -0
- package/dist/lib/rules/ce0-telemetry.js +158 -0
- package/dist/lib/rules/code-rule-registry.js +17 -0
- package/dist/lib/rules/command-match.js +185 -0
- package/dist/lib/rules/consult-evidence-binding.js +27 -0
- package/dist/lib/rules/consultation-capture-adapter.js +193 -0
- package/dist/lib/rules/content-match.js +56 -0
- package/dist/lib/rules/deny-admission.js +99 -0
- package/dist/lib/rules/durable-observation.js +190 -0
- package/dist/lib/rules/enforce-notes-version.js +421 -0
- package/dist/lib/rules/evaluation-input-hash.js +126 -0
- package/dist/lib/rules/evaluator.js +108 -0
- package/dist/lib/rules/inert-rule-families.js +51 -0
- package/dist/lib/rules/input-authority-resolver.js +241 -0
- package/dist/lib/rules/interception-schema.js +170 -0
- package/dist/lib/rules/interception-store.js +267 -0
- package/dist/lib/rules/live-input-authority.js +66 -0
- package/dist/lib/rules/local-matcher.js +108 -0
- package/dist/lib/rules/local-observe.js +79 -0
- package/dist/lib/rules/local-rule-version-repo.js +214 -0
- package/dist/lib/rules/memory-requirement.js +109 -0
- package/dist/lib/rules/notes-observe.js +39 -0
- package/dist/lib/rules/notes-path.js +261 -0
- package/dist/lib/rules/notes-rule.js +75 -0
- package/dist/lib/rules/observe-adapter.js +114 -0
- package/dist/lib/rules/observed-rule-hash.js +119 -0
- package/dist/lib/rules/prompt-submit-adapter.js +132 -0
- package/dist/lib/rules/requirement-subject.js +240 -0
- package/dist/lib/rules/rule-activity.js +67 -0
- package/dist/lib/rules/rule-version-hash.js +151 -0
- package/dist/lib/rules/runtime-scope.js +55 -0
- package/dist/lib/rules/stop-adapter.js +116 -0
- package/dist/lib/rules/stop-response-snapshot.js +174 -0
- package/dist/lib/rules/types.js +10 -0
- package/dist/lib/rules/ulid.js +46 -0
- package/dist/lib/rules/version-evaluation.js +156 -0
- package/dist/lib/scanner/agent-memory.js +99 -0
- package/dist/lib/scanner/bootstrap-summary.js +87 -0
- package/dist/lib/scanner/cache.js +59 -0
- package/dist/lib/scanner/frontmatter.js +42 -0
- package/dist/lib/scanner/parse-directives.js +69 -0
- package/dist/lib/scanner/parse-structured.js +72 -0
- package/dist/lib/scanner/render.js +73 -0
- package/dist/lib/scanner/scan.js +132 -0
- package/dist/lib/scanner/score.js +38 -0
- package/dist/lib/scanner/scout-mission.js +126 -0
- package/dist/lib/scanner/types.js +7 -0
- package/dist/lib/session-scope.js +195 -0
- package/dist/lib/spool.js +355 -0
- package/dist/lib/staleness.js +100 -0
- package/dist/lib/steer-cache.js +87 -0
- package/dist/lib/tagged-reference.js +20 -0
- package/dist/lib/temporal.js +109 -0
- package/dist/lib/turn-recap-emit.js +67 -0
- package/dist/lib/unwire.js +253 -0
- package/dist/lib/update-check.js +469 -0
- package/dist/lib/update-notifier.js +217 -0
- package/dist/lib/upgrade-apply.js +643 -0
- package/dist/lib/wire.js +1087 -0
- package/dist/lib/workspace.js +96 -0
- package/dist/lib/zip.js +154 -0
- package/dist/pretool-entry.js +37 -0
- 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
|
+
}
|