clearotron 0.4.1 → 0.5.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/bin/start.mjs +33 -8
- package/build-info.json +2 -2
- package/driver/CHANGELOG.md +23 -0
- package/driver/ask-ledger.mjs +86 -15
- package/driver/band-shape.mjs +61 -11
- package/driver/band-size.mjs +10 -0
- package/driver/close-verify.mjs +29 -2
- package/driver/common-law-coverage-status.mjs +1 -1
- package/driver/connotation-search.mjs +7 -9
- package/driver/contract-e3-backlog.mjs +34 -34
- package/driver/contract-e3-baseline.json +5 -5
- package/driver/contract-vocabulary.mjs +12 -12
- package/driver/corrections-delivered.mjs +113 -0
- package/driver/corrections-feedforward.mjs +16 -6
- package/driver/corrective-arm.mjs +11 -8
- package/driver/coverage-form.mjs +3 -0
- package/driver/coverage-union.mjs +11 -2
- package/driver/digest-queue.mjs +1 -1
- package/driver/disposition-call.mjs +1 -1
- package/driver/document-coverage.mjs +3 -2
- package/driver/effective-scope.mjs +2 -2
- package/driver/engine/mcp/band-server.mjs +77 -13
- package/driver/engine/mcp/dispositions-server.mjs +2 -2
- package/driver/engine/mcp/recording-server.mjs +10 -6
- package/driver/findings-model.mjs +16 -4
- package/driver/floor-duty.mjs +9 -0
- package/driver/gate-metrics.mjs +7 -1
- package/driver/gateway.mjs +28 -14
- package/driver/goods-evidence.mjs +295 -0
- package/driver/knockout-assess-record.mjs +1 -1
- package/driver/narrative-refutation-record.mjs +40 -2
- package/driver/package.json +1 -1
- package/driver/pipeline.mjs +1945 -314
- package/driver/placement-decisions.mjs +243 -0
- package/driver/placement-form.mjs +42 -8
- package/driver/placement-union.mjs +14 -6
- package/driver/provider-usage.mjs +10 -7
- package/driver/publish/audit-from-spine.mjs +5 -2
- package/driver/publish/index.mjs +19 -4
- package/driver/publish/xlsx.mjs +6 -6
- package/driver/recall-reconciliation.mjs +15 -5
- package/driver/record-carry.mjs +70 -6
- package/driver/record-discard.mjs +7 -1
- package/driver/record-fold.mjs +14 -0
- package/driver/record-goods.mjs +101 -5
- package/driver/register-plan.mjs +89 -0
- package/driver/registry-fidelity.mjs +34 -3
- package/driver/remedy-accounting.mjs +52 -14
- package/driver/repair-composers.mjs +265 -105
- package/driver/repair-scope.mjs +327 -0
- package/driver/repair-targets.mjs +92 -0
- package/driver/result-noun-fields.mjs +3 -3
- package/driver/screen-gate.mjs +96 -0
- package/driver/skills/clearance-common-law/SKILL.md +8 -0
- package/driver/skills/clearance-register/SKILL.md +5 -5
- package/driver/skills/clearance-register/digest.md +14 -14
- package/driver/skills/clearance-register/unit.md +3 -3
- package/driver/skills/clearance-search/delivery-contract.md +2 -58
- package/driver/skills/clearance-search/report-prose.md +12 -3
- package/driver/skills/clearance-search/risk-framework-triage.md +1 -1
- package/driver/skills/clearance-search/synthesis-rules.md +10 -13
- package/driver/skills/clearance-variants/SKILL.md +4 -4
- package/driver/skills/knockout-assess/SKILL.md +9 -14
- package/driver/skills/knockout-frame/SKILL.md +5 -5
- package/driver/skills/narrative-refutation/SKILL.md +1 -1
- package/driver/skills/placement-inquiry/SKILL.md +1 -1
- package/driver/skills/whatif-memo/SKILL.md +1 -1
- package/driver/stage-context.mjs +2 -1
- package/driver/stages-knockout.mjs +1 -1
- package/driver/stages.mjs +95 -60
- package/driver/suite-census.json +367 -19
- package/driver/synthesis-record.mjs +310 -8
- package/driver/terminal-clamp.mjs +53 -2
- package/driver/verify-knockout.mjs +22 -4
- package/driver/verify.mjs +23 -3
- package/mcp-server/CHANGELOG.md +4 -0
- package/mcp-server/lib/driver.mjs +5 -0
- package/mcp-server/lib/events.mjs +25 -4
- package/mcp-server/lib/findings.mjs +4 -2
- package/mcp-server/package.json +1 -1
- package/package.json +1 -1
- package/portal-ui/package.json +1 -1
- package/providers/jx/src/core.js +3 -4
- package/providers/jx/src/judge.js +2 -2
- package/providers/jx/src/nativeread.js +1 -2
- package/providers/oauth-mcp-bridge/CHANGELOG.md +4 -0
- package/providers/oauth-mcp-bridge/package.json +1 -1
- package/scripts/e2e-first-time.mjs +29 -12
package/driver/stages.mjs
CHANGED
|
@@ -31,7 +31,6 @@ import { coverageFormStamp } from "./coverage-form-io.mjs";
|
|
|
31
31
|
// imports node builtins and shared/driver-dir only.
|
|
32
32
|
import { UNIT_NOTE_REPAIR_TAIL } from "./register-unit-record.mjs";
|
|
33
33
|
import { grantVocabularySentence } from "./register-grant-vocabulary.mjs";
|
|
34
|
-
import { LINE_GROUNDS } from "./hit-list.mjs"; // — the dictation reads the contract, never a copy of it // — the grant sentence is per-deployment
|
|
35
34
|
import { marketplaceScopeDirective } from "./jurisdiction-systems.mjs";
|
|
36
35
|
import { MEANING_SEAT } from "./common-law-receipts.mjs"; // — the seat whose whole dispatch is the meaning sweep
|
|
37
36
|
import { meaningSweepReceiptsInstruction } from "./connotation-search.mjs"; // M1 — ONE composer; this sentence was authored four times
|
|
@@ -257,6 +256,10 @@ export function paths(runDir) {
|
|
|
257
256
|
// accumulated rows, so the two are no longer two copies of one judgment: this is what the seat writes
|
|
258
257
|
// and that is what the driver publishes.
|
|
259
258
|
placementForm: p("placement-form.json"),
|
|
259
|
+
// — placement's set-asides that stand on the run's files, as the reading step and the writer are told them: one
|
|
260
|
+
// entry per decision, with its ground, the records it covers and its exceptions. Driver-written after every
|
|
261
|
+
// placement pass, with no clock in it, so it changes only when a decision does; both stages declare it.
|
|
262
|
+
placementDecisions: p(driverRel("placement-decisions.json")),
|
|
260
263
|
// — the driver's own flag-by-flag account of the corrective pass: which findings each reviewer
|
|
261
264
|
// flag names, and whether any of them actually moved. Handed to the recheck as data so it argues
|
|
262
265
|
// with evidence rather than re-reading two documents to re-derive what the driver already knows.
|
|
@@ -836,8 +839,18 @@ const readsForReference = (skillReads) =>
|
|
|
836
839
|
// disk, and absence is itself the reason (an optional input — crowdContext, frameReopenReceipt — that this
|
|
837
840
|
// run never produced). The composer takes the list ALREADY filtered by the caller so this module stays a
|
|
838
841
|
// pure prompt table with no filesystem reach.
|
|
839
|
-
|
|
840
|
-
|
|
842
|
+
//
|
|
843
|
+
// IT DOES NOT CALL THEM UNCHANGED. An earlier pass can rewrite an input before a follow-up runs: a correction
|
|
844
|
+
// rewrites the narrative and the findings record the reviewer re-reads, and a settlement follow-up of the
|
|
845
|
+
// register reading step is sent after a pass rewrote the unit files it names. A follow-up told "unchanged"
|
|
846
|
+
// was told an input it must re-read had not moved, so no follow-up's line says it.
|
|
847
|
+
//
|
|
848
|
+
// THE REVIEW AFTER A DELIVERY-CHECK REPAIR SAYS WHICH FILES CHANGED. `changedInputs` names them — the narrative,
|
|
849
|
+
// the findings record, or both — worked out from the writer's record before and after the repair, never from
|
|
850
|
+
// file bytes; that review runs only when no other declared input moved, so the rest of its line is true.
|
|
851
|
+
const inputsForReference = (paths, { changedInputs = null } = {}) => changedInputs?.length
|
|
852
|
+
? `YOUR DECLARED INPUTS, on disk — this dispatch is a fresh session and does not carry them. Since this run's last review, the repair has changed ${changedInputs.join(" and ")} where listed above; your other inputs have not changed. Open the ones the instruction above turns on (and only those): ${paths.join(", ")}.`
|
|
853
|
+
: `YOUR DECLARED INPUTS, on disk — this dispatch is a fresh session and does not carry them, so open the ones the instruction above turns on (and only those): ${paths.join(", ")}.`;
|
|
841
854
|
|
|
842
855
|
/**
|
|
843
856
|
* The skill documents a stage's prompt ACTUALLY names for this run.
|
|
@@ -912,14 +925,17 @@ export function resolveSkillReads(name, ctx = {}) {
|
|
|
912
925
|
* blocks, then the input pointers. The instruction stays FIRST IN INTENT — the two reference lines that
|
|
913
926
|
* bracket it are addressed to a session that has nothing, and neither states a task.
|
|
914
927
|
*/
|
|
915
|
-
export function composeFollowup(name, ctx, { followup, extra = null, inputs = [], cleared = [] } = {}) {
|
|
916
|
-
const skills = resolveSkillReads(name, ctx);
|
|
928
|
+
export function composeFollowup(name, ctx, { followup, extra = null, inputs = [], cleared = [], changedInputs = null, decisions = null } = {}) {
|
|
929
|
+
const skills = [...new Set([...resolveSkillReads(name, ctx), ...(STAGES[name]?.followupSkillReads?.(ctx) ?? [])])];
|
|
917
930
|
return lines(
|
|
918
931
|
skills.length ? readsForReference(skills) : "",
|
|
919
932
|
followup,
|
|
920
933
|
clearedConstraint(cleared),
|
|
921
934
|
extra || "",
|
|
922
|
-
|
|
935
|
+
// A fresh session of the reading step or the writer is given placement's accepted set-asides as its first
|
|
936
|
+
// dispatch was, as evidence beside its own task: the placements its inputs name leave them out.
|
|
937
|
+
placementSetAsideBlock(decisions),
|
|
938
|
+
inputs.length ? inputsForReference(inputs, { name, changedInputs }) : "",
|
|
923
939
|
);
|
|
924
940
|
}
|
|
925
941
|
|
|
@@ -987,7 +1003,8 @@ export const pharmaMatter = (job) =>
|
|
|
987
1003
|
// skillReadsFor emitting the SAME list, under a custom profile and under a pharma matter, so the two call
|
|
988
1004
|
// sites cannot drift apart.
|
|
989
1005
|
// the report prose standard. General rules ONCE, in one shared file, reached by every stage that
|
|
990
|
-
// writes a line a reader sees and by
|
|
1006
|
+
// writes a line a reader sees, and by the reviewer that holds those lines to it (its skillReads name the
|
|
1007
|
+
// file) — by no other. There was no such file before: the three prose stages
|
|
991
1008
|
// overlap only on the per-customer framework, so the general rules had to be duplicated (they were, in
|
|
992
1009
|
// synthesis-rules.md and delivery-contract.md) or reach only some stages. A standard that reaches some
|
|
993
1010
|
// stages is worse than none — the rules then apply unevenly and nothing says which. So it is named
|
|
@@ -1381,7 +1398,7 @@ export const STAGES = {
|
|
|
1381
1398
|
// EACH FIELD CARRIES ITS OWN IMPERATIVE IN ITS OWN SENTENCE (: a field phrased outside one was
|
|
1382
1399
|
// written 0 of 9 times against 74 of 74 when imperative-carried).
|
|
1383
1400
|
`Hand the frame back by calling the \`record_matter_frame\` tool. Send \`prose_body\` — the commercial read of the matter in full prose: client, sector, product description, customer base, channels of trade, off-field sectors, sector-convergence flags, watchlist-owner seeds, your scope reasoning, the class scope and adjacency call with a one-line reason per class, the applicant's own and affiliated marks, and the campaign shape where you are inferring one (label an inference as an inference).`,
|
|
1384
|
-
`Send \`scope_basis\` as
|
|
1401
|
+
`Send \`scope_basis\` as \`instructed | worldwide | inferred\`, with \`scope_jurisdictions\` and \`excluded_jurisdictions\` as arrays of territories. Send \`identified_classes\` — the Nice classes you judge NECESSARY that the request did NOT instruct, each as {class, reason}, the class a whole number 1-45 and the reason one line. Add a class only for the client's own goods, never for what a competitor might hold, and give one sentence saying why — a class sent without a reason is not searched. The added class is searched like every other: the identical mark first, and the count looked at before anything is read. Omit the field or send an empty array where the instructed classes are the whole scope, which is the ordinary answer and adds nothing.`,
|
|
1385
1402
|
// The driver STAMPS the instructed-scope section from _driver/instructed-scope.json, so the seat is
|
|
1386
1403
|
// not asked to quote back values the driver wrote at intake. That retyping was the stage's
|
|
1387
1404
|
// `frame_scope_missing` loop and it is gone; see matter-frame-record.mjs.
|
|
@@ -1403,7 +1420,7 @@ export const STAGES = {
|
|
|
1403
1420
|
// frame-diff — whose reads were an enumerable pair — got only the seeded `Read`. Named here because
|
|
1404
1421
|
// a granted tool no instruction mentions is a capability the seat does not know it has, and it then
|
|
1405
1422
|
// reaches for the one the doctrine does name ( direction (a)).
|
|
1406
|
-
`To look inside this run's own files, call \`search_run_artifacts\` — a read-only literal search over the run directory. Use it instead of shell commands
|
|
1423
|
+
`To look inside this run's own files, call \`search_run_artifacts\` — a read-only literal search over the run directory. Use it instead of shell commands.`,
|
|
1407
1424
|
),
|
|
1408
1425
|
},
|
|
1409
1426
|
|
|
@@ -2095,6 +2112,10 @@ export const STAGES = {
|
|
|
2095
2112
|
// ~seconds; this is a safety margin only. stallSec stays < timeoutSec so a true silent wedge still trips.
|
|
2096
2113
|
timeoutSec: 1500, stallSec: 1100,
|
|
2097
2114
|
skillReads: ["skills/clearance-register/SKILL.md", "skills/clearance-register/unit.md"],
|
|
2115
|
+
// Every follow-up is a fresh session that calls the same register tools, so its methodology line also names the
|
|
2116
|
+
// active provider's manual, which holds THIS provider's tool names and operator vocabulary and which the opening
|
|
2117
|
+
// message tells the first session to read and follow.
|
|
2118
|
+
followupSkillReads: () => (PROVIDER_META.skillDoc ? [PROVIDER_META.skillDoc] : []),
|
|
2098
2119
|
out: (P, axis) => P.registerUnit(axis),
|
|
2099
2120
|
validate: validators.registerUnit,
|
|
2100
2121
|
// E1 — what this stage asks a model for, and what discharges each element. See THE STAGE-
|
|
@@ -2587,7 +2608,7 @@ export const STAGES = {
|
|
|
2587
2608
|
why: "CONVERTED (conversion 11): there is no path to hand back — the dispatch names no file, so the element's subject is gone rather than reassigned. The tool's own answer reports what it rendered (surfaced / incumbent / dropped counts). What stood here was the frame_scope_missing loop in miniature: the driver wrote the path into the message, gated on the file at that path, and asked for the path back.",
|
|
2588
2609
|
},
|
|
2589
2610
|
},
|
|
2590
|
-
message: ({ paths: P, axes, lateBind, intakeAsks }) => lines(
|
|
2611
|
+
message: ({ paths: P, axes, lateBind, intakeAsks, placementSetAsides }) => lines(
|
|
2591
2612
|
`First, read and follow exactly: skills/clearance-register/SKILL.md (the shared spine) then skills/clearance-register/digest.md (MODE B — DIGEST).`,
|
|
2592
2613
|
`You are register DIGEST mode. Combine the unit digests into the register findings file.`,
|
|
2593
2614
|
// T9 (A2) — the owning stage executes its committed intake checks (see common-law twin).
|
|
@@ -2610,6 +2631,7 @@ export const STAGES = {
|
|
|
2610
2631
|
`Adopt or override each placement BY ENGAGING ITS reason — an override quotes the reason it contradicts (never silently re-tiers), and a kept tier may still tighten a label while reusing the reason. On a corrective/repair pass, do NOT re-read the whole placement file: the tiers are in ${P.placementModel}, and the md's rulings tail is handed to you verbatim in this dispatch (the PLACEMENT RULINGS TAIL block) — adjudicate against it there.`,
|
|
2611
2632
|
// judgment-relocation (2026-06-23): the COMPLETE named band — run the relevance gate over the REAL
|
|
2612
2633
|
// material. PR-8: read via the band tools (shape whole + logged lookups), never by slicing the raw file.
|
|
2634
|
+
placementSetAsideBlock(placementSetAsides),
|
|
2613
2635
|
BAND_READING_CONTRACT_AFTER_PLACEMENT,
|
|
2614
2636
|
`Reconcile your Coverage ledger against the shape's crowd descriptors: an `+"`incomplete`"+` slice is an open crowd the lawyer must weigh (a count-only / unenumerable slice), never a clean.`,
|
|
2615
2637
|
// P2-A (charter P2d): identity collapse is CODE-derived before you read — the shape's Positions
|
|
@@ -2664,20 +2686,9 @@ export const STAGES = {
|
|
|
2664
2686
|
`RECORD YOUR WORK WITH \`record_register_digest\`. THE DISPATCH NAMES NO FILE FOR YOU TO WRITE, deliberately — the driver renders the findings document from what you send. You hold no Write or Edit tool for it and nothing you write by hand is read.`,
|
|
2665
2687
|
`WHAT THE CALL TAKES, AND WHAT IT DOES NOT. \`findings_rows\` / \`incumbent_rows\`: one entry per POSITION that earns a row — the \`uri\` of any one constituent, your \`flag_reason\`, and \`verify\`. \`negative_rows\`: one entry per candidate screened out — its \`uri\` and your \`drop_reason\`. \`instructed_checks\`: {ask, answer}. \`disagreement_resolutions\`: {subject, ADOPTED|OVERRODE, reason}. Plus your prose sections: \`opposition\`, \`merch_sweep\`, \`cross_checks\`, \`open_flags\`.`,
|
|
2666
2688
|
`YOU DO NOT SEND — AND MUST NOT RETYPE — any record's Mark, Owner, Country, Classes, Status, Filed or Expiry, the clickable record URL, the register name, the summary counts, the audit trail or the record ids you read. Every one of those is rendered from the band record your \`uri\` names or from this run's own receipts. The uri IS the join: a uri no band record carries is refused on the call, naming it, rather than rendered as a row of blank cells.`,
|
|
2667
|
-
//
|
|
2668
|
-
//
|
|
2669
|
-
//
|
|
2670
|
-
// ruling covered a rule that described a downstream effect — "the string you sweep" — the seat opened
|
|
2671
|
-
// the file, and it reached one variant of thirty-six, because the seat authors rows and had no
|
|
2672
|
-
// field to put the effect in. A rule the seat cannot map onto something it sends produces nothing
|
|
2673
|
-
// and no refusal.
|
|
2674
|
-
//
|
|
2675
|
-
// The dictation says SEND IT. It does not say "optional", even though the transport accepts a call
|
|
2676
|
-
// without it: the leniency is a delivery-safety property of the driver — a new instruction wired
|
|
2677
|
-
// to a refusal on its first live outing would put a no-report path on the run that exercises it —
|
|
2678
|
-
// and telling a seat a thing is optional is how it comes back unsent. What the driver forgives is
|
|
2679
|
-
// not the seat's contract.
|
|
2680
|
-
`MARK THE LIST — \`fates\`. \`${basename(P.registerHitList)}\` holds one line per enumerated record: sign, classes, territory, status, owner, the office's own reading where there is one, and its dates. Send \`fates\` as one entry per line you dispose of — \`{ "id": <the line's id>, "fate": 0 | 1 | 2, "ground": <token, when fate is 0> }\` — where 0 is NOT PICKED (scanned on the list, never opened), 1 is OPENED AND DISMISSED, 2 is REPORTED. A fate of 0 carries exactly one \`ground\`, one of: ${LINE_GROUNDS.join(" · ")}. THESE ARE THE ONLY GROUNDS A LINE CAN BE SET ASIDE ON WITHOUT OPENING IT, and each answers ONE question — a record is out of TERRITORY, or it is a different SIGN, and which of those it is is the thing a reader checks. Never one token for both. If the reason needs the record — its goods, its specification, the wording of a class head — that is not a ground, it is an OPEN: fetch it, read it, and send fate 1 with your reasoning in the row it earns.`,
|
|
2689
|
+
// The reading step is not asked to mark the list's lines with fate codes. That order named a field its tool
|
|
2690
|
+
// does not take and a fetch it cannot make, and only an operator metric read the result, which now says
|
|
2691
|
+
// it was not computed (gate-metrics.mjs). The tool still accepts codes a call carries.
|
|
2681
2692
|
`COVERAGE DOES NOT COME HERE. Your Coverage-ledger rulings ride \`record_coverage\`, row by row, exactly as described above — two transports, two statements, and the obligation ledger keeps its own writer.`,
|
|
2682
2693
|
),
|
|
2683
2694
|
},
|
|
@@ -3089,7 +3100,7 @@ export const STAGES = {
|
|
|
3089
3100
|
why: "THE SECOND frame_scope_missing. The driver holds the value in _driver/framework.json, writes it into the dispatch, asks the model to retype it, and fails the file when the retyping does not match its own copy. The audit table groups it under the tool-written envelope row; pre-bound is the sharper discharge and either removes it from the model",
|
|
3090
3101
|
},
|
|
3091
3102
|
},
|
|
3092
|
-
message: ({ paths: P, job, customerUnknown, profile, intakeAsks, enforcerSignals, framework, frameworkMethod, jxAim, registerOnly, crowdContext, dispatchBlocks, findingsSurface, depth }) => lines(
|
|
3103
|
+
message: ({ paths: P, job, customerUnknown, profile, intakeAsks, enforcerSignals, framework, frameworkMethod, jxAim, registerOnly, crowdContext, dispatchBlocks, findingsSurface, depth, placementSetAsides }) => lines(
|
|
3093
3104
|
// C4 — pharma matters (class 5 / pharma-shaped goods) FORCE-READ the field module: the
|
|
3094
3105
|
// therapeutic-goods discipline, no-use ≠ safety (pipelines run 5-10y), practitioner/pharmacist
|
|
3095
3106
|
// confusion. Conditional read (frameworkFor pattern); doctrine TABLES live elsewhere, untouched.
|
|
@@ -3140,6 +3151,7 @@ export const STAGES = {
|
|
|
3140
3151
|
// (house-brand attachment / seasonality / scale). Context, never a rule that decides a finding.
|
|
3141
3152
|
job?.campaignShape ? `Stated campaign shape (verbatim from intake — how the mark will be deployed; facts, not judgment): ${job.campaignShape}` : "",
|
|
3142
3153
|
`Inputs: register findings ${P.registerFindings}${registerOnly ? "" : `; common-law ${P.commonLaw}`}; placements ${P.placement} (structured tiers + reasons: ${P.placementModel}); matter frame ${P.matterContext}; manifest ${P.variantManifest}.`,
|
|
3154
|
+
placementSetAsideBlock(placementSetAsides),
|
|
3143
3155
|
// The skeptic's shipped sentence, word for word: a granted tool is named, or the seat cannot know it holds it.
|
|
3144
3156
|
`Re-read any of this run's own artifacts with the \`search_run_artifacts\` tool — ONE file per call, named relative to the run directory (e.g. "register-findings.md"), with \`terms\` as literal substrings OR-matched per line.`,
|
|
3145
3157
|
PLACEMENT_BORDERLINE_NOTE,
|
|
@@ -3215,22 +3227,19 @@ export const STAGES = {
|
|
|
3215
3227
|
// findings must be mirrored into it. Same compose-instruction style as the register MACHINE COVERAGE
|
|
3216
3228
|
// LEDGER: dictate the keys + closed enums; qualifiers/nuance stay in the prose. The driver validates
|
|
3217
3229
|
// it (validators.narrative) and the render consumes it; an absent file falls back to prose (legacy).
|
|
3218
|
-
`MACHINE FINDINGS (MANDATORY): beside the narrative sections, your record_synthesis call carries the findings record — a JSON OBJECT {"schema_version":${FINDINGS_SCHEMA_VERSION},"rated_under_framework":"${framework?.framework_key ?? "house-default"}","findings":[...],"coverage":[...],"context_notes":[...],"actions":[...],"ask_answers":[...]} (context_notes OPTIONAL — see the FAMOUS-NEIGHBOUR rule below; actions MANDATORY — see the ACTIONS REGISTER rule below; ask_answers — see the INTAKE ASKS rule: MANDATORY when the run carries intake asks, omit otherwise). Put ONE object in findings[] per finding in your narrative — RATED findings (they carry a band) AND the unrated off-field commercial-awareness items (disposition "off-field", NO band). What you do NOT deliver you DECLINE, by name — see DECLINATIONS below; there is no silent omission left. Each finding object has EXACTLY these keys: {"ordinal","mark","owner","band" (rated findings only),"net" (MANDATORY on every finding a reader sees
|
|
3230
|
+
`MACHINE FINDINGS (MANDATORY): beside the narrative sections, your record_synthesis call carries the findings record — a JSON OBJECT {"schema_version":${FINDINGS_SCHEMA_VERSION},"rated_under_framework":"${framework?.framework_key ?? "house-default"}","findings":[...],"coverage":[...],"context_notes":[...],"actions":[...],"ask_answers":[...]} (context_notes OPTIONAL — see the FAMOUS-NEIGHBOUR rule below; actions MANDATORY — see the ACTIONS REGISTER rule below; ask_answers — see the INTAKE ASKS rule: MANDATORY when the run carries intake asks, omit otherwise). Put ONE object in findings[] per finding in your narrative — RATED findings (they carry a band) AND the unrated off-field commercial-awareness items (disposition "off-field", NO band). What you do NOT deliver you DECLINE, by name — see DECLINATIONS below; there is no silent omission left. Each finding object has EXACTLY these keys: {"ordinal","mark","owner","band" (rated findings only),"net" (MANDATORY on every finding a reader sees),"borderline_between" (OPTIONAL, rated findings only — see THE BAND below),${frameworkMethod ? `"inputs" (rated findings only),` : ""}"disposition","meters","quadrant","source","legal_position","practical_position" (BOTH, on EVERY finding),"off_field_ground" (off-field findings only),"manageable" (notable-but-manageable findings only)}. The retired composite/level/dispute_type keys are FORBIDDEN — the validator rejects them.`,
|
|
3219
3231
|
`- ordinal: 1-based integer in your "Finding N" order, unique. mark: the conflicting mark text, verbatim as it appears in the narrative.`,
|
|
3220
3232
|
`- owner: {"name","country","registrations":[...]}. registrations = ONE object PER REGISTRATION the owner holds for this mark — ONE registration = ONE record "uri" (one owner with two Class-41 regs = two registration objects). 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 keyed by that uri, so you do NOT need to fill them and must NEVER invent or transpose a number, date, status or class. Any structured field you do include is a HINT and is OVERWRITTEN by the record; a uri with no fetched record shows "register-index entry — full record not pulled this run", never your typed values. A common-law finding with no registration → "registrations":[].`,
|
|
3221
3233
|
`- band: the framework's band WORD, EXACTLY as the framework writes it${framework ? ` (one of: ${framework.bands.map((b) => b.label).join(" / ")})` : ""} — the band your reasoning through the framework's own definitions yields. THE BAND FOLLOWS THE WORDS: your prose likelihood read and the band may not disagree. Never a number, never a code, never a word from another framework's ladder. Where the framework states ceilings or a matrix, the band is what its stated method produces${frameworkMethod ? " from the inputs you recorded" : ""} — an aggressive enforcer / owner size / partnership moves the framework's INPUTS (the legal or practical read), never the output band. Emit band ONLY on rated findings (dispositions adversarial / coexistence-partner / distinguished); an off-field awareness item carries NO band.`,
|
|
3222
3234
|
// item 10 — the DECLARATION, stated once in BAND_BORDERLINE_NOTE and appended wherever the field is
|
|
3223
3235
|
// named. It is not a band criterion and must never become one; see the note's own doc block.
|
|
3224
3236
|
`- borderline_between: ` + BAND_BORDERLINE_NOTE + (frameworkMethod ? `\n- inputs: ${inputsShape(frameworkMethod)} — the framework's own inputs for this finding, each one of the values it lists, reasoned in its order before the band. On every rated finding.` : ""),
|
|
3225
|
-
// item 9a — the
|
|
3226
|
-
// the
|
|
3227
|
-
//
|
|
3228
|
-
// semicolon
|
|
3229
|
-
//
|
|
3230
|
-
|
|
3231
|
-
// named by the pre-delivery lint (net-conclusion-form); the reasoning MOVES to the two positions
|
|
3232
|
-
// below, which is why the "do not shorten" rule survives the change unaltered.
|
|
3233
|
-
`- net: THE FINDING SENTENCE — MANDATORY on every finding that reaches a reader (the parser REFUSES the file without it: finding_net_missing). It is the single sentence a reader sees before anything else on this finding's card, the sentence the grouped-negative line states, and the one the client brief lists it by. It is the ONLY per-finding summary anywhere in the report: the card no longer authors its own one-liner and there is no "The read" section — a finding with no net reaches the reader with a risk chip and no sentence. IT IS A CONCLUSION, NOT A CHAIN: ONE sentence answering the one question a lawyer asks of this finding — IS THIS A PROBLEM FOR ME. Name the parties and the territory and state the outcome as a likelihood ("Veltra Labs' registered VELTRA is more likely than not to prevail against VELTRA PHARMA in the United States."; "Nothing on the German register reaches the applicant's class-9 goods."). NO SEMICOLON-CHAIN, NO "→", NO CONSEQUENCE CLAUSE ON THE END — the parser REFUSES a net carrying a semicolon or an arrow (findings_net_chained). If the sentence needs one to hold together, what you are writing is reasoning, and reasoning goes in legal_position / practical_position, which the reader opens the moment this sentence says yes. THE REASONING MOVES, IT NEVER DISAPPEARS: every clause the retired chain carried — territories, the goods paraphrased to the WORST overlap ("(among broad goods)" as the scope-limiter), the owner's actual business, status and use history, revocation exposure — is still owed IN FULL in those two positions. A net that got shorter because the reasoning got thinner is the one rewrite this ruling rejects. DO NOT RESTATE THE BAND: the band word is the verdict and renders as the card's own chip beside this sentence; say what is true of the world instead. NEVER AN ACTION PRESCRIPTION: no recommended step, no "the practical path is…", no imperative aimed at the reader — the reader is a lawyer who layers their own advice on top, and what a human must do lives in the typed actions register. A standalone sentence: capital letter, full stop, and read it back for number agreement. There is NO length cap and none is coming — a conclusion is short because it is a conclusion, never because it was trimmed; never drop a fact to fit, move it below. ITS SHAPE is specified in synthesis-rules.md → "The finding sentence — the shape of the typed net". Read that section before writing your first net.`,
|
|
3237
|
+
// item 9a — the finding sentence, ALWAYS visible. Written once here, rendered by the card and the MCP
|
|
3238
|
+
// brief. The line is the paragraph approved on 2026-10-02, verbatim and nothing else: at most two
|
|
3239
|
+
// sentences, the likelihood first, every fact that does not fit moved to the two positions. The two
|
|
3240
|
+
// mechanical marks (semicolon, arrow) are refused by the parser (findings_net_chained) and named by the
|
|
3241
|
+
// pre-delivery lint (net-conclusion-form); synthesis-rules.md carries the rest of the section.
|
|
3242
|
+
`- net: **The finding sentence.** At most two sentences, each at most 25 words, in words a client reads without a glossary. The first states the outcome as a likelihood: who would win against whom, for what goods, where. *"[Owner]'s earlier [mark] would probably win against [your mark] for [goods] in [territory]."* The second, only when the first cannot carry it, states what the earlier right covers: *"Their registration covers [goods]."* No "prevail". No semicolon, no arrow, no advice, no band word. Every fact that does not fit goes in the legal and practical positions below, never dropped.`,
|
|
3234
3243
|
// CHANGE 2 (disposition) — the per-finding PLACEMENT enum the report bands by. You ALREADY reason this in
|
|
3235
3244
|
// the narrative ("a documented coexistence stands on the record", "distinguished by the house mark",
|
|
3236
3245
|
// "same token, different field"); name it as a typed token. It sets PLACEMENT/ORDER ONLY and NEVER touches the
|
|
@@ -3324,7 +3333,7 @@ export const STAGES = {
|
|
|
3324
3333
|
`Decline by calling the \`record_declination\` tool. Its schema names the fields it takes and what each is for — read them there, not here. The one thing to know before you call: you cite a record or page by its POSITION in the list below — there is no field for a mark name, a uri or a page address, so anything you were not handed cannot be expressed at all. The reason vocabulary is closed: ${DECLINATION_REASON_TOKENS.join(" / ")}, each an omission synthesis-rules.md already authorises, and if your ground is none of them the rules do not let you omit the record or page. ONE OF THEM IS NOT AVAILABLE ON A LIVE RECORD IN AN INSTRUCTED CLASS: \`not-worth-the-line\` is a statement about the report's budget rather than about the mark, and a live registration inside one of the matter's own classes is never omitted for want of room — carry it, or decline it on something true of THAT MARK. The call is refused if you try, so it costs you a turn. The grounds you write are one or two lines in your OWN words on why THIS record or page does not earn a line — never machine-parsed, and what the reviewing lawyer reads. Send them in one batch where you can; a refused row never voids its neighbours, and the answer names what is still undecided so you can finish in this turn.`,
|
|
3325
3334
|
`A REFUSAL FROM THAT TOOL IS ABOUT BOOKKEEPING, NEVER ABOUT YOUR LEGAL JUDGMENT. There is exactly ONE case: declining a mark IDENTICAL to the applied-for mark, live, in one of the matter's own filed classes, on a discretionary ground — because synthesis-rules.md orders that an on-point identical mark in the relevant class is never dropped, "regardless of filer profile", so such a declination contradicts the instruction you are already following. Nothing else is refused. If that record really is the applicant's own, or already delivered under another record, say exactly that with own-right or duplicate-of-delivered and it is accepted. Whether goods are related, whether a name is off-field, whether a conflict is worth the line — those are your calls and the tool does not have an opinion about any of them.`,
|
|
3326
3335
|
`The records on your findings surface, by position:`,
|
|
3327
|
-
...findingsSurface.flatMap((r, i) => r?.kind === "page" ? [] : [` ${i}. ${r.mark ?? "(unnamed)"}${r.owner ? ` — ${r.owner}` : ""}${r.tier ? ` [${r.tier}]` : ""}${r.uri ? ` ${r.uri}` : ""}`]), ...(findingsSurface.some((r) => r?.kind === "page") ? [`The pages the web notes marked as candidates or conflicts, continuing the same positions:`, ...findingsSurface.flatMap((r, i) => r?.kind === "page" ? [` ${i}. ${r.url ?? r.page}`] : [])] : []),
|
|
3336
|
+
...findingsSurface.flatMap((r, i) => r?.kind === "page" ? [] : [` ${i}. ${r.mark ?? "(unnamed)"}${r.owner ? ` — ${r.owner}` : ""}${r.tier ? ` [${r.tier}]` : ""}${r.uri ? ` ${r.uri}` : ""}${r.goods_from ? ` — goods: ${r.goods_from}` : ""}`]), ...(findingsSurface.some((r) => r?.kind === "page") ? [`The pages the web notes marked as candidates or conflicts, continuing the same positions:`, ...findingsSurface.flatMap((r, i) => r?.kind === "page" ? [` ${i}. ${r.url ?? r.page}`] : [])] : []),
|
|
3328
3337
|
] : []),
|
|
3329
3338
|
// A1 — the home for a famous neighbour the famous-neighbour rule keeps but no record grounds. WITHOUT
|
|
3330
3339
|
// this, such a mark was forced into findings[] with an empty-uri registration, which the F-14 URI guard
|
|
@@ -3524,7 +3533,9 @@ export const STAGES = {
|
|
|
3524
3533
|
// (Independence trade-off: the narrative is opus-authored, so this is opus-refutes-opus; the independence is
|
|
3525
3534
|
// the input DIET + adversarial posture, not a different family. sonnet@high is the tier-diverse alternative.)
|
|
3526
3535
|
model: "opus", thinking: "high", timeoutSec: 900, stallSec: 600,
|
|
3527
|
-
|
|
3536
|
+
// The reviewer reads the prose manual whose rules it enforces (approved 2026-10-02): the 25-word limit and
|
|
3537
|
+
// the word list it applies come from there, and so does the finding sentence's two-sentence limit.
|
|
3538
|
+
skillReads: ["skills/narrative-refutation/SKILL.md", "skills/clearance-search/report-prose.md"],
|
|
3528
3539
|
out: (P) => P.seniorEyeReview,
|
|
3529
3540
|
validate: validators.seniorEyeReview,
|
|
3530
3541
|
// E1 — what this stage asks a model for, and what discharges each element. See THE STAGE-
|
|
@@ -3579,23 +3590,19 @@ export const STAGES = {
|
|
|
3579
3590
|
why: "the items are code-found and driver-fed, so the FINDING is mechanical; what the model owes is the flag, the quote and the verdict consequence. NO TOKEN — unlike the plan-execution table, this driver-fed block has no section gate at all",
|
|
3580
3591
|
},
|
|
3581
3592
|
},
|
|
3582
|
-
message: ({ paths: P, intakeAsks, job, registerOnly, profileSelection }) => lines(
|
|
3583
|
-
reads(["skills/narrative-refutation/SKILL.md"]),
|
|
3593
|
+
message: ({ paths: P, intakeAsks, job, registerOnly, profileSelection, placementFloorDecisions }) => lines(
|
|
3594
|
+
reads(["skills/narrative-refutation/SKILL.md", "skills/clearance-search/report-prose.md"]),
|
|
3584
3595
|
// lever 3 — WHICH FINDINGS EARN A GROUNDED PROFILE, chosen by the DRIVER and listed by
|
|
3585
3596
|
// ordinal. The band is on findings.json before this stage is dispatched, so there is nothing for
|
|
3586
3597
|
// the seat to judge: unlisted work is never asked for. Empty when every finding is profiled —
|
|
3587
3598
|
// which is the one-country product always, and any run whose cut keeps everything.
|
|
3588
3599
|
profileSelectionDirective(profileSelection),
|
|
3589
3600
|
`Adversarially refute the narrative ${P.narrative} against the source files: register findings ${P.registerFindings}${registerOnly ? "" : `, common-law ${P.commonLaw}`}, placements ${P.placement} (structured tiers + reasons: ${P.placementModel}), matter frame ${P.matterContext}.`,
|
|
3590
|
-
|
|
3601
|
+
...refutationStandingLines({ registerOnly, job, floorDecisions: placementFloorDecisions }),
|
|
3591
3602
|
// PR-8: the reviewer verifies register claims against the RECORD, on the record — the same
|
|
3592
3603
|
// read-only band tools the drafting stages used, every lookup logged to the reading audit.
|
|
3593
|
-
`REGISTER VERIFICATION TOOLS: you hold the read-only band tools — band_shape (the deterministic shape of the complete register band, incl. THE FLOORS: every live in-class identical/near-identical record, listed unconditionally), band_lookup (pull any record the narrative relies on or omits) and band_record (the official registry record fetched this run). Check the narrative's register assertions against them — a floor row the narrative neither rates nor reasons away is a FLAGGED CORRECTION. They are read-only and logged; you hold no live register tools (by design, never an outage).`,
|
|
3594
3604
|
// The skeptic's shipped sentence, word for word: a granted tool is named, or the seat cannot know it holds it.
|
|
3595
|
-
`Re-read any of this run's own artifacts with the \`search_run_artifacts\` tool — ONE file per call, named relative to the run directory (e.g. "register-findings.md"), with \`terms\` as literal substrings OR-matched per line.`,
|
|
3596
|
-
registerOnly ? REGISTER_ONLY_NOTE : "",
|
|
3597
3605
|
// C4 — the pharma field module is binding on pharma matters; the review verifies it was honoured
|
|
3598
|
-
pharmaMatter(job) ? `This is a PHARMA matter (Nice 5 / pharma goods): verify the narrative honoured the pharma field module (skills/clearance-search/field-doctrine-pharma.md) — therapeutic-area goods discipline (same therapeutic area ≈ proximate goods regardless of formulation), NO-USE never softens a pharma risk (pipelines run 5-10 years pre-launch), and practitioner/pharmacist confusion including handwriting/verbal look-alikes was weighed. A violation is a FLAGGED CORRECTION.` : "",
|
|
3599
3606
|
// C5 — the generic correction: a registered right can support an injunction without the
|
|
3600
3607
|
// owner's use (country-dependent); "no use → procedural only / no injunction risk" is a forbidden inference.
|
|
3601
3608
|
`Flag as a CORRECTION any line reasoning "the owner does not use it → procedural risk only / no injunction exposure": non-use may open a revocation DEFENCE after the grace period, it does not neutralise an enforceable registration today.`,
|
|
@@ -3603,7 +3610,7 @@ export const STAGES = {
|
|
|
3603
3610
|
`DEMOTION VERIFICATION (per the skill): for every finding at the framework's lowest band, or disposition "distinguished"/"off-field", whose senior right is same-class and in use, verify the three demotion receipts (a registered-scope comparison with the specification quoted — never the senior's trade dress; any dilution counted in that conflict's jurisdiction × goods lane; a use-meets-use read consistent with the finding's own use-check result) and the response-band reconciliation line. A missing/dishonest receipt on the conflict that would otherwise drive the verdict is BLOCKING; elsewhere a FLAGGED CORRECTION. Where the receipts exist, the demotion STANDS — audit the evidence, never re-decide the band.`,
|
|
3604
3611
|
// A3/A6 — verify the machine's own open items and the customer's explicit asks were HONOURED,
|
|
3605
3612
|
// not narrated away: an unaddressed deferral/flag or an unanswered ask is a flagged correction.
|
|
3606
|
-
|
|
3613
|
+
refutationOpenItemsLine(P),
|
|
3607
3614
|
// RETIRED. This ordered the reviewer to "verify the \"## Answers to your
|
|
3608
3615
|
// instructions\" section answers EACH of these verbatim intake asks with a labelled line … A missing
|
|
3609
3616
|
// or evasive answer is a FLAGGED CORRECTION." Every clause of it was true when it was written and
|
|
@@ -3639,10 +3646,7 @@ export const STAGES = {
|
|
|
3639
3646
|
// lettered flags were invisible for exactly that reason. The kind VOCABULARY survives verbatim
|
|
3640
3647
|
// below, because the model still declares it from its own legal read; what goes is the seat
|
|
3641
3648
|
// formatting it into prose for the driver to parse back out.
|
|
3642
|
-
|
|
3643
|
-
`WHAT THE CALL TAKES: \`verdict\` (CLEAR / CONDITIONAL / BLOCKING) and \`flags\`, one entry per flag. Each flag carries \`kind\`, \`text\` (one line, naming the file and the exact claim), optionally \`fix\` (one line — the targeted edit that would settle it) and optionally \`on\` (the finding ordinals it is about, omitted for a flag about the document rather than a finding). You do NOT number the flags: render order is the numbering.`,
|
|
3644
|
-
`TYPE EACH CORRECTION: \`kind\` 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), fact (a factual defect — record values, owners, statuses, dates, grounding), rating (a band/rating you challenge), narrative (prose, structure or voice of the narrative). DECLARE the kind from what the correction is about, never from how severe it is.`,
|
|
3645
|
-
`A BLOCKING verdict REQUIRES at least one flag. A refusal to sign that names nothing is refused by the call itself, in this turn, rather than at the gate — where its only repair is one forced re-ask of this whole stage.`,
|
|
3649
|
+
...REFUTATION_RECORDING_LINES,
|
|
3646
3650
|
),
|
|
3647
3651
|
},
|
|
3648
3652
|
|
|
@@ -3972,7 +3976,7 @@ export const STAGES = {
|
|
|
3972
3976
|
// A card that still ARRIVES with a head renders the old way, so archived runs and a drifted seat
|
|
3973
3977
|
// are byte-identical rather than gaining a second head. See carriesOwnFrame().
|
|
3974
3978
|
`WRITE THE CARD'S DETAIL ONLY — NO HEAD, NO META LINES. Your output STARTS at "### Full detail" and contains nothing above it: no "## …" heading, and none of "- ord:", "- group:", "- source:", "- net:", "- one:", "- label:", "- open:". Every one of those is composed by the driver from the record above, where they are already typed — a line you write there is discarded, not read.`,
|
|
3975
|
-
`Emit NO "### The read" narrative — RETIRED. It was a THIRD condensation of the same finding, beside this card's own one-liner and the typed net. The legal read and the enforcement read are already TYPED on the record (legal_position / practical_position) and render from there; the
|
|
3979
|
+
`Emit NO "### The read" narrative — RETIRED. It was a THIRD condensation of the same finding, beside this card's own one-liner and the typed net. The legal read and the enforcement read are already TYPED on the record (legal_position / practical_position) and render from there; the finding sentence is the typed net. Your whole output is the \`full_detail\` entries — filing, portfolio, the risk assessment, enforcement — and the driver builds the section around them.`,
|
|
3976
3980
|
// The SOURCE bullet is gone from the ask entirely. It was the transcription class in its purest
|
|
3977
3981
|
// form: a seat composing a URL from a host table it is not even given (providers/<name>.md is NOT
|
|
3978
3982
|
// in this stage's skillReads) plus a path on the record. The driver reads `source.resolved_link`
|
|
@@ -4128,7 +4132,7 @@ export const STAGES = {
|
|
|
4128
4132
|
) : "",
|
|
4129
4133
|
openAsks.length ? lines(
|
|
4130
4134
|
`THE OPEN ASKS (machine questions — a directive, proposal or probe the run raised and could not end deterministically):`,
|
|
4131
|
-
...openAsks.map((a) => `- ${a.ask_id} — [${a.born?.place}] ${a.ask?.text}`),
|
|
4135
|
+
...openAsks.map((a) => `- ${a.ask_id} — [${a.born?.place}] ${a.ask?.text}${a.part ? ` (${(a.qids ?? []).join(", ")})` : ""}`),
|
|
4132
4136
|
`For EACH ask id above send ONE row with kind "ask": verdict "immaterial" (with file_index, quote and reason) or verdict "open" (with a handoff — what the reviewing lawyer should do with it).`,
|
|
4133
4137
|
`IMMATERIAL is always available and is the terminating move — but only with a real citation. You can NEVER mark an ask executed: execution is computed by code from the plan-execution record, not asserted.`,
|
|
4134
4138
|
) : "",
|
|
@@ -4183,9 +4187,9 @@ export const PLAN_ENTRY_RERUN_RULE = `This axis's plan has already run. Do not c
|
|
|
4183
4187
|
// Step-2.6 skeptic escalated this axis → resume its session to defend or adjust.
|
|
4184
4188
|
export function buildEscalationFollowup({ paths: P, axis, flags, supplementalLane = false }) {
|
|
4185
4189
|
return lines(
|
|
4186
|
-
`
|
|
4190
|
+
`This is a fresh session: your earlier register-unit work for axis "${axis}" is not in your context. Your prior search is in your band artifact (${P.registerBand(axis)}), and your output file is ${P.registerUnit(axis)}.`,
|
|
4187
4191
|
supplementalLane ? supplementalLaneResumeLine(P, axis) : "",
|
|
4188
|
-
`Do NOT restart the search from scratch. The Step-2.6 skeptic raised the concerns below. For EACH concern relevant to THIS axis: either (a) defend your existing finding using evidence already in your
|
|
4192
|
+
`Do NOT restart the search from scratch. The Step-2.6 skeptic raised the concerns below. For EACH concern relevant to THIS axis: either (a) defend your existing finding using evidence already in your band artifact, or (b) run ONLY the narrow additional sub-query the concern requires, then revise.`,
|
|
4189
4193
|
`Every finding the concerns do not touch stays exactly as it is.`,
|
|
4190
4194
|
PLAN_ENTRY_RERUN_RULE,
|
|
4191
4195
|
``,
|
|
@@ -4201,7 +4205,7 @@ export function buildEscalationFollowup({ paths: P, axis, flags, supplementalLan
|
|
|
4201
4205
|
// The deadline envelope permits closing this axis's DEFERRED coverage rows before the analysis is written.
|
|
4202
4206
|
export function buildEnvelopeCloseFollowup({ paths: P, axis, rows, supplementalLane = false }) {
|
|
4203
4207
|
return lines(
|
|
4204
|
-
`
|
|
4208
|
+
`This is a fresh session: your earlier register-unit work for axis "${axis}" is not in your context. Your prior search is in your band artifact (${P.registerBand(axis)}), and your output file is ${P.registerUnit(axis)}.`,
|
|
4205
4209
|
supplementalLane ? supplementalLaneResumeLine(P, axis) : "",
|
|
4206
4210
|
`The Coverage ledger records DEFERRED (planned but never run) work owned by this axis — the deadline envelope permits closing it NOW, before the analysis is written:`,
|
|
4207
4211
|
rows || `(deferred row(s) for ${axis} — see the Coverage ledger)`,
|
|
@@ -4222,7 +4226,7 @@ export function buildFrameReopenFollowup({ paths: P, axis, directives, reopenFet
|
|
|
4222
4226
|
const dom = (directives ?? []).filter((d) => d.severity === "dominant-element");
|
|
4223
4227
|
const other = (directives ?? []).filter((d) => d.severity !== "dominant-element");
|
|
4224
4228
|
if (supplementalLane) return lines(
|
|
4225
|
-
`
|
|
4229
|
+
`This is a fresh session: your earlier register-unit work for axis "${axis}" is not in your context. Your prior queries are in your band artifact (${P.registerBand(axis)}).`,
|
|
4226
4230
|
`A blind, frame-INDEPENDENT re-derivation (it never saw this run's framing) found these threats the run did NOT fully scope or search:`,
|
|
4227
4231
|
...(directives ?? []).map(directiveLine),
|
|
4228
4232
|
dom.length
|
|
@@ -4234,7 +4238,7 @@ export function buildFrameReopenFollowup({ paths: P, axis, directives, reopenFet
|
|
|
4234
4238
|
SUPPLEMENTAL_LANE_STEERING,
|
|
4235
4239
|
);
|
|
4236
4240
|
return lines(
|
|
4237
|
-
`
|
|
4241
|
+
`This is a fresh session: your earlier register-unit work for axis "${axis}" is not in your context. Your prior queries are in your band artifact (${P.registerBand(axis)}).`,
|
|
4238
4242
|
`A blind, frame-INDEPENDENT re-derivation (it never saw this run's framing) found these threats the run did NOT fully scope or search:`,
|
|
4239
4243
|
...(directives ?? []).map(directiveLine),
|
|
4240
4244
|
dom.length
|
|
@@ -4492,7 +4496,7 @@ export function stageInputs(name, P, { axes = [], axis = null, registerOnly = fa
|
|
|
4492
4496
|
"placement-inquiry": [P.matterContext, P.commonLaw, P.registerNamedBand, ...units],
|
|
4493
4497
|
// B2 — the structured placement mirror joins every placement consumer's declared inputs (OPTIONAL
|
|
4494
4498
|
// like crowdContext: absent fingerprints as absent, so pre-B2 runs are byte-identical).
|
|
4495
|
-
"register-digest": [P.variantManifest, P.matterContext, P.placement, P.placementModel, P.registerNamedBand, ...units],
|
|
4499
|
+
"register-digest": [P.variantManifest, P.matterContext, P.placement, P.placementModel, P.placementDecisions, P.registerNamedBand, ...units],
|
|
4496
4500
|
// A-4 (item 12) — planExecution and the coverage ledger are what skepticDeferralExtra is BUILT from,
|
|
4497
4501
|
// and they were the two things this stage consumed without declaring, so they could change without
|
|
4498
4502
|
// staling it. Declaring them was tried in Wave A and HELD BACK, because on its own it parks the run:
|
|
@@ -4524,9 +4528,9 @@ export function stageInputs(name, P, { axes = [], axis = null, registerOnly = fa
|
|
|
4524
4528
|
// digest-funnel's settlement flush restamps the skeptic against both files and deliberately does
|
|
4525
4529
|
// NOT restamp synthesis — "their staleness recompute is the contract" — which is the behaviour
|
|
4526
4530
|
// this declaration extends, not a new one it introduces.
|
|
4527
|
-
synthesis: [P.registerFindings, P.commonLaw, P.placement, P.placementModel, P.registerNamedBand, P.matterContext, P.variantManifest, P.skepticFlags, P.frameReopenReceipt, P.crowdContext, P.crowdContextMd, P.planExecution, P.registerCoverageLedger], // A3/F8;
|
|
4531
|
+
synthesis: [P.registerFindings, P.commonLaw, P.placement, P.placementModel, P.placementDecisions, P.registerNamedBand, P.matterContext, P.variantManifest, P.skepticFlags, P.frameReopenReceipt, P.crowdContext, P.crowdContextMd, P.planExecution, P.registerCoverageLedger], // A3/F8;
|
|
4528
4532
|
"case-law": [P.narrative],
|
|
4529
|
-
"narrative-refutation": [P.narrative, P.registerFindings, P.commonLaw, P.placement, P.placementModel, P.matterContext, P.skepticFlags, P.frameReopenReceipt], // A3/F8
|
|
4533
|
+
"narrative-refutation": [P.narrative, P.registerFindings, P.commonLaw, P.placement, P.placementModel, P.placementDecisions, P.matterContext, P.skepticFlags, P.frameReopenReceipt], // A3/F8
|
|
4530
4534
|
// P2 clause 4 — P.findings joins the declared inputs of every stage that READS it. All three read it
|
|
4531
4535
|
// today and none declared it, which is exactly how copper-vault's delivery gate came to be evaluated
|
|
4532
4536
|
// over a findings set that had moved: findings.json is authored by synthesis but rewritten afterwards
|
|
@@ -4754,7 +4758,7 @@ export const BAND_READING_STAGES = new Set(["placement-inquiry", "register-diges
|
|
|
4754
4758
|
// was handed the same offer paged an exhausted group 2,498 times (measured on a test run, 2026-10-13).
|
|
4755
4759
|
export const GROUP_READING_STAGES = new Set(["placement-inquiry"]);
|
|
4756
4760
|
// The contract as the stages after placement read it: without "Every floor has a fate on the form.", which is an
|
|
4757
|
-
// order to placement, whose form it names. The digest and synthesis owe no floor a fate (
|
|
4761
|
+
// order to placement, whose form it names. The digest and synthesis owe no floor a fate (the owner's ruling,
|
|
4758
4762
|
// 2026-10-14). Removed from the one contract, never restated, so the two cannot drift apart.
|
|
4759
4763
|
export const FLOOR_FATE_ORDER = "Every floor has a fate on the form.";
|
|
4760
4764
|
export const BAND_READING_CONTRACT_AFTER_PLACEMENT = BAND_READING_CONTRACT.replace(` ${FLOOR_FATE_ORDER}`, "");
|
|
@@ -4762,3 +4766,34 @@ export const BAND_READING_CONTRACT_AFTER_PLACEMENT = BAND_READING_CONTRACT.repla
|
|
|
4762
4766
|
// The register reading step's order on the waiting families. One constant, because the cross-check
|
|
4763
4767
|
// follow-up reads it word for word (repair-composers.mjs); declared last so no line above it moves.
|
|
4764
4768
|
export const DECIDE_WAITING_FAMILIES = "WHERE THE PLAN ABOVE HAS WAITING FAMILIES, DECIDE EVERY ONE. Release each one you ask with `record_released_families`: its qids, as listed above, and why looking wider would change what you tell the client. Then call register_execute_plan again with those qids; it runs only what you released. Record each one you do not ask with `record_withheld_families`: its qids and why it was not asked. A family you leave unasked was never searched, so it is recorded withheld-by-judgment; one nobody decided holds up delivery. The reasons go into the audit workbook, not the report.";
|
|
4769
|
+
|
|
4770
|
+
// ── THE REVIEWER'S STANDING LINES, ONE TEXT FOR BOTH OF ITS REVIEWS ───────────────────────────────────
|
|
4771
|
+
//
|
|
4772
|
+
// The full review and the review after a delivery-check repair read the same standing tools and notes, the
|
|
4773
|
+
// same check on open items and the same recording lines. Each lives here once, so the two messages cannot
|
|
4774
|
+
// drift apart; the full review's message is byte-identical to what it was before they moved.
|
|
4775
|
+
// PLACEMENT'S ACCEPTED SET-ASIDES, FOR THE READING STEP AND THE WRITER (approved wording, 2026-10-18). Placement keeps
|
|
4776
|
+
// its set-asides out of placements.json, and neither stage was shown them: the driver lists the decisions that stand
|
|
4777
|
+
// on the run's files when the message is built, each with its ground and the records it covers, under this
|
|
4778
|
+
// introduction. Nothing is printed where none stands.
|
|
4779
|
+
export const PLACEMENT_SET_ASIDES_INTRO = "Placement's accepted set-asides are listed below with their grounds, the records they cover, and any exceptions. Carry those decisions forward under the placement rules. Where a conclusion depends on a set-aside, check its ground against the supporting evidence and flag an unsupported decision.";
|
|
4780
|
+
export const placementSetAsideBlock = (decisions) => (Array.isArray(decisions) && decisions.length ? lines(PLACEMENT_SET_ASIDES_INTRO, ...decisions) : "");
|
|
4781
|
+
|
|
4782
|
+
export const refutationStandingLines = ({ registerOnly = false, job = {}, floorDecisions = null } = {}) => [
|
|
4783
|
+
PLACEMENT_BORDERLINE_NOTE,
|
|
4784
|
+
`REGISTER VERIFICATION TOOLS: you hold the read-only band tools — band_shape (the deterministic shape of the complete register band, including floors marked on their lines; crowded groups may show only their first page), band_lookup (pull any record the narrative relies on or omits) and band_record (the official registry record fetched this run). Check the narrative's register assertions against them. A floor row the narrative neither rates nor reasons away is a FLAGGED CORRECTION unless a validated placement decision already accounts for it under the placement rules. Those decisions are listed below with their grounds and the records they cover. Check those grounds against the evidence; flag an unsupported decision. They are read-only and logged; you hold no live register tools (by design, never an outage).`,
|
|
4785
|
+
// The validated decisions themselves, written by the driver from the placement form (pipeline.mjs
|
|
4786
|
+
// placementFloorDecisionLines); none stands where the list is empty.
|
|
4787
|
+
...(Array.isArray(floorDecisions) && floorDecisions.length ? floorDecisions : ["(none)"]),
|
|
4788
|
+
`Re-read any of this run's own artifacts with the \`search_run_artifacts\` tool — ONE file per call, named relative to the run directory (e.g. "register-findings.md"), with \`terms\` as literal substrings OR-matched per line.`,
|
|
4789
|
+
registerOnly ? REGISTER_ONLY_NOTE : "",
|
|
4790
|
+
pharmaMatter(job) ? `This is a PHARMA matter (Nice 5 / pharma goods): verify the narrative honoured the pharma field module (skills/clearance-search/field-doctrine-pharma.md) — therapeutic-area goods discipline (same therapeutic area ≈ proximate goods regardless of formulation), NO-USE never softens a pharma risk (pipelines run 5-10 years pre-launch), and practitioner/pharmacist confusion including handwriting/verbal look-alikes was weighed. A violation is a FLAGGED CORRECTION.` : "",
|
|
4791
|
+
];
|
|
4792
|
+
export const refutationOpenItemsLine = (P) =>
|
|
4793
|
+
`Also verify against ${P.skepticFlags} and ${P.frameReopenReceipt} (JSON "deferrals"): every skeptic flag and every reopen deferral must be either visible as a coverage[]/narrative open item or explicitly reasoned immaterial — one that appears in neither place is a FLAGGED CORRECTION. Files absent ⇒ skip.`;
|
|
4794
|
+
export const REFUTATION_RECORDING_LINES = Object.freeze([
|
|
4795
|
+
`RECORD YOUR REVIEW WITH \`record_narrative_refutation\`. THE DISPATCH NAMES NO FILE FOR YOU TO WRITE, deliberately — the driver renders the review from what you send, so a flag the corrective ladder cannot parse cannot be written. You hold no Write or Edit tool for it and nothing you write by hand is read.`,
|
|
4796
|
+
`WHAT THE CALL TAKES: \`verdict\` (CLEAR / CONDITIONAL / BLOCKING) and \`flags\`, one entry per flag. Each flag carries \`kind\`, \`text\` (one line, naming the file and the exact claim), optionally \`fix\` (one line — the targeted edit that would settle it) and optionally \`on\` (the finding ordinals it is about, omitted for a flag about the document rather than a finding). You do NOT number the flags: render order is the numbering.`,
|
|
4797
|
+
`TYPE EACH CORRECTION: \`kind\` 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), fact (a factual defect — record values, owners, statuses, dates, grounding), rating (a band/rating you challenge), narrative (prose, structure or voice of the narrative). DECLARE the kind from what the correction is about, never from how severe it is.`,
|
|
4798
|
+
`A BLOCKING verdict REQUIRES at least one flag. A refusal to sign that names nothing is refused by the call itself, in this turn, rather than at the gate — where its only repair is one forced re-ask of this whole stage.`,
|
|
4799
|
+
]);
|