@happyvertical/smrt-ingestion 0.55.6 → 0.55.8

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 (77) hide show
  1. package/AGENTS.md +13 -3
  2. package/FEEDBACK.md +156 -0
  3. package/README.md +15 -3
  4. package/REVIEW.md +137 -0
  5. package/dist/chunks/{execution-C6HJvl9e.js → execution-C7sTFXFU.js} +375 -11
  6. package/dist/chunks/execution-C7sTFXFU.js.map +1 -0
  7. package/dist/chunks/execution-internal-DWteDHM2.js.map +1 -1
  8. package/dist/chunks/feedback-C3OHD4sA.js +625 -0
  9. package/dist/chunks/feedback-C3OHD4sA.js.map +1 -0
  10. package/dist/chunks/{extraction-bseWZuWN.js → proposal-errors-z24VKWnQ.js} +10 -2
  11. package/dist/chunks/proposal-errors-z24VKWnQ.js.map +1 -0
  12. package/dist/dto.d.ts +2 -0
  13. package/dist/dto.d.ts.map +1 -1
  14. package/dist/execution-internal.d.ts +3 -1
  15. package/dist/execution-internal.d.ts.map +1 -1
  16. package/dist/execution.d.ts +15 -1
  17. package/dist/execution.d.ts.map +1 -1
  18. package/dist/execution.js +1 -1
  19. package/dist/feedback-contracts.d.ts +51 -0
  20. package/dist/feedback-contracts.d.ts.map +1 -0
  21. package/dist/feedback-dto.d.ts +106 -0
  22. package/dist/feedback-dto.d.ts.map +1 -0
  23. package/dist/feedback-internal.d.ts +19 -0
  24. package/dist/feedback-internal.d.ts.map +1 -0
  25. package/dist/feedback.d.ts +54 -0
  26. package/dist/feedback.d.ts.map +1 -0
  27. package/dist/manifest.json +34 -1
  28. package/dist/models.js +1 -1
  29. package/dist/models.js.map +1 -1
  30. package/dist/proposal-contracts.d.ts +4 -0
  31. package/dist/proposal-contracts.d.ts.map +1 -1
  32. package/dist/proposal-dto.d.ts +4 -0
  33. package/dist/proposal-dto.d.ts.map +1 -1
  34. package/dist/proposal-errors.d.ts +5 -0
  35. package/dist/proposal-errors.d.ts.map +1 -0
  36. package/dist/proposal-sdk.d.ts.map +1 -1
  37. package/dist/proposals.d.ts +4 -1
  38. package/dist/proposals.d.ts.map +1 -1
  39. package/dist/proposals.js +114 -15
  40. package/dist/proposals.js.map +1 -1
  41. package/dist/review-dto.d.ts +115 -0
  42. package/dist/review-dto.d.ts.map +1 -0
  43. package/dist/server.d.ts +24 -0
  44. package/dist/server.d.ts.map +1 -1
  45. package/dist/server.js +146 -54
  46. package/dist/server.js.map +1 -1
  47. package/dist/smrt-knowledge.json +97 -14
  48. package/dist/svelte/components/ActionReview.svelte +232 -0
  49. package/dist/svelte/components/ActionReview.svelte.d.ts +15 -0
  50. package/dist/svelte/components/ActionReview.svelte.d.ts.map +1 -0
  51. package/dist/svelte/components/EvidenceViewer.svelte +31 -0
  52. package/dist/svelte/components/EvidenceViewer.svelte.d.ts +8 -0
  53. package/dist/svelte/components/EvidenceViewer.svelte.d.ts.map +1 -0
  54. package/dist/svelte/components/InboxView.svelte +119 -0
  55. package/dist/svelte/components/InboxView.svelte.d.ts +9 -0
  56. package/dist/svelte/components/InboxView.svelte.d.ts.map +1 -0
  57. package/dist/svelte/components/IntakeInbox.svelte +11 -0
  58. package/dist/svelte/components/IntakeInbox.svelte.d.ts +10 -0
  59. package/dist/svelte/components/IntakeInbox.svelte.d.ts.map +1 -0
  60. package/dist/svelte/components/IntakeReview.svelte +11 -0
  61. package/dist/svelte/components/IntakeReview.svelte.d.ts +10 -0
  62. package/dist/svelte/components/IntakeReview.svelte.d.ts.map +1 -0
  63. package/dist/svelte/components/ReviewView.svelte +243 -0
  64. package/dist/svelte/components/ReviewView.svelte.d.ts +9 -0
  65. package/dist/svelte/components/ReviewView.svelte.d.ts.map +1 -0
  66. package/dist/svelte/i18n.d.ts +72 -0
  67. package/dist/svelte/i18n.d.ts.map +1 -0
  68. package/dist/svelte/i18n.js +72 -0
  69. package/dist/svelte/index.d.ts +5 -0
  70. package/dist/svelte/index.d.ts.map +1 -0
  71. package/dist/svelte/index.js +3 -0
  72. package/dist/svelte/view-utils.d.ts +13 -0
  73. package/dist/svelte/view-utils.d.ts.map +1 -0
  74. package/dist/svelte/view-utils.js +96 -0
  75. package/package.json +49 -22
  76. package/dist/chunks/execution-C6HJvl9e.js.map +0 -1
  77. package/dist/chunks/extraction-bseWZuWN.js.map +0 -1
