@happyvertical/smrt-ingestion 0.57.29 → 0.57.31
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/PROPOSALS.md +145 -9
- package/README.md +12 -0
- package/REVIEW.md +9 -0
- package/dist/chunks/{execution-Dv3G0d62.js → execution-BxkUOtLf.js} +119 -3
- package/dist/chunks/execution-BxkUOtLf.js.map +1 -0
- package/dist/chunks/{feedback-PLOZth0a.js → feedback-D69e1hX5.js} +3 -3
- package/dist/chunks/{feedback-PLOZth0a.js.map → feedback-D69e1hX5.js.map} +1 -1
- package/dist/chunks/proposal-contracts-CqVVPvqq.js.map +1 -1
- package/dist/chunks/{reviewer-instruction-zn11aVA5.js → reviewer-instruction-Ip4W4f0j.js} +2 -2
- package/dist/chunks/{reviewer-instruction-zn11aVA5.js.map → reviewer-instruction-Ip4W4f0j.js.map} +1 -1
- package/dist/execution-internal.d.ts +4 -0
- package/dist/execution-internal.d.ts.map +1 -1
- package/dist/execution.d.ts +7 -0
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +1 -1
- package/dist/failure-capture.d.ts +73 -0
- package/dist/failure-capture.d.ts.map +1 -0
- package/dist/manifest.json +1 -1
- package/dist/models.js +1 -1
- package/dist/models.js.map +1 -1
- package/dist/proposal-contracts.d.ts +8 -0
- package/dist/proposal-contracts.d.ts.map +1 -1
- package/dist/proposal-dto.d.ts +39 -0
- package/dist/proposal-dto.d.ts.map +1 -1
- package/dist/proposal-sdk.d.ts.map +1 -1
- package/dist/proposal-validation.d.ts +2 -1
- package/dist/proposal-validation.d.ts.map +1 -1
- package/dist/proposals.d.ts +2 -0
- package/dist/proposals.d.ts.map +1 -1
- package/dist/proposals.js +235 -22
- package/dist/proposals.js.map +1 -1
- package/dist/provider-failure.d.ts +15 -0
- package/dist/provider-failure.d.ts.map +1 -1
- package/dist/server.d.ts +15 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +39 -6
- package/dist/server.js.map +1 -1
- package/dist/smrt-knowledge.json +14 -14
- package/package.json +17 -17
- package/dist/chunks/execution-Dv3G0d62.js.map +0 -1
package/PROPOSALS.md
CHANGED
|
@@ -186,7 +186,8 @@ Model output can contain only offered handler versions, schema-valid arguments,
|
|
|
186
186
|
retained evidence locations and offered alternative handler/candidate keys.
|
|
187
187
|
Candidate IDs must occur in the offered set, and evidence IDs in retained source
|
|
188
188
|
results. Unknown enums, invented IDs, extra authority/tool/approval fields and
|
|
189
|
-
malformed structures fail closed
|
|
189
|
+
malformed structures fail closed (an invented candidate target alone is dropped
|
|
190
|
+
for review instead, see below). Missing required fields are retained as
|
|
190
191
|
`missingFields`, with `needs_review`; values are never invented to satisfy a
|
|
191
192
|
schema. Observed page/time/source granularity is preserved. Logical scan splits
|
|
192
193
|
use `proposeDocumentSplits`; originals and hashes remain intact.
|
|
@@ -237,6 +238,34 @@ rejected, even when the earlier split on that evidence was dropped. Like
|
|
|
237
238
|
reply. Stored output is never re-validated, so earlier attempts and their
|
|
238
239
|
digests replay unchanged.
|
|
239
240
|
|
|
241
|
+
An invented target — a value in an offered handler's candidate reference field
|
|
242
|
+
that is not among the offered candidates for that field's model — no longer
|
|
243
|
+
rejects the attempt (#4289). The validator drops the key from the arguments
|
|
244
|
+
(no placeholder) and revalidates what remains through the required-only path
|
|
245
|
+
above: a dropped required field becomes a computed `missingFields` entry, a
|
|
246
|
+
dropped optional field is simply absent, and either way the suggestion is
|
|
247
|
+
`needs_review` for the reviewer to choose an offered target.
|
|
248
|
+
`provenance.unofferedTargetsDropped` records `{suggestions, fields}` counts
|
|
249
|
+
only, never IDs, labels or field names; it is absent when nothing was dropped
|
|
250
|
+
and removed whenever the suggestions are discarded. Every candidate field that
|
|
251
|
+
stays in the arguments has been checked against the offered set, so no
|
|
252
|
+
unoffered value survives as a target. The attempt still rejects as before for
|
|
253
|
+
an unoffered handler or alternative, unknown evidence (argument or reference),
|
|
254
|
+
a non-string target, a target field the handler schema does not declare in
|
|
255
|
+
`properties`, any other argument error, or a drop that exposes a refusal other
|
|
256
|
+
than `required`.
|
|
257
|
+
|
|
258
|
+
The exact dropped value is also searched for in the kept suggestions and splits
|
|
259
|
+
(JSON-escaped, keys included); an exact echo, such as the ID repeated in an
|
|
260
|
+
explanation or another argument, rejects the attempt. This guard fails closed
|
|
261
|
+
on short or common values: a dropped `"1"` or `"a"` almost always occurs
|
|
262
|
+
somewhere else in the output, so such a reply rejects rather than being kept.
|
|
263
|
+
It is an exact-match check, not a general leak filter: a case variant, a
|
|
264
|
+
reformatted copy or a fragment of the ID in free text (an explanation or a
|
|
265
|
+
text argument) is not detected and may reach the reviewer as ordinary model
|
|
266
|
+
prose. Free text is never a target and never authority; only the checked
|
|
267
|
+
candidate fields are.
|
|
268
|
+
|
|
240
269
|
A rejected reply ends the attempt as `provider_error` with the `malformed_output`
|
|
241
270
|
warning and a bounded, value-free `provenance.failure` `{category, reason}` (#4207).
|
|
242
271
|
The reason lists schema-owned paths, keywords and schema constants, for example
|
|
@@ -314,14 +343,121 @@ A generator call that throws ends the attempt as `provider_error` with the
|
|
|
314
343
|
`unavailable` warning and `provenance.failure` `{category: 'unavailable',
|
|
315
344
|
reason}`. The reason is value-free by construction: a provider's own text can
|
|
316
345
|
quote the prompt or document, so it is never copied. The reason is built only
|
|
317
|
-
from a fixed phrase and
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
`
|
|
346
|
+
from a fixed phrase and:
|
|
347
|
+
|
|
348
|
+
- for an SDK `AIError` only, the HTTP status (from a structured field, or from
|
|
349
|
+
the exact `<status> ...` / `TypeSafe request failed (<status>): ...` shapes
|
|
350
|
+
the SDK produces), the SDK error code (from the closed list of codes the SDK
|
|
351
|
+
raises), for a schema rejection the quoted tokens that are JSON Schema
|
|
352
|
+
keywords, and the OpenAI SDK's exact fixed transport messages
|
|
353
|
+
(`Connection error.`, `Request timed out.`, `Request was aborted.`,
|
|
354
|
+
`(no status code or body)`), which its `mapError` keeps without a cause;
|
|
355
|
+
- for the SDK adapter's own refusal of a reply it did receive, a fixed problem:
|
|
356
|
+
finish reason other than `stop` (named from the closed list `stop`, `length`,
|
|
357
|
+
`tool_calls`, `content_filter`, otherwise `other`), truncation, tool calls,
|
|
358
|
+
an unexpected response model, no text content, an empty reply, a reply over
|
|
359
|
+
the output limit, or a reply that is not valid JSON (#4285);
|
|
360
|
+
- for any other error (#4285), the code-defined constructor name (an
|
|
361
|
+
identifier ending in `Error` or `Exception`; never the settable `name`),
|
|
362
|
+
an `AbortError`/`TimeoutError` name, a network `code` from a closed list
|
|
363
|
+
(`ECONNREFUSED`, `ECONNRESET`, `ETIMEDOUT`, `ENOTFOUND`, `EAI_AGAIN`,
|
|
364
|
+
`UND_ERR_*`, TLS certificate codes, ...) read from the error, up to three
|
|
365
|
+
`cause` levels and an `AggregateError`'s entries, and a structured numeric
|
|
366
|
+
status. A timeout or abort is named as one, except that a structured HTTP
|
|
367
|
+
status always wins over an abort name or network timeout code on a non-SDK
|
|
368
|
+
error, whether on the error itself or in its cause chain. An SDK error's
|
|
369
|
+
abort is read only from its code or exact transport message.
|
|
370
|
+
|
|
371
|
+
For example: `provider rejected the response schema (HTTP 400, code API_ERROR);
|
|
372
|
+
unsupported response-schema keywords: uniqueItems`,
|
|
373
|
+
`provider response incomplete (finish reason length)`,
|
|
374
|
+
`provider call failed (class TypeError, network ECONNREFUSED)`,
|
|
375
|
+
`provider call aborted or timed out (class DOMException, name TimeoutError)`, or
|
|
376
|
+
`provider call failed (class Error)`. It is cut at 500 characters.
|
|
377
|
+
|
|
378
|
+
**Why some failures were a bare `provider call failed` (#4285).** The SDK
|
|
379
|
+
adapter's own response checks threw plain `Error`s (finish reason not `stop`,
|
|
380
|
+
e.g. `length` when the reply reached `maxTokens`; truncation; tool calls; an
|
|
381
|
+
unexpected response model; non-text or oversized content) and `JSON.parse`
|
|
382
|
+
threw a `SyntaxError` for an empty or non-JSON reply. The reason deliberately
|
|
383
|
+
reads nothing from a non-SDK error, so all of these collapsed into the fixed
|
|
384
|
+
phrase. Transport failures through the OpenAI SDK already carried
|
|
385
|
+
`code API_ERROR`. The adapter now raises `ProposalResponseError` with a fixed
|
|
386
|
+
problem, and other non-SDK errors contribute the transport facts above. The
|
|
387
|
+
category is unchanged (`unavailable`).
|
|
388
|
+
|
|
389
|
+
### Failed-attempt capture (opt-in, #4285)
|
|
390
|
+
|
|
391
|
+
The value-free reason cannot show what the model actually sent. A host that
|
|
392
|
+
needs that for diagnosis can opt in to keeping it:
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
proposals: {
|
|
396
|
+
// ...
|
|
397
|
+
failureCapture: {
|
|
398
|
+
enabled: true, // required; absent or false keeps capture off
|
|
399
|
+
maxBytes: 16384, // default 16384, at most 65536 (UTF-8 bytes, after redaction)
|
|
400
|
+
redact: ({ text, source }) => hostRedaction(text), // required to retain text
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
`ProposalConfiguration.failureCapture` is **off by default**. When enabled with
|
|
406
|
+
a host `redact` hook, a failed interpretation attempt (`provider_error`) keeps
|
|
407
|
+
one of:
|
|
408
|
+
|
|
409
|
+
- `raw_response`: the reply text the SDK adapter refused (for example invalid
|
|
410
|
+
JSON or a `length` finish), or
|
|
411
|
+
- `generated_output`: the generator's parsed output, as JSON, that failed
|
|
412
|
+
validation, the declared-completion check or the output limit.
|
|
413
|
+
|
|
414
|
+
Errors without model output (transport, timeouts, authority, decision
|
|
415
|
+
failures) capture nothing. Successful attempts never store a capture.
|
|
416
|
+
|
|
417
|
+
Without a `redact` hook, only `status: 'redaction_failed'` metadata is stored,
|
|
418
|
+
with `redacted: false` and no text; the candidate text is not materialized.
|
|
419
|
+
There is no built-in sanitizer. Hosts own the hook's semantic redaction policy;
|
|
420
|
+
the service cannot verify that the returned text removes every document secret.
|
|
421
|
+
|
|
422
|
+
The text, cut to the larger of the generation `maxOutputBytes` and
|
|
423
|
+
`maxBytes`, goes through the host `redact` hook, and the result is cut to
|
|
424
|
+
`maxBytes` without splitting a character (`truncated: true` when either cut
|
|
425
|
+
applied). NUL and unpaired surrogates are stored as U+FFFD so PostgreSQL JSON accepts the record. When
|
|
426
|
+
the hook throws, returns a non-string or exceeds its asynchronous wait budget,
|
|
427
|
+
only `status: 'redaction_failed'` is stored. The budget is the generation
|
|
428
|
+
`timeoutMs`, cut to half of the analysis lease still left when the hook starts
|
|
429
|
+
(no time left: the hook is not called). The hook runs after the authority
|
|
430
|
+
recheck, reserving the rest of the lease for the second recheck and publication.
|
|
431
|
+
This timer cannot preempt synchronous work or cancel the hook. Hosts must use
|
|
432
|
+
bounded, nonblocking redactors. Missing or failed redaction does not replace the
|
|
433
|
+
attempt's real failure or value-free reason; hook errors are discarded.
|
|
434
|
+
|
|
435
|
+
**Where it lives.** In the attempt row's `data` JSON, as `failureCapture`
|
|
436
|
+
beside the result fields, never inside `result`: it needs no migration, is not
|
|
437
|
+
part of `output_digest` or any configuration digest, never appears in
|
|
438
|
+
`getCompletedAnalysis` or any other snapshot, and is not public read
|
|
439
|
+
configuration (`proposalReadConfiguration` omits it, so read-only hosts still
|
|
440
|
+
match). Proposal digests, replay and frozen generation configuration are
|
|
441
|
+
unchanged by enabling it.
|
|
442
|
+
|
|
443
|
+
**Reading it back.** Only
|
|
444
|
+
`IngestionService.getFailedAttemptCapture(itemId, attemptId?)` returns it
|
|
445
|
+
(`FailedAttemptCapture` from `/dto`, or `null` when nothing was stored). The
|
|
446
|
+
attempt defaults to the item's current analysis attempt. It requires the
|
|
447
|
+
execution catalog and the current **reviewer** authority for that item (the
|
|
448
|
+
same gate as `getItemDisposition`) inside the caller's tenant and confidential
|
|
449
|
+
scope; every denial, expiry, cancellation or foreign item fails closed before
|
|
450
|
+
the row is read. It is never part of a list DTO, inbox row, review page,
|
|
451
|
+
log line, checkpoint name, telemetry or error message.
|
|
452
|
+
Publication and reads also reject a persisted `captured` record with
|
|
453
|
+
`redacted: false`; capture text must be marked as processed by a configured
|
|
454
|
+
host hook. Persisted caps must remain within 1–65536 bytes, and captured text
|
|
455
|
+
must fit its declared UTF-8 byte cap; malformed records fail closed.
|
|
456
|
+
|
|
457
|
+
**Retention and deletion.** It follows the item. There is no separate delete
|
|
458
|
+
API: `expire`, `sweepRetention` and the `repairDeletions` retry of an
|
|
459
|
+
interrupted propagation all empty attempt `data`, which removes the capture
|
|
460
|
+
with the rest of the payload; a revoked item is unreadable before that.
|
|
325
461
|
|
|
326
462
|
`createSDKProposalDecisionClient(client)` adapts an existing SDK client’s optional
|
|
327
463
|
capability without changing its errors or protocol. Optional `decision` uses public core `executeDecision` and the existing SDK
|
package/README.md
CHANGED
|
@@ -262,6 +262,18 @@ and `maxSuggestions` are each capped at 20; `timeoutMs` is capped at 2147483647.
|
|
|
262
262
|
Invalid limits are rejected when constructing `IngestionService`, before receipt
|
|
263
263
|
or interpretation. See [REVIEW.md](REVIEW.md) for the published server review host.
|
|
264
264
|
|
|
265
|
+
`proposals.failureCapture` (`{ enabled, maxBytes?, redact? }`) is off by
|
|
266
|
+
default. With `enabled: true` and a host `redact` hook, a failed interpretation
|
|
267
|
+
attempt keeps the model output (or the parsed output that failed validation)
|
|
268
|
+
for diagnosis: cut to
|
|
269
|
+
`maxBytes` (default 16384, at most 65536 UTF-8 bytes) after the host
|
|
270
|
+
`redact` hook, stored beside the attempt result (not digested), readable only
|
|
271
|
+
through the reviewer-authorized `getFailedAttemptCapture(itemId, attemptId?)`
|
|
272
|
+
and removed with the item. A missing or failed hook stores only
|
|
273
|
+
`redaction_failed` metadata, never text. Hosts own the semantic redaction policy;
|
|
274
|
+
no built-in sanitizer is supplied. Invalid settings are rejected at construction.
|
|
275
|
+
See [PROPOSALS.md](PROPOSALS.md#failed-attempt-capture-opt-in-4285).
|
|
276
|
+
|
|
265
277
|
## Trusted internal sources
|
|
266
278
|
|
|
267
279
|
A host with a trusted internal source, such as chat messages recorded in
|
package/REVIEW.md
CHANGED
|
@@ -135,6 +135,15 @@ Changing it or itemId destroys the old view and fences late callback results.
|
|
|
135
135
|
Denied refresh clears prior originals, candidates, arguments and results.
|
|
136
136
|
Missing confidence is unavailable; page/time links exist only for observed
|
|
137
137
|
locations. Provider errors and unresolved/partial results remain review states.
|
|
138
|
+
A host that enabled `proposals.failureCapture` may fetch a failed attempt's
|
|
139
|
+
redacted model output with `getFailedAttemptCapture(itemId, attemptId?)`.
|
|
140
|
+
Retaining text requires a configured host redaction hook; a missing or failed
|
|
141
|
+
hook yields only `redaction_failed` metadata. The host owns that redaction policy.
|
|
142
|
+
The getter requires current reviewer authority for that item and fails closed
|
|
143
|
+
otherwise;
|
|
144
|
+
`load`, inbox rows and review pages never include it, so a host shows it only
|
|
145
|
+
behind its own explicit diagnostic action (see
|
|
146
|
+
[PROPOSALS.md](PROPOSALS.md#failed-attempt-capture-opt-in-4285)).
|
|
138
147
|
|
|
139
148
|
## Submitter-scoped decisions
|
|
140
149
|
|
|
@@ -47,8 +47,92 @@ var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["modu
|
|
|
47
47
|
//#region src/execution-internal.ts
|
|
48
48
|
var discoveryTransaction = /* @__PURE__ */ Symbol("ingestion.discoveryTransaction");
|
|
49
49
|
var generationSnapshotRead = /* @__PURE__ */ Symbol("ingestion.generationSnapshotRead");
|
|
50
|
+
var completeWithFailureCapture = /* @__PURE__ */ Symbol("ingestion.completeWithFailureCapture");
|
|
51
|
+
var analysisLeaseRemaining = /* @__PURE__ */ Symbol("ingestion.analysisLeaseRemaining");
|
|
50
52
|
var listReadGate = /* @__PURE__ */ Symbol("ingestion.listReadGate");
|
|
51
53
|
//#endregion
|
|
54
|
+
//#region src/failure-capture.ts
|
|
55
|
+
var FAILURE_CAPTURE_DEFAULT_MAX_BYTES = 16384;
|
|
56
|
+
var FAILURE_CAPTURE_MAX_BYTES = 65536;
|
|
57
|
+
function assertFailureCapture(config) {
|
|
58
|
+
if (config === void 0) return;
|
|
59
|
+
if (!config || typeof config !== "object" || typeof config.enabled !== "boolean" || config.maxBytes !== void 0 && (!Number.isSafeInteger(config.maxBytes) || config.maxBytes < 1 || config.maxBytes > 65536) || config.redact !== void 0 && typeof config.redact !== "function") throw new Error("Invalid failure capture configuration");
|
|
60
|
+
}
|
|
61
|
+
function truncateUtf8(text, maxBytes) {
|
|
62
|
+
const bytes = Buffer.from(text, "utf8");
|
|
63
|
+
if (bytes.length <= maxBytes) return {
|
|
64
|
+
text,
|
|
65
|
+
truncated: false
|
|
66
|
+
};
|
|
67
|
+
let end = maxBytes;
|
|
68
|
+
while (end > 0 && (bytes[end] & 192) === 128) end--;
|
|
69
|
+
return {
|
|
70
|
+
text: bytes.subarray(0, end).toString("utf8"),
|
|
71
|
+
truncated: true
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function storable(text) {
|
|
75
|
+
return text.replaceAll(String.fromCharCode(0), "�").replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "�");
|
|
76
|
+
}
|
|
77
|
+
async function prepareFailureCapture(config, candidate, bounds) {
|
|
78
|
+
if (config?.enabled !== true) return void 0;
|
|
79
|
+
const maxBytes = config.maxBytes ?? 16384;
|
|
80
|
+
const hook = config.redact;
|
|
81
|
+
const base = {
|
|
82
|
+
version: 1,
|
|
83
|
+
source: candidate.source,
|
|
84
|
+
redacted: !!hook,
|
|
85
|
+
maxBytes,
|
|
86
|
+
capturedAt: bounds.now.toISOString()
|
|
87
|
+
};
|
|
88
|
+
if (!hook || bounds.timeoutMs < 1) return {
|
|
89
|
+
...base,
|
|
90
|
+
status: "redaction_failed",
|
|
91
|
+
truncated: false
|
|
92
|
+
};
|
|
93
|
+
let raw;
|
|
94
|
+
try {
|
|
95
|
+
raw = candidate.text();
|
|
96
|
+
} catch {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (typeof raw !== "string" || !raw.length) return void 0;
|
|
100
|
+
const input = truncateUtf8(raw, Math.max(bounds.inputBytes, maxBytes));
|
|
101
|
+
let text = input.text;
|
|
102
|
+
let timer;
|
|
103
|
+
try {
|
|
104
|
+
const redacted = await Promise.race([Promise.resolve().then(() => hook.call(config, {
|
|
105
|
+
text: input.text,
|
|
106
|
+
source: candidate.source
|
|
107
|
+
})), new Promise((_resolve, reject) => {
|
|
108
|
+
timer = setTimeout(() => reject(/* @__PURE__ */ new Error("timeout")), bounds.timeoutMs);
|
|
109
|
+
})]);
|
|
110
|
+
if (typeof redacted !== "string") throw new Error("invalid");
|
|
111
|
+
text = redacted;
|
|
112
|
+
} catch {
|
|
113
|
+
return {
|
|
114
|
+
...base,
|
|
115
|
+
status: "redaction_failed",
|
|
116
|
+
truncated: false
|
|
117
|
+
};
|
|
118
|
+
} finally {
|
|
119
|
+
clearTimeout(timer);
|
|
120
|
+
}
|
|
121
|
+
const stored = truncateUtf8(storable(text), maxBytes);
|
|
122
|
+
return {
|
|
123
|
+
...base,
|
|
124
|
+
status: "captured",
|
|
125
|
+
text: stored.text,
|
|
126
|
+
truncated: input.truncated || stored.truncated
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function storedFailureCapture(value) {
|
|
130
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
131
|
+
const record = value;
|
|
132
|
+
if (record.version !== 1 || !["raw_response", "generated_output"].includes(String(record.source)) || !["captured", "redaction_failed"].includes(String(record.status)) || typeof record.truncated !== "boolean" || typeof record.redacted !== "boolean" || typeof record.maxBytes !== "number" || !Number.isSafeInteger(record.maxBytes) || record.maxBytes < 1 || record.maxBytes > 65536 || typeof record.capturedAt !== "string" || (record.status === "captured" ? typeof record.text !== "string" || record.redacted !== true || Buffer.byteLength(record.text, "utf8") > record.maxBytes : record.text !== void 0)) return void 0;
|
|
133
|
+
return record;
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
52
136
|
//#region src/proposal-errors.ts
|
|
53
137
|
var HandlerArgumentsInvalidError = class extends Error {
|
|
54
138
|
issues;
|
|
@@ -7057,7 +7141,7 @@ var IntakeExecutionService = class IntakeExecutionService {
|
|
|
7057
7141
|
if (!Array.isArray(references)) throw new Error("Feedback lineage unavailable");
|
|
7058
7142
|
if (references.length === 0) return;
|
|
7059
7143
|
if (!this.options.feedback) throw new Error("Feedback configuration unavailable");
|
|
7060
|
-
const { IntakeFeedbackService } = await import("./feedback-
|
|
7144
|
+
const { IntakeFeedbackService } = await import("./feedback-D69e1hX5.js").then((n) => n.r);
|
|
7061
7145
|
await new IntakeFeedbackService(this.options, this).assertActionLineage(String(bound.action.id), db, String(bound.proposal.id));
|
|
7062
7146
|
}
|
|
7063
7147
|
async getAction(actionId) {
|
|
@@ -8222,6 +8306,38 @@ var IntakeExecutionService = class IntakeExecutionService {
|
|
|
8222
8306
|
return row ? this.dispositionDTO(row) : void 0;
|
|
8223
8307
|
});
|
|
8224
8308
|
}
|
|
8309
|
+
/**
|
|
8310
|
+
* A failed attempt's opt-in diagnostic capture (#4285) under the current
|
|
8311
|
+
* reviewer authority for this item, inside the caller's tenant and
|
|
8312
|
+
* confidential scope; every denial fails closed before the row is read.
|
|
8313
|
+
*/
|
|
8314
|
+
async getFailedAttemptCapture(itemId, attemptId) {
|
|
8315
|
+
return this.tx(async (db) => {
|
|
8316
|
+
const item = await this.item(db, itemId);
|
|
8317
|
+
await this.reviewerAccess(db, item);
|
|
8318
|
+
let id2 = attemptId;
|
|
8319
|
+
if (id2 === void 0) {
|
|
8320
|
+
const [analysis] = await this.rows(db, "intake_analyses", "item_id=? AND revision=?", [item.id, item.analysis_revision]);
|
|
8321
|
+
if (!analysis?.current_attempt_id) throw new Error("Analysis unavailable");
|
|
8322
|
+
id2 = String(analysis.current_attempt_id);
|
|
8323
|
+
}
|
|
8324
|
+
const [attempt] = await this.rows(db, "intake_analysis_attempts", "id=? AND item_id=?", [id2, item.id]);
|
|
8325
|
+
if (!attempt) throw new Error("Analysis unavailable");
|
|
8326
|
+
const capture = storedFailureCapture(object(attempt.data).failureCapture);
|
|
8327
|
+
if (!capture || !attempt.safe_error) return null;
|
|
8328
|
+
return {
|
|
8329
|
+
itemId: String(item.id),
|
|
8330
|
+
attemptId: String(attempt.id),
|
|
8331
|
+
source: capture.source,
|
|
8332
|
+
status: capture.status,
|
|
8333
|
+
...capture.status === "captured" ? { text: capture.text } : {},
|
|
8334
|
+
truncated: capture.truncated,
|
|
8335
|
+
redacted: capture.redacted,
|
|
8336
|
+
maxBytes: capture.maxBytes,
|
|
8337
|
+
capturedAt: capture.capturedAt
|
|
8338
|
+
};
|
|
8339
|
+
});
|
|
8340
|
+
}
|
|
8225
8341
|
/** Close an item as handled without an action. Terminal; replay returns the same disposition. */
|
|
8226
8342
|
async resolveItem(input) {
|
|
8227
8343
|
const frozen = JSON.parse(canonical(JSON.parse(JSON.stringify(input))));
|
|
@@ -8600,6 +8716,6 @@ async function continueIntakeReview(service, actionId, task) {
|
|
|
8600
8716
|
return service.applyAction(actionId);
|
|
8601
8717
|
}
|
|
8602
8718
|
//#endregion
|
|
8603
|
-
export { __toESM as C,
|
|
8719
|
+
export { __toESM as A, storedFailureCapture as C, generationSnapshotRead as D, discoveryTransaction as E, listReadGate as O, prepareFailureCapture as S, completeWithFailureCapture as T, HandlerArgumentsInvalidError as _, resolveIntakePolicy as a, FAILURE_CAPTURE_MAX_BYTES as b, HANDLER_ARGUMENT_ISSUE_LIMIT as c, schemaOwnedPath as d, require_ajv as f, GenerationSourceStaleError as g, GenerationSnapshotStaleError as h, intakeBindingDigest as i, __exportAll as k, HANDLER_ARGUMENT_PATH_LIMIT as l, redactedCeiling as m, IntakeExecutionService as n, feedbackActionTransaction as o, UNFINISHED_ACTION_STATES as p, continueIntakeReview as r, feedbackDiscoveryContext as s, IntakeAccessDeniedError as t, describeArgumentRefusal as u, ProposalsNotConfiguredError as v, analysisLeaseRemaining as w, assertFailureCapture as x, FAILURE_CAPTURE_DEFAULT_MAX_BYTES as y };
|
|
8604
8720
|
|
|
8605
|
-
//# sourceMappingURL=execution-
|
|
8721
|
+
//# sourceMappingURL=execution-BxkUOtLf.js.map
|