scoutline 0.23.0 → 0.24.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.
Files changed (47) hide show
  1. package/README.md +49 -1
  2. package/dist/capabilities/investigation.d.ts +134 -0
  3. package/dist/capabilities/investigation.d.ts.map +1 -0
  4. package/dist/capabilities/investigation.js +278 -0
  5. package/dist/capabilities/investigation.js.map +1 -0
  6. package/dist/commands/investigate.d.ts +232 -0
  7. package/dist/commands/investigate.d.ts.map +1 -0
  8. package/dist/commands/investigate.js +838 -0
  9. package/dist/commands/investigate.js.map +1 -0
  10. package/dist/commands/vision.d.ts.map +1 -1
  11. package/dist/commands/vision.js +15 -2
  12. package/dist/commands/vision.js.map +1 -1
  13. package/dist/index.d.ts +21 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +373 -6
  16. package/dist/index.js.map +1 -1
  17. package/dist/lib/investigate-claims.d.ts +90 -0
  18. package/dist/lib/investigate-claims.d.ts.map +1 -0
  19. package/dist/lib/investigate-claims.js +188 -0
  20. package/dist/lib/investigate-claims.js.map +1 -0
  21. package/dist/lib/investigate-extract.d.ts +35 -0
  22. package/dist/lib/investigate-extract.d.ts.map +1 -0
  23. package/dist/lib/investigate-extract.js +101 -0
  24. package/dist/lib/investigate-extract.js.map +1 -0
  25. package/dist/lib/investigate-planner.d.ts +58 -0
  26. package/dist/lib/investigate-planner.d.ts.map +1 -0
  27. package/dist/lib/investigate-planner.js +141 -0
  28. package/dist/lib/investigate-planner.js.map +1 -0
  29. package/dist/providers/registry.d.ts.map +1 -1
  30. package/dist/providers/registry.js +4 -1
  31. package/dist/providers/registry.js.map +1 -1
  32. package/dist/providers/types.d.ts +30 -1
  33. package/dist/providers/types.d.ts.map +1 -1
  34. package/dist/providers/types.js.map +1 -1
  35. package/dist/providers/zai/adapter.d.ts.map +1 -1
  36. package/dist/providers/zai/adapter.js +217 -3
  37. package/dist/providers/zai/adapter.js.map +1 -1
  38. package/dist/providers/zai/layout-parsing.d.ts +76 -0
  39. package/dist/providers/zai/layout-parsing.d.ts.map +1 -0
  40. package/dist/providers/zai/layout-parsing.js +151 -0
  41. package/dist/providers/zai/layout-parsing.js.map +1 -0
  42. package/dist/providers/zai/media.d.ts +19 -0
  43. package/dist/providers/zai/media.d.ts.map +1 -1
  44. package/dist/providers/zai/media.js +61 -0
  45. package/dist/providers/zai/media.js.map +1 -1
  46. package/package.json +1 -1
  47. package/skills/scoutline/SKILL.md +71 -1
package/README.md CHANGED
@@ -416,7 +416,7 @@ executor preflight, Provider selection, and `doctor`.
416
416
  | `search` | Yes | Yes | Yes | Yes | Yes (incl. `type: "video"`) | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Parallel (declarative semantic), Jina (neural web search) |
417
417
  | `vision.interpret-image` (analyze) | Yes | Yes | No | No | No | No | No | No | No | No | No | No | No | No | No | Provider-specific media limits; uncached |
418
418
  | `vision.ui-artifact` (ui-to-code) | Yes | Available | No | No | No | No | No | No | No | No | No | No | No | No | No | Live-attested; conformance-gated |
419
- | `vision.extract-text` | Yes | Pending | No | No | No | No | No | No | No | No | No | No | No | No | No | Implemented, pending live conformance |
419
+ | `vision.extract-text` | Yes (GLM-OCR engine: PDF ≤50MB, images ≤10MB, content-hash cached; exhaustion falls back to the vision model) | Pending | No | No | No | No | No | No | No | No | No | No | No | No | No | Implemented, pending live conformance |
420
420
  | `vision.diagnose-error` | Yes | Available | No | No | No | No | No | No | No | No | No | No | No | No | No | Live-attested; conformance-gated |