package/AGENTS.md CHANGED
@@ -27,9 +27,19 @@ submission never run inside ingestion database transactions.
27
27
 
28
28
  Validation: `pnpm test`, `pnpm test:postgres`, `pnpm test:providers`, `pnpm typecheck`, `pnpm build`.
29
29
  The PostgreSQL command provisions a real database and fails if unavailable.
30
+ Fixture teardown uses `src/test-support/postgres-cleanup.ts`: only owned
31
+ exec_/ing_/ext_/sources_ names, normal DROP, bounded 55006-only retry. Never
32
+ force-terminate backends, grant signal privileges, or ignore leaked sessions.
30
33
  Build includes browser import validation. The provider lane exercises local SDK
31
34
  adapters and process isolation, without claiming live remote recognition quality.
32
- The component/e2e/evaluation
33
- commands are reserved by ADR 0004 and fail explicitly until their owning children
34
- supply real suites.
35
+ `src/svelte` owns transport-neutral review components and browser-safe host callbacks.
36
+ See [FEEDBACK.md](FEEDBACK.md) for revision-bound explicit feedback, scoped example retrieval,
37
+ provider-boundary revalidation and authorized routing policy adoption.
38
+ See [REVIEW.md](REVIEW.md) for authenticated hosts, bounded saved-review reloads,
39
+ assignment ownership, logical split re-extraction and the maintained browser proof.
40
+ UI validation additionally requires `pnpm test:components` and `pnpm test:e2e`;
41
+ `typecheck` includes Svelte and `build` includes the types-first `/svelte` entry.
42
+ `pnpm test:evaluation` runs repository evaluation tooling/format/fault contracts.
43
+ Measured held-out quality is a separate frozen-protocol, budget-gated run; tooling
44
+ success does not establish reference quality or permit automatic actions.
35
45
  See ../../docs/test-matrix/3670-ingestion-foundation.md for behavior coverage.
