@anthusai/papyrus 1.4.0-next.4 → 1.4.0-next.6

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 (69) hide show
  1. package/amplify/data/resource.js +13 -3
  2. package/amplify/data/resource.ts +13 -3
  3. package/amplify/data/schema.js +10 -0
  4. package/amplify/data/schema.ts +10 -0
  5. package/amplify/functions/category-action/handler.ts +20 -19
  6. package/amplify/functions/console-chat-responder/src/main.rs +1 -1
  7. package/amplify/functions/content-actions/handler.py +23 -0
  8. package/amplify/functions/content-actions/requirements.txt +1 -1
  9. package/amplify/functions/content-actions/resource.js +1 -1
  10. package/amplify/functions/content-actions/resource.ts +1 -1
  11. package/amplify/functions/renditions/requirements.txt +1 -1
  12. package/amplify/functions/shared/reference-curation-metadata.ts +15 -0
  13. package/amplify/functions/shared/slack-events.ts +2 -2
  14. package/amplify/publication/renditions-function.js +1 -1
  15. package/amplify/publication/renditions-function.ts +1 -1
  16. package/app/api/local-preview/derive/route.ts +28 -0
  17. package/app/api/local-preview/media/route.ts +25 -0
  18. package/app/globals.css +28 -28
  19. package/app/layout.tsx +8 -5
  20. package/app/newsroom/[section]/[...selection]/page.tsx +0 -1
  21. package/app/newsroom/[section]/page.tsx +0 -1
  22. package/app/newsroom/insights/[threadId]/page.tsx +5 -16
  23. package/app/newsroom/insights/page.tsx +4 -12
  24. package/components/board-card-excerpts.tsx +45 -0
  25. package/components/markus-ir-preview.tsx +47 -2
  26. package/components/news-desk-page.tsx +0 -1
  27. package/components/news-desk-taxonomy-client.ts +25 -220
  28. package/components/newsroom-article-editor.tsx +135 -39
  29. package/components/newsroom-assignment-detail.tsx +35 -1
  30. package/components/newsroom-board-view.tsx +29 -7
  31. package/components/newsroom-newsprint-board.css +10 -2
  32. package/components/newsroom-ops-overview.tsx +27 -5
  33. package/components/newsroom-organizer-shell.tsx +25 -7
  34. package/components/newsroom-organizer.css +196 -4
  35. package/components/priming-proof-page.tsx +17 -8
  36. package/components/prospectus-account-chooser.tsx +98 -0
  37. package/components/story-reporting-trail-client.ts +91 -0
  38. package/components/story-reporting-trail.tsx +115 -0
  39. package/components/topic-steering-workspace.tsx +154 -671
  40. package/components/ui/sheet.tsx +1 -0
  41. package/components/wiki-concepts-view.tsx +153 -0
  42. package/components/wiki-index-client.ts +51 -0
  43. package/lib/content-actions-client.ts +3 -0
  44. package/lib/content-actions-demo.ts +55 -3
  45. package/lib/content-item-lifecycle.ts +4 -2
  46. package/lib/content-source-context.ts +9 -1
  47. package/lib/front-matter-fields.ts +42 -0
  48. package/lib/graphql-content-repository.ts +42 -7
  49. package/lib/local-preview-seed.ts +55 -2
  50. package/lib/local-preview-tenant.ts +27 -0
  51. package/lib/newsroom-articles.ts +2 -0
  52. package/lib/newsroom-board.ts +4 -0
  53. package/lib/newsroom-forum-routes.ts +2 -43
  54. package/lib/newsroom-index-filters.ts +3 -40
  55. package/lib/newsroom-media-backend.ts +5 -0
  56. package/lib/newsroom-nav.ts +1 -3
  57. package/lib/newsroom-organizer-nav.ts +5 -12
  58. package/lib/newsroom-section-routing.ts +1 -1
  59. package/lib/newsroom-sections.ts +12 -0
  60. package/lib/papyrus-web-locations.ts +3 -24
  61. package/lib/priming-proof-report.ts +1 -0
  62. package/lib/prospectus-tenant.ts +22 -0
  63. package/lib/semantic-graph.ts +5 -5
  64. package/lib/site-brand.ts +9 -0
  65. package/lib/story-reporting-trail.ts +106 -0
  66. package/lib/tenant-keys.ts +32 -0
  67. package/lib/wiki.ts +56 -0
  68. package/package.json +15 -1
  69. package/routes.manifest.json +23 -7
@@ -227,7 +227,7 @@ const schema = a.schema({
227
227
  status: a.string().required(),
228
228
  relationId: a.id(),
229
229
  }),
