@anthusai/papyrus 2.0.0-next.8 → 2.0.0-next.81

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 (213) hide show
  1. package/amplify/auth/resource.js +16 -1
  2. package/amplify/auth/resource.ts +19 -1
  3. package/amplify/data/function-handler.js +20 -0
  4. package/amplify/data/function-handler.ts +40 -0
  5. package/amplify/data/resource.js +151 -61
  6. package/amplify/data/resource.ts +157 -61
  7. package/amplify/data/schema.js +2096 -1980
  8. package/amplify/data/schema.ts +198 -69
  9. package/amplify/functions/assignment-action/data-access.js +14 -15
  10. package/amplify/functions/assignment-action/data-access.ts +13 -14
  11. package/amplify/functions/assignment-action/handler.ts +1 -1
  12. package/amplify/functions/automation-view/handler.py +17 -0
  13. package/amplify/functions/automation-view/resource.js +24 -0
  14. package/amplify/functions/automation-view/resource.ts +34 -0
  15. package/amplify/functions/automation-view/schema.js +26 -0
  16. package/amplify/functions/automation-view/schema.ts +28 -0
  17. package/amplify/functions/automation-view/wire.js +56 -0
  18. package/amplify/functions/automation-view/wire.ts +76 -0
  19. package/amplify/functions/content-actions/handler.py +61 -2
  20. package/amplify/functions/content-actions/requirements.txt +1 -0
  21. package/amplify/functions/content-actions/resource.js +1 -1
  22. package/amplify/functions/content-actions/resource.ts +1 -1
  23. package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/handler.py +3 -3
  24. package/amplify/functions/editorial-checks/requirements.txt +1 -0
  25. package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/resource.js +7 -7
  26. package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/resource.ts +7 -7
  27. package/amplify/functions/editorial-checks/schema.js +122 -0
  28. package/amplify/{plugins → functions}/editorial-checks/schema.ts +40 -12
  29. package/amplify/functions/editorial-checks/wire.js +53 -0
  30. package/amplify/functions/editorial-checks/wire.ts +61 -0
  31. package/amplify/functions/monitoring-view/handler.py +11 -0
  32. package/amplify/functions/monitoring-view/resource.js +24 -0
  33. package/amplify/functions/monitoring-view/resource.ts +34 -0
  34. package/amplify/functions/monitoring-view/schema.js +17 -0
  35. package/amplify/functions/monitoring-view/schema.ts +19 -0
  36. package/amplify/functions/monitoring-view/wire.js +37 -0
  37. package/amplify/functions/monitoring-view/wire.ts +47 -0
  38. package/amplify/functions/public-forms/core.js +247 -0
  39. package/amplify/functions/public-forms/core.ts +310 -0
  40. package/amplify/functions/public-forms/handler.ts +41 -0
  41. package/amplify/functions/public-forms/origins.js +35 -0
  42. package/amplify/functions/public-forms/origins.ts +43 -0
  43. package/amplify/functions/public-forms/resource.js +9 -0
  44. package/amplify/functions/public-forms/resource.ts +10 -0
  45. package/amplify/functions/public-forms/wire.js +25 -0
  46. package/amplify/functions/public-forms/wire.ts +32 -0
  47. package/amplify/functions/shared/editorial-context.ts +63 -4
  48. package/amplify/functions/shared/python-bundle.js +20 -14
  49. package/amplify/functions/shared/python-bundle.ts +25 -18
  50. package/amplify/plugins/newsletter/config.js +245 -0
  51. package/amplify/plugins/newsletter/config.ts +305 -0
  52. package/amplify/plugins/newsletter/function/handler.py +6 -0
  53. package/amplify/plugins/newsletter/function/requirements.txt +5 -0
  54. package/amplify/plugins/newsletter/ops/handler.py +12 -0
  55. package/amplify/plugins/newsletter/ops/resource.js +27 -0
  56. package/amplify/plugins/newsletter/ops/resource.ts +37 -0
  57. package/amplify/plugins/newsletter/papyrus.plugin.js +263 -0
  58. package/amplify/plugins/newsletter/papyrus.plugin.ts +311 -0
  59. package/amplify/plugins/newsletter/schema.js +57 -0
  60. package/amplify/plugins/newsletter/schema.ts +62 -0
  61. package/amplify/plugins/newsletter/secure-string-parameter.js +107 -0
  62. package/amplify/plugins/newsletter/secure-string-parameter.ts +120 -0
  63. package/amplify/plugins/newsletter/sending.js +140 -0
  64. package/amplify/plugins/newsletter/sending.ts +186 -0
  65. package/amplify/plugins/reader-steering/config.js +182 -0
  66. package/amplify/plugins/reader-steering/config.ts +290 -0
  67. package/amplify/plugins/reader-steering/function/ai_moderation.py +246 -0
  68. package/amplify/plugins/reader-steering/function/handler.py +1554 -0
  69. package/amplify/plugins/reader-steering/function/moderation-prompt.md +27 -0
  70. package/amplify/plugins/reader-steering/function/moderation.py +316 -0
  71. package/amplify/plugins/reader-steering/function/proposals.py +255 -0
  72. package/amplify/plugins/reader-steering/function/resource.js +27 -0
  73. package/amplify/plugins/reader-steering/function/resource.ts +35 -0
  74. package/amplify/plugins/reader-steering/papyrus.plugin.js +186 -0
  75. package/amplify/plugins/reader-steering/papyrus.plugin.ts +212 -0
  76. package/amplify/plugins/reader-steering/schema.js +205 -0
  77. package/amplify/plugins/reader-steering/schema.ts +207 -0
  78. package/amplify/plugins/registry.js +4 -2
  79. package/amplify/plugins/registry.ts +4 -2
  80. package/amplify/plugins/signup/schema.js +2 -1
  81. package/amplify/plugins/signup/schema.ts +2 -1
  82. package/amplify/plugins/types.ts +5 -0
  83. package/amplify/plugins/wire.js +1 -0
  84. package/amplify/plugins/wire.ts +1 -0
  85. package/amplify/publication/projection-lease.js +30 -0
  86. package/amplify/publication/projection-lease.ts +39 -0
  87. package/amplify/publication/redirect-and-index.js +105 -0
  88. package/amplify/publication/redirect-rules.js +73 -0
  89. package/amplify/publication/redirect-rules.ts +93 -0
  90. package/amplify/publication/s3-projection.js +7 -1
  91. package/amplify/publication/s3-projection.ts +9 -1
  92. package/amplify/site-backend-config.ts +18 -1
  93. package/amplify/site-backend-names.js +4 -2
  94. package/amplify/site-backend-names.ts +4 -2
  95. package/amplify/site-backend.js +45 -3
  96. package/amplify/site-backend.ts +51 -3
  97. package/app/api/auth/prospectus/sign-in/route.ts +4 -0
  98. package/app/api/newsletter/confirm/route.ts +13 -0
  99. package/app/api/newsletter/preferences/route.ts +13 -0
  100. package/app/api/newsletter/state/route.ts +9 -0
  101. package/app/api/newsletter/subscribe/route.ts +9 -0
  102. package/app/api/newsletter/unsubscribe/route.ts +13 -0
  103. package/app/api/newsroom/curation/context/route.ts +9 -0
  104. package/app/api/newsroom/curation/priming/route.ts +9 -0
  105. package/app/api/newsroom/curation/publication/route.ts +9 -0
  106. package/app/api/reader/comment/delete/route.ts +9 -0
  107. package/app/api/reader/comment/edit/route.ts +9 -0
  108. package/app/api/reader/comment/route.ts +9 -0
  109. package/app/api/reader/flag/route.ts +9 -0
  110. package/app/api/reader/handle/route.ts +9 -0
  111. package/app/api/reader/me/route.ts +9 -0
  112. package/app/api/reader/rating/route.ts +9 -0
  113. package/app/api/reader/report/route.ts +9 -0
  114. package/app/api/reader/retired/route.ts +9 -0
  115. package/app/api/reader/submit/route.ts +9 -0
  116. package/app/api/reader/vote/route.ts +9 -0
  117. package/bin/papyrus-infra.mjs +20 -1
  118. package/components/automation-panel.tsx +49 -0
  119. package/components/automation-run-now.tsx +97 -0
  120. package/components/automation-view.tsx +192 -0
  121. package/components/editorial-checks-admin-panel.tsx +36 -11
  122. package/components/moderation-panel.tsx +248 -0
  123. package/components/monitoring-overview-view.tsx +241 -0
  124. package/components/monitoring-panel.tsx +40 -0
  125. package/components/news-desk-client-provider.tsx +18 -18
  126. package/components/news-desk-taxonomy-client.ts +28 -8
  127. package/components/newsletter-panel.tsx +474 -0
  128. package/components/newsletter-sections.tsx +163 -0
  129. package/components/newsroom-access-gate.tsx +15 -1
  130. package/components/newsroom-article-editor.tsx +6 -6
  131. package/components/newsroom-articles-view.tsx +6 -6
  132. package/components/newsroom-board-view.tsx +8 -3
  133. package/components/newsroom-curation-bootstrap.tsx +45 -0
  134. package/components/newsroom-ops-overview.tsx +22 -92
  135. package/components/newsroom-ops-shell.tsx +2 -2
  136. package/components/newsroom-organizer.css +33 -0
  137. package/components/newsroom-overview-skeleton.tsx +25 -0
  138. package/components/newsroom-references-view.tsx +192 -49
  139. package/components/notification-center.tsx +273 -0
  140. package/components/publication-cyclotron-panel.tsx +15 -10
  141. package/components/reader-auth-state.ts +1 -1
  142. package/components/reference-add-entry.tsx +75 -0
  143. package/components/reference-curation-controls.tsx +31 -22
  144. package/components/reference-cyclotron-priming.tsx +58 -19
  145. package/components/reference-cyclotron-suggestion.tsx +10 -6
  146. package/components/reference-priming.tsx +14 -10
  147. package/components/reference-relevance-review.tsx +3 -3
  148. package/components/reference-section-suggestion.tsx +1 -1
  149. package/components/topic-steering-workspace.tsx +223 -144
  150. package/components/use-editorial-checks.ts +12 -10
  151. package/infra/amplify-app-shell.js +94 -16
  152. package/infra/amplify-app-shell.ts +106 -18
  153. package/infra/cloud-email-config.js +32 -0
  154. package/infra/cloud-email-config.ts +39 -0
  155. package/infra/cloud-email.js +57 -0
  156. package/infra/cloud-email.test.js +69 -0
  157. package/infra/cloud-email.test.ts +66 -0
  158. package/infra/cloud-email.ts +60 -0
  159. package/infra/index.js +1 -0
  160. package/infra/secure-string-parameter-handler.js +41 -0
  161. package/infra/secure-string-parameter-handler.ts +41 -0
  162. package/infra/secure-string-parameter.js +79 -0
  163. package/infra/secure-string-parameter.ts +91 -0
  164. package/infra/site-config.js +88 -6
  165. package/infra/site-config.ts +134 -6
  166. package/lib/automation-client.ts +54 -0
  167. package/lib/automation-fixture.ts +93 -0
  168. package/lib/automation-overview.ts +232 -0
  169. package/lib/category-repository.ts +11 -9
  170. package/lib/curation-routes.ts +345 -0
  171. package/lib/cyclotron-suggestions.ts +4 -4
  172. package/lib/editorial-checks-backend.ts +1 -1
  173. package/lib/editorial-checks-client.ts +19 -1
  174. package/lib/editorial-checks-demo.ts +2 -2
  175. package/lib/editorial-checks-settings.ts +3 -0
  176. package/lib/editorial-checks.ts +8 -11
  177. package/lib/editorial-preview.ts +5 -5
  178. package/lib/monitoring-client.ts +29 -0
  179. package/lib/monitoring-overview-fixture.ts +51 -0
  180. package/lib/monitoring-overview.ts +145 -0
  181. package/lib/news-desk-session.ts +12 -21
  182. package/lib/newsletter-api.ts +418 -0
  183. package/lib/newsletter-client.ts +46 -0
  184. package/lib/newsletter-fixture.ts +184 -0
  185. package/lib/newsletter-model.ts +202 -0
  186. package/lib/newsroom-organizer-nav.ts +2 -1
  187. package/lib/prospectus-session.ts +15 -14
  188. package/lib/prospectus-sign-in-routes.ts +84 -19
  189. package/lib/prospectus-site-identity.ts +24 -1
  190. package/lib/reader-api.ts +145 -0
  191. package/lib/reader-moderation.ts +220 -0
  192. package/lib/reader-retirement-route.ts +89 -0
  193. package/lib/reader-subject.md +29 -0
  194. package/lib/reader-subject.ts +53 -0
  195. package/lib/reference-review-details.ts +71 -0
  196. package/lib/reference-review-request.ts +14 -0
  197. package/lib/relevance-decisions.ts +42 -10
  198. package/lib/relevance-status.ts +2 -2
  199. package/lib/review-client.ts +99 -0
  200. package/lib/review-fixture.ts +45 -0
  201. package/lib/review-requests.ts +238 -0
  202. package/lib/semantic-graph.ts +2 -0
  203. package/lib/site-brand-tenant.ts +11 -6
  204. package/lib/site-brand.ts +6 -3
  205. package/lib/site-origin.ts +67 -0
  206. package/lib/use-reference-review-data.ts +44 -0
  207. package/middleware.ts +14 -3
  208. package/package.json +56 -3
  209. package/routes.manifest.json +215 -2
  210. package/amplify/plugins/editorial-checks/function/requirements.txt +0 -1
  211. package/amplify/plugins/editorial-checks/papyrus.plugin.js +0 -71
  212. package/amplify/plugins/editorial-checks/papyrus.plugin.ts +0 -87
  213. package/amplify/plugins/editorial-checks/schema.js +0 -94