421
421
  | `vision.diagram` | Yes | Pending | No | No | No | No | No | No | No | No | No | No | No | No | No | Implemented, pending live conformance |
422
422
  | `vision.chart` | Yes | Pending | No | No | No | No | No | No | No | No | No | No | No | No | No | Implemented, pending live conformance |
@@ -428,6 +428,7 @@ executor preflight, Provider selection, and `doctor`.
428
428
  | `crawl` | **No** | **No** | Yes | No | No | Yes (async) | No | No | No | No | No | Yes (sync) | No | **No** | No | Tavily sync; Firecrawl async (resumable after Ctrl-C) |
429
429
  | `map` | **No** | **No** | Yes | No | No | Yes | No | No | No | No | No | Yes | No | **No** | No | URL-set discovery; no per-page content |
430
430
  | `research` | **No** | **No** | Yes | Yes | **No** | **No** | Yes | Yes | Yes | Yes | Yes | No | No | **No** | No | Tavily, Exa, Parallel, Perplexity (Agent API `high` preset), Jina DeepSearch, You.com, and Linkup research report synthesis |
431
+ | `investigation` (EvidencePack) | Yes | **No** (no reader) | Yes | Yes | **No** (no reader) | Yes | Yes | **No** (no reader) | Yes | Yes | Yes | Yes | **No** (no reader) | **No** (no reader) | **No** (no reader) | Provider-composed — supplied by the search+reader supplier union (Z.AI, Tavily, Exa, Firecrawl, Parallel, Jina AI, You.com, Linkup, Spider.cloud); `--synthesize` is Z.AI-only |
431
432
  | `repo search` / `repo read` / `repo tree` / `repo brief` | Yes | **No** | **No** | **No** | **No** | **No** | **No** | **No** | **No** | No | No | No | No | No | No | Participates in selection; only Z.AI supplies `repository-exploration` |
432
433
  | `tools`, `tool`, `call` (Raw tools) | Yes | No | No | No | No | No | No | No | No | No | No | No | No | No | No | Z.AI-only; accepts but ignores `--provider` |
433
434
  | `code` (Code Mode) | Yes | No | No | No | No | No | No | No | No | No | No | No | No | No | No | Z.AI-only; accepts but ignores `--provider` |
@@ -525,6 +526,53 @@ the supplier wire supports them (rejected with `UNSUPPORTED_OPTION`
525
526
  elsewhere — never silently dropped). `science get <identifier>` fetches
526
527
  one work by bare DOI, numeric PMID, or arXiv id.
527
528
 