package/FEEDBACK.md ADDED
@@ -0,0 +1,156 @@
1
+ # Explicit ingestion feedback
2
+
3
+ Configure `IngestionOptions.feedback` to opt in. The existing `intake_feedback`
4
+ ledger owns these records; no new schema, embedding service or provider is added.
5
+ `FeedbackConfiguration` sets a version, maximum examples, scan count, serialized
6
+ bytes and lexical similarity threshold, plus a live scoped authorization callback.
7
+ Hard ceilings are 20 examples, 1,000 scanned records and 1 MB. Choose substantially
8
+ smaller application limits. The proposal's complete serialized request, including
9
+ examples, must also fit the current minimum application/source/provider budget.
10
+
11
+ `recordFeedback` accepts the exact displayed action revision, review version and
12
+ binding hash, an explicit correct/incorrect judgment, optional reason text and a
13
+ request ID. The server resolves reviewer, tenant/confidential scope, retained
14
+ source evidence, extraction/generation versions and current handler arguments.
15
+ A replay returns the same immutable receipt; changed payloads conflict.
16
+ `supersedesId` appends a replacement for the specified prior interpretation
17
+ judgment. A second successor conflicts. Revised actions make old bindings
18
+ ineligible. Approval and successful execution never imply that extracted fields
19
+ are correct.
20
+
21
+ Decision and downstream execution facts are captured inside their owning
22
+ transaction, keyed by immutable event ID and signal, when the configured capture
23
+ authority allows the optional memory projection and it fits the configured byte
24
+ cap. Denial or an oversized automatic projection leaves the underlying
25
+ authoritative decision/outcome intact, including failure and reconciliation.
26
+ Explicit `recordFeedback` and `observeFeedback` requests still reject invalid or
27
+ oversized writes; actual database failures still propagate and roll back. Failed/rolled-back domain
28
+ work and unknown external outcomes remain distinct. `observeFeedback` can replay
29
+ an authorized existing event; it cannot supply a correctness label or fabricate
30
+ an execution result. An initial denial does not mutate retention. Once authorized,
31
+ a narrowed privacy ceiling survives business rollback and later revocation.
32
+
33
+ ## Retrieval and provider boundaries
34
+
35
+ `retrieveFeedback({ itemId, query })` derives the current offered catalog,
36
+ candidates and model/prompt/configuration versions on the server. Callers cannot
37
+ provide candidate authority. The deterministic matcher uses lowercase Unicode
38
+ word-set Jaccard similarity (minimum 0.2), then immutable record ID for ties.
39
+ Scanning, recursive provenance checks and returned examples are bounded; a limited scan does not promise an
40
+ exhaustive history search. Both positive and negative explicit examples are kept.
41
+
42
+ Every selected source must still be readable in the same tenant and confidential
43
+ scope, with its current action/analysis binding, target grants, handler version,
44
+ model/prompt/configuration compatibility and retention. Each source's current
45
+ provider policy must allow the generation recipient and any configured decision
46
+ recipient; the source owner rechecks that policy on both initial and final live
47
+ contexts. Receiving checks cover every offered handler, before and after source
48
+ checks, using each live grant, actual provider recipients and the narrowest byte
49
+ ceiling. Both retrieval and reference revalidation budget the full reconstructed
50
+ examples. A receiving item's provider grant cannot substitute for a source grant.
51
+ Superseded, revoked, deleted or incompatible sources are excluded. Current explicit human corrections
52
+ take precedence: a generation carrying one does not retrieve learned examples.
53
+
54
+ Full examples exist only in the authorized provider request. The SDK proposal
55
+ adapter includes that typed selection in its serialized user message when
56
+ present; disabled feedback leaves the original request shape unchanged. Saved generation
57
+ provenance contains the receiving query, selection configuration digest and
58
+ immutable feedback IDs/digests, not copied source example content. Selected
59
+ references are rechecked before generation, capability probing, decision calls,
60
+ publication and completed-result reads. A newly added example does not invalidate
61
+ an older selection; a revoked or superseded selected example does. Feedback
62
+ lineage is bounded and fails closed. Saved-action reads and pending decisions,
63
+ automatic authorization, preview publication/replay and execution also revalidate
64
+ selected lineage under the
65
+ owning transaction. Revoking, deleting or superseding a selected example blocks
66
+ pending actions; regenerate their proposals and obtain fresh approval to recover.
67
+ A preview replay checks the exact persisted proposal it returns, including its
68
+ analysis attempt; a newer action revision cannot supply replacement lineage.
69
+ Plan replay and final sealed plan-step publication use the same gate.
70
+ For already successful actions, current-authorized durable outcomes remain
71
+ readable/replayable, but invalid learned lineage suppresses saved proposal
72
+ display, arguments and plan payload. An empty selection carries no learned source
73
+ and does not turn optional feedback-capture denial into action denial. Examples
74
+ never expand the offered catalog, candidate IDs, operation permissions or
75
+ automation eligibility.
76
+
77
+ All durable feedback belongs to the source item's existing retention/redaction
78
+ lifecycle. There is no separate memory store or delayed indexing writer to clean
79
+ up. Hosts using other derived stores still implement the existing `purgeDerived`
80
+ contract. Core `LearningMemory` is intentionally not used here: its success/failure
81
+ reinforcement and default ancestor-scope fallback do not represent separate
82
+ correctness/decision/outcome signals and strict confidential-scope eligibility.
83
+
84
+ ## Routing suggestions and adoption
85
+
86
+ `suggestRoutingRule` requires repeated current explicit positive judgments
87
+ from distinct source items with matching handler/version and arguments, and returns supporting immutable IDs,
88
+ shared query terms and the policy owner's preview/version. Suggestions cannot
89
+ execute or modify policy. `getRoutingRule` rechecks the displayed binding and all
90
+ supporting examples. Arguments are routing preferences, never executable grants.
91
+
92
+ By default matching compares **all** action arguments, preserving existing host
93
+ behavior. Create handlers commonly have per-document content and idempotency
94
+ keys, which must remain distinct. Such hosts can explicitly declare a routing-only
95
+ subset in trusted server configuration before capturing judgments:
96
+
97
+ ```ts
98
+ feedback: {
99
+ // ...existing limits, authorize and policy owner
100
+ routing: [{
101
+ handlerId: 'host:create-document',
102
+ handlerVersion: '1',
103
+ version: 'routing-fields-1',
104
+ fields: ['destinationId', 'category'],
105
+ }],
106
+ }
107
+ ```
108
+
109
+ Each declaration must name a configured handler/version and a nonempty, unique
110
+ allowlist of its top-level `argsSchema.properties`; duplicate declarations,
111
+ unknown properties and prototype keys reject. There are no dotted paths,
112
+ caller-supplied selectors or implicit exclusions (including request IDs).
113
+ Optional absent fields stay absent and differ from explicit `null`; at least one
114
+ selected value must be present. The host must select preferences only, never
115
+ grants, provider permissions or automation controls.
116
+
117
+ Capture retains the full immutable action arguments and binding plus the
118
+ versioned subset. For opted-in handlers `RoutingRule.args` contains only selected
119
+ values and `RoutingRule.projection` carries the canonical sorted fields and
120
+ version. Independent support must match that entire contract and those values;
121
+ full original source arguments, provenance and current access are still checked.
122
+ Existing unprojected feedback is not retroactively reinterpreted: record fresh
123
+ explicit judgments after enabling or changing a declaration. Changing a version,
124
+ field list or selected value invalidates old suggestions on reads, adoption and
125
+ replay, including changes inside policy-owner callbacks. Full argument feedback
126
+ retrieval remains unchanged; hosts may present matching examples from
127
+ `retrieveFeedback`, but suggestion creation revalidates every supplied ID.
128
+
129
+ `adoptRoutingRule` requires the exact suggestion digest and expected policy
130
+ version plus current reviewer and adoption authority. The configured policy owner
131
+ must perform its version compare-and-swap and audit on the supplied database
132
+ executor. The ingestion transaction records the exact returned version/audit ID.
133
+ Replays do not adopt twice. Revocation or permission/policy widening rolls back
134
+ both changes. The host callback may store routing preferences only: it must not
135
+ change grants, provider permissions or automation controls. Adoption always
136
+ returns `automaticActionEligible: false`; subsequent proposals retain normal
137
+ current policy and explicit review requirements.
138
+
139
+ ## Review UI and evidence
140
+
141
+ The optional `IntakeReviewHost.feedback` callback carries the exact displayed
142
+ revision and binding. Correct/incorrect controls are explicit and independent of
143
+ Approve/Apply. Unsaved argument edits disable correctness controls until the
144
+ displayed binding is current again. Hosts must authenticate that callback and connect it to
145
+ `recordFeedback`; client-supplied reviewer/scope fields are not accepted. The
146
+ maintained browser fixture demonstrates this transport with CSRF protection and
147
+ rejects substituted revisions.
148
+
149
+ See [the behavior matrix](../../docs/test-matrix/3676-ingestion-feedback.md) for
150
+ validation and the frozen learning protocol, and the
151
+ [routing projection matrix](../../docs/test-matrix/3732-ingestion-routing-projection.md)
152
+ for the optional subset contract. The small authored deterministic
153
+ cohort demonstrates contract-level influence, not provider quality or measured
154
+ production improvement. Real-provider evaluation belongs to #3677. There are no
155
+ sampled automatic outcomes in this feature; reporting that stratum as unavailable
156
+ avoids inventing correctness labels from successful jobs.
package/README.md CHANGED
@@ -65,9 +65,10 @@ Validation commands are `pnpm test`, `pnpm test:postgres`, `pnpm test:providers`
65
65
  `pnpm build` (including built browser import inspection). The PostgreSQL lane