@@ -1,12 +1,12 @@
1
1
  "use client";
2
2
 
3
- import { useState } from "react";
3
+ import { useId, useRef, useState, type KeyboardEvent } from "react";
4
4
  import { primingStateText, type PrimingRequestView } from "../lib/relevance-status";
5
5
 
6
6
  export type PrimingFormInput = { url: string; label: string; explanation: string };
7
7
 
8
8
  /**
9
- * A compact "Add a reference" form for a pasted URL. The page is read in the
9
+ * The "Paste a URL" option of the Add a reference area. The page is read in the
10
10
  * background and the outcome is shown beside each added reference.
11
11
  */
12
12
  export function ReferenceCyclotronPriming({
@@ -23,6 +23,19 @@ export function ReferenceCyclotronPriming({
23
23
  const [explanation, setExplanation] = useState("");
24
24
  const [message, setMessage] = useState<string | null>(null);
25
25
 
26
+ const ratingLabelId = useId();
27
+ const buttons = useRef<Array<HTMLButtonElement | null>>([]);
28
+
29
+ function moveSelection(event: KeyboardEvent<HTMLButtonElement>, index: number) {
30
+ const forward = event.key === "ArrowRight" || event.key === "ArrowDown";
31
+ const backward = event.key === "ArrowLeft" || event.key === "ArrowUp";
32
+ if (!forward && !backward) return;
33
+ event.preventDefault();
34
+ const next = (index + (forward ? 1 : -1) + labels.length) % labels.length;
35
+ setLabel(labels[next]);
36
+ buttons.current[next]?.focus();
37
+ }
38
+
26
39
  async function submit() {
27
40
  setMessage("Adding…");
28
41
  try {
@@ -36,16 +49,16 @@ export function ReferenceCyclotronPriming({
36
49
  }
37
50
 
38
51
  return (
39
- <section aria-label="Add a reference" className="space-y-2 text-sm" data-reference-cyclotron-priming>
52
+ <div className="space-y-2 text-sm" data-reference-cyclotron-priming>
40
53
  <form
41
- className="flex flex-wrap items-end gap-3"
54
+ className="flex flex-col gap-3"
42
55
  onSubmit={(event) => {
43
56
  event.preventDefault();
44
57
  void submit();
45
58
  }}
46
59
  >
47
- <label className="flex min-w-64 flex-1 flex-col gap-1">
48
- <span className="text-xs text-muted-foreground">Add a reference by URL</span>
60
+ <label className="flex flex-col gap-1">
61
+ <span className="text-xs text-muted-foreground">Web page address</span>
49
62
  <input
50
63
  aria-label="Reference URL"
51
64
  onChange={(event) => setUrl(event.target.value)}
@@ -55,20 +68,46 @@ export function ReferenceCyclotronPriming({
55
68
  value={url}
56
69
  />
57
70
  </label>
71
+ <div className="flex flex-col gap-1">
72
+ <span className="text-xs text-muted-foreground" id={ratingLabelId}>Should Papyrus include or exclude pages like this?</span>
73
+ <div aria-labelledby={ratingLabelId} className="flex flex-wrap gap-2" role="radiogroup">
74
+ {labels.map((choice, index) => {
75
+ const checked = choice === label;
76
+ return (
77
+ <button
78
+ aria-checked={checked}
79
+ className={`min-w-32 flex-1 rounded border px-4 py-3 text-base font-semibold capitalize ${checked ? "border-foreground bg-foreground text-background" : "border-border bg-transparent"}`}
80
+ data-rating-choice={choice}
81
+ key={choice}
82
+ onClick={() => setLabel(choice)}
83
+ onKeyDown={(event) => moveSelection(event, index)}
84
+ ref={(node) => { buttons.current[index] = node; }}
85
+ role="radio"
86
+ tabIndex={checked || (!labels.includes(label) && index === 0) ? 0 : -1}
87
+ type="button"
88
+ >
89
+ {choice}
90
+ </button>
91
+ );
92
+ })}
93
+ </div>
94
+ </div>
58
95
  <label className="flex flex-col gap-1">
59
- <span className="text-xs text-muted-foreground">Include or exclude</span>
60
- <select aria-label="Include or exclude" onChange={(event) => setLabel(event.target.value)} value={label}>
61
- {labels.map((choice) => (
62
- <option key={choice} value={choice}>{choice}</option>
63
- ))}
64
- </select>
65
- </label>
66
- <label className="flex min-w-48 flex-1 flex-col gap-1">
67
- <span className="text-xs text-muted-foreground">Why (optional)</span>
68
- <input aria-label="Reason" onChange={(event) => setExplanation(event.target.value)} type="text" value={explanation} />
96
+ <span className="text-sm font-medium">Why?</span>
97
+ <textarea
98
+ aria-label="Reason"
99
+ className="w-full"
100
+ onChange={(event) => setExplanation(event.target.value)}
101
+ placeholder="Why? A sentence or two helps Papyrus learn what you want."
102
+ rows={4}
103
+ value={explanation}
104
+ />
105
+ <span className="text-xs text-muted-foreground">Optional, but a short reason helps Papyrus learn what you want.</span>
69
106
  </label>
70
- <button className="cyclotron-review-secondary" type="submit">Add reference</button>
71
- {message ? <p className="basis-full text-xs" role="status">{message}</p> : null}
107
+ <div>
108
+ <button className="cyclotron-review-secondary" type="submit">Add reference</button>
109
+ </div>
110
+ {message ? <p className="text-xs" role="status">{message}</p> : null}
72
111
  </form>
73
112
  {requests.length ? (
74
113
  <ul aria-label="Added references" className="space-y-1 text-xs text-muted-foreground">
@@ -79,6 +118,6 @@ export function ReferenceCyclotronPriming({
79
118
  ))}
80
119
  </ul>
81
120
  ) : null}
82
- </section>
121
+ </div>
83
122
  );
84
123
  }
@@ -57,11 +57,12 @@ export function ReferenceSuggestionBlock({
57
57
  const choose = (choice: SuggestionChoice) => onCurate?.(curationForSuggestionChoice(decision, choice));
58
58
  const suggestsAccept = decision.positiveLabel !== null && decision.label === decision.positiveLabel;
59
59
  return (
60
- <section aria-label="Suggestion" className="space-y-2 border-y border-foreground py-3" data-reference-suggestion={referenceLineageId}>
61
- <h3 className="text-xs font-semibold uppercase tracking-wide text-foreground">Suggestion</h3>
60
+ <section aria-label="Publication prediction" className="space-y-2 border-y border-foreground py-3" data-reference-suggestion={referenceLineageId}>
61
+ <h3 className="text-xs font-semibold uppercase tracking-wide text-foreground">Publication prediction</h3>
62
62
  <p className="text-sm text-foreground">
63
- The cyclotron suggests <span className="font-semibold">{decision.label}</span> ({suggestionConfidenceWords(decision)}).
63
+ Papyrus suggests <span className="font-semibold">{decision.label}</span> ({suggestionConfidenceWords(decision)}).
64
64
  </p>
65
+ {decision.reviewDetail ? <p className="text-xs text-foreground">Why review was requested: {decision.reviewDetail}</p> : null}
65
66
  <p className="text-xs text-foreground" data-reference-suggestion-notice>
66
67
  A suggestion never changes the status until an editor acts. This reference is {statusLabel.toLowerCase()}.
67
68
  </p>
@@ -99,14 +100,17 @@ export function ReferenceSuggestionProvenance({ decision }: { decision: Relevanc
99
100
  <summary className="cursor-pointer font-semibold underline-offset-4 hover:underline">How this suggestion was made</summary>
100
101
  {summary ? (
101
102
  <ul className="mt-2 space-y-1">
102
- <li>{summary.teachingLabelsSentence}.</li>
103
- <li>{summary.primingExamplesSentence}.</li>
103
+ {summary.teachingLabelsSentence ? <li>{summary.teachingLabelsSentence}.</li> : null}
104
+ {summary.primingExamplesSentence ? <li>{summary.primingExamplesSentence}.</li> : null}
105
+ {decision.provenance?.system ? <li>Source: {decision.provenance.system === "cyclotron-lab" ? "Shared publication classifier" : decision.provenance.system}.</li> : null}
106
+ {decision.provenance?.output ? <li>Publication output: {decision.provenance.output}.</li> : null}
107
+ {decision.classifierId ? <li>Classifier: {decision.classifierId}.</li> : null}
104
108
  <li>Guidelines code {summary.doctrineShortHash ?? "not recorded"}.</li>
105
109
  <li>Suggestion {summary.modelVersion ?? "revision not recorded"}.</li>
106
110
  <li>Decided {formatSuggestionTime(summary.decidedAt)}.</li>
107
111
  </ul>
108
112
  ) : (
109
- <p className="mt-2">This suggestion was made before the details were recorded. Only its revision and confidence are known.</p>
113
+ <p className="mt-2">Additional provenance was not recorded for this prediction.</p>
110
114
  )}
111
115
  </details>
112
116
  );
@@ -1,18 +1,22 @@
1
1
  "use client";
2
2
 
3
- import { useState } from "react";
4
3
  import { PrimingPanel, type PrimingPanelProps } from "cyclotron/components/priming-panel";
5
- import { Button } from "./ui/button";
6
4
 
7
- /** Papyrus supplies its transport/configuration; Cyclotron owns preview and labels. */
5
+ /**
6
+ * The "Import a file" option of the Add a reference area. Papyrus supplies the
7
+ * transport and configuration; Cyclotron owns the preview and label controls.
8
+ * It is only rendered by `ReferenceAddEntry`, never as a section of its own.
9
+ */
8
10
  export function ReferencePriming(props: PrimingPanelProps) {
9
- const [open, setOpen] = useState(false);
10
11
  return (
11
- <section className="shrink-0 space-y-3" aria-label="Representative reference examples">
12
- <Button aria-expanded={open} onClick={() => setOpen((value) => !value)} variant="outline">
13
- {open ? "Hide example references" : "Add example references (optional)"}
14
- </Button>
15
- {open ? <div className="max-h-[55dvh] space-y-3 overflow-y-auto pr-1"><p className="text-sm text-muted-foreground">Corrections to extracted content: describe what needs fixing, then enter the corrected title and abstract or summary. The note is saved with your correction; it does not automatically regenerate the content. Choose Publish / Not publish separately. An explanation of that judgment is optional.</p><PrimingPanel {...props} renderItem={props.renderItem ?? ((item) => <div className="space-y-2"><p className="whitespace-pre-wrap text-sm">{String(item.values.abstract ?? item.values.text ?? "")}</p><p className="break-all text-xs text-muted-foreground">{String(item.values.source_uri ?? "")}</p></div>)} /></div> : null}
16
- </section>
12
+ <PrimingPanel
13
+ {...props}
14
+ renderItem={props.renderItem ?? ((item) => (
15
+ <div className="space-y-2">
16
+ <p className="whitespace-pre-wrap text-sm">{String(item.values.abstract ?? item.values.text ?? "")}</p>
17
+ <p className="break-all text-xs text-muted-foreground">{String(item.values.source_uri ?? "")}</p>
18
+ </div>
19
+ ))}
20
+ />
17
21
  );
18
22
  }
@@ -28,7 +28,7 @@ export function ReferenceRelevanceReview({
28
28
  }: {
29
29
  disabled?: boolean;
30
30
  decision: RelevanceDecisionView;
31
- onCurate: (curation: RelevanceCuration) => void;
31
+ onCurate: (curation: RelevanceCuration) => Promise<void> | void;
32
32
  referenceLineageId: string;
33
33
  }) {
34
34
  const [shareable, setShareable] = useState(false);
@@ -47,10 +47,10 @@ export function ReferenceRelevanceReview({
47
47
  disabled={disabled}
48
48
  itemId={referenceLineageId}
49
49
  mode={decision.reviewControl === "thumbs" && classes.length === 2 ? "thumbs" : "labels"}
50
- onReview={(review) => {
50
+ onReview={async (review) => {
51
51
  try {
52
52
  setError(null);
53
- onCurate(curationForRelevanceReview(decision, { ...review, shareable }));
53
+ await onCurate(curationForRelevanceReview(decision, { ...review, shareable }));
54
54
  } catch (failure) {
55
55
  setError(failure instanceof Error ? failure.message : String(failure));
56
56
  }
@@ -40,7 +40,7 @@ export function SectionSuggestionBlock({
40
40
  <section aria-label="Suggested Section" className="space-y-2 border-y border-foreground py-3" data-reference-section-suggestion={referenceLineageId}>
41
41
  <h3 className="text-xs font-semibold uppercase tracking-wide text-foreground">Suggested Section</h3>
42
42
  <p className="text-sm text-foreground">
43
- The cyclotron suggests <span className="font-semibold">{titleOf(sections, suggestion.sectionId)}</span>
43
+ Papyrus suggests <span className="font-semibold">{titleOf(sections, suggestion.sectionId)}</span>
44
44
  {suggestion.confidence !== null ? ` (${formatPercentage(suggestion.confidence)})` : ""}.
45
45
  </p>
46
46
  {others.length ? (