529
+ ### Investigation (`investigate`)
530
+
531
+ `scoutline investigate <question>` runs a local, transparent,
532
+ cache-resumable pipeline ([ADR-0013](https://github.com/vikasagarwal101/scoutline/blob/main/docs/adr/0013-local-investigation-pipeline.md)):
533
+ plan sub-queries → fan-out search → Fusion merge → read the top
534
+ `--sources` (default 5) → deterministic passage extraction → an
535
+ EvidencePack (`schemaVersion` 1). No provider-side job runs — distinct
536
+ from Research, an opaque billed provider job. The pack is data, not
537
+ prose: agents consume it directly and text output modes fall back to
538
+ JSON (agent-synthesis is the default; you write the prose). Warm re-runs
539
+ replay the response cache (`coverage.cacheHits` reflects it).
540
+
541
+ ```bash
542
+ scoutline investigate "rust async runtime benchmarks"
543
+ scoutline investigate "rust async | rust tokio" # pipes split explicit sub-queries
544
+ scoutline investigate "topic" --provider tavily,exa --sources 8
545
+ scoutline investigate "topic" --max-chars 20000 --synthesize
546
+ ```
547
+
548
+ Sub-query planning precedence: explicit pipes (the `--merge` grammar) >
549
+ `--context <path>` (a local notes file — it never leaves the machine,
550
+ only the derived sub-query strings are searched) > deterministic
551
+ templates of the bare question (original, key terms,
552
+ overview/evidence/criticism; deduped, capped at 5). Provider selection
553
+ reuses search's fan-out activation tiers verbatim (comma-list/`all`
554
+ fan-out, single pin, `config set fanout true`). Cost is stated in one
555
+ stderr notice before any billable work: N sub-queries × M arms billable
556
+ searches + up to K reads.
557
+
558
+ Controls: `--sources <n>`, `--max-chars <n>` (passages trim first, late
559
+ sources drop; the full untrimmed pack is saved and recoverable via
560
+ `scoutline history show <ref>`), `--no-cache`, `--no-journal`, `--save`,
561
+ `--isolated`. Sources surfaced but unread land in `coverage.unread` with
562
+ a reason code — never silently dropped. `--synthesize` attaches an
563
+ additive `brief` via Z.AI chat (Z.AI-only; absent by default; a
564
+ synthesis failure is the run's terminal error, never a degraded pack).
565
+ `--depth`, `--arms`, and `--budget-tokens` are rejected with
566
+ `VALIDATION_ERROR` by design.
567
+
568
+ `--verify` turns the positional into a statement: sentence-claims
569
+ (≤ 8, fail-loud) are searched verbatim and matched to the extracted
570
+ passages; the pack gains an additive `verify` block — per claim, a
571
+ verdict (`corroborated` / `contradicted` / `unresolved`), evidence
572
+ pointers, and a negation-cue count. `contradicted` is a disclosed
573
+ negation-cue heuristic (hint-grade), not semantic judgment;
574
+ `--context` + `--verify` is a mode-conflict VALIDATION_ERROR.
575
+
528
576
  ## Usage
529
577
 
530
578
  The CLI is self-documenting. Use `--help` at any level:
@@ -0,0 +1,134 @@
1
+ /**
2
+ * EvidencePack schema + total decoder (T1, docs/plans/investigate-pipeline
3
+ * PRD AC-6; ADR-0013 §7).
4
+ *
5
+ * The EvidencePack is the self-contained deliverable of an Investigation
6
+ * (CONTEXT.md glossary): question, sub-queries, sources with per-source
7
+ * content hashes and extracted passages, and a coverage block. The pack is
8
+ * data, not prose — agent-synthesis is the contract; `--synthesize` (T7)
9
+ * attaches a `brief` additively and is not part of this schema.
10
+ *
11
+ * This module declares the pack type, its total decoder, and the
12
+ * contentSha256 shape predicate. It imports NOTHING from other src modules
13
+ * (self-contained by ticket contract; hashing itself lands in T5 — this
14
+ * module only validates hash *shape*).
15
+ *
16
+ * Decoder discipline mirrors capabilities/reader.ts exactly:
17
+ * - accepts `unknown`, returns the pack or `null`, never throws,
18
+ * never trusts a generic cast;
19
+ * - reject primitives and arrays at the top level;
20
+ * - `schemaVersion` MUST be the literal number 1 (rejects "1", 1.5,
21
+ * bigints, any future version);
22
+ * - `title: null` is a valid decoded value (reader parity);
23
+ * - optional fields preserved verbatim when present.
24
+ */
25
+ /** `[start, end)` character offsets into the source `content` string. */
26
+ export type CharRange = readonly [number, number];
27
+ /**
28
+ * One extracted passage. `quote` is pinned to the content by `charRange`:
29
+ * `content.slice(...charRange) === quote` for every passage (D4). The pin
30
+ * is enforced where content is available (assembly in T5, extraction in
31
+ * T3); the decoder enforces the shape so a decoded pack is at least
32
+ * structurally sound.
33
+ */
34
+ export interface EvidencePassage {
35
+ readonly quote: string;
36
+ readonly charRange: CharRange;
37
+ }
38
+ /** One read source: reader-envelope fields + passages. */
39
+ export interface EvidenceSource {
40
+ readonly url: string;
41
+ /** The URL the Reader actually fetched (provider rewrite possible). */
42
+ readonly finalUrl: string;
43
+ /** Page title if the provider returned one; `null` if absent (reader parity). */
44
+ readonly title: string | null;
45
+ /** ISO-8601 UTC Z timestamp captured when the read resolved (D5). */
46
+ readonly fetchedAt: string;
47
+ /** Provider id that surfaced the source (search-arm winner). */
48
+ readonly provider: string;
49
+ /** Mirrors the read `format`; `"markdown"` or `"text"`. */
50
+ readonly contentFormat: "markdown" | "text";
51
+ /** Lowercase hex SHA-256 of the UTF-8 normalized content string (D5). */
52
+ readonly contentSha256: string;
53
+ readonly passages: readonly EvidencePassage[];
54
+ }
55
+ /** Coverage block: how much of the planned grid actually produced evidence. */
56
+ export interface EvidenceCoverage {
57
+ /** Number of planned sub-queries. */
58
+ readonly subQueries: number;
59
+ /** Number of search arms actually used. */
60
+ readonly armsUsed: number;
61
+ /** Number of post-cluster candidate sources surfaced. */
62
+ readonly sourcesConsidered: number;
63
+ /** Number of sources whose read resolved successfully. */
64
+ readonly sourcesRead: number;
65
+ /** Count of search arms + reads served warm from cache (D5). */
66
+ readonly cacheHits: number;
67
+ /**
68
+ * Sources surfaced but not read, each with a reason code only —
69
+ * redacted, no error prose crossing the interface (house rule, D5).
70
+ */
71
+ readonly unread: readonly {
72
+ readonly url: string;
73
+ readonly reason: string;
74
+ }[];
75
+ }
76
+ /** The self-contained Investigation deliverable (PRD AC-6). */
77
+ export interface EvidencePack {
78
+ readonly schemaVersion: 1;
79
+ readonly question: string;
80
+ readonly subQueries: readonly string[];
81
+ readonly sources: readonly EvidenceSource[];
82
+ readonly coverage: EvidenceCoverage;
83
+ /**
84
+ * investigate-verify lane T2 (PRD AC-6): the additive claim-
85
+ * corroboration block. ABSENT on question-mode packs (byte-identity
86
+ * pin); present only when `investigate --verify` assembled the pack.
87
+ */
88
+ readonly verify?: VerifyBlock;
89
+ }
90
+ /** The deterministic verdict vocabulary (cue heuristic, PRD AC-5). */
91
+ export type ClaimVerdict = "corroborated" | "contradicted" | "unresolved";
92
+ /** One evidence pointer into the pack's own `sources` array. */
93
+ export interface ClaimEvidencePointer {
94
+ readonly sourceIndex: number;
95
+ readonly passageIndex: number;
96
+ }
97
+ /**
98
+ * One claim row: the claim text, its verdict, the count of cue-bearing
99
+ * matching passages (agent re-judgment input — the cue heuristic is
100
+ * DISCLOSED hint-grade), and first-encounter evidence pointers.
101
+ */
102
+ export interface ClaimRow {
103
+ readonly text: string;
104
+ readonly verdict: ClaimVerdict;
105
+ readonly negationCues: number;
106
+ readonly evidence: readonly ClaimEvidencePointer[];
107
+ }
108
+ /** The additive verify block: the statement plus one row per claim. */
109
+ export interface VerifyBlock {
110
+ readonly statement: string;
111
+ readonly claims: readonly ClaimRow[];
112
+ }
113
+ /**
114
+ * `contentSha256` validity: a 64-character lowercase hex string —
115
+ * the exact shape of `createHash("sha256")…digest("hex")` output.
116
+ * Ruling (ticket T1): hex-shape is enforced at decode, so an
117
+ * uppercased, truncated, or non-hex string fails closed. Full
118
+ * recompute-vs-content binding belongs to assembly (T5), which is the
119
+ * only place the paired content string exists.
120
+ */
121
+ export declare function isValidContentSha256(value: unknown): value is string;
122
+ /**
123
+ * Decode an `unknown` value into a canonical `EvidencePack`. Returns the
124
+ * typed pack on success, `null` for any malformed value. NEVER throws,
125
+ * NEVER trusts a generic cast.
126
+ *
127
+ * `title: null` is valid (reader parity). `sources` and `passages` may be
128
+ * empty arrays (a pack whose every read failed is still a valid, sad pack).
129
+ * `brief` (T7) is additive: unknown keys are NOT rejected — a decoded pack
130
+ * carries exactly the AC-6 keys, and an input carrying extra keys decodes
131
+ * to the canonical subset.
132
+ */
133
+ export declare function decodeInvestigationPack(value: unknown): EvidencePack | null;
134
+ //# sourceMappingURL=investigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"investigation.d.ts","sourceRoot":"","sources":["../../src/capabilities/investigation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,278 @@
1
+ /**
2
+ * EvidencePack schema + total decoder (T1, docs/plans/investigate-pipeline
3
+ * PRD AC-6; ADR-0013 §7).
4
+ *
5
+ * The EvidencePack is the self-contained deliverable of an Investigation
6
+ * (CONTEXT.md glossary): question, sub-queries, sources with per-source
7
+ * content hashes and extracted passages, and a coverage block. The pack is
8
+ * data, not prose — agent-synthesis is the contract; `--synthesize` (T7)
9
+ * attaches a `brief` additively and is not part of this schema.
10
+ *
11
+ * This module declares the pack type, its total decoder, and the
12
+ * contentSha256 shape predicate. It imports NOTHING from other src modules
13
+ * (self-contained by ticket contract; hashing itself lands in T5 — this
14
+ * module only validates hash *shape*).
15
+ *
16
+ * Decoder discipline mirrors capabilities/reader.ts exactly:
17
+ * - accepts `unknown`, returns the pack or `null`, never throws,
18
+ * never trusts a generic cast;
19
+ * - reject primitives and arrays at the top level;
20
+ * - `schemaVersion` MUST be the literal number 1 (rejects "1", 1.5,
21
+ * bigints, any future version);
22
+ * - `title: null` is a valid decoded value (reader parity);
23
+ * - optional fields preserved verbatim when present.
24
+ */
25
+ // ---------------------------------------------------------------------------
26
+ // Field predicates
27
+ // ---------------------------------------------------------------------------
28
+ function isPlainObject(value) {
29
+ return typeof value === "object" && value !== null && !Array.isArray(value);
30
+ }
31
+ function isNonEmptyString(value) {
32
+ return typeof value === "string" && value.length > 0;
33
+ }
34
+ function isFiniteNumber(value) {
35
+ return typeof value === "number" && Number.isFinite(value);
36
+ }
37
+ /**
38
+ * `contentSha256` validity: a 64-character lowercase hex string —
39
+ * the exact shape of `createHash("sha256")…digest("hex")` output.
40
+ * Ruling (ticket T1): hex-shape is enforced at decode, so an
41
+ * uppercased, truncated, or non-hex string fails closed. Full
42
+ * recompute-vs-content binding belongs to assembly (T5), which is the
43
+ * only place the paired content string exists.
44
+ */
45
+ export function isValidContentSha256(value) {
46
+ if (typeof value !== "string" || value.length !== 64)
47
+ return false;
48
+ for (const ch of value) {
49
+ const code = ch.charCodeAt(0);
50
+ const isDigit = code >= 48 && code <= 57;
51
+ const isLowerHex = (code >= 97 && code <= 102) || isDigit;
52
+ if (!isLowerHex)
53
+ return false;
54
+ }
55
+ return true;
56
+ }
57
+ // ---------------------------------------------------------------------------
58
+ // Total decoder
59
+ // ---------------------------------------------------------------------------
60
+ function decodeCharRange(value) {
61
+ // PR #264 F2: the documented `[start, end)` invariant, enforced at
62
+ // decode — safe integers, non-negative start, strictly increasing
63
+ // (an empty range cannot quote a non-empty passage).
64
+ return (Array.isArray(value) &&
65
+ value.length === 2 &&
66
+ Number.isSafeInteger(value[0]) &&
67
+ Number.isSafeInteger(value[1]) &&
68
+ value[0] >= 0 &&
69
+ value[1] > value[0]);
70
+ }
71
+ function decodePassage(value) {
72
+ if (!isPlainObject(value))
73
+ return null;
74
+ if (!isNonEmptyString(value.quote))
75
+ return null;
76
+ if (!decodeCharRange(value.charRange))
77
+ return null;
78
+ return { quote: value.quote, charRange: [value.charRange[0], value.charRange[1]] };
79
+ }
80
+ function decodeSource(value) {
81
+ if (!isPlainObject(value))
82
+ return null;
83
+ if (!isNonEmptyString(value.url))
84
+ return null;
85
+ if (!isNonEmptyString(value.finalUrl))
86
+ return null;
87
+ const title = value.title;
88
+ if (title !== null && typeof title !== "string")
89
+ return null;
90
+ if (!isNonEmptyString(value.fetchedAt))
91
+ return null;
92
+ if (!isNonEmptyString(value.provider))
93
+ return null;
94
+ if (value.contentFormat !== "markdown" && value.contentFormat !== "text")
95
+ return null;
96
+ if (!isValidContentSha256(value.contentSha256))
97
+ return null;
98
+ if (!Array.isArray(value.passages))
99
+ return null;
100
+ const passages = [];
101
+ for (const raw of value.passages) {
102
+ const passage = decodePassage(raw);
103
+ if (passage === null)
104
+ return null;
105
+ passages.push(passage);
106
+ }
107
+ return {
108
+ url: value.url,
109
+ finalUrl: value.finalUrl,
110
+ title: title,
111
+ fetchedAt: value.fetchedAt,
112
+ provider: value.provider,
113
+ contentFormat: value.contentFormat,
114
+ contentSha256: value.contentSha256,
115
+ passages,
116
+ };
117
+ }
118
+ function decodeCoverage(value) {
119
+ if (!isPlainObject(value))
120
+ return null;
121
+ if (!isFiniteNumber(value.subQueries))
122
+ return null;
123
+ if (!isFiniteNumber(value.armsUsed))
124
+ return null;
125
+ if (!isFiniteNumber(value.sourcesConsidered))
126
+ return null;
127
+ if (!isFiniteNumber(value.sourcesRead))
128
+ return null;
129
+ if (!isFiniteNumber(value.cacheHits))
130
+ return null;
131
+ if (!Array.isArray(value.unread))
132
+ return null;
133
+ const unread = [];
134
+ for (const raw of value.unread) {
135
+ if (!isPlainObject(raw))
136
+ return null;
137
+ if (!isNonEmptyString(raw.url))
138
+ return null;
139
+ if (!isNonEmptyString(raw.reason))
140
+ return null;
141
+ unread.push({ url: raw.url, reason: raw.reason });
142
+ }
143
+ return {
144
+ subQueries: value.subQueries,
145
+ armsUsed: value.armsUsed,
146
+ sourcesConsidered: value.sourcesConsidered,
147
+ sourcesRead: value.sourcesRead,
148
+ cacheHits: value.cacheHits,
149
+ unread,
150
+ };
151
+ }
152
+ /**
153
+ * Decode an `unknown` value into a canonical `EvidencePack`. Returns the
154
+ * typed pack on success, `null` for any malformed value. NEVER throws,
155
+ * NEVER trusts a generic cast.
156
+ *
157
+ * `title: null` is valid (reader parity). `sources` and `passages` may be
158
+ * empty arrays (a pack whose every read failed is still a valid, sad pack).
159
+ * `brief` (T7) is additive: unknown keys are NOT rejected — a decoded pack
160
+ * carries exactly the AC-6 keys, and an input carrying extra keys decodes
161
+ * to the canonical subset.
162
+ */
163
+ export function decodeInvestigationPack(value) {
164
+ // PR #264 F1: total containment for the never-throws contract — a
165
+ // throwing getter or Proxy trap on untrusted input must surface as
166
+ // a fail-closed null, never as an exception out of the decoder.
167
+ try {
168
+ return decodeInvestigationPackInner(value);
169
+ }
170
+ catch {
171
+ return null;
172
+ }
173
+ }
174
+ function decodeInvestigationPackInner(value) {
175
+ if (!isPlainObject(value))
176
+ return null;
177
+ if (value.schemaVersion !== 1)
178
+ return null;
179
+ if (!isNonEmptyString(value.question))
180
+ return null;
181
+ if (!Array.isArray(value.subQueries))
182
+ return null;
183
+ for (const q of value.subQueries) {
184
+ if (!isNonEmptyString(q))
185
+ return null;
186
+ }
187
+ if (!Array.isArray(value.sources))
188
+ return null;
189
+ const sources = [];
190
+ for (const raw of value.sources) {
191
+ const source = decodeSource(raw);
192
+ if (source === null)
193
+ return null;
194
+ sources.push(source);
195
+ }
196
+ const coverage = decodeCoverage(value.coverage);
197
+ if (coverage === null)
198
+ return null;
199
+ // investigate-verify lane T2 (D4): additive-optional `verify` — absent
200
+ // keeps the canonical subset (question-mode byte identity); present is
201
+ // validated row-by-row and fails closed on any malformed row.
202
+ const verify = decodeVerifyBlock(value.verify, sources.length, (sourceIndex) => sources[sourceIndex] === undefined ? 0 : sources[sourceIndex].passages.length);
203
+ if (verify === undefined)
204
+ return null;
205
+ return {
206
+ schemaVersion: 1,
207
+ question: value.question,
208
+ subQueries: [...value.subQueries],
209
+ sources,
210
+ coverage,
211
+ ...(verify !== null ? { verify } : {}),
212
+ };
213
+ }
214
+ const CLAIM_VERDICTS = ["corroborated", "contradicted", "unresolved"];
215
+ /**
216
+ * Decode the additive verify block. `undefined` = malformed (the caller
217
+ * fails closed); `null` = absent (the canonical subset stands); the
218
+ * decoded block = present + valid.
219
+ *
220
+ * PR #270 babysit: pointer RANGE is cross-checked against the decoded
221
+ * sources of the SAME pack (sourceIndex < sourceCount; passageIndex <
222
+ * that source's passage count) — a shape-safe but out-of-range pointer
223
+ * is malformed, INCLUDING any pointer into a zero-source pack (it can
224
+ * never dereference; assembly emits empty evidence there by
225
+ * construction, so only hand-built input reaches that arm).
226
+ */
227
+ function decodeVerifyBlock(value, sourceCount, passageCountAt) {
228
+ if (value === undefined)
229
+ return null;
230
+ if (!isPlainObject(value))
231
+ return undefined;
232
+ if (!isNonEmptyString(value.statement))
233
+ return undefined;
234
+ if (!Array.isArray(value.claims))
235
+ return undefined;
236
+ const claims = [];
237
+ for (const raw of value.claims) {
238
+ if (!isPlainObject(raw))
239
+ return undefined;
240
+ if (!isNonEmptyString(raw.text))
241
+ return undefined;
242
+ if (typeof raw.verdict !== "string" || !CLAIM_VERDICTS.includes(raw.verdict)) {
243
+ return undefined;
244
+ }
245
+ if (typeof raw.negationCues !== "number" ||
246
+ !Number.isSafeInteger(raw.negationCues) ||
247
+ raw.negationCues < 0) {
248
+ return undefined;
249
+ }
250
+ if (!Array.isArray(raw.evidence))
251
+ return undefined;
252
+ const evidence = [];
253
+ for (const pointer of raw.evidence) {
254
+ if (!isPlainObject(pointer))
255
+ return undefined;
256
+ if (!isSafeIndex(pointer.sourceIndex) || !isSafeIndex(pointer.passageIndex)) {
257
+ return undefined;
258
+ }
259
+ if (pointer.sourceIndex >= sourceCount ||
260
+ pointer.passageIndex >= passageCountAt(pointer.sourceIndex)) {
261
+ return undefined;
262
+ }
263
+ evidence.push({ sourceIndex: pointer.sourceIndex, passageIndex: pointer.passageIndex });
264
+ }
265
+ claims.push({
266
+ text: raw.text,
267
+ verdict: raw.verdict,
268
+ negationCues: raw.negationCues,
269
+ evidence,
270
+ });
271
+ }
272
+ return { statement: value.statement, claims };
273
+ }
274
+ /** Finite, safe, non-negative integer index (evidence pointer guard). */
275
+ function isSafeIndex(value) {
276
+ return (typeof value === "number" && Number.isSafeInteger(value) && value >= 0);
277
+ }
278
+ //# sourceMappingURL=investigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"investigation.js","sourceRoot":"","sources":["../../src/capabilities/investigation.ts"],"names":[],"mappings":"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"}