clearotron 0.3.1-beta.3 → 0.3.1-beta.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/build-info.json +2 -2
- package/driver/CHANGELOG.md +8 -0
- package/driver/citation-census.json +3 -3
- package/driver/common-law-receipts.mjs +11 -1
- package/driver/connotation-search.mjs +56 -5
- package/driver/contract-e3-backlog.mjs +31 -31
- package/driver/contract-vocabulary.mjs +59 -58
- package/driver/engine/mcp/gather-config.mjs +1 -1
- package/driver/gateway.mjs +29 -2
- package/driver/matter-frame-record.mjs +54 -1
- package/driver/package.json +1 -1
- package/driver/portal-service.mjs +43 -4
- package/driver/stages.mjs +17 -3
- package/driver/suite-census.json +38 -8
- package/driver/verify.mjs +83 -7
- package/mcp-server/CHANGELOG.md +4 -0
- package/mcp-server/package.json +1 -1
- package/package.json +1 -1
- package/portal-ui/dist/assets/{index-C-QysgZM.js → index-ChIQsMYp.js} +209 -103
- package/portal-ui/dist/assets/{index-CaSZbEMb.css → index-DBIs21e4.css} +22 -0
- package/portal-ui/dist/index.html +2 -2
- package/portal-ui/package.json +1 -1
- package/providers/oauth-mcp-bridge/CHANGELOG.md +4 -0
- package/providers/oauth-mcp-bridge/package.json +1 -1
- package/scripts/citation-line-check.mjs +53 -2
- package/scripts/deprecate-below.mjs +146 -0
- package/scripts/test-run.mjs +24 -1
- package/shared/connect-clients.mjs +52 -16
- package/shared/driver-dir.mjs +1 -1
package/build-info.json
CHANGED
package/driver/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# clearotron-driver
|
|
2
2
|
|
|
3
|
+
## 0.3.1-beta.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6d0c8f5: Fixed: The portal now tells your browser not to store the data its screens read. Those responses carry people's names, company access and run lists, and nothing previously said how long a browser could keep them.
|
|
8
|
+
|
|
9
|
+
For operators: every JSON response from the portal now sends `Cache-Control: no-store` and `Vary: Accept`. A route that sets a stricter policy of its own keeps it.
|
|
10
|
+
|
|
3
11
|
## 0.3.1-beta.3
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -21,7 +21,17 @@ import { driverDir } from "../shared/driver-dir.mjs"; // — one definition of
|
|
|
21
21
|
|
|
22
22
|
export const MIN_CELLS_PER_VARIANT = 7;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
// THE GRID CELL KEY, and it is the same class as the connotation join: one side is a term and platform
|
|
25
|
+
// WE dictated, the other is what a provider echoed into the ledger. It already stripped wrapping quotes
|
|
26
|
+
// and lowercased; it did not fold a CURLY quote, an em dash, a non-breaking space or a compatibility
|
|
27
|
+
// form, so the failure that stopped a production clearance on 2026-09-16 was available here too — one
|
|
28
|
+
// gate over, with the same shape and no arm on it.
|
|
29
|
+
//
|
|
30
|
+
// It composes `queryKey`, which is the one author of what "the same text" means across a provider
|
|
31
|
+
// boundary, and keeps its own wrapping-quote strip because a term arrives quoted here and does not there.
|
|
32
|
+
import { queryKey } from "./connotation-search.mjs";
|
|
33
|
+
|
|
34
|
+
const norm = (s) => queryKey(String(s || "").trim().replace(/^["'`\u2018\u2019\u201c\u201d]+|["'`\u2018\u2019\u201c\u201d]+$/g, ""));
|
|
25
35
|
|
|
26
36
|
// A table data row's cells, or null if the line isn't one.
|
|
27
37
|
function rowCells(ln) {
|
|
@@ -45,7 +45,10 @@ export function pickConnotationTerms(terms, maxTerms = 6) {
|
|
|
45
45
|
for (const t of (terms ?? [])) {
|
|
46
46
|
const v = String(t ?? "").trim();
|
|
47
47
|
if (!v) continue;
|
|
48
|
-
|
|
48
|
+
// KEYED THE SAME WAY THE GATES COMPARE. A producer that folds less than its consumer dictates two
|
|
49
|
+
// terms the gate can only see as one, and a seat recording either satisfies it for both — the gate
|
|
50
|
+
// then passes a query that never ran, which is the fault it exists to catch, inverted.
|
|
51
|
+
const k = queryKey(v);
|
|
49
52
|
if (seen.has(k)) continue;
|
|
50
53
|
seen.add(k);
|
|
51
54
|
picked.push(v);
|
|
@@ -83,7 +86,7 @@ const NON_LATIN_LETTER_RE = /(?![\p{Script=Latin}])\p{L}/u;
|
|
|
83
86
|
* Returns ["<form> <shape>", …] like buildConnotationQueries. PURE.
|
|
84
87
|
*/
|
|
85
88
|
export function buildTranslitConnotationQueries(modelVariants, { shapes = CONNOTATION_SHAPES_TRANSLIT, maxTerms = 8, coreTerms = [] } = {}) {
|
|
86
|
-
const seen = new Set((coreTerms ?? []).map((t) =>
|
|
89
|
+
const seen = new Set((coreTerms ?? []).map((t) => queryKey(t)).filter(Boolean));
|
|
87
90
|
const picked = [];
|
|
88
91
|
for (const v of (modelVariants ?? [])) {
|
|
89
92
|
const value = String(v?.value ?? "").trim();
|
|
@@ -93,7 +96,7 @@ export function buildTranslitConnotationQueries(modelVariants, { shapes = CONNOT
|
|
|
93
96
|
for (const form of value.split(" / ")) {
|
|
94
97
|
const f = form.trim();
|
|
95
98
|
if (!f) continue;
|
|
96
|
-
const k = f
|
|
99
|
+
const k = queryKey(f);
|
|
97
100
|
if (seen.has(k)) continue;
|
|
98
101
|
seen.add(k);
|
|
99
102
|
picked.push(f);
|
|
@@ -177,7 +180,7 @@ export function meaningAnglesFromMatterContext(md, { alreadyQueried = [], maxAng
|
|
|
177
180
|
if (!m) return [];
|
|
178
181
|
const value = m[1].trim();
|
|
179
182
|
if (/^none\b/i.test(value)) return [];
|
|
180
|
-
const seen = new Set((alreadyQueried ?? []).map((q) =>
|
|
183
|
+
const seen = new Set((alreadyQueried ?? []).map((q) => queryKey(q)).filter(Boolean));
|
|
181
184
|
const picked = [];
|
|
182
185
|
for (const part of value.split(";")) {
|
|
183
186
|
const q = sanitizeMeaningAngle(part);
|
|
@@ -186,7 +189,7 @@ export function meaningAnglesFromMatterContext(md, { alreadyQueried = [], maxAng
|
|
|
186
189
|
// keeps it, and a lone `"` dictated as a query is a search nobody asked for that no receipt can ever
|
|
187
190
|
// match — the failure this change exists to stop. Dropped explicitly rather than as a side effect.
|
|
188
191
|
if (!q || !/[\p{L}\p{N}]/u.test(q) || q.length > maxLen) continue;
|
|
189
|
-
const k = q
|
|
192
|
+
const k = queryKey(q);
|
|
190
193
|
if (seen.has(k)) continue;
|
|
191
194
|
seen.add(k);
|
|
192
195
|
picked.push(q);
|
|
@@ -225,6 +228,54 @@ const SECTION_RE = /reputational|connotation/i;
|
|
|
225
228
|
* in common-law-receipts.mjs (parsePrRiskQueries); this entries parser lives here so the P2-A-owned file is
|
|
226
229
|
* untouched. Never throws; an unparseable ledger reads as no recorded entries. PURE.
|
|
227
230
|
*/
|
|
231
|
+
/**
|
|
232
|
+
* The key two spellings of one meaning query are compared on. ONE AUTHOR, here, beside the parser that
|
|
233
|
+
* reads the ledger — the gate in verify.mjs imports it rather than carrying a second copy.
|
|
234
|
+
*
|
|
235
|
+
* WHY THE RAW STRINGS CANNOT BE COMPARED. The dictated queries are written by the driver; the recorded
|
|
236
|
+
* ones come back through a provider, which returns the text it echoes with typographic punctuation. On a
|
|
237
|
+
* production clearance, 2026-09-16, exactly one of sixty-one queries differed — a single character, a
|
|
238
|
+
* right single quotation mark where the driver wrote an apostrophe, at the same length. The grid had run
|
|
239
|
+
* every query and recorded every one. The join said a query was unrecorded, the stage failed four times
|
|
240
|
+
* byte-identically, and the clearance stopped.
|
|
241
|
+
*
|
|
242
|
+
* THE ORIGINAL TEXT IS NOT TOUCHED. This is a comparison key and nothing else: the ledger keeps what the
|
|
243
|
+
* provider returned and the refusal quotes what the driver dictated, because a reader chasing a genuinely
|
|
244
|
+
* missing query needs the spelling that was asked for, not a flattened one.
|
|
245
|
+
*
|
|
246
|
+
* WHAT IS FOLDED, and nothing beyond it: the four curly quotes to their straight forms, a non-breaking
|
|
247
|
+
* space to a space, runs of whitespace to one, and case. Deliberately NOT accents or punctuation in
|
|
248
|
+
* general — two queries differing by a letter are two queries, and a key that folded them would hide the
|
|
249
|
+
* skipped-query fault this gate exists to catch.
|
|
250
|
+
*
|
|
251
|
+
* ONE HALF OF THAT SENTENCE NEEDS SAYING OUT LOUD, because omitting it cost a fail-open. NFKC folds the
|
|
252
|
+
* two ENCODINGS of one accented letter — composed U+00E9 and decomposed e + U+0301 — while leaving the
|
|
253
|
+
* accented letter distinct from its unaccented form. Mixed-source transliterations are exactly where
|
|
254
|
+
* both encodings arrive, so two producer rows that look different fold to one key here. EVERY producer
|
|
255
|
+
* that dedups a dictated list must therefore key on THIS function: a producer folding less than the gate
|
|
256
|
+
* dictates queries the gate cannot tell apart, and the gate then passes on a seat recording one of them.
|
|
257
|
+
*/
|
|
258
|
+
export const queryKey = (s) => String(s ?? "")
|
|
259
|
+
// NFKC FIRST, and it does the largest share of the work: it folds the compatibility forms a provider
|
|
260
|
+
// can return for characters we wrote plainly — full-width Latin, ligatures, the non-breaking space in
|
|
261
|
+
// some sources, composed accents to a single canonical form. Doing it first also means the explicit
|
|
262
|
+
// folds below only have to name what Unicode does NOT unify, which is the punctuation classes.
|
|
263
|
+
.normalize("NFKC")
|
|
264
|
+
.replace(/[\u2018\u2019\u201a\u201b\u2032\u00b4\u0060]/g, "'") // single quotes, primes, backtick
|
|
265
|
+
.replace(/[\u201c\u201d\u201e\u201f\u2033\u00ab\u00bb]/g, '"') // double quotes and guillemets
|
|
266
|
+
.replace(/[\u2010-\u2015\u2212\u2043]/g, "-") // every dash and minus form
|
|
267
|
+
.replace(/\u2026/g, "...") // an ellipsis is three dots
|
|
268
|
+
.replace(/[\u200b\u200c\u200d\u2060\ufeff]/g, "") // zero-width: invisible, never meaning
|
|
269
|
+
.replace(/[\u00a0\u2000-\u200a\u202f\u205f\u3000]/g, " ") // every space form NFKC left alone
|
|
270
|
+
.replace(/\s+/g, " ")
|
|
271
|
+
.trim()
|
|
272
|
+
// TRAILING PUNCTUATION ONLY, never leading and never internal. A provider commonly returns a question
|
|
273
|
+
// it was handed with a full stop or question mark appended; it does not commonly remove one from the
|
|
274
|
+
// front, and stripping internal punctuation would fold two genuinely different queries together.
|
|
275
|
+
.replace(/[.,;:!?]+$/, "")
|
|
276
|
+
.trim()
|
|
277
|
+
.toLowerCase();
|
|
278
|
+
|
|
228
279
|
export function parsePrRiskResults(ledgerRaw) {
|
|
229
280
|
let parsed;
|
|
230
281
|
try { parsed = JSON.parse(ledgerRaw); } catch { return []; }
|
|
@@ -185,7 +185,7 @@ export const E3_BACKLOG = [
|
|
|
185
185
|
// it one: authored once in renderConnotationObligations, and reaching the seat through the perplexity
|
|
186
186
|
// MCP server (driver/engine/mcp/perplexity-server.mjs:111) rather than a stage message. Three rows
|
|
187
187
|
// pointing at one block would fabricate two authored sites the surface does not have.
|
|
188
|
-
where: "driver/connotation-search.mjs:
|
|
188
|
+
where: "driver/connotation-search.mjs:1435-1448 (renderConnotationObligations; delivered to the seat via driver/engine/mcp/perplexity-server.mjs:111 — a TOOL RESPONSE, no longer a stage message)",
|
|
189
189
|
surface: "tool-response",
|
|
190
190
|
// ── (a) THE ORIGINAL SUBJECT WAS DELETED BY DESIGN — DISCHARGED, NOT FAILED ────────────────────
|
|
191
191
|
// The old rows dictated `receipt_id` (an 8-char token the seat copied) and `quote`. Both are gone:
|
|
@@ -256,7 +256,7 @@ export const E3_BACKLOG = [
|
|
|
256
256
|
{
|
|
257
257
|
stage: "register-unit",
|
|
258
258
|
kind: "literal-json-skeleton",
|
|
259
|
-
where: "driver/stages.mjs:
|
|
259
|
+
where: "driver/stages.mjs:2253 (the non-supplemental-lane branch)",
|
|
260
260
|
surface: "stage-message",
|
|
261
261
|
evidence: "BAND ARTIFACT (MANDATORY): ALSO write the COMPLETE NAMED BAND for this axis to <path> — a JSON ARRAY, one block per register_enumerate / count-probe call, in the named-band contract: {\"state\":\"enumerated\",\"query\":\"<what was searched>\",\"total_hits\":N,\"records\":[{record_id, mark_text, classes, status,",
|
|
262
262
|
reparsedBy: "driver/named-band.mjs parseNamedBand / bandRecords / bandCrowds / mergeNamedBands (named in driver/skills/prelim-register/unit.md:60-62); validators.registerUnit",
|
|
@@ -265,7 +265,7 @@ export const E3_BACKLOG = [
|
|
|
265
265
|
{
|
|
266
266
|
stage: "register-unit",
|
|
267
267
|
kind: "exactly-these-keys",
|
|
268
|
-
where: "driver/stages.mjs:
|
|
268
|
+
where: "driver/stages.mjs:2217",
|
|
269
269
|
surface: "stage-message",
|
|
270
270
|
evidence: "Every block you append MUST carry \"state\":\"enumerated\" (ONLY if you paged it to has_more:false) or \"state\":\"incomplete\" — EXACTLY those two strings; there is no \"verified\"/\"checked\"/\"complete\"/\"clean\" state, and any other value fails the stage.",
|
|
271
271
|
reparsedBy: "driver/named-band.mjs parseNamedBand (off-enum state fails validators.registerUnit)",
|
|
@@ -283,7 +283,7 @@ export const E3_BACKLOG = [
|
|
|
283
283
|
{
|
|
284
284
|
stage: "register-unit",
|
|
285
285
|
kind: "exactly-these-keys",
|
|
286
|
-
where: "driver/stages.mjs:
|
|
286
|
+
where: "driver/stages.mjs:4191 (the frame-reopen / scoped-retry message builder). A second number stood here and had been stale for some time: it pointed at a contract-element description rather than a builder, at its old line and at every mechanical shift of it. Two candidate builders sit beside 4157 and picking one would be a guess, so the wrong pointer is removed rather than moved a third time — one accurate citation beats one accurate and one invented.",
|
|
287
287
|
surface: "stage-message",
|
|
288
288
|
evidence: "Every block you append MUST carry \"state\":\"enumerated\" (ONLY if paged to has_more:false) or \"state\":\"incomplete\" — EXACTLY those two strings … (re-dispatch builders, which REPLACE def.message)",
|
|
289
289
|
reparsedBy: "driver/named-band.mjs parseNamedBand. Scope warning: these builders replace def.message on every escalation / envelope-close / frame-reopen dispatch, so an E3 lint that walks STAGES[*].message only never sees them",
|
|
@@ -301,7 +301,7 @@ export const E3_BACKLOG = [
|
|
|
301
301
|
{
|
|
302
302
|
stage: "placement-inquiry",
|
|
303
303
|
kind: "exactly-these-keys",
|
|
304
|
-
where: "driver/stages.mjs:
|
|
304
|
+
where: "driver/stages.mjs:2413",
|
|
305
305
|
surface: "stage-message",
|
|
306
306
|
evidence: "· tier EXACTLY one of headline-candidate / sheet-2 / watchlist-annex / out-of-scope-filtered.",
|
|
307
307
|
reparsedBy: "driver/placement-form.mjs / driver/placement-model.mjs via validators.placement",
|
|
@@ -346,7 +346,7 @@ export const E3_BACKLOG = [
|
|
|
346
346
|
// (coverage-form.mjs coverageFormBrief) and the tool schema, with every row receiver-validated at
|
|
347
347
|
// call time. Same dictated vocabulary, same authored site, new route — this row's evidence follows
|
|
348
348
|
// the dictation so the row keeps describing something that exists.
|
|
349
|
-
where: "driver/stages.mjs:
|
|
349
|
+
where: "driver/stages.mjs:2618 (the digest message) + driver/coverage-form.mjs (coverageFormBrief — the dispatch block carrying the enum and the row shape)",
|
|
350
350
|
surface: "stage-message",
|
|
351
351
|
evidence: "Record a \"status\" and a \"reason\" on EVERY row ONLY by calling the … tool — the driver validates each row as it arrives, holds the record itself, and renders both the ## Coverage ledger table and the coverage JSON from it",
|
|
352
352
|
reparsedBy: "driver/coverage-call.mjs validateCoverageCall (receiver-validated at call time, the same predicates the gate judges with) + driver/coverage-form.mjs rowIsSettled via validators.registerFindings over the _driver/ accumulator",
|
|
@@ -429,7 +429,7 @@ export const E3_BACKLOG = [
|
|
|
429
429
|
{
|
|
430
430
|
stage: "frame-diff",
|
|
431
431
|
kind: "exactly-these-keys",
|
|
432
|
-
where: "driver/stages.mjs:
|
|
432
|
+
where: "driver/stages.mjs:2798",
|
|
433
433
|
surface: "stage-message",
|
|
434
434
|
evidence: "For each blind-model variant / field / source the run did NOT scope or search, emit one directive {layer, item, observation, severity} … severity = dominant-element (the omission is ON the spine) | material (a real omission worth a targeted sweep) | minor (already covered, or presentation only).",
|
|
435
435
|
reparsedBy: "driver/verify.mjs validators.frameDiff + driver/pipeline.mjs runSupplementalSweeps (the parser REFUSES a firing variant directive that dictates nothing dispatchable)",
|
|
@@ -453,7 +453,7 @@ export const E3_BACKLOG = [
|
|
|
453
453
|
{
|
|
454
454
|
stage: "synthesis",
|
|
455
455
|
kind: "literal-json-skeleton",
|
|
456
|
-
where: "driver/stages.mjs:
|
|
456
|
+
where: "driver/stages.mjs:3178",
|
|
457
457
|
surface: "stage-message",
|
|
458
458
|
evidence: "MACHINE FINDINGS (MANDATORY): … a JSON OBJECT {\"schema_version\":<FINDINGS_SCHEMA_VERSION>,\"rated_under_framework\":\"…\",\"findings\":[...],\"coverage\":[...],\"context_notes\":[...],\"actions\":[...],\"ask_answers\":[...]} … Each finding object has EXACTLY these keys: {\"ordinal\",\"mark\",\"owner\",\"band\",\"net\",\"bor",
|
|
459
459
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson via validators.narrative",
|
|
@@ -467,7 +467,7 @@ export const E3_BACKLOG = [
|
|
|
467
467
|
{
|
|
468
468
|
stage: "synthesis",
|
|
469
469
|
kind: "exactly-these-keys",
|
|
470
|
-
where: "driver/stages.mjs:
|
|
470
|
+
where: "driver/stages.mjs:3214",
|
|
471
471
|
surface: "stage-message",
|
|
472
472
|
evidence: "- off_field_ground (MANDATORY on every off-field finding, FORBIDDEN on every other disposition): EXACTLY one bare token of: ${OFF_FIELD_GROUNDS.join(\" / \")}",
|
|
473
473
|
reparsedBy: "driver/findings-model.mjs validateOffFieldGround — the enum is imported from findings-model.mjs and interpolated back into the prompt, so code already holds the list it asks the model to type",
|
|
@@ -476,7 +476,7 @@ export const E3_BACKLOG = [
|
|
|
476
476
|
{
|
|
477
477
|
stage: "synthesis",
|
|
478
478
|
kind: "literal-json-skeleton",
|
|
479
|
-
where: "driver/stages.mjs:
|
|
479
|
+
where: "driver/stages.mjs:3215",
|
|
480
480
|
surface: "stage-message",
|
|
481
481
|
evidence: "- manageable …: {\"category\":\"<EXACTLY one of large-competitor / commercial-partner / troll / well-known-enforcer>\",\"reason\":\"<one-two lines…>\"}",
|
|
482
482
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson",
|
|
@@ -485,16 +485,16 @@ export const E3_BACKLOG = [
|
|
|
485
485
|
{
|
|
486
486
|
stage: "synthesis",
|
|
487
487
|
kind: "literal-json-skeleton",
|
|
488
|
-
where: "driver/stages.mjs:
|
|
488
|
+
where: "driver/stages.mjs:3231",
|
|
489
489
|
surface: "stage-message",
|
|
490
490
|
evidence: "- meters: {\"mark_similarity\":{...},\"goods_proximity\":{...},\"use\":{...},\"enforcer\":{...}} — all four present, each {\"token\",\"basis\",\"source\"}. … mark_similarity = high | medium | low. goods_proximity = high | medium | low. enforcer = high | medium | low | unknown. use = confirmed | not-confirmed | un",
|
|
491
|
-
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson; driver/verify.mjs:
|
|
491
|
+
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson; driver/verify.mjs:1108 checkFindingsSibling gates meters.*.source; finding_basis_source_missing",
|
|
492
492
|
removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
|
|
493
493
|
},
|
|
494
494
|
{
|
|
495
495
|
stage: "synthesis",
|
|
496
496
|
kind: "literal-json-skeleton",
|
|
497
|
-
where: "driver/stages.mjs:
|
|
497
|
+
where: "driver/stages.mjs:3232",
|
|
498
498
|
surface: "stage-message",
|
|
499
499
|
evidence: "- quadrant: {\"x\",\"y\"} numbers in [0,1]. x = goods/services proximity (0 = distant, 1 = identical). y = mark similarity (0 = distinct, 1 = identical).",
|
|
500
500
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson",
|
|
@@ -503,7 +503,7 @@ export const E3_BACKLOG = [
|
|
|
503
503
|
{
|
|
504
504
|
stage: "synthesis",
|
|
505
505
|
kind: "literal-json-skeleton",
|
|
506
|
-
where: "driver/stages.mjs:
|
|
506
|
+
where: "driver/stages.mjs:3233",
|
|
507
507
|
surface: "stage-message",
|
|
508
508
|
evidence: "- source: {\"source_type\",\"resolved_link\"}. source_type EXACTLY one of: register-vendor / register-euipo / common-law-marketplace / common-law-web / case-law",
|
|
509
509
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson",
|
|
@@ -512,7 +512,7 @@ export const E3_BACKLOG = [
|
|
|
512
512
|
{
|
|
513
513
|
stage: "synthesis",
|
|
514
514
|
kind: "exactly-these-keys",
|
|
515
|
-
where: "driver/stages.mjs:
|
|
515
|
+
where: "driver/stages.mjs:3234",
|
|
516
516
|
surface: "stage-message",
|
|
517
517
|
evidence: "coverage[]: ONE object per coverage AREA, EXACTLY {\"area\",\"state\",\"note\"}. … state EXACTLY one of: confirmed-clean / coverage-limited / open / not-searched / note.",
|
|
518
518
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson; the render owns the coverage panel from these typed states",
|
|
@@ -521,7 +521,7 @@ export const E3_BACKLOG = [
|
|
|
521
521
|
{
|
|
522
522
|
stage: "synthesis",
|
|
523
523
|
kind: "literal-json-skeleton",
|
|
524
|
-
where: "driver/stages.mjs:
|
|
524
|
+
where: "driver/stages.mjs:3243",
|
|
525
525
|
surface: "stage-message",
|
|
526
526
|
evidence: "use_check = {\"source\",\"quality\"}: … quality: OPTIONAL, EXACTLY one of owner-site / independent / register-mirror … own_rights = {\"source\"}",
|
|
527
527
|
reparsedBy: "driver/verify.mjs:988 checkFindingsSibling (finding_use_check_missing); driver/own-rights.mjs:19-22",
|
|
@@ -530,7 +530,7 @@ export const E3_BACKLOG = [
|
|
|
530
530
|
{
|
|
531
531
|
stage: "synthesis",
|
|
532
532
|
kind: "literal-json-skeleton",
|
|
533
|
-
where: "driver/stages.mjs:
|
|
533
|
+
where: "driver/stages.mjs:3300",
|
|
534
534
|
surface: "stage-message",
|
|
535
535
|
evidence: "MARK ASSESSMENT … STRUCTURED FORM …: either field may instead be an OBJECT {\"read\":\"…\",\"spectrum\":\"…\",\"per_class\":[{\"class\":\"5\",\"note\":\"…\"}],\"per_market\":[{\"market\":\"CN\",\"note\":\"…\"}],\"counter_registrations\":[{\"mark\":\"…\",\"uri\":\"/mark/…\",\"note\":\"…\"}],\"acquired\":\"<optional>\",\"note\":\"<optional residual>",
|
|
536
536
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson; the report collapses the rows behind toggles and the audit workbook renders them",
|
|
@@ -539,7 +539,7 @@ export const E3_BACKLOG = [
|
|
|
539
539
|
{
|
|
540
540
|
stage: "synthesis",
|
|
541
541
|
kind: "literal-json-skeleton",
|
|
542
|
-
where: "driver/stages.mjs:
|
|
542
|
+
where: "driver/stages.mjs:3306",
|
|
543
543
|
surface: "stage-message",
|
|
544
544
|
evidence: "FOUR ANSWERS …: \"four_answers\": {\"third_party_rights\":{...},\"objection_likelihood\":{...},\"registrability\":{...},\"client_enforceability\":{...}} … Each answer … is {\"read\":\"…\",\"token\":\"…\",\"basis\":\"…\",\"ordinals\":[…]}. Tokens (closed enums …): third_party_rights = strong|moderate|weak; objection_likelih",
|
|
545
545
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson",
|
|
@@ -557,7 +557,7 @@ export const E3_BACKLOG = [
|
|
|
557
557
|
{
|
|
558
558
|
stage: "synthesis",
|
|
559
559
|
kind: "exactly-these-keys",
|
|
560
|
-
where: "driver/stages.mjs:
|
|
560
|
+
where: "driver/stages.mjs:3313",
|
|
561
561
|
surface: "stage-message",
|
|
562
562
|
evidence: "COVERAGE JUDGMENT …: emit \"coverage_judgment\": {\"sufficient\":<bool>, \"reason\":\"<one line…>\"} — EXACTLY those two keys. Do NOT emit \"rows\": the driver writes that register itself … anything you type there is replaced wholesale.",
|
|
563
563
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson. The \"Do NOT emit rows\" clause is the purest E3 case in the tree — the prompt names a field, dictates its shape and states in the same breath that code overwrites it",
|
|
@@ -566,7 +566,7 @@ export const E3_BACKLOG = [
|
|
|
566
566
|
{
|
|
567
567
|
stage: "synthesis",
|
|
568
568
|
kind: "literal-json-skeleton",
|
|
569
|
-
where: "driver/stages.mjs:
|
|
569
|
+
where: "driver/stages.mjs:3156",
|
|
570
570
|
surface: "stage-message",
|
|
571
571
|
// RE-QUOTED, NOT PARKED. The writer's conversion reworded this dictation — the
|
|
572
572
|
// ask answers ride the findings RECORD now and the driver renders the labelled line into both the
|
|
@@ -590,7 +590,7 @@ export const E3_BACKLOG = [
|
|
|
590
590
|
{
|
|
591
591
|
stage: "synthesis",
|
|
592
592
|
kind: "dictated-line-shape",
|
|
593
|
-
where: "driver/stages.mjs:
|
|
593
|
+
where: "driver/stages.mjs:3077 (restated at driver/skills/prelim-search/synthesis-rules.md:428)",
|
|
594
594
|
surface: "stage-message",
|
|
595
595
|
evidence: "END that finding's actual-use line with a literal \"- **Use-check source:** <result URL | \"perplexity_research — no result\">\" line",
|
|
596
596
|
reparsedBy: "driver/verify.mjs validators.narrative (spec-11 hard reject); the repair hint re-dictates the literal at driver/gateway.mjs:2153",
|
|
@@ -599,7 +599,7 @@ export const E3_BACKLOG = [
|
|
|
599
599
|
{
|
|
600
600
|
stage: "synthesis",
|
|
601
601
|
kind: "dictated-line-shape",
|
|
602
|
-
where: "driver/stages.mjs:
|
|
602
|
+
where: "driver/stages.mjs:3090 (restated at driver/skills/prelim-search/synthesis-rules.md:475)",
|
|
603
603
|
surface: "stage-message",
|
|
604
604
|
evidence: "END that finding's reasoning with a literal \"- **Own-rights source:** <record URI(s) | \"no applicant-owned registrations in the searched register material\">\" line",
|
|
605
605
|
reparsedBy: "driver/own-rights.mjs:19-22 — \"This module only requires the 'Own-rights source:' line to exist\"; repair hint at driver/gateway.mjs:2361 (the `own_rights_missing` branch; re-verified 2026-08-29 — the old :1736 predated this branch and pointed into the A4 repeat-signature block)",
|
|
@@ -608,7 +608,7 @@ export const E3_BACKLOG = [
|
|
|
608
608
|
{
|
|
609
609
|
stage: "synthesis",
|
|
610
610
|
kind: "exactly-these-keys",
|
|
611
|
-
where: "driver/stages.mjs:
|
|
611
|
+
where: "driver/stages.mjs:3292",
|
|
612
612
|
surface: "stage-message",
|
|
613
613
|
evidence: "add it to the top-level \"context_notes\" array — each object EXACTLY {\"type\":\"famous-neighbour-ungrounded\",\"mark\",\"owner\",\"context\"}",
|
|
614
614
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson",
|
|
@@ -617,7 +617,7 @@ export const E3_BACKLOG = [
|
|
|
617
617
|
{
|
|
618
618
|
stage: "synthesis",
|
|
619
619
|
kind: "literal-json-skeleton",
|
|
620
|
-
where: "driver/stages.mjs:
|
|
620
|
+
where: "driver/stages.mjs:3180",
|
|
621
621
|
surface: "stage-message",
|
|
622
622
|
evidence: "- owner: {\"name\",\"country\",\"registrations\":[...]}. … Each registration: {\"uri\", optionally \"classes\":[\"9\",\"41\"],\"status\",\"filed\",\"expiry\",\"jurisdiction\"}. The \"uri\" is the ONLY field that matters: the driver BINDS classes/status/filed/expiry/jurisdiction AND the owner name from the FETCHED record ke",
|
|
623
623
|
reparsedBy: "driver/findings-model.mjs:813 parseFindingsJson + the record-binding join. Six of the seven keys are stated in the prompt and overwritten by code in the same sentence",
|
|
@@ -626,16 +626,16 @@ export const E3_BACKLOG = [
|
|
|
626
626
|
{
|
|
627
627
|
stage: "case-law",
|
|
628
628
|
kind: "literal-json-skeleton",
|
|
629
|
-
where: "driver/stages.mjs:
|
|
629
|
+
where: "driver/stages.mjs:3462",
|
|
630
630
|
surface: "stage-message",
|
|
631
631
|
evidence: "ALSO write the RETRIEVAL RECORD to <path> — a JSON OBJECT with EXACTLY these keys: {\"schema_version\":1,\"queries\":[{\"query\":\"<the search you dispatched, verbatim>\",\"jurisdiction\":\"…\",\"results\":<how many hits it returned>}, …],\"citations\":[{\"proceeding\":\"…\",\"forum\":\"…\",\"jurisdiction\":\"…\",\"decided\":\"…\"",
|
|
632
|
-
reparsedBy: "driver/verify.mjs validators.caseLaw — the ledger arm, armed by the stage-contract marker `citations` (stages.mjs:
|
|
632
|
+
reparsedBy: "driver/verify.mjs validators.caseLaw — the ledger arm, armed by the stage-contract marker `citations` (stages.mjs:1820)",
|
|
633
633
|
removedByMove: "M5 moves `queries[]` to the call log (and is itself blocked: tool-calls.jsonl records no arguments); the envelope, schema_version, `read` enum and `citations[]` skeleton survive M5 entirely",
|
|
634
634
|
},
|
|
635
635
|
{
|
|
636
636
|
stage: "case-law",
|
|
637
637
|
kind: "dictated-line-shape",
|
|
638
|
-
where: "driver/stages.mjs:
|
|
638
|
+
where: "driver/stages.mjs:3470",
|
|
639
639
|
surface: "stage-message",
|
|
640
640
|
evidence: "EVERY \"Grounded profile\" section MUST start its body with the line \"- ord: <N>\" naming which finding it grounds (use the ordinal from this list; a profile that grounds no listed finding omits the line)",
|
|
641
641
|
reparsedBy: "driver/publish/parse.mjs:339 parseCaseLawProfiles (\"the optional '- ord: <N>' first body line … gives an EXACT join\"); driver/findings-model.mjs:273 /^-\\s*ord:\\s*(\\d+)\\s*$/m; driver/publish/index.mjs:776",
|
|
@@ -669,7 +669,7 @@ export const E3_BACKLOG = [
|
|
|
669
669
|
{
|
|
670
670
|
stage: "narrative-refutation",
|
|
671
671
|
kind: "dictated-line-shape",
|
|
672
|
-
where: "driver/stages.mjs:
|
|
672
|
+
where: "driver/stages.mjs:3602",
|
|
673
673
|
surface: "stage-message",
|
|
674
674
|
// RE-QUOTED BY CONVERSION 9. The LINE-TOKEN half is gone — no "anywhere on the line", no "[kind: …]
|
|
675
675
|
// token", no "a line with no token is treated as fact", because a kind is a typed field now and an
|
|
@@ -684,7 +684,7 @@ export const E3_BACKLOG = [
|
|
|
684
684
|
// because an un-anchorable row lands in the NOT-CHECKED slice, and that is coverage lost rather than
|
|
685
685
|
// a pass.
|
|
686
686
|
evidence: "is ONE of coverage-disposition | fact | rating | narrative — pick the one your own legal read says the correction IS: coverage-disposition (a coverage row / disposition placement is wrong or dishonest)",
|
|
687
|
-
reparsedBy: "driver/verify.mjs:
|
|
687
|
+
reparsedBy: "driver/verify.mjs:784 CORRECTION_KIND_RE = /\\[kind:\\s*([a-z][a-z-]*)\\s*\\]/i → parseCorrectionKinds (verify.mjs:1007), consumed in pipelineInner() in pipeline.mjs for the run.jsonl `correction-kinds` histogram, which since #1558 also carries `kindChannelOk` — the counts are DERIVED from the parsed rows, and that key states whether the reviewer's kind channel produced anything at all rather than leaving a reader to infer it by comparing untyped against total. Telemetry only today",
|
|
688
688
|
removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
|
|
689
689
|
},
|
|
690
690
|
{
|
|
@@ -697,7 +697,7 @@ export const E3_BACKLOG = [
|
|
|
697
697
|
// `[on: -]` case went from a value to an ABSENCE — you omit the field — which is the one part a
|
|
698
698
|
// reader could get wrong from the old wording, since there is no value meaning "no finding".
|
|
699
699
|
evidence: "**AND EVERY FLAG CARRIES WHICH FINDING IT IS ABOUT** — the `on` field, an array of ordinals. Same rule as `kind`: you send the values, the driver renders the token.",
|
|
700
|
-
reparsedBy: "driver/verify.mjs:
|
|
700
|
+
reparsedBy: "driver/verify.mjs:801 CORRECTION_ON_RE = /\\[on:\\s*([0-9,\\s-]*?)\\s*\\]/i. SKILL-FILE ONLY — the stage message at stages.mjs:1842-1877 never mentions `[on:]`. This is #850's \"the element shape is in the skill file, not the stage message\" in its purest form: an E3 lint reading stages.mjs alone sees the [kind:] token and misses its twin",
|
|
701
701
|
removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
|
|
702
702
|
},
|
|
703
703
|
{
|
|
@@ -768,7 +768,7 @@ export const E3_BACKLOG = [
|
|
|
768
768
|
{
|
|
769
769
|
stage: "report-card",
|
|
770
770
|
kind: "literal-json-skeleton",
|
|
771
|
-
where: "driver/stages.mjs:
|
|
771
|
+
where: "driver/stages.mjs:3911",
|
|
772
772
|
surface: "stage-message",
|
|
773
773
|
evidence: "The finding's OWN record — the ONLY source for this card …:\\n```json\\n<JSON.stringify(finding, null, 2)>\\n```",
|
|
774
774
|
reparsedBy: "none — this is the INPUT side, and that is why it belongs in the survey: a full JSON object rendered into the prompt is exactly the mechanism #850 proves produced R-RECEIPT (the model pattern-matches a shown shape). E3's clause 1 as written (\"a code fence or inline example showing the exact object shape the model must emit\") does not reach an injected record, so the lint needs an explicit rule for shown-but-not-owed structure",
|