@happyvertical/smrt-ingestion 0.57.26 → 0.57.28

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 (49) hide show
  1. package/FEEDBACK.md +7 -0
  2. package/PROPOSALS.md +69 -3
  3. package/README.md +4 -1
  4. package/REVIEW.md +50 -11
  5. package/agents/execution.md +4 -2
  6. package/dist/argument-issues.d.ts +29 -0
  7. package/dist/argument-issues.d.ts.map +1 -0
  8. package/dist/chunks/{execution-BzVQax0n.js → execution-Dv3G0d62.js} +102 -12
  9. package/dist/chunks/execution-Dv3G0d62.js.map +1 -0
  10. package/dist/chunks/{feedback-D3UTF8fm.js → feedback-PLOZth0a.js} +3 -3
  11. package/dist/chunks/{feedback-D3UTF8fm.js.map → feedback-PLOZth0a.js.map} +1 -1
  12. package/dist/chunks/{reviewer-instruction-CEc3AOuU.js → reviewer-instruction-zn11aVA5.js} +2 -2
  13. package/dist/chunks/{reviewer-instruction-CEc3AOuU.js.map → reviewer-instruction-zn11aVA5.js.map} +1 -1
  14. package/dist/execution.d.ts +8 -5
  15. package/dist/execution.d.ts.map +1 -1
  16. package/dist/execution.js +1 -1
  17. package/dist/manifest.json +1 -1
  18. package/dist/models.js +1 -1
  19. package/dist/models.js.map +1 -1
  20. package/dist/proposal-dto.d.ts +14 -0
  21. package/dist/proposal-dto.d.ts.map +1 -1
  22. package/dist/proposal-errors.d.ts +8 -1
  23. package/dist/proposal-errors.d.ts.map +1 -1
  24. package/dist/proposal-validation.d.ts +19 -8
  25. package/dist/proposal-validation.d.ts.map +1 -1
  26. package/dist/proposals.d.ts +1 -1
  27. package/dist/proposals.d.ts.map +1 -1
  28. package/dist/proposals.js +50 -49
  29. package/dist/proposals.js.map +1 -1
  30. package/dist/review-dto.d.ts +26 -2
  31. package/dist/review-dto.d.ts.map +1 -1
  32. package/dist/review-host.d.ts.map +1 -1
  33. package/dist/server.d.ts +2 -0
  34. package/dist/server.d.ts.map +1 -1
  35. package/dist/server.js +4 -4
  36. package/dist/server.js.map +1 -1
  37. package/dist/smrt-knowledge.json +21 -21
  38. package/dist/svelte/components/ReviewView.svelte +67 -8
  39. package/dist/svelte/components/ReviewView.svelte.d.ts.map +1 -1
  40. package/dist/svelte/i18n.d.ts +2 -0
  41. package/dist/svelte/i18n.d.ts.map +1 -1
  42. package/dist/svelte/i18n.js +2 -0
  43. package/dist/svelte/index.d.ts +1 -1
  44. package/dist/svelte/index.d.ts.map +1 -1
  45. package/dist/svelte/view-utils.d.ts +5 -1
  46. package/dist/svelte/view-utils.d.ts.map +1 -1
  47. package/dist/svelte/view-utils.js +5 -1
  48. package/package.json +13 -13
  49. package/dist/chunks/execution-BzVQax0n.js.map +0 -1
package/FEEDBACK.md CHANGED
@@ -38,6 +38,13 @@ decision by that actor, never as reviewer correctness evidence; consumers that
38
38
  derive reviewer agreement must exclude `selfDecision: true` events, and nothing
39
39
  in this package turns them into automation eligibility.
40
40
 