66
66
  requires the repository's configured database service and never silently skips.
67
67
  The provider lane exercises local SDK adapters and process isolation; it does not
68
- claim live remote recognition quality. Component, e2e and evaluation command names are reserved by the ADR and
69
- explicitly unavailable until their owning children deliver the corresponding
70
- capability. See the [behavior matrix](../../docs/test-matrix/3670-ingestion-foundation.md).
68
+ claim live remote recognition quality. `pnpm test:components` and `pnpm test:e2e`
69
+ cover the maintained review surface. `pnpm test:evaluation` checks repository
70
+ evaluation tooling contracts; measured held-out quality requires a separately
71
+ frozen protocol and an approved aggregate provider budget. See the [behavior matrix](../../docs/test-matrix/3670-ingestion-foundation.md).
71
72
 
72
73
  ## Authoritative review and execution
73
74
 
@@ -149,3 +150,14 @@ only receipt preservation, never domain writes, AI tools or external actions.
149
150
 
150
151
  See [PROPOSALS.md](PROPOSALS.md) for bounded application catalog discovery, durable
151
152
  interpretation revisions, optional typed decisions and explicit generated preview.
153
+
154
+ ## Human review
155
+
156
+ Mount the `/svelte` inbox and review components through an authenticated host using
157
+ the browser-safe `IntakeReviewHost` DTO contract. See [REVIEW.md](REVIEW.md) for
158
+ exact revision-bound callbacks, live evidence access, logical split corrections,
159
+ assignment ownership, and the maintained upload-to-domain-result browser fixture.
160
+
161
+ Optional explicit feedback and scoped example retrieval are documented in
162
+ [FEEDBACK.md](FEEDBACK.md). Approval and execution outcomes remain separate from
163
+ interpretation correctness; routing policy adoption is explicit and versioned.
package/REVIEW.md ADDED
@@ -0,0 +1,137 @@
1
+ # Authenticated review surfaces
2
+
3
+ `@happyvertical/smrt-ingestion/svelte` exports `IntakeInbox`, `IntakeReview` and
4
+ `EvidenceViewer`. The browser-safe DTO entry exports their `IntakeReviewHost`
5
+ callback contract. Import styling/theme configuration from smrt-ui in the host.
6
+ Components use smrt-ui primitives and the `ingestion.*` i18n catalog.
7
+
8
+ The host authenticates every request, resolves tenant/actor/confidential scope
9
+ from its session, enforces CSRF on mutations, and constructs `IngestionService`.
10
+ Never accept scope, reviewer, permissions or a principal from callback JSON.
11
+ Only supply authorized evidence URLs and escaped text; original URLs are
12
+ same-origin authenticated handlers that recheck `readEvidence` on every read.
13
+ Candidate discovery uses `findCandidates` with current grants. Presentation
14
+ state and disabled buttons provide no server authority.
15
+
16
+ `listReviews(itemId, {cursor?,limit?})` reloads saved action identities and their
17
+ current plan membership without browser storage. It returns at most 50 actions,
18
+ with an opaque action-ID cursor. Every payload requires current item, handler,
19
+ parent plan and target access under the owning transaction. Denied reads fail
20
+ closed. Target reads check current authorization separately from historical
21
+ revision freshness: unfinished drift returns state-only stale reviews without
22
+ removing unrelated entries; succeeded results remain readable after authorized
23
+ target changes. Apply still enforces exact bound target revisions. Expired entries
24
+ contain only review identity/state. Stale entries never disclose old args or target
25
+ labels; an authorized parent plan additionally exposes `stalePlan` identity, key,
26
+ current plan revision and handler identity. Hosts must collect fresh explicit args
27
+ from the reviewer/current authorized evidence and call `previewPlan` with that
28
+ exact plan CAS and the current completed analysis attempt. Action revision is not
29
+ plan revision. Re-expansion preserves action identity and requires fresh approval.
30
+ Success results are rechecked through the durable result reader.
31
+ Plan membership contains the exact parent args/version so edits call
32
+ `previewPlan`, not per-step correction. An item may have more review pages; the
33
+ host must aggregate state across pages when projecting a production inbox state.
34
+
35
+ The host's `load` callback supplies a current `ItemReviewView`, using
36
+ `getCompletedAnalysis` with no historical fallback. Generated suggestions bind
37
+ the **current generation attempt**, not `generation.source.attemptId` (the prior
38
+ extraction). `previewGeneratedProposals` publishes exact reviews and continues to reject stale
39
+ generation candidate pins. When `listReviews` reports `generationStale`, the host
40
+ omits obsolete generation output and renders authorized saved reviews/results.
41
+ Completed saved actions do not hide healthy unprepared suggestions. The saved-binding hint is not
42
+ an authoritative generation-availability check: a fresh human preview can bind a
43
+ current target while the immutable generation still pins its former revision.
44
+ `getCompletedAnalysis` remains strict and throws server-only
45
+ `GenerationSnapshotStaleError` only after every current catalog/provider/candidate
46
+ read is authorized and an immutable candidate revision differs. The maintained
47
+ host catches only that class, reacquires `listReviews` under current owning
48
+ authority, and returns that new page without generation output. It never reuses
49
+ the earlier page after an error. Denials and unknown failures propagate; healthy
50
+ generation still exposes unprepared sibling suggestions. Stale entries expose handler
51
+ and attempt identity only when that attempt is still the current completed/partial
52
+ analysis. An empty-args editor submits fresh explicit human arguments through
53
+ `previewProposal` or `previewPlan` with the saved CAS; it never reuses old generated
54
+ arguments, rewrites the generation snapshot or transfers approval. Analysis-stale
55
+ entries without an attempt require normal reprocessing. Approve,
56
+ reject, defer and correct call `submitDecision`; corrected args create a new
57
+ revision which requires a separate human approval. After an approve/defer/reject
58
+ decision, optional `editAction` calls `previewProposal` with the current action
59
+ revision to publish a new review; completed/executing/unknown actions cannot be
60
+ revised. Local dirty args disable Apply but confer no authority. Plan edits re-expand through
61
+ `previewPlan` with the current **plan** revision. `applyAction` accepts only an
62
+ action ID. Unknown external outcomes require server reconciliation; the UI
63
+ never offers a blind resend. Stable result IDs survive reload and retry.
64
+
65
+ Replace `contextKey` whenever authenticated tenant/session context changes.
66
+ Changing it or itemId destroys the old view and fences late callback results.
67
+ Denied refresh clears prior originals, candidates, arguments and results.
68
+ Missing confidence is unavailable; page/time links exist only for observed
69
+ locations. Provider errors and unresolved/partial results remain review states.
70
+
71
+ ## Assignment and logical splits
72
+
73
+ Assignment is explicitly host-owned, durable and versioned. `assign` receives
74
+ an expected assignment version and request ID; the host must authorize the
75
+ manager, constrain eligible assignees, CAS the durable record and reject stale
76
+ writes. Assignment does not grant read, review or execution rights. The maintained
77
+ fixture provisions its own SQLite assignment table before serving requests; no
78
+ production ingestion table or migration is introduced for assignment.
79
+
80
+ `reviseLogicalSplit` authorizes the current generation through the same-executor
81
+ catalog/candidate gate and the existing reviewer grant and policy reviewer list.
82
+ Process access alone cannot mint or replay a human correction; reviewer authority
83
+ is checked before mutation and again before publication. A generation without a
84
+ reviewable catalogue cannot be corrected through this reviewer API.
85
+ It requires all observed pages exactly once, an exact
86
+ current attempt/revision and a request ID. It records the authenticated actor
87
+ and predecessor as a **human correction** in a new immutable extraction
88
+ configuration, queues re-extraction and immediately makes previous suggestions
89
+ and approvals stale. It never changes original bytes/evidence or labels a human
90
+ edit as model output. The host processes the new extraction, then calls
91
+ `prepareGeneration` and the normal fenced interpretation stage. The supported
92
+ immediate-predecessor extraction pin is unchanged. The generator receives a
93
+ human correction only after its digest matches the authoritative source. Ordinary
94
+ `analyze` calls cannot mint an extraction correction; the owning split API is the
95
+ authenticated origin, and forged interpretation corrections fail before provider
96
+ disclosure. If its proposed grouping differs from the correction, suggestions are withheld
97
+ with `human_split_not_respected`. New proposals require new explicit review.
98
+ The reference host runs these stages synchronously for browser determinism;
99
+ production hosts dispatch the existing durable analysis jobs.
100
+
101
+ `feedback` is an optional explicit correctness callback, separate from approval
102
+ choice and execution success. No learning, feedback storage or rule promotion is
103
+ implemented by these components; #3676 owns those services. Do not pass feedback
104
+ or a feedback callback to readers without the relevant host grant.
105
+
106
+ ## Maintained browser proof
107
+
108
+ `pnpm test:components` runs real Svelte component tests; `pnpm test:e2e` runs the
109
+ package-local authenticated Vite application under Chromium. The fixture uses
110
+ HttpOnly same-site sessions, CSRF, real SQLite/assets/ingestion/content APIs,
111
+ production unpdf child extraction and a deterministic proposal generator. Its
112
+ hardcoded test login is fixture-only and is never a production auth provider.
113
+ Image/audio originals remain inspectable when no OCR/speech provider is
114
+ configured; the suite makes no recognition-quality claim and spends no provider
115
+ budget. `reference/review-host.ts` is a maintained development fixture, not a
116
+ published server entry. Browser tests show actual approved args and persisted
117
+ ContentDocument results, stale tabs, reload, retries and negative access.
118
+
119
+ Run full package `test`, `test:postgres`, `test:providers`, `build`, `typecheck`,
120
+ `test:components`, `test:e2e`; use the root Node/pnpm versions. Set a short
121
+ `CI_TEST_TMPDIR`/`TMPDIR`, and optionally
122
+ `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` to the supported installed Chromium.
123
+ `pnpm test:evaluation` checks repository evaluation tooling contracts; measured
124
+ held-out quality remains a separate frozen-protocol, budget-gated #3677 run.
125
+
126
+ The existing CI browser job includes ingestion changes and shared UI primitive
127
+ changes in affected mode, and runs the ingestion browser suite in full mode. Its
128
+ normal dependency build precedes the suite and failed runs upload browser evidence.
129
+
130
+ The maintained host derives inbox state by traversing bounded public review pages,
131
+ authorizing every action/parent/target before classification. It retains only
132
+ scalar totals and the requested page; an off-page denial denies the whole view.
133
+ The component's Load more and subsequent refresh/mutation reload every displayed
134
+ page using fresh cursors, then publish the combined authorized set together. Old
135
+ page payloads are cleared while loading; any unavailable page clears all payloads.
136
+ This keeps plan controls and earlier steps visible across page boundaries without
137
+ reusing a prior authorization decision.