230
- ReferenceInsightActionResult: a.customType({
230
+ ReferenceNoteActionResult: a.customType({
231
231
  ok: a.boolean().required(),
232
232
  referenceId: a.id().required(),
233
233
  messageId: a.id().required(),
@@ -309,7 +309,7 @@ const schema = a.schema({
309
309
  allow.groups(categoryWriteGroups),
310
310
  ])
311
311
  .handler(a.handler.function(categoryAction)),
312
- createReferenceInsight: a
312
+ createReferenceNote: a
313
313
  .mutation()
314
314
  .arguments({
315
315
  referenceId: a.id().required(),
@@ -318,7 +318,7 @@ const schema = a.schema({
318
318
  actorSub: a.string(),
319
319
  actorLabel: a.string(),
320
320
  })
321
- .returns(a.ref("ReferenceInsightActionResult"))
321
+ .returns(a.ref("ReferenceNoteActionResult"))
322
322
  .authorization((allow) => [
323
323
  allow.groups(categoryWriteGroups),
324
324
  ])
@@ -1018,6 +1018,7 @@ const schema = a.schema({
1018
1018
  NewsroomSection: a
1019
1019
  .model({
1020
1020
  id: a.id().required(),
1021
+ tenantId: a.string(),
1021
1022
  title: a.string().required(),
1022
1023
  type: a.string().required(),
1023
1024
  editorialMission: a.string().required(),
@@ -1036,6 +1037,7 @@ const schema = a.schema({
1036
1037
  })
1037
1038
  .secondaryIndexes((index) => [
1038
1039
  index("sortOrder").sortKeys(["id"]).queryField("listNewsroomSectionsBySortOrder"),
1040
+ index("tenantId").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByTenantAndSortOrder"),
1039
1041
  index("type").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByTypeAndSortOrder"),
1040
1042
  index("enabledStatus").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByEnabledStatusAndSortOrder"),
1041
1043
  ])
@@ -1624,6 +1626,7 @@ const schema = a.schema({
1624
1626
  .model({
1625
1627
  id: a.id().required(),
1626
1628
  lineageId: a.id().required(),
1629
+ tenantId: a.string(),
1627
1630
  versionNumber: a.integer().required(),
1628
1631
  previousVersionId: a.id(),
1629
1632
  versionState: a.string().required(),
@@ -1636,6 +1639,7 @@ const schema = a.schema({
1636
1639
  typeStatus: a.string().required(),
1637
1640
  stage: a.string(),
1638
1641
  slug: a.string().required(),
1642
+ tenantSlug: a.string(),
1639
1643
  shortSlug: a.string(),
1640
1644
  section: a.string(),
1641
1645
  sectionStatus: a.string(),
@@ -1663,6 +1667,7 @@ const schema = a.schema({
1663
1667
  .secondaryIndexes((index) => [
1664
1668
  index("lineageId").sortKeys(["versionNumber"]).queryField("listItemsByLineageAndVersion"),
1665
1669
  index("slug").queryField("itemBySlug"),
1670
+ index("tenantSlug").queryField("itemByTenantSlug"),
1666
1671
  index("typeStatus").sortKeys(["publishedAt"]).queryField("listItemsByTypeStatusAndPublishedAt"),
1667
1672
  index("sectionStatus").sortKeys(["publishedAt"]).queryField("listItemsBySectionStatusAndPublishedAt"),
1668
1673
  index("versionState").sortKeys(["updatedAt"]).queryField("listItemsByVersionStateAndUpdatedAt"),
@@ -1710,6 +1715,7 @@ const schema = a.schema({
1710
1715
  .model({
1711
1716
  id: a.id().required(),
1712
1717
  itemId: a.id().required(),
1718
+ tenantId: a.string(),
1713
1719
  type: a.string().required(),
1714
1720
  role: a.string().required(),
1715
1721
  sortKey: a.string().required(),
@@ -1822,11 +1828,13 @@ const schema = a.schema({
1822
1828
  id: a.id().required(),
1823
1829
  sourceItemId: a.id().required(),
1824
1830
  itemLineageId: a.id().required(),
1831
+ tenantId: a.string(),
1825
1832
  versionNumber: a.integer().required(),
1826
1833
  type: a.string().required(),
1827
1834
  status: a.string().required(),
1828
1835
  typeStatus: a.string().required(),
1829
1836
  slug: a.string().required(),
1837
+ tenantSlug: a.string(),
1830
1838
  shortSlug: a.string(),
1831
1839
  section: a.string(),
1832
1840
  sectionStatus: a.string(),
@@ -1849,6 +1857,7 @@ const schema = a.schema({
1849
1857
  })
1850
1858
  .secondaryIndexes((index) => [
1851
1859
  index("slug").queryField("publishedItemBySlug"),
1860
+ index("tenantSlug").queryField("publishedItemByTenantSlug"),
1852
1861
  index("typeStatus").sortKeys(["publishedAt"]).queryField("listPublishedItemsByTypeStatusAndPublishedAt"),
1853
1862
  index("sectionStatus").sortKeys(["publishedAt"]).queryField("listPublishedItemsBySectionStatusAndPublishedAt"),
1854
1863
  index("itemLineageId").sortKeys(["versionNumber"]).queryField("listPublishedItemsByLineageAndVersion"),
@@ -1861,6 +1870,7 @@ const schema = a.schema({
1861
1870
  .model({
1862
1871
  id: a.id().required(),
1863
1872
  sourceMediaAssetId: a.id().required(),
1873
+ tenantId: a.string(),
1864
1874
  publishedItemId: a.id().required(),
1865
1875
  sourceItemId: a.id().required(),
1866
1876
  itemLineageId: a.id().required(),
@@ -246,7 +246,7 @@ const schema = a.schema({
246
246
  relationId: a.id(),
247
247
  }),
248
248
 
249
- ReferenceInsightActionResult: a.customType({
249
+ ReferenceNoteActionResult: a.customType({
250
250
  ok: a.boolean().required(),
251
251
  referenceId: a.id().required(),
252
252
  messageId: a.id().required(),
@@ -336,7 +336,7 @@ const schema = a.schema({
336
336
  ])
337
337
  .handler(a.handler.function(categoryAction)),
338
338
 
339
- createReferenceInsight: a
339
+ createReferenceNote: a
340
340
  .mutation()
341
341
  .arguments({
342
342
  referenceId: a.id().required(),
@@ -345,7 +345,7 @@ const schema = a.schema({
345
345
  actorSub: a.string(),
346
346
  actorLabel: a.string(),
347
347
  })
348
- .returns(a.ref("ReferenceInsightActionResult"))
348
+ .returns(a.ref("ReferenceNoteActionResult"))
349
349
  .authorization((allow) => [
350
350
  allow.groups(categoryWriteGroups),
351
351
  ])
@@ -1100,6 +1100,7 @@ const schema = a.schema({
1100
1100
  NewsroomSection: a
1101
1101
  .model({
1102
1102
  id: a.id().required(),
1103
+ tenantId: a.string(),
1103
1104
  title: a.string().required(),
1104
1105
  type: a.string().required(),
1105
1106
  editorialMission: a.string().required(),
@@ -1118,6 +1119,7 @@ const schema = a.schema({
1118
1119
  })
1119
1120
  .secondaryIndexes((index) => [
1120
1121
  index("sortOrder").sortKeys(["id"]).queryField("listNewsroomSectionsBySortOrder"),
1122
+ index("tenantId").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByTenantAndSortOrder"),
1121
1123
  index("type").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByTypeAndSortOrder"),
1122
1124
  index("enabledStatus").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByEnabledStatusAndSortOrder"),
1123
1125
  ])
@@ -1725,6 +1727,7 @@ const schema = a.schema({
1725
1727
  .model({
1726
1728
  id: a.id().required(),
1727
1729
  lineageId: a.id().required(),
1730
+ tenantId: a.string(),
1728
1731
  versionNumber: a.integer().required(),
1729
1732
  previousVersionId: a.id(),
1730
1733
  versionState: a.string().required(),
@@ -1737,6 +1740,7 @@ const schema = a.schema({
1737
1740
  typeStatus: a.string().required(),
1738
1741
  stage: a.string(),
1739
1742
  slug: a.string().required(),
1743
+ tenantSlug: a.string(),
1740
1744
  shortSlug: a.string(),
1741
1745
  section: a.string(),
1742
1746
  sectionStatus: a.string(),
@@ -1764,6 +1768,7 @@ const schema = a.schema({
1764
1768
  .secondaryIndexes((index) => [
1765
1769
  index("lineageId").sortKeys(["versionNumber"]).queryField("listItemsByLineageAndVersion"),
1766
1770
  index("slug").queryField("itemBySlug"),
1771
+ index("tenantSlug").queryField("itemByTenantSlug"),
1767
1772
  index("typeStatus").sortKeys(["publishedAt"]).queryField("listItemsByTypeStatusAndPublishedAt"),
1768
1773
  index("sectionStatus").sortKeys(["publishedAt"]).queryField("listItemsBySectionStatusAndPublishedAt"),
1769
1774
  index("versionState").sortKeys(["updatedAt"]).queryField("listItemsByVersionStateAndUpdatedAt"),
@@ -1814,6 +1819,7 @@ const schema = a.schema({
1814
1819
  .model({
1815
1820
  id: a.id().required(),
1816
1821
  itemId: a.id().required(),
1822
+ tenantId: a.string(),
1817
1823
  type: a.string().required(),
1818
1824
  role: a.string().required(),
1819
1825
  sortKey: a.string().required(),
@@ -1930,11 +1936,13 @@ const schema = a.schema({
1930
1936
  id: a.id().required(),
1931
1937
  sourceItemId: a.id().required(),
1932
1938
  itemLineageId: a.id().required(),
1939
+ tenantId: a.string(),
1933
1940
  versionNumber: a.integer().required(),
1934
1941
  type: a.string().required(),
1935
1942
  status: a.string().required(),
1936
1943
  typeStatus: a.string().required(),
1937
1944
  slug: a.string().required(),
1945
+ tenantSlug: a.string(),
1938
1946
  shortSlug: a.string(),
1939
1947
  section: a.string(),
1940
1948
  sectionStatus: a.string(),
@@ -1957,6 +1965,7 @@ const schema = a.schema({
1957
1965
  })
1958
1966
  .secondaryIndexes((index) => [
1959
1967
  index("slug").queryField("publishedItemBySlug"),
1968
+ index("tenantSlug").queryField("publishedItemByTenantSlug"),
1960
1969
  index("typeStatus").sortKeys(["publishedAt"]).queryField("listPublishedItemsByTypeStatusAndPublishedAt"),
1961
1970
  index("sectionStatus").sortKeys(["publishedAt"]).queryField("listPublishedItemsBySectionStatusAndPublishedAt"),
1962
1971
  index("itemLineageId").sortKeys(["versionNumber"]).queryField("listPublishedItemsByLineageAndVersion"),
@@ -1970,6 +1979,7 @@ const schema = a.schema({
1970
1979
  .model({
1971
1980
  id: a.id().required(),
1972
1981
  sourceMediaAssetId: a.id().required(),
1982
+ tenantId: a.string(),
1973
1983
  publishedItemId: a.id().required(),
1974
1984
  sourceItemId: a.id().required(),
1975
1985
  itemLineageId: a.id().required(),
@@ -918,6 +918,7 @@ const baseDefinitions = {
918
918
  ]),
919
919
  NewsroomSection: modelWithoutSubscriptions({
920
920
  id: a.id().required(),
921
+ tenantId: a.string(),
921
922
  title: a.string().required(),
922
923
  type: a.string().required(),
923
924
  editorialMission: a.string().required(),
@@ -936,6 +937,7 @@ const baseDefinitions = {
936
937
  })
937
938
  .secondaryIndexes((index) => [
938
939
  index("sortOrder").sortKeys(["id"]).queryField("listNewsroomSectionsBySortOrder"),
940
+ index("tenantId").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByTenantAndSortOrder"),
939
941
  index("type").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByTypeAndSortOrder"),
940
942
  index("enabledStatus").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByEnabledStatusAndSortOrder"),
941
943
  ])
@@ -1503,6 +1505,7 @@ const baseDefinitions = {
1503
1505
  Item: modelWithoutSubscriptions({
1504
1506
  id: a.id().required(),
1505
1507
  lineageId: a.id().required(),
1508
+ tenantId: a.string(),
1506
1509
  versionNumber: a.integer().required(),
1507
1510
  previousVersionId: a.id(),
1508
1511
  versionState: a.string().required(),
@@ -1515,6 +1518,7 @@ const baseDefinitions = {
1515
1518
  status: a.string().required(),
1516
1519
  typeStatus: a.string().required(),
1517
1520
  slug: a.string().required(),
1521
+ tenantSlug: a.string(),
1518
1522
  shortSlug: a.string(),
1519
1523
  section: a.string(),
1520
1524
  sectionStatus: a.string(),
@@ -1542,6 +1546,7 @@ const baseDefinitions = {
1542
1546
  .secondaryIndexes((index) => [
1543
1547
  index("lineageId").sortKeys(["versionNumber"]).queryField("listItemsByLineageAndVersion"),
1544
1548
  index("slug").queryField("itemBySlug"),
1549
+ index("tenantSlug").queryField("itemByTenantSlug"),
1545
1550
  index("typeStatus").sortKeys(["publishedAt"]).queryField("listItemsByTypeStatusAndPublishedAt"),
1546
1551
  index("sectionStatus").sortKeys(["publishedAt"]).queryField("listItemsBySectionStatusAndPublishedAt"),
1547
1552
  index("versionState").sortKeys(["updatedAt"]).queryField("listItemsByVersionStateAndUpdatedAt"),
@@ -1586,6 +1591,7 @@ const baseDefinitions = {
1586
1591
  MediaAsset: modelWithoutSubscriptions({
1587
1592
  id: a.id().required(),
1588
1593
  itemId: a.id().required(),
1594
+ tenantId: a.string(),
1589
1595
  type: a.string().required(),
1590
1596
  role: a.string().required(),
1591
1597
  sortKey: a.string().required(),
@@ -1669,11 +1675,13 @@ const baseDefinitions = {
1669
1675
  id: a.id().required(),
1670
1676
  sourceItemId: a.id().required(),
1671
1677
  itemLineageId: a.id().required(),
1678
+ tenantId: a.string(),
1672
1679
  versionNumber: a.integer().required(),
1673
1680
  type: a.string().required(),
1674
1681
  status: a.string().required(),
1675
1682
  typeStatus: a.string().required(),
1676
1683
  slug: a.string().required(),
1684
+ tenantSlug: a.string(),
1677
1685
  shortSlug: a.string(),
1678
1686
  section: a.string(),
1679
1687
  sectionStatus: a.string(),
@@ -1696,6 +1704,7 @@ const baseDefinitions = {
1696
1704
  })
1697
1705
  .secondaryIndexes((index) => [
1698
1706
  index("slug").queryField("publishedItemBySlug"),
1707
+ index("tenantSlug").queryField("publishedItemByTenantSlug"),
1699
1708
  index("typeStatus").sortKeys(["publishedAt"]).queryField("listPublishedItemsByTypeStatusAndPublishedAt"),
1700
1709
  index("sectionStatus").sortKeys(["publishedAt"]).queryField("listPublishedItemsBySectionStatusAndPublishedAt"),
1701
1710
  index("itemLineageId").sortKeys(["versionNumber"]).queryField("listPublishedItemsByLineageAndVersion"),
@@ -1707,6 +1716,7 @@ const baseDefinitions = {
1707
1716
  PublishedMediaAsset: modelWithoutSubscriptions({
1708
1717
  id: a.id().required(),
1709
1718
  sourceMediaAssetId: a.id().required(),
1719
+ tenantId: a.string(),
1710
1720
  publishedItemId: a.id().required(),
1711
1721
  sourceItemId: a.id().required(),
1712
1722
  itemLineageId: a.id().required(),
@@ -994,6 +994,7 @@ const baseDefinitions = {
994
994
 
995
995
  NewsroomSection: modelWithoutSubscriptions({
996
996
  id: a.id().required(),
997
+ tenantId: a.string(),
997
998
  title: a.string().required(),
998
999
  type: a.string().required(),
999
1000
  editorialMission: a.string().required(),
@@ -1012,6 +1013,7 @@ const baseDefinitions = {
1012
1013
  })
1013
1014
  .secondaryIndexes((index) => [
1014
1015
  index("sortOrder").sortKeys(["id"]).queryField("listNewsroomSectionsBySortOrder"),
1016
+ index("tenantId").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByTenantAndSortOrder"),
1015
1017
  index("type").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByTypeAndSortOrder"),
1016
1018
  index("enabledStatus").sortKeys(["sortOrder"]).queryField("listNewsroomSectionsByEnabledStatusAndSortOrder"),
1017
1019
  ])
@@ -1598,6 +1600,7 @@ const baseDefinitions = {
1598
1600
  Item: modelWithoutSubscriptions({
1599
1601
  id: a.id().required(),
1600
1602
  lineageId: a.id().required(),
1603
+ tenantId: a.string(),
1601
1604
  versionNumber: a.integer().required(),
1602
1605
  previousVersionId: a.id(),
1603
1606
  versionState: a.string().required(),
@@ -1610,6 +1613,7 @@ const baseDefinitions = {
1610
1613
  status: a.string().required(),
1611
1614
  typeStatus: a.string().required(),
1612
1615
  slug: a.string().required(),
1616
+ tenantSlug: a.string(),
1613
1617
  shortSlug: a.string(),
1614
1618
  section: a.string(),
1615
1619
  sectionStatus: a.string(),
@@ -1637,6 +1641,7 @@ const baseDefinitions = {
1637
1641
  .secondaryIndexes((index) => [
1638
1642
  index("lineageId").sortKeys(["versionNumber"]).queryField("listItemsByLineageAndVersion"),
1639
1643
  index("slug").queryField("itemBySlug"),
1644
+ index("tenantSlug").queryField("itemByTenantSlug"),
1640
1645
  index("typeStatus").sortKeys(["publishedAt"]).queryField("listItemsByTypeStatusAndPublishedAt"),
1641
1646
  index("sectionStatus").sortKeys(["publishedAt"]).queryField("listItemsBySectionStatusAndPublishedAt"),
1642
1647
  index("versionState").sortKeys(["updatedAt"]).queryField("listItemsByVersionStateAndUpdatedAt"),
@@ -1684,6 +1689,7 @@ const baseDefinitions = {
1684
1689
  MediaAsset: modelWithoutSubscriptions({
1685
1690
  id: a.id().required(),
1686
1691
  itemId: a.id().required(),
1692
+ tenantId: a.string(),
1687
1693
  type: a.string().required(),
1688
1694
  role: a.string().required(),
1689
1695
  sortKey: a.string().required(),
@@ -1770,11 +1776,13 @@ const baseDefinitions = {
1770
1776
  id: a.id().required(),
1771
1777
  sourceItemId: a.id().required(),
1772
1778
  itemLineageId: a.id().required(),
1779
+ tenantId: a.string(),
1773
1780
  versionNumber: a.integer().required(),
1774
1781
  type: a.string().required(),
1775
1782
  status: a.string().required(),
1776
1783
  typeStatus: a.string().required(),
1777
1784
  slug: a.string().required(),
1785
+ tenantSlug: a.string(),
1778
1786
  shortSlug: a.string(),
1779
1787
  section: a.string(),
1780
1788
  sectionStatus: a.string(),
@@ -1797,6 +1805,7 @@ const baseDefinitions = {
1797
1805
  })
1798
1806
  .secondaryIndexes((index) => [
1799
1807
  index("slug").queryField("publishedItemBySlug"),
1808
+ index("tenantSlug").queryField("publishedItemByTenantSlug"),
1800
1809
  index("typeStatus").sortKeys(["publishedAt"]).queryField("listPublishedItemsByTypeStatusAndPublishedAt"),
1801
1810
  index("sectionStatus").sortKeys(["publishedAt"]).queryField("listPublishedItemsBySectionStatusAndPublishedAt"),
1802
1811
  index("itemLineageId").sortKeys(["versionNumber"]).queryField("listPublishedItemsByLineageAndVersion"),
@@ -1809,6 +1818,7 @@ const baseDefinitions = {
1809
1818
  PublishedMediaAsset: modelWithoutSubscriptions({
1810
1819
  id: a.id().required(),
1811
1820
  sourceMediaAssetId: a.id().required(),
1821
+ tenantId: a.string(),
1812
1822
  publishedItemId: a.id().required(),
1813
1823
  sourceItemId: a.id().required(),
1814
1824
  itemLineageId: a.id().required(),
@@ -4,12 +4,12 @@ import { Amplify } from "aws-amplify";
4
4
  import { generateClient } from "aws-amplify/data";
5
5
  import type { Schema } from "../../data/resource";
6
6
  import { putJsonModelPayload, putTextModelPayload, readJsonModelPayload } from "../shared/model-payloads";
7
- import { referenceCurationMetadata } from "../shared/reference-curation-metadata";
7
+ import { curationActorKind, referenceCurationMetadata } from "../shared/reference-curation-metadata";
8
8
 
9
9
  type ReviewHandler = Schema["reviewSteeringProposal"]["functionHandler"];
10
10
  type ReferenceCurationHandler = Schema["reviewReferenceCuration"]["functionHandler"];
11
11
  type ReferenceQualityHandler = Schema["setReferenceQualityRating"]["functionHandler"];
12
- type ReferenceInsightHandler = Schema["createReferenceInsight"]["functionHandler"];
12
+ type ReferenceNoteHandler = Schema["createReferenceNote"]["functionHandler"];
13
13
  type MoveReferenceCorpusHandler = Schema["moveReferenceCorpus"]["functionHandler"];
14
14
  type StartReferenceCurationHandler = Schema["startReferenceCuration"]["functionHandler"];
15
15
  type GetReferenceCurationStatusHandler = Schema["getReferenceCurationStatus"]["functionHandler"];
@@ -24,7 +24,7 @@ type CategoryActionEvent =
24
24
  | Parameters<ReviewHandler>[0]
25
25
  | Parameters<ReferenceCurationHandler>[0]
26
26
  | Parameters<ReferenceQualityHandler>[0]
27
- | Parameters<ReferenceInsightHandler>[0]
27
+ | Parameters<ReferenceNoteHandler>[0]
28
28
  | Parameters<MoveReferenceCorpusHandler>[0]
29
29
  | Parameters<StartReferenceCurationHandler>[0]
30
30
  | Parameters<GetReferenceCurationStatusHandler>[0]
@@ -89,7 +89,7 @@ export const handler = async (event: CategoryActionEvent) => {
89
89
  if (fieldName === "reviewSteeringProposal") return reviewSteeringProposal(event as Parameters<ReviewHandler>[0]);
90
90
  if (fieldName === "reviewReferenceCuration") return reviewReferenceCuration(event as Parameters<ReferenceCurationHandler>[0]);
91
91
  if (fieldName === "setReferenceQualityRating") return setReferenceQualityRating(event as Parameters<ReferenceQualityHandler>[0]);
92
- if (fieldName === "createReferenceInsight") return createReferenceInsight(event as Parameters<ReferenceInsightHandler>[0]);
92
+ if (fieldName === "createReferenceNote") return createReferenceNote(event as Parameters<ReferenceNoteHandler>[0]);
93
93
  if (fieldName === "moveReferenceCorpus") return moveReferenceCorpus(event as Parameters<MoveReferenceCorpusHandler>[0]);
94
94
  if (fieldName === "startReferenceCuration") return startReferenceCuration(event as Parameters<StartReferenceCurationHandler>[0]);
95
95
  if (fieldName === "getReferenceCurationStatus") return getReferenceCurationStatus(event as Parameters<GetReferenceCurationStatusHandler>[0]);
@@ -234,6 +234,7 @@ async function reviewReferenceCuration(event: Parameters<ReferenceCurationHandle
234
234
  referenceLineageId,
235
235
  decisionRelationId: normalizeOptionalString(event.arguments.decisionRelationId),
236
236
  shareable: event.arguments.shareable ?? null,
237
+ actorKind: curationActorKind(event.identity),
237
238
  }),
238
239
  { filename: "metadata.json", now },
239
240
  );
@@ -403,7 +404,7 @@ async function setReferenceQualityRating(event: Parameters<ReferenceQualityHandl
403
404
  };
404
405
  }
405
406
 
406
- async function createReferenceInsight(event: Parameters<ReferenceInsightHandler>[0]) {
407
+ async function createReferenceNote(event: Parameters<ReferenceNoteHandler>[0]) {
407
408
  const client = await getDataClient();
408
409
  const referenceId = normalizeRequiredString(event.arguments.referenceId, "referenceId");
409
410
  const summary = normalizeRequiredString(event.arguments.summary, "summary");
@@ -414,10 +415,10 @@ async function createReferenceInsight(event: Parameters<ReferenceInsightHandler>
414
415
  const actorLabel = normalizeOptionalString(event.arguments.actorLabel) ?? getIdentityLabel(event);
415
416
  const actor = actorLabel ?? actorSub ?? "Papyrus newsroom";
416
417
  const referenceLineageId = normalizeOptionalString(reference.lineageId) ?? referenceId;
417
- const messageId = `message-reference-insight-${safeId(referenceLineageId)}-${now.replace(/[^0-9TZ]/g, "")}-${randomUUID().slice(0, 8)}`;
418
+ const messageId = `message-reference-note-${safeId(referenceLineageId)}-${now.replace(/[^0-9TZ]/g, "")}-${randomUUID().slice(0, 8)}`;
418
419
  const relationId = `semantic-relation-${hashStable([
419
420
  `message#${messageId}`,
420
- "insight_about",
421
+ "note_about",
421
422
  `reference#${referenceId}`,
422
423
  ]).slice(0, 24)}`;
423
424
 
@@ -425,7 +426,7 @@ async function createReferenceInsight(event: Parameters<ReferenceInsightHandler>
425
426
  client.models.Message.create({
426
427
  ...buildCanonicalMessageInput({
427
428
  id: messageId,
428
- messageKind: "insight",
429
+ messageKind: "note",
429
430
  messageDomain: "knowledge",
430
431
  summary,
431
432
  source: "newsroom",
@@ -436,7 +437,7 @@ async function createReferenceInsight(event: Parameters<ReferenceInsightHandler>
436
437
  threadId: messageId,
437
438
  sequenceNumber: 1,
438
439
  }),
439
- "create insight Message",
440
+ "create note Message",
440
441
  );
441
442
  await putTextModelPayload(
442
443
  client as any,
@@ -452,7 +453,7 @@ async function createReferenceInsight(event: Parameters<ReferenceInsightHandler>
452
453
  "metadata",
453
454
  "metadata",
454
455
  {
455
- kind: "reference.insight.created",
456
+ kind: "reference.note.created",
456
457
  targetKind: "reference",
457
458
  targetId: referenceId,
458
459
  targetLineageId: referenceLineageId,
@@ -463,8 +464,8 @@ async function createReferenceInsight(event: Parameters<ReferenceInsightHandler>
463
464
  client.models.SemanticRelation.create({
464
465
  id: relationId,
465
466
  relationState: "current",
466
- predicate: "insight_about",
467
- ...semanticRelationTypeFieldsForPredicate("insight_about"),
467
+ predicate: "note_about",
468
+ ...semanticRelationTypeFieldsForPredicate("note_about"),
468
469
  subjectKind: "message",
469
470
  subjectId: messageId,
470
471
  subjectLineageId: messageId,
@@ -476,7 +477,7 @@ async function createReferenceInsight(event: Parameters<ReferenceInsightHandler>
476
477
  subjectStateKey: semanticStateKey("message", messageId),
477
478
  objectStateKey: semanticStateKey("reference", referenceLineageId),
478
479
  objectSubjectStateKey: `${semanticStateKey("reference", referenceLineageId)}#message`,
479
- predicateObjectStateKey: `insight_about#${semanticStateKey("reference", referenceLineageId)}`,
480
+ predicateObjectStateKey: `note_about#${semanticStateKey("reference", referenceLineageId)}`,
480
481
  subjectVersionKey: semanticVersionKey("message", messageId),
481
482
  objectVersionKey: semanticVersionKey("reference", referenceId),
482
483
  score: 1,
@@ -492,17 +493,17 @@ async function createReferenceInsight(event: Parameters<ReferenceInsightHandler>
492
493
  updatedAt: now,
493
494
  newsroomFeedKey: "semanticRelations",
494
495
  metadata: JSON.stringify({
495
- kind: "reference.insight",
496
+ kind: "reference.note",
496
497
  summary,
497
498
  actor,
498
499
  }),
499
500
  }),
500
- "create insight_about relation",
501
+ "create note_about relation",
501
502
  );
502
503
  await updateNewsroomSummaryForSemanticRelationDelta(
503
504
  client,
504
505
  {
505
- relationTypeKey: "insight_about",
506
+ relationTypeKey: "note_about",
506
507
  relationDomain: "commentary",
507
508
  subjectKind: "message",
508
509
  objectKind: "reference",
@@ -1497,10 +1498,10 @@ function semanticRelationTypeFieldsForPredicate(predicate: string): {
1497
1498
  relationDomain: "curation",
1498
1499
  };
1499
1500
  }
1500
- if (predicate === "insight_about") {
1501
+ if (predicate === "note_about") {
1501
1502
  return {
1502
- relationTypeId: "semantic-relation-type-insight-about",
1503
- relationTypeKey: "insight_about",
1503
+ relationTypeId: "semantic-relation-type-note-about",
1504
+ relationTypeKey: "note_about",
1504
1505
  relationDomain: "knowledge",
1505
1506
  };
1506
1507
  }
@@ -2190,7 +2190,7 @@ fn build_openai_messages(
2190
2190
  ) -> Vec<Value> {
2191
2191
  let mut messages = vec![json!({
2192
2192
  "role": "system",
2193
- "content": "You are Papyrus, an editorial assistant for an autonomous newsroom. Be concise, accurate, and concrete. Raw console chat turns are working memory and are excluded from default semantic searches unless explicitly requested. When a chat produces durable insight, recommend creating an insight Message instead of making every chat turn canonical knowledge. Use execute_tactus for Papyrus runtime work. Distinguish references from assignments: Reference.* is for scholarly sources; Assignment.* is for newsroom work items (research, curation, intake). When the user provides a URL and asks to add, register, or file a reference, immediately call Reference.create{ url = \"<url>\", title = \"<optional>\", apply = true }—do not use Reference.register, papyrus.reference.create, or Assignment.create unless they asked for research work. For \"most recent references\" or similar, immediately call Reference.list{ limit = <count>, order = \"newest\" } and summarize. For \"last/latest/most recent research assignment\" (or \"research assignment\" without a specific id), immediately call Assignment.list{ type = \"research\", limit = 1 } (includes research.edition-candidate, research.tavily-deep, and other research.* types), then Assignment.get{ id = \"<that id>\" } if the user wants detail—do not use Reference.list and do not list all assignment types (curation.reference-intake is not a research assignment). To create research work, use Assignment.create{ type = \"research\", title = \"...\", apply = true }."
2193
+ "content": "You are Papyrus, an editorial assistant for an autonomous newsroom. Be concise, accurate, and concrete. Raw console chat turns are working memory and are excluded from default semantic searches unless explicitly requested. When a chat produces durable note, recommend creating a note Message instead of making every chat turn canonical knowledge. Use execute_tactus for Papyrus runtime work. Distinguish references from assignments: Reference.* is for scholarly sources; Assignment.* is for newsroom work items (research, curation, intake). When the user provides a URL and asks to add, register, or file a reference, immediately call Reference.create{ url = \"<url>\", title = \"<optional>\", apply = true }—do not use Reference.register, papyrus.reference.create, or Assignment.create unless they asked for research work. For \"most recent references\" or similar, immediately call Reference.list{ limit = <count>, order = \"newest\" } and summarize. For \"last/latest/most recent research assignment\" (or \"research assignment\" without a specific id), immediately call Assignment.list{ type = \"research\", limit = 1 } (includes research.edition-candidate, research.tavily-deep, and other research.* types), then Assignment.get{ id = \"<that id>\" } if the user wants detail—do not use Reference.list and do not list all assignment types (curation.reference-intake is not a research assignment). To create research work, use Assignment.create{ type = \"research\", title = \"...\", apply = true }."
2194
2194
  })];
2195
2195
  if !static_prompt.publication_mission.trim().is_empty() {
2196
2196
  messages.push(json!({
@@ -22,6 +22,7 @@ from papyrus_content.rebuild_trigger import (
22
22
  trigger_rebuild,
23
23
  trigger_staging_build,
24
24
  )
25
+ from papyrus_content.story_reporting import save_story_version
25
26
  from papyrus_content.publishing import (
26
27
  ItemFields,
27
28
  PublishError,
@@ -188,6 +189,28 @@ def run_projection_task(task: dict) -> dict:
188
189
 
189
190
  def save_item_draft_action(arguments: dict, actor: str) -> dict:
190
191
  client, _claims = create_authoring_client()
192
+ if arguments.get("newVersion") and arguments.get("id"):
193
+ existing = client.get_record("Item", arguments["id"])
194
+ if existing is None:
195
+ raise PublishError("not-found", "That story was not found.")
196
+ record = save_story_version(
197
+ client,
198
+ existing.get("lineageId") or existing["id"],
199
+ front_matter_yaml=arguments.get("frontMatterYaml"),
200
+ body_markus=arguments.get("bodyMarkus") or "",
201
+ actor=actor,
202
+ change_reason=arguments.get("changeReason") or "edited in the newsroom",
203
+ )
204
+ return {
205
+ "ok": True,
206
+ "item": {
207
+ "id": record["id"],
208
+ "contentHash": record["contentHash"],
209
+ "status": record["status"],
210
+ "slug": record["slug"],
211
+ "versionNumber": record.get("versionNumber"),
212
+ },
213
+ }
191
214
  fields = ItemFields(
192
215
  type=arguments["type"],
193
216
  slug=arguments["slug"],
@@ -1,5 +1,5 @@
1
1
  PyYAML>=6.0.2,<7
2
2
  citeproc-py>=0.8.2,<1
3
- anthus-markus==0.5.1
3
+ anthus-markus==0.7.0
4
4
  Pillow>=11.3,<12
5
5
  awscrt>=0.23,<1
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
7
7
  import { pythonLambdaCode } from "../shared/python-bundle.js";
8
8
  const dirname = path.dirname(fileURLToPath(import.meta.url));
9
9
  const projectRoot = path.resolve(dirname, "../../..");
10
- export const contentActionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.5.1", "Pillow>=11.3,<12", "awscrt>=0.23,<1"];
10
+ export const contentActionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.7.0", "Pillow>=11.3,<12", "awscrt>=0.23,<1"];
11
11
  function installCheckoutRequirements(outputDir) {
12
12
  const requirementsPath = path.join(projectRoot, "amplify/functions/content-actions/requirements.txt");
13
13
  execSync(`python3 -m pip install -r "${requirementsPath}" -t "${outputDir}" --no-cache-dir --platform manylinux2014_aarch64 --implementation cp --python-version 3.12 --only-binary=:all: --ignore-requires-python`, { cwd: projectRoot, stdio: "inherit" });
@@ -10,7 +10,7 @@ import { pythonLambdaCode, type SiteBundleFile } from "../shared/python-bundle";
10
10
  const dirname = path.dirname(fileURLToPath(import.meta.url));
11
11
  const projectRoot = path.resolve(dirname, "../../..");
12
12
 
13
- export const contentActionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.5.1", "Pillow>=11.3,<12", "awscrt>=0.23,<1"];
13
+ export const contentActionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.7.0", "Pillow>=11.3,<12", "awscrt>=0.23,<1"];
14
14
 
15
15
  function installCheckoutRequirements(outputDir: string): void {
16
16
  const requirementsPath = path.join(projectRoot, "amplify/functions/content-actions/requirements.txt");
@@ -1,4 +1,4 @@
1
1
  PyYAML>=6.0.2,<7
2
2
  citeproc-py>=0.8.2,<1
3
- anthus-markus==0.5.1
3
+ anthus-markus==0.7.0
4
4
  Pillow>=11.3,<12
@@ -12,6 +12,20 @@ export type ReferenceCurationMetadataInput = {
12
12
  referenceLineageId: string
13
13
  decisionRelationId?: string | null
14
14
  shareable?: boolean | null
15
+ actorKind?: CurationActorKind | null
16
+ }
17
+
18
+ export type CurationActorKind = "human" | "service"
19
+
20
+ /**
21
+ * A curation is human only when the caller signed in through the user pool, so
22
+ * AppSync supplied a verified subject claim. Request arguments never decide it;
23
+ * IAM-signed service callers and agents have no such claim.
24
+ */
25
+ export function curationActorKind(identity: unknown): CurationActorKind {
26
+ const claims = (identity as {claims?: Record<string, unknown>} | null | undefined)?.claims
27
+ const subject = claims?.sub
28
+ return typeof subject === "string" && subject.trim() !== "" ? "human" : "service"
15
29
  }
16
30
 
17
31
  export function referenceCurationMetadata(input: ReferenceCurationMetadataInput): Record<string, unknown> {
@@ -23,6 +37,7 @@ export function referenceCurationMetadata(input: ReferenceCurationMetadataInput)
23
37
  curationReasonCode: input.reasonCode,
24
38
  referenceId: input.referenceId,
25
39
  referenceLineageId: input.referenceLineageId,
40
+ ...(input.actorKind ? {actorKind: input.actorKind} : {}),
26
41
  ...(decisionRelationId ? {decisionRelationId} : {}),
27
42
  ...(decisionRelationId ? {shareable: input.shareable === true} : {}),
28
43
  }
@@ -69,9 +69,9 @@ export function slackAgentInstructions(): string {
69
69
  "",
70
70
  "Be concise, accurate, and concrete. Slack has no web UI: do not use papyrus.web.navigate, papyrus.web.current_location, or assume the user can see papyrus:// pages.",
71
71
  "",
72
- "Raw console chat turns are working memory and are excluded from default semantic searches unless explicitly requested. When a chat produces durable insight, recommend creating an insight Message instead of making every chat turn canonical knowledge.",
72
+ "Raw console chat turns are working memory and are excluded from default semantic searches unless explicitly requested. When a chat produces durable note, recommend creating a note Message instead of making every chat turn canonical knowledge.",
73
73
  "",
74
- "Respond openly to questions, commands, and discussion—the same conversational stance as the web console. Do not treat every message as a citation submission. Register references or create insights only when the user shares URLs/DOIs or asks you to file, summarize, or comment on specific material.",
74
+ "Respond openly to questions, commands, and discussion—the same conversational stance as the web console. Do not treat every message as a citation submission. Register references or create notes only when the user shares URLs/DOIs or asks you to file, summarize, or comment on specific material.",
75
75
  "",
76
76
  'For requests like "most recent references" or "tell me about recent references", do not ask clarifying questions first: immediately call execute_tactus with a Reference.list snippet, then summarize the results.',
77
77
  "",
@@ -11,7 +11,7 @@ import { pythonLambdaCode } from "../functions/shared/python-bundle.js";
11
11
  import { RENDITIONS_EPHEMERAL_STORAGE_MB, RENDITIONS_MEDIA_PREFIX, RENDITIONS_MEMORY_MB, RENDITIONS_TIMEOUT_SECONDS, renditionsEnvironment, renditionsEventPattern, } from "./renditions-settings.js";
12
12
  const dirname = path.dirname(fileURLToPath(import.meta.url));
13
13
  const projectRoot = path.resolve(dirname, "../..");
14
- export const renditionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.5.1", "Pillow>=11.3,<12"];
14
+ export const renditionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.7.0", "Pillow>=11.3,<12"];
15
15
  function installCheckoutRequirements(outputDir) {
16
16
  const requirementsPath = path.join(projectRoot, "amplify/functions/renditions/requirements.txt");
17
17
  execSync(`python3 -m pip install -r "${requirementsPath}" -t "${outputDir}" --no-cache-dir --platform manylinux2014_aarch64 --implementation cp --python-version 3.12 --only-binary=:all: --ignore-requires-python`, { cwd: projectRoot, stdio: "inherit" });
@@ -22,7 +22,7 @@ import {
22
22
  const dirname = path.dirname(fileURLToPath(import.meta.url));
23
23
  const projectRoot = path.resolve(dirname, "../..");
24
24
 
25
- export const renditionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.5.1", "Pillow>=11.3,<12"];
25
+ export const renditionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.7.0", "Pillow>=11.3,<12"];
26
26
 
27
27
  export type RenditionsFunctionProps = {
28
28
  siteBucket: s3.IBucket;