41
+ Generated-output validity is not a feedback signal. A suggestion kept because
42
+ its arguments missed only required fields (#4284, PROPOSALS.md) is recorded as
43
+ incomplete — `needs_review` with those fields in `missingFields` — not as an
44
+ invalid reply with a `provenance.failure`. It produces no feedback record by
45
+ itself; only the reviewer's explicit judgment or approval of the completed
46
+ arguments does, through the paths above.
47
+
41
48
  ## Reviewer routing choices
42
49
 
43
50
  A `reviewer_routing` record is appended inside the owning transaction when
package/PROPOSALS.md CHANGED
@@ -115,6 +115,36 @@ without automatic retry that would bypass application boundary checks. The
115
115
  adapter's public identity is exactly provider/model/version; credentials and raw
116
116
  provider errors are never provenance.
117
117
 
118
+ The fixed system instruction (`proposalInstructions`, extended per item by
119
+ `proposalInstructionsFor` with the handler argument contract and split
120
+ eligibility) is generic and value-free. It treats evidence as untrusted data,
121
+ never instructions, and limits suggestions to offered handlers and candidates.
122
+ It asks the model to fill every argument readable from the evidence
123
+ (identifiers, numbers, dates, quantities, amounts and currency) in the form its
124
+ schema requires, never inventing a value the evidence does not show; a value
125
+ that cannot be expressed in that form is treated as absent. Each value must be
126
+ the one whose label or context matches the field's name and description; when
127
+ several similar values appear, a field whose named value is missing is treated
128
+ as absent rather than given a substitute. A candidate reference is chosen only
129
+ from that handler's listed candidates, and an evidence reference copies the
130
+ supplied `evidenceId`. `missingFields` lists exactly the required fields left
131
+ out of `args`, and a required field is left out only when its value is genuinely
132
+ absent or no offered candidate matches. On required-only schema refusals, the
133
+ validator computes the absent required set and corrects a mismatched model
134
+ declaration; the instruction guides the model without making its declaration
135
+ authoritative. Absent optional fields stay out
136
+ of both `args` and `missingFields`. The model prefers `no_action` when no
137
+ offered handler's description fits the document's role, and `unknown` when the
138
+ evidence cannot be interpreted (#4290). Domain routing, such as which received
139
+ documents an application ignores, belongs in host handler descriptions or
140
+ reviewer guidance, not in this text. The text is not persisted. It is not part
141
+ of the frozen interpretation configuration, the input, catalog or output
142
+ digests, or the stored generation output, so a package release that changes it
143
+ leaves stored attempts readable and previewable unchanged. New attempts send the
144
+ new text, but their digests do not record it; a host that needs provenance to
145
+ tell the two apart bumps its own `promptVersion`, which, like any configuration
146
+ change, makes earlier attempts read as stale (`GenerationSnapshotStaleError`).
147
+
118
148
  A trusted custom `ProposalGenerator` must likewise honor cancellation, bound its
119
149
  response, and explicitly declare validated `complete` or `unknown` completion.
120
150
  The SDK currently normalizes missing/unknown finish reasons to `stop`
@@ -156,11 +186,44 @@ Model output can contain only offered handler versions, schema-valid arguments,
156
186
  retained evidence locations and offered alternative handler/candidate keys.
157
187
  Candidate IDs must occur in the offered set, and evidence IDs in retained source
158
188
  results. Unknown enums, invented IDs, extra authority/tool/approval fields and
159
- malformed structures fail closed. Missing required top-level fields are retained
160
- as `missingFields`, with `needs_review`; values are never invented to satisfy a
189
+ malformed structures fail closed. Missing required fields are retained as
190
+ `missingFields`, with `needs_review`; values are never invented to satisfy a
161
191
  schema. Observed page/time/source granularity is preserved. Logical scan splits
162
192
  use `proposeDocumentSplits`; originals and hashes remain intact.
163
193
 
194
+ When a suggestion's arguments fail the handler schema **only** on `required`
195
+ (#4284), the suggestion is kept rather than rejecting the attempt: its
196
+ arguments stay exactly as generated and `missingFields` names every missing
197
+ required argument. The schema, not the model, decides what is missing. A
198
+ declaration that matches the computed set (in any order) is kept exactly as the
199
+ model wrote it, so an already valid reply is unchanged byte for byte and replay
200
+ stays deterministic. A declaration that differs (unlisted misses, or listed
201
+ fields that are present or optional) is replaced by the sorted computed set and
202
+ the suggestion is `needs_review` even when nothing is left missing;
203
+ `provenance.missingFieldsCorrection` then records `{suggestions, added,
204
+ removed}` counts only, and is absent otherwise and dropped whenever the
205
+ suggestions are discarded. A miss at the
206
+ argument root is the bare property name; a miss inside a present nested object
207
+ or array item is an RFC 6901 JSON Pointer relative to the arguments, such as
208
+ `/vendor/name` or `/lines/0/sku`. An entry starting with `/` is therefore a
209
+ pointer, so a handler should not declare a root property whose name itself
210
+ starts with `/`. Names come from the handler schema's own `required` lists,
211
+ never from argument values or model-chosen keys; `required` inside `allOf` or
212
+ inside object-form `dependencies` (`{a: {required: ['b']}}`) counts like any
213
+ other. The schema walk does not follow `$ref`: a miss directly at a property
214
+ whose schema is a `$ref` is kept, but a miss deeper inside the referenced
215
+ definition cannot be named from the schema and rejects (fail-safe). The attempt still rejects as before when any other
216
+ keyword fails beside or instead of `required`: type, enum, pattern, bounds,
217
+ `additionalProperties`, an `anyOf`/`oneOf` branch, an `if`/`then`/`else` branch
218
+ (Ajv adds an `if` error), `not`, or array-form `dependencies` (its own keyword,
219
+ although it names the missing property). It also rejects when a miss lies under
220
+ a key the schema does not declare, or when more than 30 fields are missing.
221
+ Handler schemas compile in Ajv strict mode, so draft-2019 keywords such as
222
+ `dependentRequired` are refused at compile time. Such a suggestion is ordinary
223
+ `needs_review` output: the decision gate can only withhold readiness, never
224
+ grant it, `automaticActionEligible` stays false, and generated preview of
225
+ incomplete arguments fails the handler schema (see Explicit preview below).
226
+
164
227
  A generated split whose groups fail that check is dropped, not the whole reply
165
228
  (#4288): the suggestions and any other splits are validated as before, the
166
229
  dropped split is never published or applied, and `provenance.splitsDropped`
@@ -371,7 +434,10 @@ Selections must reference current persisted validated `ready_for_review` or
371
434
  `needs_review` output (#4208); a `provider_error` attempt, an unoffered handler or
372
435
  a non-interpretation stage is rejected. A `needs_review` suggestion whose
373
436
  `missingFields` are still absent fails the handler schema inside the ordinary
374
- preview (`Invalid handler payload`) and publishes nothing; the reviewer supplies
437
+ preview (`HandlerArgumentsInvalidError`, `Invalid handler payload`, whose
438
+ value-free `issues` name the missing schema fields, for example
439
+ `{ path: '/title', keyword: 'required' }`; see REVIEW.md) and publishes
440
+ nothing; the reviewer supplies
375
441
  the missing values through the explicit human path (`previewProposal` /
376
442
  `previewPlan`, as the published review host does for `preview({args})`), and the
377
443
  handler's `validate` and `preview` run again on the completed arguments.
package/README.md CHANGED
@@ -210,7 +210,10 @@ Reviewers can start any offered handler for an item (`startReviewerAction`) or
210
210
  close it as handled without action (`resolveItem`); the published host adapter
211
211
  wires both as `startAction`/`resolve` and exposes the offered `catalog`. Hosts
212
212
  with their own transport add the two POST operations behind the same session,
213
- CSRF and reviewer checks as `decide`. The `intake_dispositions` table requires
213
+ CSRF and reviewer checks as `decide`, and map a thrown
214
+ `HandlerArgumentsInvalidError` (name and value-free `issues`) from `startAction`
215
+ exactly as they do for `preview` so the form stays inline (see
216
+ [REVIEW.md](REVIEW.md)). The `intake_dispositions` table requires
214
217
  a manifest migration before upgrading.
215
218
 
216
219
  ## Recipe preview
package/REVIEW.md CHANGED
@@ -35,7 +35,9 @@ Plan membership contains the exact parent args/version so edits call
35
35
  `previewPlan`, not per-step correction. An item may have more review pages; the
36
36
  host must aggregate state across pages when projecting a production inbox state.
37
37
 
38
- A `needs_review` suggestion is completable, not only rejectable (#4208). The
38
+ A `needs_review` suggestion is completable, not only rejectable (#4208). That
39
+ includes a suggestion kept because its arguments missed only required fields
40
+ (#4284); nested misses appear as JSON Pointers such as `/vendor/name`. The
39
41
  component shows its `missingFields`, an editable `Suggested arguments (JSON)`
40
42
  draft prefilled from the generated arguments, and the candidate picker for
41
43
  declared candidate fields; Prepare review stays disabled while required fields
@@ -45,21 +47,49 @@ which the published host publishes through the ordinary `previewProposal` /
45
47
  `previewPlan` with the same `ui:<index>` intention, never by rewriting the
46
48
  generation. The handler validates the human arguments again before a
47
49
  `waiting_review` action exists, approval remains a separate explicit decision,
48
- `ActionReview` lists required arguments missing from the current draft while
49
- editing, and no authority or automation eligibility is added: a failed attempt,
50
+ `ActionReview` lists top-level required arguments missing from the current
51
+ draft while editing (nested misses named by JSON Pointer in `missingFields` are
52
+ not re-checked in the browser; the server's revalidation refuses them and the
53
+ component shows that inline as `HandlerArgumentsInvalidError`), and no authority or automation eligibility is added: a failed attempt,
50
54
  an unoffered handler or a foreign stage is still refused by the host.
51
55
  `preview` throws on every failure, as before. When the handler's argument
52
56
  schema or `validate` refused the arguments being previewed (operation preview,
53
- which also carries corrections, or plan preview), the server throws
54
- `HandlerArgumentsInvalidError` (`name` set, messages unchanged). Apply-time and
57
+ which also carries corrections, a reviewer-started action, or plan preview),
58
+ the server throws `HandlerArgumentsInvalidError` (`name` set, messages
59
+ unchanged). An argument-schema refusal also carries `issues`: a frozen list of
60
+ at most `HANDLER_ARGUMENT_ISSUE_LIMIT` (20) `{ path, keyword? }` entries
61
+ (`HandlerArgumentIssue`). `path` is built only from schema-declared property
62
+ names, `required` names and real array indexes and is cut at
63
+ `HANDLER_ARGUMENT_PATH_LIMIT` (160)
64
+ characters (never splitting a `~0`/`~1` escape). Segments are escaped per RFC
65
+ 6901 (`~` as `~0`, `/` as `~1`), with two departures: `/` is the whole
66
+ arguments object (never a key `""`), and `?` stands for a data-named key. A
67
+ `required` refusal appends the missing schema name to the parent's path. The
68
+ format relates to a suggestion's `missingFields` as follows: a root path
69
+ `/name` is the bare `missingFields` entry `name` (unescaped), and a nested
70
+ entry is the same escaped pointer in both (for example `/vendor/a~1b~0c`).
71
+ The bundled view shows a root issue without its leading `/`, so its refused
72
+ fields read like the missing-information list. `ProposalValidationError`
73
+ reasons share the schema-owned segment rule but stay unescaped.
74
+ `keyword` is the failing schema keyword. Argument values, Ajv
75
+ `params`/messages and handler messages are never included. A `validate`
76
+ refusal has no `issues` (the handler contract returns only `ok`). The size and
77
+ shape preconditions checked before the schema runs (arguments over the policy
78
+ byte limit, or a handler schema that is not a closed `type: 'object'` with
79
+ `additionalProperties: false`) stay a plain `Error`: they fail closed as a
80
+ denial, never as the inline refusal. Apply-time and
55
81
  external-send revalidation and result-schema checks keep a plain `Error`. The component shows an inline message and
56
82
  keeps the view and draft when `preview` either rejects with an error whose
57
83
  `name` is `HandlerArgumentsInvalidError` or resolves `{ rejected: 'invalid' }`
58
- (`PreviewRejection`). A transport that crosses a process boundary preserves
59
- the inline UX by keeping that name (for example re-throwing an `Error` with
84
+ (`PreviewRejection`, optionally with the same `issues`). A transport that
85
+ crosses a process boundary preserves the inline UX by keeping that name and
86
+ `issues` (for example re-throwing an `Error` with
60
87
  `name = 'HandlerArgumentsInvalidError'` in the browser callback) or by
61
- returning `{ rejected: 'invalid' }` for that case only, as the maintained
62
- fixture's `previewForReview` does. Without either, the refusal behaves like
88
+ returning `{ rejected: 'invalid', issues? }` for that case only, as the
89
+ maintained fixture's `previewForReview` and `startActionForReview` do. Since
90
+ #4281 the fixture's rejection body also carries `issues` when the schema
91
+ refused; read `rejected === 'invalid'` rather than comparing the whole body
92
+ with strict equality. Without either, the refusal behaves like
63
93
  any other failure: the view is cleared exactly as before this change, and the
64
94
  reviewer's in-memory draft returns after an authorized refresh. Every other
65
95
  thrown preview or candidate-search failure (denied, revoked, unavailable or
@@ -346,8 +376,17 @@ needs the reviewer grant and keeps its handler fixed, so only its arguments can
346
376
  be corrected),
347
377
  runs the handler's normal `validate`/`preview`, publishes a `waiting_review`
348
378
  revision and requires the same explicit approval and apply as a generated
349
- proposal. Replays with the same request return the same review; changed arguments
350
- or reason conflict. Such actions are never automation-eligible: `authorizeAutomatic`
379
+ proposal. The reviewer typed these arguments, so a handler argument-schema or
380
+ `validate` refusal throws `HandlerArgumentsInvalidError` with the value-free
381
+ `issues` described above, and the rolled-back transaction leaves no action row
382
+ (#4281). Every other refusal (input shape, access, handler unavailable, item
383
+ resolved, identity or request conflict, normalization mismatch) stays a plain
384
+ denial. `startAction` follows the `preview` contract: it throws, or a transport
385
+ may resolve `{ rejected: 'invalid', issues? }` for that one case. The component
386
+ keeps the start form, handler, arguments and reason, shows an inline refusal and
387
+ lists any field paths; any other failure clears the view as before. Replays
388
+ with the same request return the same review; changed arguments or reason
389
+ conflict. Such actions are never automation-eligible: `authorizeAutomatic`
351
390
  refuses them regardless of policy opt-ins. The UI pre-fills arguments only from a
352
391
  same-handler suggestion (for example a `needs_review` one) and a single original's
353
392
  evidence references, lists the required fields still missing, and submits exactly
@@ -84,8 +84,10 @@ refuses plan handlers and resolved items, binds the current analysis revision's
84
84
  completed/partial attempt, inserts an action keyed `reviewer:<requestId>` with
85
85
  `data.origin = 'reviewer-selected'`, and reuses `buildBinding`/`publish`: schema
86
86
  validation, `validate`, `preview`, exact normalized arguments, target locks,
87
- evidence pins and the request ledger behave exactly as for `previewProposal`.
88
- Replays re-preview against the original revision and return the same review.
87
+ evidence pins and the request ledger behave exactly as for `previewProposal`,
88
+ including the typed `HandlerArgumentsInvalidError` (with value-free `issues`)
89
+ for an argument-schema or `validate` refusal of the reviewer's arguments;
90
+ every other refusal stays a plain `Error` (#4281). Replays re-preview against the original revision and return the same review.
89
91
  Approval, apply, retention, redaction and reconciliation are unchanged.
90
92
  `authorizeAutomatic` refuses `reviewer-selected` actions and resolved items;
91
93
  human routing is never machine authority.
@@ -0,0 +1,29 @@
1
+ import { type ErrorObject } from 'ajv';
2
+ import type { HandlerArgumentIssue } from './review-dto.js';
3
+ /**
4
+ * Keep only path segments the schema itself names: indexes into an actual
5
+ * array in the instance, and keys declared under `properties`. Anything else
6
+ * (keys under `additionalProperties`/`patternProperties`, numeric keys of an
7
+ * object, or an unknown key) is data and becomes `?`. `/` is the whole
8
+ * instance. With `escaped`, kept segments are RFC 6901-escaped (`~0`, `~1`);
9
+ * without it (the `ProposalValidationError` reason format) they are not.
10
+ */
11
+ export declare function schemaOwnedPath(instancePath: string, schema: unknown, instance?: unknown, escaped?: boolean): string;
12
+ /** Most field details one `HandlerArgumentsInvalidError` carries. */
13
+ export declare const HANDLER_ARGUMENT_ISSUE_LIMIT = 20;
14
+ /** Longest issue path; a deeper path keeps its prefix. */
15
+ export declare const HANDLER_ARGUMENT_PATH_LIMIT = 160;
16
+ /**
17
+ * Value-free field details for an argument-schema refusal: RFC 6901-escaped
18
+ * schema-owned paths (see `schemaOwnedPath`) and the failing schema keyword. A `required` failure
19
+ * names the schema-declared missing property; no other Ajv `params`, message,
20
+ * or instance value is ever read into the result. Bounded and frozen.
21
+ */
22
+ export declare function handlerArgumentIssues(errors: readonly ErrorObject[] | null | undefined, schema: unknown, instance: unknown): readonly HandlerArgumentIssue[];
23
+ /**
24
+ * Re-validate refused arguments with every error collected, only to describe
25
+ * the refusal. The authoritative accept/refuse decision is the caller's own
26
+ * validator; this never changes it.
27
+ */
28
+ export declare function describeArgumentRefusal(schema: Record<string, unknown>, value: unknown): readonly HandlerArgumentIssue[];
29
+ //# sourceMappingURL=argument-issues.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"argument-issues.d.ts","sourceRoot":"","sources":["../src/argument-issues.ts"],"names":[],"mappings":"AAAA,OAAY,EAAE,KAAK,WAAW,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAkB5D;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,OAAO,EACf,QAAQ,CAAC,EAAE,OAAO,EAClB,OAAO,UAAQ,GACd,MAAM,CAgDR;AAED,qEAAqE;AACrE,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAC/C,0DAA0D;AAC1D,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAK/C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,IAAI,GAAG,SAAS,EACjD,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,OAAO,GAChB,SAAS,oBAAoB,EAAE,CAgCjC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,OAAO,GACb,SAAS,oBAAoB,EAAE,CAajC"}
@@ -51,9 +51,11 @@ var listReadGate = /* @__PURE__ */ Symbol("ingestion.listReadGate");
51
51
  //#endregion
52
52
  //#region src/proposal-errors.ts
53
53
  var HandlerArgumentsInvalidError = class extends Error {
54
- constructor(message) {
54
+ issues;
55
+ constructor(message, issues) {
55
56
  super(message);
56
57
  this.name = "HandlerArgumentsInvalidError";
58
+ if (issues?.length) this.issues = issues;
57
59
  }
58
60
  };
59
61
  var ProposalsNotConfiguredError = class extends Error {
@@ -6383,8 +6385,93 @@ var require_ajv = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6383
6385
  });
6384
6386
  }));
6385
6387
  //#endregion
6386
- //#region src/feedback-internal.ts
6388
+ //#region src/argument-issues.ts
6387
6389
  var import_ajv = /* @__PURE__ */ __toESM(require_ajv(), 1);
6390
+ function schemaNodes(node) {
6391
+ if (!node || typeof node !== "object" || Array.isArray(node)) return [];
6392
+ const current = node;
6393
+ return [current, ...[
6394
+ "oneOf",
6395
+ "anyOf",
6396
+ "allOf"
6397
+ ].flatMap((keyword) => Array.isArray(current[keyword]) ? current[keyword].flatMap(schemaNodes) : [])];
6398
+ }
6399
+ function escapeSegment(segment) {
6400
+ return segment.replace(/~/g, "~0").replace(/\//g, "~1");
6401
+ }
6402
+ function schemaOwnedPath(instancePath, schema, instance, escaped = false) {
6403
+ if (!instancePath) return "/";
6404
+ let nodes = schemaNodes(schema);
6405
+ let value = instance;
6406
+ const segments = instancePath.split("/").slice(1);
6407
+ const kept = [];
6408
+ for (const raw of segments) {
6409
+ const segment = raw.replace(/~1/g, "/").replace(/~0/g, "~");
6410
+ if (/^\d+$/.test(segment) && Array.isArray(value)) {
6411
+ kept.push(segment);
6412
+ value = value[Number(segment)];
6413
+ nodes = nodes.flatMap((node) => node.type === "array" || node.items !== void 0 ? schemaNodes(node.items) : []);
6414
+ continue;
6415
+ }
6416
+ value = value && typeof value === "object" && !Array.isArray(value) ? value[segment] : void 0;
6417
+ const owners = nodes.filter((node) => {
6418
+ const properties = node.properties;
6419
+ return !!properties && typeof properties === "object" && Object.hasOwn(properties, segment);
6420
+ });
6421
+ if (owners.length) {
6422
+ kept.push(segment);
6423
+ nodes = owners.flatMap((node) => schemaNodes(node.properties[segment]));
6424
+ } else {
6425
+ kept.push("?");
6426
+ nodes = nodes.flatMap((node) => typeof node.additionalProperties === "object" ? schemaNodes(node.additionalProperties) : []);
6427
+ }
6428
+ }
6429
+ return `/${kept.map((segment) => escaped && segment !== "?" ? escapeSegment(segment) : segment).join("/")}`;
6430
+ }
6431
+ var HANDLER_ARGUMENT_ISSUE_LIMIT = 20;
6432
+ var HANDLER_ARGUMENT_PATH_LIMIT = 160;
6433
+ var ERRORS_EXAMINED = 200;
6434
+ var KEYWORD = /^[A-Za-z$][A-Za-z0-9_$-]{0,63}$/;
6435
+ function handlerArgumentIssues(errors, schema, instance) {
6436
+ const issues = [];
6437
+ const seen = /* @__PURE__ */ new Set();
6438
+ const paths = /* @__PURE__ */ new Map();
6439
+ const all = errors ?? [];
6440
+ for (let index = 0; index < all.length && index < ERRORS_EXAMINED && issues.length < 20; index++) {
6441
+ const error = all[index];
6442
+ let path = paths.get(error.instancePath);
6443
+ if (path === void 0) {
6444
+ path = schemaOwnedPath(error.instancePath, schema, instance, true);
6445
+ paths.set(error.instancePath, path);
6446
+ }
6447
+ const missing = error.params.missingProperty;
6448
+ if (error.keyword === "required" && typeof missing === "string") path = `${path === "/" ? "" : path}/${escapeSegment(missing)}`;
6449
+ if (path.length > 160) path = path.slice(0, 160).replace(/~$/, "");
6450
+ const keyword = KEYWORD.test(error.keyword) ? error.keyword : void 0;
6451
+ const key = `${path}\0${keyword ?? ""}`;
6452
+ if (seen.has(key)) continue;
6453
+ seen.add(key);
6454
+ issues.push(Object.freeze(keyword ? {
6455
+ path,
6456
+ keyword
6457
+ } : { path }));
6458
+ }
6459
+ return Object.freeze(issues);
6460
+ }
6461
+ function describeArgumentRefusal(schema, value) {
6462
+ try {
6463
+ const check = new import_ajv.default({
6464
+ strict: true,
6465
+ allErrors: true,
6466
+ validateFormats: false
6467
+ }).compile(schema);
6468
+ return check(value) ? Object.freeze([]) : handlerArgumentIssues(check.errors, schema, value);
6469
+ } catch {
6470
+ return Object.freeze([]);
6471
+ }
6472
+ }
6473
+ //#endregion
6474
+ //#region src/feedback-internal.ts
6388
6475
  var feedbackActionTransaction = /* @__PURE__ */ Symbol("ingestion.feedbackActionTransaction");
6389
6476
  var feedbackDiscoveryContext = /* @__PURE__ */ Symbol("ingestion.feedbackDiscoveryContext");
6390
6477
  //#endregion
@@ -6640,13 +6727,14 @@ var IntakeExecutionService = class IntakeExecutionService {
6640
6727
  }
6641
6728
  /**
6642
6729
  * `arguments` marks arguments being previewed (operation preview, which
6643
- * also carries corrections, and plan preview): only their schema refusal is
6644
- * the correctable `HandlerArgumentsInvalidError`. Apply-time and
6730
+ * also carries corrections, reviewer-started actions and plan preview):
6731
+ * only their schema refusal is the correctable
6732
+ * `HandlerArgumentsInvalidError`, with value-free field `issues`. Apply-time and
6645
6733
  * external-send revalidation and result-schema checks keep the plain error.
6646
6734
  */
6647
6735
  validate(schema, value, limit, arguments_ = false) {
6648
6736
  if (Buffer.byteLength(canonical(value)) > limit || schema.type !== "object" || schema.additionalProperties !== false) throw new Error("Invalid handler payload");
6649
- if (!this.ajv.compile(schema)(value)) throw arguments_ ? new HandlerArgumentsInvalidError("Invalid handler payload") : /* @__PURE__ */ new Error("Invalid handler payload");
6737
+ if (!this.ajv.compile(schema)(value)) throw arguments_ ? new HandlerArgumentsInvalidError("Invalid handler payload", describeArgumentRefusal(schema, value)) : /* @__PURE__ */ new Error("Invalid handler payload");
6650
6738
  }
6651
6739
  /**
6652
6740
  * The read-only half of `access`: current host authority, policy and
@@ -6969,7 +7057,7 @@ var IntakeExecutionService = class IntakeExecutionService {
6969
7057
  if (!Array.isArray(references)) throw new Error("Feedback lineage unavailable");
6970
7058
  if (references.length === 0) return;
6971
7059
  if (!this.options.feedback) throw new Error("Feedback configuration unavailable");
6972
- const { IntakeFeedbackService } = await import("./feedback-D3UTF8fm.js").then((n) => n.r);
7060
+ const { IntakeFeedbackService } = await import("./feedback-PLOZth0a.js").then((n) => n.r);
6973
7061
  await new IntakeFeedbackService(this.options, this).assertActionLineage(String(bound.action.id), db, String(bound.proposal.id));
6974
7062
  }
6975
7063
  async getAction(actionId) {
@@ -7167,9 +7255,11 @@ var IntakeExecutionService = class IntakeExecutionService {
7167
7255
  });
7168
7256
  }
7169
7257
  /**
7170
- * `reviewed` marks arguments a reviewer is previewing or correcting: only
7171
- * then is a refusal the typed `HandlerArgumentsInvalidError`. Apply-time
7172
- * verification and plan step expansion keep the plain error.
7258
+ * `reviewed` marks arguments a reviewer is previewing, correcting or
7259
+ * starting a chosen handler with: only then is an argument-schema or
7260
+ * `validate` refusal the typed `HandlerArgumentsInvalidError`. Every other
7261
+ * refusal here stays a plain denial; apply-time verification and plan step
7262
+ * expansion keep the plain error.
7173
7263
  */
7174
7264
  async buildBinding(db, item, input, reviewed = false) {
7175
7265
  const handler = this.operation(this.handler(input.handlerId, input.handlerVersion));
@@ -8119,7 +8209,7 @@ var IntakeExecutionService = class IntakeExecutionService {
8119
8209
  handlerVersion: handler.version,
8120
8210
  args: frozen.args
8121
8211
  };
8122
- const binding = await this.buildBinding(db, item, preview);
8212
+ const binding = await this.buildBinding(db, item, preview, true);
8123
8213
  return this.publish(db, item, preview, binding);
8124
8214
  });
8125
8215
  }
@@ -8510,6 +8600,6 @@ async function continueIntakeReview(service, actionId, task) {
8510
8600
  return service.applyAction(actionId);
8511
8601
  }
8512
8602
  //#endregion
8513
- export { listReadGate as _, resolveIntakePolicy as a, require_ajv as c, GenerationSnapshotStaleError as d, GenerationSourceStaleError as f, generationSnapshotRead as g, discoveryTransaction as h, intakeBindingDigest as i, UNFINISHED_ACTION_STATES as l, ProposalsNotConfiguredError as m, IntakeExecutionService as n, feedbackActionTransaction as o, HandlerArgumentsInvalidError as p, continueIntakeReview as r, feedbackDiscoveryContext as s, IntakeAccessDeniedError as t, redactedCeiling as u, __exportAll as v, __toESM as y };
8603
+ export { __toESM as C, __exportAll as S, HandlerArgumentsInvalidError as _, resolveIntakePolicy as a, generationSnapshotRead as b, HANDLER_ARGUMENT_ISSUE_LIMIT as c, schemaOwnedPath as d, require_ajv as f, GenerationSourceStaleError as g, GenerationSnapshotStaleError as h, intakeBindingDigest as i, 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, listReadGate as x, discoveryTransaction as y };
8514
8604
 
8515
- //# sourceMappingURL=execution-BzVQax0n.js.map
8605
+ //# sourceMappingURL=execution-Dv3G0d62.js.map