@rubytech/create-maxy-code 0.1.497 → 0.1.499

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 (223) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/active-rules/dist/index.d.ts +3 -7
  3. package/payload/platform/lib/active-rules/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/active-rules/dist/index.js +20 -52
  5. package/payload/platform/lib/active-rules/dist/index.js.map +1 -1
  6. package/payload/platform/lib/active-rules/src/index.test.ts +35 -69
  7. package/payload/platform/lib/active-rules/src/index.ts +17 -58
  8. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +55 -9
  9. package/payload/platform/plugins/docs/references/admin-ui.md +36 -6
  10. package/payload/platform/plugins/docs/references/internals.md +2 -2
  11. package/payload/platform/plugins/docs/references/sweep-guide.md +16 -0
  12. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-signature.test.d.ts +2 -0
  13. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-signature.test.d.ts.map +1 -0
  14. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-signature.test.js +53 -0
  15. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-signature.test.js.map +1 -0
  16. package/payload/platform/plugins/email/mcp/dist/__tests__/signature.test.d.ts +2 -0
  17. package/payload/platform/plugins/email/mcp/dist/__tests__/signature.test.d.ts.map +1 -0
  18. package/payload/platform/plugins/email/mcp/dist/__tests__/signature.test.js +50 -0
  19. package/payload/platform/plugins/email/mcp/dist/__tests__/signature.test.js.map +1 -0
  20. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts.map +1 -1
  21. package/payload/platform/plugins/email/mcp/dist/lib/compose.js +15 -2
  22. package/payload/platform/plugins/email/mcp/dist/lib/compose.js.map +1 -1
  23. package/payload/platform/plugins/email/mcp/dist/lib/signature.d.ts +29 -0
  24. package/payload/platform/plugins/email/mcp/dist/lib/signature.d.ts.map +1 -0
  25. package/payload/platform/plugins/email/mcp/dist/lib/signature.js +55 -0
  26. package/payload/platform/plugins/email/mcp/dist/lib/signature.js.map +1 -0
  27. package/payload/platform/plugins/email/references/email-reference.md +10 -0
  28. package/payload/platform/plugins/memory/PLUGIN.md +2 -0
  29. package/payload/platform/plugins/memory/mcp/dist/index.js +2 -2
  30. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  31. package/payload/platform/plugins/memory/mcp/dist/scripts/__tests__/dream-cycle-sweep-decision.test.d.ts +2 -0
  32. package/payload/platform/plugins/memory/mcp/dist/scripts/__tests__/dream-cycle-sweep-decision.test.d.ts.map +1 -0
  33. package/payload/platform/plugins/memory/mcp/dist/scripts/__tests__/dream-cycle-sweep-decision.test.js +84 -0
  34. package/payload/platform/plugins/memory/mcp/dist/scripts/__tests__/dream-cycle-sweep-decision.test.js.map +1 -0
  35. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep-decision.d.ts +54 -0
  36. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep-decision.d.ts.map +1 -0
  37. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep-decision.js +58 -0
  38. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep-decision.js.map +1 -0
  39. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.d.ts +30 -0
  40. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.d.ts.map +1 -0
  41. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js +204 -0
  42. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js.map +1 -0
  43. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js +30 -0
  44. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js.map +1 -1
  45. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-read-active-rules.test.js +10 -9
  46. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-read-active-rules.test.js.map +1 -1
  47. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts +4 -2
  48. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -1
  49. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +38 -0
  50. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -1
  51. package/payload/platform/plugins/memory/mcp/vitest.config.ts +2 -0
  52. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +10 -4
  53. package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +2 -0
  54. package/payload/platform/plugins/memory/skills/preference-audit/SKILL.md +16 -0
  55. package/payload/platform/plugins/sweep/PLUGIN.md +5 -1
  56. package/payload/platform/plugins/sweep/skills/email-graph-sweep/SKILL.md +165 -0
  57. package/payload/platform/services/claude-session-manager/dist/preference-reconciliation-audit.d.ts +19 -19
  58. package/payload/platform/services/claude-session-manager/dist/preference-reconciliation-audit.d.ts.map +1 -1
  59. package/payload/platform/services/claude-session-manager/dist/preference-reconciliation-audit.js +28 -34
  60. package/payload/platform/services/claude-session-manager/dist/preference-reconciliation-audit.js.map +1 -1
  61. package/payload/server/package.json +2 -1
  62. package/payload/server/public/activity.html +6 -6
  63. package/payload/server/public/assets/{AdminLoginScreens-BXDYzNbq.js → AdminLoginScreens-Ce5aBBWF.js} +1 -1
  64. package/payload/server/public/assets/AdminShell-BFVVkWFC.js +2 -0
  65. package/payload/server/public/assets/{activity-cVe5ZnG7.js → activity-CKUYOLd2.js} +1 -1
  66. package/payload/server/public/assets/admin-BWb8me-E.js +1 -0
  67. package/payload/server/public/assets/{arc-BrHWN2Kr.js → arc-CpWWSum8.js} +1 -1
  68. package/payload/server/public/assets/architecture-YZFGNWBL-D-AX2VuA.js +1 -0
  69. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-1OxSL3rT.js → architectureDiagram-Q4EWVU46-D2EzaII0.js} +1 -1
  70. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-C6yKiblF.js → blockDiagram-DXYQGD6D-8kDpaNSZ.js} +1 -1
  71. package/payload/server/public/assets/{bot-Bb8yj02k.js → bot-DESMpxSQ.js} +1 -1
  72. package/payload/server/public/assets/{browser-BdWeCfYJ.js → browser-CpLq_DIo.js} +1 -1
  73. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-BzTyHS1I.js → c4Diagram-AHTNJAMY-CbwmZpK3.js} +1 -1
  74. package/payload/server/public/assets/{calendar-B4KbpiXR.js → calendar-ClOwyuz-.js} +1 -1
  75. package/payload/server/public/assets/channel-DZ5sh6YQ.js +1 -0
  76. package/payload/server/public/assets/chat-MvnxPJZ5.js +1 -0
  77. package/payload/server/public/assets/chevron-left-BzIg4in6.js +1 -0
  78. package/payload/server/public/assets/chevron-right-BcFSa9C3.js +1 -0
  79. package/payload/server/public/assets/{chunk-2KRD3SAO-BGAUfWvM.js → chunk-2KRD3SAO-PFheZ9mw.js} +1 -1
  80. package/payload/server/public/assets/{chunk-336JU56O-M1H_u2Qv.js → chunk-336JU56O-CCFOp5VK.js} +2 -2
  81. package/payload/server/public/assets/chunk-426QAEUC-CcjBLp4a.js +1 -0
  82. package/payload/server/public/assets/{chunk-4BX2VUAB-CkxXXCiF.js → chunk-4BX2VUAB-Hz4JWOf2.js} +1 -1
  83. package/payload/server/public/assets/{chunk-4TB4RGXK-DPWZYGHH.js → chunk-4TB4RGXK-4xeV0s85.js} +1 -1
  84. package/payload/server/public/assets/{chunk-55IACEB6-CBkNmqrt.js → chunk-55IACEB6-4QKgBpoh.js} +1 -1
  85. package/payload/server/public/assets/{chunk-5FUZZQ4R-uIqIu9ha.js → chunk-5FUZZQ4R-ms3K6Z5z.js} +1 -1
  86. package/payload/server/public/assets/{chunk-5PVQY5BW-B_S7XzpE.js → chunk-5PVQY5BW-CIC4GIGi.js} +1 -1
  87. package/payload/server/public/assets/{chunk-67CJDMHE-BbMV1lgW.js → chunk-67CJDMHE-B-XrWVmV.js} +1 -1
  88. package/payload/server/public/assets/{chunk-7N4EOEYR-C49Mv-nQ.js → chunk-7N4EOEYR-C7ECOUYQ.js} +1 -1
  89. package/payload/server/public/assets/{chunk-AA7GKIK3-Dy_pJOp_.js → chunk-AA7GKIK3-DOZ6Fxwk.js} +1 -1
  90. package/payload/server/public/assets/{chunk-BSJP7CBP-Ce-OmPqn.js → chunk-BSJP7CBP-4cJ_b0c6.js} +1 -1
  91. package/payload/server/public/assets/{chunk-CIAEETIT-tnjq-APC.js → chunk-CIAEETIT--mhZipWM.js} +1 -1
  92. package/payload/server/public/assets/{chunk-EDXVE4YY-uzO7kO4e.js → chunk-EDXVE4YY-jZpVwob_.js} +1 -1
  93. package/payload/server/public/assets/{chunk-ENJZ2VHE-DQMOsG1f.js → chunk-ENJZ2VHE-Nn-p-xIA.js} +1 -1
  94. package/payload/server/public/assets/{chunk-FMBD7UC4-Top6y08S.js → chunk-FMBD7UC4-DyNpcKOS.js} +1 -1
  95. package/payload/server/public/assets/{chunk-FOC6F5B3-B9LPNCUS.js → chunk-FOC6F5B3-C0P8q1uz.js} +1 -1
  96. package/payload/server/public/assets/{chunk-ICPOFSXX-DeIt3WoY.js → chunk-ICPOFSXX-CdXQ5SfI.js} +2 -2
  97. package/payload/server/public/assets/{chunk-K5T4RW27-DAnRM04h.js → chunk-K5T4RW27-BVZJKKsT.js} +1 -1
  98. package/payload/server/public/assets/{chunk-KGLVRYIC-C0QYcbLe.js → chunk-KGLVRYIC-QlVWTe0V.js} +1 -1
  99. package/payload/server/public/assets/{chunk-LIHQZDEY-BjvA5ykt.js → chunk-LIHQZDEY-CpGVZutP.js} +1 -1
  100. package/payload/server/public/assets/{chunk-ORNJ4GCN-Cs46Gj7z.js → chunk-ORNJ4GCN-WVcS6fUC.js} +1 -1
  101. package/payload/server/public/assets/{chunk-OYMX7WX6-CBHIFMBx.js → chunk-OYMX7WX6-B7hiSTed.js} +1 -1
  102. package/payload/server/public/assets/chunk-QZHKN3VN-B2WjDYBE.js +1 -0
  103. package/payload/server/public/assets/{chunk-U2HBQHQK-5_DL8yx6.js → chunk-U2HBQHQK-DJPnZxGy.js} +1 -1
  104. package/payload/server/public/assets/{chunk-X2U36JSP-BDCaWRe9.js → chunk-X2U36JSP-DilBs1Yc.js} +1 -1
  105. package/payload/server/public/assets/{chunk-XPW4576I-B10QuxYb.js → chunk-XPW4576I-B5-uyrJ0.js} +1 -1
  106. package/payload/server/public/assets/{chunk-YZCP3GAM-81jJqyDd.js → chunk-YZCP3GAM-BNO4z0Mv.js} +1 -1
  107. package/payload/server/public/assets/{chunk-ZZ45TVLE-DGx3J6Dx.js → chunk-ZZ45TVLE-BzHMQpip.js} +1 -1
  108. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CT3jNrze.js +1 -0
  109. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DJRsjAkC.js +1 -0
  110. package/payload/server/public/assets/clock-Dr3NGtjR.js +1 -0
  111. package/payload/server/public/assets/clone-FcEDnoMT.js +1 -0
  112. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-CRDvLRXs.js → cose-bilkent-S5V4N54A-3DWYmn1o.js} +1 -1
  113. package/payload/server/public/assets/{dagre--rdjN6xZ.js → dagre-Cpy31xJW.js} +1 -1
  114. package/payload/server/public/assets/{dagre-KV5264BT-DHbVQPnV.js → dagre-KV5264BT-C8fyxHFd.js} +1 -1
  115. package/payload/server/public/assets/data-BjqC4hyM.js +1 -0
  116. package/payload/server/public/assets/{diagram-5BDNPKRD-D8HC1Idg.js → diagram-5BDNPKRD-ycyhnLvr.js} +1 -1
  117. package/payload/server/public/assets/{diagram-G4DWMVQ6-evvg8aey.js → diagram-G4DWMVQ6-BkeYicIt.js} +1 -1
  118. package/payload/server/public/assets/{diagram-MMDJMWI5-4hZuk-Dd.js → diagram-MMDJMWI5-BcGZU-Q3.js} +1 -1
  119. package/payload/server/public/assets/{diagram-TYMM5635-Cwei1ql9.js → diagram-TYMM5635-DuBDCFb_.js} +1 -1
  120. package/payload/server/public/assets/{dist-B2N0v8hZ.js → dist-BYc_arNy.js} +1 -1
  121. package/payload/server/public/assets/{erDiagram-SMLLAGMA-BG5OK4Fx.js → erDiagram-SMLLAGMA-DmkeOzvp.js} +1 -1
  122. package/payload/server/public/assets/{flatten-naJ5PJ4f.js → flatten-QjnJ1Gcl.js} +1 -1
  123. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-CPB_poda.js → flowDiagram-DWJPFMVM-CkE-pjuB.js} +1 -1
  124. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-CD6BL1UP.js → ganttDiagram-T4ZO3ILL-Cjiy3kvE.js} +1 -1
  125. package/payload/server/public/assets/gitGraph-7Q5UKJZL-D1uhnP9U.js +1 -0
  126. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-C-e8FDGn.js → gitGraphDiagram-UUTBAWPF-CsI4lKZm.js} +1 -1
  127. package/payload/server/public/assets/{graph-COyGp2x1.js → graph-B7niLM97.js} +3 -3
  128. package/payload/server/public/assets/{graph-labels-CR-HqNdV.js → graph-labels-DykmXYHA.js} +1 -1
  129. package/payload/server/public/assets/{graphlib-CdCZY1Mj.js → graphlib-BkXxC6D5.js} +1 -1
  130. package/payload/server/public/assets/info-OMHHGYJF-oNm27GAV.js +1 -0
  131. package/payload/server/public/assets/infoDiagram-42DDH7IO-LxTftqyS.js +2 -0
  132. package/payload/server/public/assets/{isEmpty-Bnpg7b8f.js → isEmpty-BavJI9Cn.js} +1 -1
  133. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CFLhfPpo.js → ishikawaDiagram-UXIWVN3A-D8lZtjRc.js} +1 -1
  134. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-BN0PaMgT.js → journeyDiagram-VCZTEJTY-kLE7SiR_.js} +1 -1
  135. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CmRilACp.js → kanban-definition-6JOO6SKY-ove6JuD3.js} +1 -1
  136. package/payload/server/public/assets/{line-DR6Zk7d6.js → line-CZMSoxM6.js} +1 -1
  137. package/payload/server/public/assets/{linear-CAOWPodQ.js → linear-Be8IK9hK.js} +1 -1
  138. package/payload/server/public/assets/{maximize-2-ne1kaQlS.js → maximize-2-BbzPm7o8.js} +1 -1
  139. package/payload/server/public/assets/{mermaid-parser.core-0vmQl6Gn.js → mermaid-parser.core-BBADqbnp.js} +2 -2
  140. package/payload/server/public/assets/{mermaid.core-DWgpHiLh.js → mermaid.core-mH3N7K0I.js} +3 -3
  141. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CViR7VGV.js → mindmap-definition-QFDTVHPH-BjwwwWil.js} +1 -1
  142. package/payload/server/public/assets/operator-DCNWUKP_.js +1 -0
  143. package/payload/server/public/assets/{ordinal-Wx4m9zHk.js → ordinal-BHeIKG-K.js} +1 -1
  144. package/payload/server/public/assets/packet-4T2RLAQJ-eQNVGiK3.js +1 -0
  145. package/payload/server/public/assets/{page-DwfYACyC.js → page-C4TrTU6r.js} +4 -4
  146. package/payload/server/public/assets/page-DUgrGrJp.js +1 -0
  147. package/payload/server/public/assets/{pdf-render-0hyh3Jlf.js → pdf-render-fJz4vym9.js} +1 -1
  148. package/payload/server/public/assets/pie-ZZUOXDRM-E1u-48rt.js +1 -0
  149. package/payload/server/public/assets/{pieDiagram-DEJITSTG-B7YQ1_Kr.js → pieDiagram-DEJITSTG-D-lXWWta.js} +1 -1
  150. package/payload/server/public/assets/{public-BACeh5xm.js → public-DXJXQPwe.js} +1 -1
  151. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-Dxs0nGu5.js → quadrantDiagram-34T5L4WZ-13QyG_AO.js} +1 -1
  152. package/payload/server/public/assets/radar-PYXPWWZC-Cn2cGN90.js +1 -0
  153. package/payload/server/public/assets/{reduce-BUmc8RDR.js → reduce-Fm685to3.js} +1 -1
  154. package/payload/server/public/assets/{requirementDiagram-MS252O5E-DDNYDqZc.js → requirementDiagram-MS252O5E-Bx45Bgn4.js} +1 -1
  155. package/payload/server/public/assets/{rotate-ccw-tY4mfSrJ.js → rotate-ccw-L42fL8ey.js} +1 -1
  156. package/payload/server/public/assets/routines-JOV6xdYh.js +1 -0
  157. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DLWoegU5.js → sankeyDiagram-XADWPNL6-Cj-Gq25v.js} +1 -1
  158. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DINNPlTY.js → sequenceDiagram-FGHM5R23-B8RDRq93.js} +1 -1
  159. package/payload/server/public/assets/{src-DHSQDYx-.js → src-D3VYuW_Z.js} +1 -1
  160. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Dsan8EIl.js → stateDiagram-FHFEXIEX-DoyFF1Kl.js} +1 -1
  161. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Bml-X4-H.js +1 -0
  162. package/payload/server/public/assets/{tasks-C4nPXsbX.js → tasks-GNtvZL8F.js} +1 -1
  163. package/payload/server/public/assets/{time-entry-format-CmqjpGG2.js → time-entry-format-BreNpFLJ.js} +1 -1
  164. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CISzecz5.js → timeline-definition-GMOUNBTQ-Df4RQXm6.js} +1 -1
  165. package/payload/server/public/assets/treeView-SZITEDCU-CimabhXy.js +1 -0
  166. package/payload/server/public/assets/treemap-W4RFUUIX-Cg264rpM.js +1 -0
  167. package/payload/server/public/assets/{triangle-alert-DKZ69dOa.js → triangle-alert-DumCWC08.js} +1 -1
  168. package/payload/server/public/assets/{useCopyFeedback-Cf5jFDR5.js → useCopyFeedback-DHCtz8qX.js} +1 -1
  169. package/payload/server/public/assets/useSubAccountSwitcher-Bc7XHr0L.js +9 -0
  170. package/payload/server/public/assets/{useSubAccountSwitcher-DFnDNIDO.css → useSubAccountSwitcher-DPHQJO7E.css} +1 -1
  171. package/payload/server/public/assets/{useVoiceRecorder-BVdKbTku.js → useVoiceRecorder-Cu6zvuFx.js} +2 -2
  172. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-Bh2s76nJ.js → vennDiagram-DHZGUBPP-D2o5og9l.js} +1 -1
  173. package/payload/server/public/assets/wardley-RL74JXVD-tbgfCg0E.js +1 -0
  174. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-Grzw0FHg.js → wardleyDiagram-NUSXRM2D-BDueObbS.js} +1 -1
  175. package/payload/server/public/assets/wrench-iWkROE1V.js +1 -0
  176. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-7pY90HjH.js → xychartDiagram-5P7HB3ND-BTYs4Fgh.js} +1 -1
  177. package/payload/server/public/browser.html +5 -5
  178. package/payload/server/public/calendar.html +8 -7
  179. package/payload/server/public/chat.html +15 -14
  180. package/payload/server/public/data.html +12 -12
  181. package/payload/server/public/graph.html +10 -10
  182. package/payload/server/public/index.html +16 -16
  183. package/payload/server/public/operator.html +16 -15
  184. package/payload/server/public/public.html +15 -14
  185. package/payload/server/public/routines.html +20 -0
  186. package/payload/server/public/tasks.html +7 -7
  187. package/payload/server/server.js +464 -260
  188. package/payload/server/public/assets/AdminShell-CiTHCp5t.js +0 -2
  189. package/payload/server/public/assets/admin-BbcLizN0.js +0 -1
  190. package/payload/server/public/assets/architecture-YZFGNWBL-CZQzGRSM.js +0 -1
  191. package/payload/server/public/assets/channel-uhtvXKHn.js +0 -1
  192. package/payload/server/public/assets/chat-BEcbZB3e.js +0 -1
  193. package/payload/server/public/assets/chevron-left-Cy_RXwhn.js +0 -1
  194. package/payload/server/public/assets/chevron-right-CEjdB4AT.js +0 -1
  195. package/payload/server/public/assets/chunk-426QAEUC-D4XtWgLR.js +0 -1
  196. package/payload/server/public/assets/chunk-QZHKN3VN-Qlc2PFAj.js +0 -1
  197. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CBH5ngSm.js +0 -1
  198. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Ck3eNZce.js +0 -1
  199. package/payload/server/public/assets/clone-Cv8evfNb.js +0 -1
  200. package/payload/server/public/assets/data-L-hMHLBN.js +0 -1
  201. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CBZPQJLj.js +0 -1
  202. package/payload/server/public/assets/info-OMHHGYJF-1vIoX-kP.js +0 -1
  203. package/payload/server/public/assets/infoDiagram-42DDH7IO-BDInZV9G.js +0 -2
  204. package/payload/server/public/assets/operator-Q0F_EEyq.js +0 -1
  205. package/payload/server/public/assets/packet-4T2RLAQJ-CTU0gCGb.js +0 -1
  206. package/payload/server/public/assets/page-bRjlk8Dt.js +0 -1
  207. package/payload/server/public/assets/pie-ZZUOXDRM-D-EEHxhC.js +0 -1
  208. package/payload/server/public/assets/radar-PYXPWWZC-DHXATZGB.js +0 -1
  209. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B4yeYYgL.js +0 -1
  210. package/payload/server/public/assets/treeView-SZITEDCU-CC7ouMFd.js +0 -1
  211. package/payload/server/public/assets/treemap-W4RFUUIX-CaCg27im.js +0 -1
  212. package/payload/server/public/assets/useSubAccountSwitcher-DdctgpPL.js +0 -9
  213. package/payload/server/public/assets/wardley-RL74JXVD-bMPsqQZ7.js +0 -1
  214. /package/payload/server/public/assets/{_baseFor-k8hYPe-U.js → _baseFor-Bvwvhrz4.js} +0 -0
  215. /package/payload/server/public/assets/{array-BFDiaBgf.js → array-D3d-WgFW.js} +0 -0
  216. /package/payload/server/public/assets/{chunk-TPjIAO9U.js → chunk-fQC6bEKA.js} +0 -0
  217. /package/payload/server/public/assets/{cytoscape.esm-Ch0xptA4.js → cytoscape.esm-Cun-OM6a.js} +0 -0
  218. /package/payload/server/public/assets/{defaultLocale-ZeknFqNe.js → defaultLocale-CisKV5Ew.js} +0 -0
  219. /package/payload/server/public/assets/{init-0VJVrkRJ.js → init-D9ZOVaZ3.js} +0 -0
  220. /package/payload/server/public/assets/{katex-Br7bH10N.js → katex-C-3ZDK8o.js} +0 -0
  221. /package/payload/server/public/assets/{path-INs8XTPH.js → path-BMOgQSLM.js} +0 -0
  222. /package/payload/server/public/assets/{preload-helper-CH6UZRzu.js → preload-helper-DL2DwvxV.js} +0 -0
  223. /package/payload/server/public/assets/{rough.esm-DU9bZLvZ.js → rough.esm-BrTFrov0.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.497",
3
+ "version": "0.1.499",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -1,7 +1,5 @@
1
1
  export declare const SAME_SUBJECT_COSINE = 0.85;
2
- export declare const INJECTION_RULE_CAP = 12;
3
2
  export declare const ACTIVE_CANDIDATE_FLOOR = 0.4;
4
- export declare const ACTIVE_CANDIDATE_LIMIT = 30;
5
3
  export interface RuleCandidate {
6
4
  preferenceId: string;
7
5
  category: string;
@@ -19,9 +17,7 @@ export interface ActiveRule {
19
17
  confidence: number;
20
18
  observedAt: string;
21
19
  }
22
- export declare function cosine(a: number[], b: number[]): number;
23
- export declare function deconflictBySubject(records: RuleCandidate[], cosineThreshold?: number): ActiveRule[];
24
- export declare function formatStandingRulesBlock(rules: ActiveRule[], cap?: number): string;
20
+ export declare function formatStandingRulesBlock(rules: ActiveRule[]): string;
25
21
  interface MinimalSession {
26
22
  run: (q: string, p: Record<string, unknown>) => Promise<{
27
23
  records: Array<{
@@ -43,7 +39,7 @@ export interface StandingRulesInjection {
43
39
  }
44
40
  export declare function resolveOwnerUserId(session: MinimalSession, accountId: string): Promise<string | null>;
45
41
  export declare function queryActiveRuleCandidates(session: MinimalSession, accountId: string): Promise<RuleCandidate[]>;
46
- export declare function resolveActiveRules(session: MinimalSession, accountId: string, cap?: number): Promise<ActiveRuleResolution>;
47
- export declare function activeRuleSet(session: MinimalSession, accountId: string, cap?: number): Promise<ActiveRule[]>;
42
+ export declare function resolveActiveRules(session: MinimalSession, accountId: string): Promise<ActiveRuleResolution>;
43
+ export declare function activeRuleSet(session: MinimalSession, accountId: string): Promise<ActiveRule[]>;
48
44
  export {};
49
45
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAYvD;AAOD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,aAAa,EAAE,EACxB,eAAe,GAAE,MAA4B,GAC5C,UAAU,EAAE,CAgBd;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,UAAU,EAAE,EACnB,GAAG,GAAE,MAA2B,GAC/B,MAAM,CAIR;AAED,UAAU,cAAc;IACtB,GAAG,EAAE,CACH,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACvB,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC/D;AAMD,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,UAAU,GAAG,aAAa,CAAC;AACpE,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE/D,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAID,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,eAAe,CAAC;CACzB;AAOD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAaxB;AAoED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,EAAE,CAAC,CAE1B;AAGD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAA2B,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAG/B;AAID,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAA2B,GAC/B,OAAO,CAAC,UAAU,EAAE,CAAC,CAEvB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAKD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAIpE;AAED,UAAU,cAAc;IACtB,GAAG,EAAE,CACH,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACvB,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC/D;AAMD,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,UAAU,GAAG,aAAa,CAAC;AACpE,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE/D,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAID,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,eAAe,CAAC;CACzB;AAOD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAaxB;AAgED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,EAAE,CAAC,CAE1B;AAKD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC,CAI/B;AAID,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,CAAC,CAEvB"}
@@ -5,56 +5,25 @@
5
5
  // free of neo4j-driver types so both an MCP process and the UI can import the
6
6
  // built dist.
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ACTIVE_CANDIDATE_LIMIT = exports.ACTIVE_CANDIDATE_FLOOR = exports.INJECTION_RULE_CAP = exports.SAME_SUBJECT_COSINE = void 0;
9
- exports.cosine = cosine;
10
- exports.deconflictBySubject = deconflictBySubject;
8
+ exports.ACTIVE_CANDIDATE_FLOOR = exports.SAME_SUBJECT_COSINE = void 0;
11
9
  exports.formatStandingRulesBlock = formatStandingRulesBlock;
12
10
  exports.resolveOwnerUserId = resolveOwnerUserId;
13
11
  exports.queryActiveRuleCandidates = queryActiveRuleCandidates;
14
12
  exports.resolveActiveRules = resolveActiveRules;
15
13
  exports.activeRuleSet = activeRuleSet;
14
+ // Write-time only: profile-update routes a same-subject write (a neighbour at
15
+ // or above this raw-cosine threshold) into the existing node instead of minting
16
+ // a duplicate. Injection no longer dedups — it surfaces every stored active
17
+ // preference verbatim (Task 1951) — so this constant has no read-side use.
16
18
  exports.SAME_SUBJECT_COSINE = 0.85;
17
- exports.INJECTION_RULE_CAP = 12;
18
19
  exports.ACTIVE_CANDIDATE_FLOOR = 0.4;
19
- exports.ACTIVE_CANDIDATE_LIMIT = 30;
20
- function cosine(a, b) {
21
- if (!a.length || !b.length || a.length !== b.length)
22
- return 0;
23
- let dot = 0;
24
- let na = 0;
25
- let nb = 0;
26
- for (let i = 0; i < a.length; i++) {
27
- dot += a[i] * b[i];
28
- na += a[i] * a[i];
29
- nb += b[i] * b[i];
30
- }
31
- if (na === 0 || nb === 0)
32
- return 0;
33
- return dot / (Math.sqrt(na) * Math.sqrt(nb));
34
- }
35
- // records MUST be confidence-desc on entry. Greedy: the first record of a
36
- // cluster is the winner; any later record within cosineThreshold of an
37
- // already-kept winner is a rephrasing and is dropped. A record with no usable
38
- // embedding is never folded — it is kept as its own subject (we cannot prove it
39
- // is a duplicate).
40
- function deconflictBySubject(records, cosineThreshold = exports.SAME_SUBJECT_COSINE) {
41
- const winners = [];
42
- for (const r of records) {
43
- const emb = r.embedding;
44
- const isDup = Array.isArray(emb) &&
45
- emb.length > 0 &&
46
- winners.some((w) => Array.isArray(w.embedding) &&
47
- w.embedding.length > 0 &&
48
- cosine(emb, w.embedding) >= cosineThreshold);
49
- if (!isDup)
50
- winners.push(r);
51
- }
52
- return winners.map(({ embedding: _embedding, ...rest }) => rest);
53
- }
54
- function formatStandingRulesBlock(rules, cap = exports.INJECTION_RULE_CAP) {
20
+ // Render every rule verbatim. Injection has no cap (Task 1951): concision is
21
+ // enforced at write time by the conversational-memory skill so each stored
22
+ // value is already short, not by truncating the block here.
23
+ function formatStandingRulesBlock(rules) {
55
24
  if (rules.length === 0)
56
25
  return "";
57
- const lines = rules.slice(0, cap).map((r) => `- ${r.value}`);
26
+ const lines = rules.map((r) => `- ${r.value}`);
58
27
  return `## Standing rules\n${lines.join("\n")}`;
59
28
  }
60
29
  // The account's owner identity (Task 1461). One `AdminUser {role:'owner'}` is
@@ -80,11 +49,8 @@ async function resolveOwnerUserId(session, accountId) {
80
49
  // most-recent wins de-confliction. The trashed predicate mirrors graph-trash's
81
50
  // `notTrashed()` exactly (label + deletedAt) so this lib stays dependency-free.
82
51
  async function queryOwnerCandidates(session, accountId, ownerUserId) {
83
- // ACTIVE_CANDIDATE_LIMIT is inlined as a Cypher literal rather than bound as a
84
- // param: a plain JS number bound to `LIMIT $p` serializes as a FLOAT and Neo4j
85
- // rejects it ("not a valid value. Must be a non-negative integer"). This lib
86
- // is dependency-free (no neo4j-driver), so it cannot call `neo4j.int()`; the
87
- // constant is a hardcoded integer, so inlining it is safe and gate-clean.
52
+ // No LIMIT every owner admin preference above the floor is a candidate
53
+ // (Task 1951). The result is bounded by how many the owner has, not by a cap.
88
54
  const result = await session.run(`
89
55
  MATCH (up:UserProfile {accountId: $accountId, userId: $ownerUserId})-[:HAS_PREFERENCE]->(pref:Preference {scope: 'admin'})
90
56
  WHERE NOT pref:Trashed AND pref.deletedAt IS NULL
@@ -94,7 +60,6 @@ async function queryOwnerCandidates(session, accountId, ownerUserId) {
94
60
  pref.key AS key, pref.value AS value, pref.confidence AS confidence,
95
61
  pref.observedAt AS observedAt, pref.embedding AS embedding
96
62
  ORDER BY pref.confidence DESC, pref.observedAt DESC
97
- LIMIT ${exports.ACTIVE_CANDIDATE_LIMIT}
98
63
  `, { accountId, ownerUserId, floor: exports.ACTIVE_CANDIDATE_FLOOR });
99
64
  return result.records.map((r) => ({
100
65
  preferenceId: r.get("preferenceId"),
@@ -128,14 +93,17 @@ async function resolveCandidates(session, accountId) {
128
93
  async function queryActiveRuleCandidates(session, accountId) {
129
94
  return (await resolveCandidates(session, accountId)).candidates;
130
95
  }
131
- // The account's active, de-conflicted, bounded rule-set plus its provenance.
132
- async function resolveActiveRules(session, accountId, cap = exports.INJECTION_RULE_CAP) {
96
+ // The account's active rule-set plus its provenance. Every owner candidate is
97
+ // returned verbatim, in `confidence DESC, observedAt DESC` order — no cap, no
98
+ // de-confliction (Task 1951). Only the read-facing `embedding` is dropped.
99
+ async function resolveActiveRules(session, accountId) {
133
100
  const { candidates, ownerUserId, source } = await resolveCandidates(session, accountId);
134
- return { rules: deconflictBySubject(candidates).slice(0, cap), ownerUserId, source };
101
+ const rules = candidates.map(({ embedding: _embedding, ...rest }) => rest);
102
+ return { rules, ownerUserId, source };
135
103
  }
136
104
  // The rule array alone — the unchanged call boundary for profile-read and the
137
105
  // ui/server injection wrapper.
138
- async function activeRuleSet(session, accountId, cap = exports.INJECTION_RULE_CAP) {
139
- return (await resolveActiveRules(session, accountId, cap)).rules;
106
+ async function activeRuleSet(session, accountId) {
107
+ return (await resolveActiveRules(session, accountId)).rules;
140
108
  }
141
109
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,76 +1,12 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import {
3
- cosine,
4
- deconflictBySubject,
5
3
  formatStandingRulesBlock,
6
4
  resolveActiveRules,
7
5
  activeRuleSet,
8
6
  queryActiveRuleCandidates,
9
- INJECTION_RULE_CAP,
10
7
  type RuleCandidate,
11
8
  } from "./index.js";
12
9
 
13
- const vec = (n: number, fill: number): number[] => Array(n).fill(fill);
14
-
15
- function cand(over: Partial<RuleCandidate>): RuleCandidate {
16
- return {
17
- preferenceId: "p",
18
- category: "communication",
19
- key: "k",
20
- value: "v",
21
- confidence: 0.5,
22
- observedAt: "2026-07-01T00:00:00Z",
23
- embedding: vec(4, 1),
24
- ...over,
25
- };
26
- }
27
-
28
- describe("cosine", () => {
29
- it("is 1 for identical vectors and 0 for an empty one", () => {
30
- expect(cosine([1, 0, 0], [1, 0, 0])).toBeCloseTo(1, 6);
31
- expect(cosine([], [1, 2, 3])).toBe(0);
32
- });
33
- });
34
-
35
- describe("deconflictBySubject", () => {
36
- it("folds a near-duplicate into the higher-confidence winner", () => {
37
- const a = cand({
38
- preferenceId: "a",
39
- key: "header_rule",
40
- value: "use header A",
41
- confidence: 0.8,
42
- embedding: [1, 0, 0, 0],
43
- });
44
- const b = cand({
45
- preferenceId: "b",
46
- key: "doc_header",
47
- value: "use header A restated",
48
- confidence: 0.5,
49
- embedding: [0.99, 0.01, 0, 0],
50
- });
51
- const out = deconflictBySubject([a, b], 0.85);
52
- expect(out.map((r) => r.preferenceId)).toEqual(["a"]);
53
- });
54
-
55
- it("keeps genuinely different subjects", () => {
56
- const a = cand({ preferenceId: "a", embedding: [1, 0, 0, 0] });
57
- const b = cand({ preferenceId: "b", embedding: [0, 1, 0, 0] });
58
- expect(deconflictBySubject([a, b], 0.85).map((r) => r.preferenceId)).toEqual([
59
- "a",
60
- "b",
61
- ]);
62
- });
63
-
64
- it("never folds a candidate with no embedding", () => {
65
- const a = cand({ preferenceId: "a", embedding: [1, 0, 0, 0] });
66
- const b = cand({ preferenceId: "b", embedding: null });
67
- expect(deconflictBySubject([a, b], 0.85).map((r) => r.preferenceId)).toEqual([
68
- "a",
69
- "b",
70
- ]);
71
- });
72
- });
73
-
74
10
  // A fake Neo4j session that dispatches on query text: the owner-resolution
75
11
  // query (matches `role: 'owner'`) returns a configurable owner userId or none;
76
12
  // the candidate query (matches HAS_PREFERENCE) returns configurable pref rows
@@ -115,7 +51,7 @@ const prefRow = (over: Partial<RuleCandidate>): Record<string, unknown> => ({
115
51
  ...over,
116
52
  });
117
53
 
118
- describe("resolveActiveRules — owner-scoped selection", () => {
54
+ describe("resolveActiveRules — owner-scoped, uncapped, verbatim", () => {
119
55
  it("returns the owner's prefs with source=owner when an owner exists", async () => {
120
56
  const s = fakeSession({
121
57
  ownerId: "owner-35fed05e",
@@ -132,6 +68,36 @@ describe("resolveActiveRules — owner-scoped selection", () => {
132
68
  expect(s.candidateRuns).toBe(1);
133
69
  });
134
70
 
71
+ it("returns MORE than 12 candidates with no cap and no truncation", async () => {
72
+ const rows = Array.from({ length: 20 }, (_, i) =>
73
+ prefRow({
74
+ preferenceId: `p${i}`,
75
+ value: `rule ${i}`,
76
+ confidence: 1 - i * 0.01,
77
+ }),
78
+ );
79
+ const s = fakeSession({ ownerId: "owner-x", prefRows: rows });
80
+ const res = await resolveActiveRules(s, "acct-1");
81
+ expect(res.rules.length).toBe(20);
82
+ expect(res.rules.map((r) => r.preferenceId)).toEqual(
83
+ rows.map((r) => r.preferenceId),
84
+ );
85
+ });
86
+
87
+ it("preserves the candidate order verbatim (no reordering, no dedup)", async () => {
88
+ // Two rows that a cosine dedup would once have folded (identical embeddings)
89
+ // are BOTH returned now — injection never dedups.
90
+ const s = fakeSession({
91
+ ownerId: "owner-1",
92
+ prefRows: [
93
+ prefRow({ preferenceId: "a", value: "use header A", embedding: [1, 0, 0, 0] }),
94
+ prefRow({ preferenceId: "b", value: "use header A restated", embedding: [1, 0, 0, 0] }),
95
+ ],
96
+ });
97
+ const res = await resolveActiveRules(s, "acct-1");
98
+ expect(res.rules.map((r) => r.preferenceId)).toEqual(["a", "b"]);
99
+ });
100
+
135
101
  it("returns empty with source=no-owner and never runs the candidate query", async () => {
136
102
  const s = fakeSession({ ownerId: null });
137
103
  const res = await resolveActiveRules(s, "acct-1");
@@ -176,10 +142,10 @@ describe("resolveActiveRules — owner-scoped selection", () => {
176
142
 
177
143
  describe("formatStandingRulesBlock", () => {
178
144
  it("returns empty string for no rules", () => {
179
- expect(formatStandingRulesBlock([], INJECTION_RULE_CAP)).toBe("");
145
+ expect(formatStandingRulesBlock([])).toBe("");
180
146
  });
181
147
 
182
- it("caps the number of rendered rules", () => {
148
+ it("renders every rule, with no cap", () => {
183
149
  const rules = Array.from({ length: 20 }, (_, i) => ({
184
150
  preferenceId: `p${i}`,
185
151
  category: "communication",
@@ -188,8 +154,8 @@ describe("formatStandingRulesBlock", () => {
188
154
  confidence: 1 - i * 0.01,
189
155
  observedAt: "2026-07-01T00:00:00Z",
190
156
  }));
191
- const block = formatStandingRulesBlock(rules, 12);
157
+ const block = formatStandingRulesBlock(rules);
192
158
  expect(block).toContain("## Standing rules");
193
- expect((block.match(/^- /gm) ?? []).length).toBe(12);
159
+ expect((block.match(/^- /gm) ?? []).length).toBe(20);
194
160
  });
195
161
  });
@@ -4,10 +4,12 @@
4
4
  // free of neo4j-driver types so both an MCP process and the UI can import the
5
5
  // built dist.
6
6
 
7
+ // Write-time only: profile-update routes a same-subject write (a neighbour at
8
+ // or above this raw-cosine threshold) into the existing node instead of minting
9
+ // a duplicate. Injection no longer dedups — it surfaces every stored active
10
+ // preference verbatim (Task 1951) — so this constant has no read-side use.
7
11
  export const SAME_SUBJECT_COSINE = 0.85;
8
- export const INJECTION_RULE_CAP = 12;
9
12
  export const ACTIVE_CANDIDATE_FLOOR = 0.4;
10
- export const ACTIVE_CANDIDATE_LIMIT = 30;
11
13
 
12
14
  export interface RuleCandidate {
13
15
  preferenceId: string;
@@ -28,52 +30,12 @@ export interface ActiveRule {
28
30
  observedAt: string;
29
31
  }
30
32
 
31
- export function cosine(a: number[], b: number[]): number {
32
- if (!a.length || !b.length || a.length !== b.length) return 0;
33
- let dot = 0;
34
- let na = 0;
35
- let nb = 0;
36
- for (let i = 0; i < a.length; i++) {
37
- dot += a[i] * b[i];
38
- na += a[i] * a[i];
39
- nb += b[i] * b[i];
40
- }
41
- if (na === 0 || nb === 0) return 0;
42
- return dot / (Math.sqrt(na) * Math.sqrt(nb));
43
- }
44
-
45
- // records MUST be confidence-desc on entry. Greedy: the first record of a
46
- // cluster is the winner; any later record within cosineThreshold of an
47
- // already-kept winner is a rephrasing and is dropped. A record with no usable
48
- // embedding is never folded — it is kept as its own subject (we cannot prove it
49
- // is a duplicate).
50
- export function deconflictBySubject(
51
- records: RuleCandidate[],
52
- cosineThreshold: number = SAME_SUBJECT_COSINE,
53
- ): ActiveRule[] {
54
- const winners: RuleCandidate[] = [];
55
- for (const r of records) {
56
- const emb = r.embedding;
57
- const isDup =
58
- Array.isArray(emb) &&
59
- emb.length > 0 &&
60
- winners.some(
61
- (w) =>
62
- Array.isArray(w.embedding) &&
63
- w.embedding.length > 0 &&
64
- cosine(emb, w.embedding) >= cosineThreshold,
65
- );
66
- if (!isDup) winners.push(r);
67
- }
68
- return winners.map(({ embedding: _embedding, ...rest }) => rest);
69
- }
70
-
71
- export function formatStandingRulesBlock(
72
- rules: ActiveRule[],
73
- cap: number = INJECTION_RULE_CAP,
74
- ): string {
33
+ // Render every rule verbatim. Injection has no cap (Task 1951): concision is
34
+ // enforced at write time by the conversational-memory skill so each stored
35
+ // value is already short, not by truncating the block here.
36
+ export function formatStandingRulesBlock(rules: ActiveRule[]): string {
75
37
  if (rules.length === 0) return "";
76
- const lines = rules.slice(0, cap).map((r) => `- ${r.value}`);
38
+ const lines = rules.map((r) => `- ${r.value}`);
77
39
  return `## Standing rules\n${lines.join("\n")}`;
78
40
  }
79
41
 
@@ -139,11 +101,8 @@ async function queryOwnerCandidates(
139
101
  accountId: string,
140
102
  ownerUserId: string,
141
103
  ): Promise<RuleCandidate[]> {
142
- // ACTIVE_CANDIDATE_LIMIT is inlined as a Cypher literal rather than bound as a
143
- // param: a plain JS number bound to `LIMIT $p` serializes as a FLOAT and Neo4j
144
- // rejects it ("not a valid value. Must be a non-negative integer"). This lib
145
- // is dependency-free (no neo4j-driver), so it cannot call `neo4j.int()`; the
146
- // constant is a hardcoded integer, so inlining it is safe and gate-clean.
104
+ // No LIMIT every owner admin preference above the floor is a candidate
105
+ // (Task 1951). The result is bounded by how many the owner has, not by a cap.
147
106
  const result = await session.run(
148
107
  `
149
108
  MATCH (up:UserProfile {accountId: $accountId, userId: $ownerUserId})-[:HAS_PREFERENCE]->(pref:Preference {scope: 'admin'})
@@ -154,7 +113,6 @@ async function queryOwnerCandidates(
154
113
  pref.key AS key, pref.value AS value, pref.confidence AS confidence,
155
114
  pref.observedAt AS observedAt, pref.embedding AS embedding
156
115
  ORDER BY pref.confidence DESC, pref.observedAt DESC
157
- LIMIT ${ACTIVE_CANDIDATE_LIMIT}
158
116
  `,
159
117
  { accountId, ownerUserId, floor: ACTIVE_CANDIDATE_FLOOR },
160
118
  );
@@ -201,14 +159,16 @@ export async function queryActiveRuleCandidates(
201
159
  return (await resolveCandidates(session, accountId)).candidates;
202
160
  }
203
161
 
204
- // The account's active, de-conflicted, bounded rule-set plus its provenance.
162
+ // The account's active rule-set plus its provenance. Every owner candidate is
163
+ // returned verbatim, in `confidence DESC, observedAt DESC` order — no cap, no
164
+ // de-confliction (Task 1951). Only the read-facing `embedding` is dropped.
205
165
  export async function resolveActiveRules(
206
166
  session: MinimalSession,
207
167
  accountId: string,
208
- cap: number = INJECTION_RULE_CAP,
209
168
  ): Promise<ActiveRuleResolution> {
210
169
  const { candidates, ownerUserId, source } = await resolveCandidates(session, accountId);
211
- return { rules: deconflictBySubject(candidates).slice(0, cap), ownerUserId, source };
170
+ const rules = candidates.map(({ embedding: _embedding, ...rest }) => rest);
171
+ return { rules, ownerUserId, source };
212
172
  }
213
173
 
214
174
  // The rule array alone — the unchanged call boundary for profile-read and the
@@ -216,7 +176,6 @@ export async function resolveActiveRules(
216
176
  export async function activeRuleSet(
217
177
  session: MinimalSession,
218
178
  accountId: string,
219
- cap: number = INJECTION_RULE_CAP,
220
179
  ): Promise<ActiveRule[]> {
221
- return (await resolveActiveRules(session, accountId, cap)).rules;
180
+ return (await resolveActiveRules(session, accountId)).rules;
222
181
  }
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
- content-hash: sha256:5db8891dfc1b60b2180597591dcad1b7ca9e89612f488314dd07e7dd73e5c119
4
+ content-hash: sha256:de872279f0c40b8dee0a8ef51dba6534e2452d6034ca2765d6ab912447bc95b3
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -1905,6 +1905,22 @@ A site capture becomes one of these too: an enquiry becomes a new contact routed
1905
1905
 
1906
1906
  Run a sweep a second time and it proposes nothing it already recorded on the first run, because those records are now in memory and it recognises them. A repeat sweep is quiet on purpose; that is the sign your graph is already up to date.
1907
1907
 
1908
+ ## Automatic email→graph sweep (opt-in)
1909
+
1910
+ The sweep above runs only when you ask, and it proposes rather than writes. There is a second, opt-in routine that runs on a schedule and writes on its own: the automatic email→graph sweep, set up through the `email-graph-sweep` skill. On each run it reads the new inbound mail on your mailbox, pulls out the organisations, people, and live jobs it finds, checks each against what Maxy already holds, saves the genuinely new ones, and then sends you a short report of what it read and saved.
1911
+
1912
+ Turning it on needs two things, and Maxy tells you which is missing if either is absent:
1913
+
1914
+ - **A connected mailbox.** The routine reads your mail, so a mail account (a standard IMAP mailbox, or a Microsoft 365 mailbox) must be connected. With no mailbox connected there is nothing to sweep, and Maxy says so instead of switching anything on.
1915
+ - **A place to send the report.** The routine reports over a persistent channel, so you name the WhatsApp number or Telegram chat that receives it, and that destination must already be registered as an admin or account-manager. If it is not registered, Maxy tells you that rather than falling back to a silent run.
1916
+
1917
+ Two things to know before you switch it on:
1918
+
1919
+ - **It messages you on every run.** It is a report you receive each time, not a silent background job. If you want a quiet, always-on tidy-up of the graph instead, that is a different routine.
1920
+ - **It is one-account, deliberate opt-in.** Maxy does not turn this on for you automatically, and it is held back from broad rollout for now while a safety fix for scheduled runs lands. Enable it for an account you are watching, not as a default.
1921
+
1922
+ Turn it off with the same skill: ask to stop the automatic email sweep and Maxy cancels the schedule, so no further runs fire.
1923
+
1908
1924
  ---
1909
1925
  # Slides
1910
1926
  Source: https://docs.getmaxy.com/slides.md
@@ -2994,6 +3010,35 @@ either is a regression.
2994
3010
 
2995
3011
  **Public visitor surface.** The public-host root (`GET /`), the `/:slug` agent routes, and the admin-host `/public` / `/public-chat` previews all serve one shell, `public.html` → [`app/public-entry.tsx`](../../../ui/app/public-entry.tsx) → `PublicChat`. `PublicChat` reuses `useSession` purely as the magic-link gatekeeper — it drives `AccessGate`, resolves the agent slug from the path, and handles `?token=` verification; once the grant is satisfied it mounts `ChatSurface variant="public"`, whose transcript reads the visitor-scoped, **delivered-only** stream `GET /api/public-reader/stream` ([`server/routes/public-reader.ts`](../../../ui/server/routes/public-reader.ts)) — the visitor sees the agent's delivered prose, never the tool/tool-result/directive bytes the legacy `/api/chat` SSE render exposed. The human visitor's branding is resolved client-side by `useSession`. For the head only, the server injects per-agent link-preview meta — `<title>`, `og:title`/`og:description`/`og:image`, `theme-color`, and a per-agent favicon, resolved from the same branding cache `useSession` reads — into the served shell, so a link-preview crawler (which never runs the client bundle) gets a branded card per agent instead of one generic shell; an agent with no branding cache gets the clean brand-default shell with no empty meta tags. There is exactly one public client surface and it is 1:1 visitor↔agent: the earlier `?surface=next` A/B handle is retired, group messaging is retired (not a supported product surface), and a former `/g/<slug>` group URL now serves the same 1:1 shell — a stale bookmark gets the 1:1 chat, never a broken render.
2996
3012
 
3013
+ ### Routines
3014
+
3015
+ The Routines surface (`/routines`) is the admin view of the account's
3016
+ automation `:Event` nodes — the device's scheduled agent turns and tool
3017
+ dispatches, which the Calendar surface deliberately excludes (`calendar.ts`
3018
+ unions only appointment events, `actionPlugin IS NULL`). It renders one card per
3019
+ routine (title, human-readable schedule, next run, channel/destination or tool,
3020
+ status); a card opens a detail modal modeled on the calendar `EventDetailModal`.
3021
+ The modal edits the prose instruction (`agentPrompt`, agent-dispatch routines
3022
+ only) and the schedule via a friendly builder (frequency daily/weekly/monthly,
3023
+ day-of-week, day-of-month, time) that falls back to a raw-cron field for patterns
3024
+ it cannot represent.
3025
+
3026
+ The route (`server/routes/admin/routines.ts`) is account-scoped like `calendar.ts`
3027
+ (a foreign-account or non-automation `eventId` 404s):
3028
+
3029
+ | Route | Behaviour |
3030
+ |-------|-----------|
3031
+ | `GET /api/admin/routines` | Lists automation Events: `recurrence IS NOT NULL OR agentChannel IS NOT NULL OR actionPlugin IS NOT NULL`. Keyed by the `eventId` property. |
3032
+ | `GET /api/admin/routines/:eventId` | One routine, same automation+account guard. |
3033
+ | `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt` and/or `recurrence`. Cron validation and the timezone-aware `nextRun` recompute copy the scheduling plugin's `schedule-update` tool. An invalid cron is rejected 400 with no write. Only creation and deletion stay agent-only (`schedule-event`/`schedule-cancel`). |
3034
+
3035
+ Observability rides `[admin:routines]`: `op=list accountId=<8> count=<n>`,
3036
+ `op=get id=<8> found=<bool>`, and `op=patch id=<8> fields=<…> outcome=ok|rejected
3037
+ reason=<invalid-cron|not-found> nextRun=<…> cron=<serialized>`. A `count=0` while
3038
+ routines exist for the account is the account-scope-miss signature; the logged
3039
+ `cron=` on `outcome=ok` confirms the persisted expression without opening the
3040
+ graph.
3041
+
2997
3042
  ### Graph
2998
3043
 
2999
3044
  | Mount | Purpose |
@@ -3302,12 +3347,13 @@ authoritative. This section names the surfaces and what backs each.
3302
3347
  > owns all navigation; the full-width top header bar, the burger flyout, and the
3303
3348
  > "Powered by Claude Code" footer strip are retired. After the redesign:
3304
3349
  >
3305
- > - **Nav rows** are Dashboard, Chat, Tasks, Calendar, Data, the brand container
3306
- > row (Projects / Properties / Jobs, opening the graph filtered to the brand's
3307
- > primary container), Graph (the unfiltered whole graph at `/graph`, waypoints
3308
- > icon active on plain `/graph`; the container row is active only when a
3309
- > `label=` filter is present), Activity, and Browser. The active row carries an
3310
- > accent left indicator. The older People / Agents / Artefacts entries in the
3350
+ > - **Nav rows** are Dashboard, Chat, Tasks, Calendar, Routines (the automation
3351
+ > `:Event` nodes at `/routines`, `Zap` icon), Data, the brand container
3352
+ > row (Projects / Properties / Jobs, `Folder` icon, opening the graph filtered
3353
+ > to the brand's primary container), Graph (the unfiltered whole graph at
3354
+ > `/graph`, waypoints icon active on plain `/graph`; the container row is
3355
+ > active only when a `label=` filter is present), Activity, and Browser. The
3356
+ > active row carries an accent left indicator. The older People / Agents / Artefacts entries in the
3311
3357
  > table below are pre-redesign.
3312
3358
  > - **Dashboard home** renders on `/` (a greeting, stat cards, a Live-now column,
3313
3359
  > a Recent artefacts card, and a Channels column), consuming existing endpoints
@@ -4244,13 +4290,13 @@ Standing rules the operator gives over a channel are `Preference` nodes. Two mec
4244
4290
 
4245
4291
  **Reconcile by meaning on write (`profile-update`).** The existence check is two-tier. First an exact `(category, key)` match — the classic fast path, unchanged. When that misses, a semantic-neighbour lookup runs over the `preference_embedding` vector index, scoped to the same `accountId` and `scope:'admin'`, non-trashed. If the nearest neighbour is at or above `SAME_SUBJECT_COSINE` (0.85), the write lands on that node through the existing reinforce/update/contradict curve instead of minting a duplicate; the matched neighbours are returned in the tool result so the agent can classify future writes against real prior state. The confidence constants are unchanged — only the join key widens, so a rephrasing under a new `key` no longer forks the rule and a correction demotes the prior node rather than adding a contradictory one.
4246
4292
 
4247
- **Inject the active rule-set every turn (channel gateways).** The one definition of "this account's active rules" is `@maxy/active-rules`: the account owner's admin-scope preferences (resolve the seeded `AdminUser {role:'owner'}`, then select through that owner's `UserProfile` via `HAS_PREFERENCE`), a bounded, floor-filtered (`confidence >= 0.4`), confidence-ordered candidate query, then semantic de-confliction (one winner per subject at the same 0.85 cosine), capped to `INJECTION_RULE_CAP` (12). A preference owned by a non-owner profile (an operator's, stranded on the operator's own profile while managing the account) is never injected; an account with no seeded owner injects nothing. `profile-read` exposes this same owner-scoped set as `activeRules`, and the three inbound gateways (`wa-gateway`, `telegram-gateway`, `webchat-gateway`) fetch it for the effective session account and attach it as `standingRules` on the inbound frame; the channel builders prepend it as a `## Standing rules` block above `## Context`. Both channel-server inbound paths carry the block: the single-target SSE loop parses the whole frame, and the unified multi-target door reader (`runDoorStream`,) reconstructs it through the shared `doorInboundPayload` seam whose `parseFrame` closures read `standingRules` off the frame. The read is by code, not agent discretion, so a rule set last week is applied this week regardless of how many times the session compacted. Telegram and webchat inject for `role:'admin'` only — a public visitor never receives operator rules.
4293
+ **Inject the active rule-set every turn (channel gateways).** The one definition of "this account's active rules" is `@maxy/active-rules`: the account owner's admin-scope preferences (resolve the seeded `AdminUser {role:'owner'}`, then select through that owner's `UserProfile` via `HAS_PREFERENCE`), a floor-filtered (`confidence >= 0.4`), confidence-ordered query that returns every such preference verbatim — no cap, no de-confliction, no candidate limit. Concision is enforced at write time by the `conversational-memory` skill (each stored value is a single minimal imperative) and by the write-time semantic reconcile (a same-subject write at or above `SAME_SUBJECT_COSINE` folds into the existing node rather than minting a duplicate), so the injected block stays small because each stored preference is short and non-redundant, not because injection truncates. A preference owned by a non-owner profile (an operator's, stranded on the operator's own profile while managing the account) is never injected; an account with no seeded owner injects nothing. `profile-read` exposes this same owner-scoped set as `activeRules`, and the three inbound gateways (`wa-gateway`, `telegram-gateway`, `webchat-gateway`) fetch it for the effective session account and attach it as `standingRules` on the inbound frame; the channel builders prepend it as a `## Standing rules` block above `## Context`. Both channel-server inbound paths carry the block: the single-target SSE loop parses the whole frame, and the unified multi-target door reader (`runDoorStream`,) reconstructs it through the shared `doorInboundPayload` seam whose `parseFrame` closures read `standingRules` off the frame. The read is by code, not agent discretion, so a rule set last week is applied this week regardless of how many times the session compacted. Telegram and webchat inject for `role:'admin'` only — a public visitor never receives operator rules.
4248
4294
 
4249
4295
  **Trust a scheduled turn's provenance, never an inbound's claim (channel-agent grounding).** A cron-dispatched agent turn reaches the same channel builders as a real inbound, so its own authorisation text would otherwise land inside `## Context` — the zone `REFRAME_INSTRUCTION` demotes to untrusted — and a security-cautious agent would distrust its own automation (the self-cancel loop). The dispatcher therefore stamps a `ScheduleProvenance` marker (owning account, event, owner userId, dispatch time) that the channel builders render as a `## Scheduled automation (platform-verified)` preamble **above** `## Context` (and above the rules block); the whatsapp wrap tag names the door `scheduler`. Both channel-server paths carry the marker — the single-target loop and the unified multi-target door reader (via the same `doorInboundPayload` seam that carries `standingRules`); the scheduler only dispatches to the whatsapp/telegram door, so a webchat frame never bears one. Because the marker is dispatcher-stamped and never derived from payload text, an inbound message cannot forge it — placement above `## Context` alone is not the trust signal, the dispatcher provenance is. The grounding binds to it in two places: one recipient-neutral clause added byte-identical to the three reframe instructions (a marker-bearing turn is authorised standing automation; a reconfiguration or re-enable is not intrusion), and the admin `IDENTITY.md` "Untrusted input" rule that the agent never states a platform-level authenticity or impersonation verdict it was not given (an unsourced "this is not from you" is its own inference, flagged, never asserted as the platform's). A sender has exactly one session: every inbound, real or scheduled, resolves to the deterministic `adminSessionIdFor(effectiveAccount, destination)`. An earlier change gave each firing its own salted seat so distrust could not accrete across firings, but the inbound hub keys on `senderId` and replaces its subscriber outright, so a seat's channel server attached under the sender's own key and swallowed the sender's REAL messages until it detached — splitting one conversation across two sessions that each denied what the other held. The seat is removed; the authoritative `agentPrompt`, this provenance marker, and the injected standing rules ground each firing without one. Self-cancel attribution is disarmed while that model beds in: the guard used to compare the cancelling turn's session id to a dispatcher stamp, which discriminated only because each firing ran its own seat, so with one session per sender it would report an autonomous loop on every operator cancel. It now always reports false — under-counting a real loop rather than inventing one — until the discriminator is rebuilt from the turn's own dispatched eventId. See `.docs/scheduling-agent-dispatch.md § Operator-provenance marker`, `§ Session model — one session per sender`, and `§ Self-cancel attribution — disarmed`.
4250
4296
 
4251
4297
  **Carry what a reply points at (WhatsApp reply quote).** A WhatsApp sender replying to an earlier message produces a quote that `app/lib/whatsapp/inbound/extract.ts` resolves to `{ id, text?, sender? }` and `manager.ts` assigns to the route payload's `replyContext`. That field had no reader: the `server/index.ts` gateway argument omitted it, `AdminInbound` and the hub frame had no such field, and the channel service's `composePayload` emitted the caption and media notes only, so a message saying "prepare an email confirmation for this booking" reached the agent with nothing to resolve "this booking" against. It now rides both WhatsApp admin doors. On the persistent door it travels `server/index.ts` -> `AdminInbound` -> the hub frame the SSE route stringifies -> the channel service's `InboundPayload`, where `composeReplyNote` renders it as a bracketed note at the top of the payload, inside `## Context` and above the caption and any woven media notes: the quoted body is sender-controlled and belongs in the reframed untrusted zone, never in the platform preamble. Both channel-server inbound paths carry it, through the same `doorInboundPayload` seam that carries `standingRules` and the schedule provenance marker: the single-target SSE loop parses the whole frame, and the unified multi-target door reader rebuilds the payload field by field, so a field that seam omits is dropped on multi-target sessions alone. That seam is guarded by a test which reads the `InboundPayload` declaration and the rebuild function rather than a fixture, because the pre-existing byte-identity guard compared one hardcoded payload and so stayed green for every field added after it was written. On the passive account-manager door there is no channel server and no `## Context` frame, so the one-shot's whole initial prompt is read at face value; `composePassivePrompt` therefore puts the BARE sentence above the requirement and never the quoted body. The body arrives from the sender's own client and is never checked against the message store, so quoting it in a platform-voiced bracket on the door with no untrusted zone would let a modified client put words the agent never said into a `work-create` filing. The empty-text drop gate still tests the requirement alone, so a quote never rescues an inbound carrying no requirement of its own. The quoted body is capped at `QUOTED_TEXT_CAP` (500 characters, `…` appended when cut) because it is unbounded sender-controlled input, and the cut lands on whole characters so a body whose 500th boundary falls inside a surrogate pair cannot emit a lone surrogate at a position the sender chose. Only the channel service renders a body, so the cap lives there alone; platform/ui's `app/lib/whatsapp/reply-quote.ts` holds just the bare sentence for the passive door, and both packages hardcode that sentence in their own tests so the two doors cannot drift apart on the wording (the packages never cross-import, the same arrangement `REFRAME_INSTRUCTION` and `MediaRef` use). Telegram and webchat extract no quote at all, so neither carries one. `payloadBytes` measures the whole inner payload, so a reply carrying a quote produces a visibly larger `[reframe] op=applied … payloadBytes=<n>` than the same text without one, and a bare-text-length `payloadBytes` on an inbound whose store row has a non-null `quotedId` is the signature of this defect returning. Because the field is optional at every hop, dropping it from either `server/index.ts` argument would be silent (tsc stays green, and no unit test executes that wiring file), so the `check-reply-context-threaded` build gate asserts both argument sites.
4252
4298
 
4253
- **Observability.** `[preference-write] op=reconcile … mode=<reinforce|update|contradict|new> similarity=…` — a stream of `mode=new` for subjects that already exist is the duplicate-minting signature. `[preference-inject] op=inject channel=<wa|tg|web> injected=<N> owner=<8> source=<owner|no-owner|owner-error|fetch-error>` — injection selects only the account owner's admin preferences, so `source=owner injected=0` is a genuinely empty owner, `source=no-owner` is an account with no seeded owner (injects nothing, a missed owner seeding), and `injected=0 source=owner` on an account whose owner holds rules is the write-only regression re-appearing. `[preference-audit] op=drift accountId=… storedActive=… injectedActive=… duplicateClusters=…` — the standing reconciliation audit (claude-session-manager, 5-minute tick) flags any account whose store holds more active rows than injection would surface, the no-event detector for drift.
4299
+ **Observability.** `[preference-write] op=reconcile … mode=<reinforce|update|contradict|new> similarity=…` — a stream of `mode=new` for subjects that already exist is the duplicate-minting signature. `[preference-inject] op=inject channel=<wa|tg|web> injected=<N> owner=<8> source=<owner|no-owner|owner-error|fetch-error>` — injection selects only the account owner's admin preferences, so `source=owner injected=0` is a genuinely empty owner, `source=no-owner` is an account with no seeded owner (injects nothing, a missed owner seeding), and `injected=0 source=owner` on an account whose owner holds rules is the write-only regression re-appearing. `[preference-inject] op=reconcile accountId=… stored=… injected=…` — the standing reconciliation audit (claude-session-manager, 5-minute tick) flags any account whose stored active count diverges from what injection surfaces; injection now surfaces every stored active preference verbatim, so `stored == injected` is the healthy signal and any gap is a dropped-row regression (a reintroduced cap, filter, or truncation). A clean pass logs `op=reconcile drifted=0`, the no-event detector.
4254
4300
 
4255
4301
  **Consult-before-send gate.** Injection (above) puts the owner's active rules in front of every channel turn, but the growing layer-2 `Preference` set is read on demand with `profile-read`, a per-turn judgement the agent can skip, the miss that dropped a customer signature on a delivered document. `hooks/preference-consult-gate.sh` (admin plugin) is the deliverable-boundary enforcement: a PreToolUse gate on customer-facing document deliverables (`browser-pdf-save`/`SendUserFile` to `memory/users/<phone>/documents/`, and email/Outlook sends carrying attachments) that blocks (exit 2) when no `profile-read` ran after the last user message in the transcript. It fires on documents only, never on casual replies. **Observability:** `[preference-gate] op=allow tool=<name> consulted=true` on an allowed document deliverable, `op=bypass tool=<name> detail=no profile-read this turn` on a block; a stream of `op=bypass` is the un-consulted-send signature. The advisory companion `hooks/preference-consult-directive.sh` injects the two-layer architecture reminder every turn (`[pref-wrapper] op=inject`). The placement half, promoting finished deliverables out of `output/` scratch, is counted by the `data-manager` reconcile audit (`scratch-refs`, `stranded`); making that audit run on a standing periodic cadence is a filed follow-up.
4256
4302