@almadar/std 16.235.0 → 16.236.0

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 (244) hide show
  1. package/behaviors/behaviors-registry.json +4402 -1898
  2. package/behaviors/lolo/infra/atoms/std-approval-gate.lolo +25 -41
  3. package/behaviors/lolo/infra/atoms/std-audit-capture.lolo +0 -5
  4. package/behaviors/lolo/infra/atoms/std-cache-aside.lolo +0 -24
  5. package/behaviors/lolo/infra/atoms/std-circuit-breaker.lolo +1 -17
  6. package/behaviors/lolo/infra/atoms/std-data-erasure.lolo +17 -24
  7. package/behaviors/lolo/infra/atoms/std-data-import.lolo +8 -11
  8. package/behaviors/lolo/infra/atoms/std-game-clock.lolo +2 -0
  9. package/behaviors/lolo/infra/atoms/std-knowledge-loop.lolo +0 -5
  10. package/behaviors/lolo/infra/atoms/std-lifecycle.lolo +3 -1
  11. package/behaviors/lolo/infra/atoms/std-mod-queue.lolo +40 -18
  12. package/behaviors/lolo/infra/atoms/std-notification-preferences.lolo +20 -11
  13. package/behaviors/lolo/infra/atoms/std-notify-on-event.lolo +0 -5
  14. package/behaviors/lolo/infra/atoms/std-permission-matrix.lolo +23 -11
  15. package/behaviors/lolo/infra/atoms/std-rate-limiter.lolo +84 -22
  16. package/behaviors/lolo/infra/atoms/std-status-lifecycle.lolo +1 -6
  17. package/behaviors/lolo/ml/atoms/std-graph-builder.lolo +3 -1
  18. package/behaviors/lolo/ml/atoms/std-ml-classify.lolo +0 -4
  19. package/behaviors/lolo/ml/atoms/std-ml-similarity.lolo +0 -4
  20. package/behaviors/lolo/ui/avl/atoms/ui-avl-state-machine.lolo +12 -0
  21. package/behaviors/lolo/ui/core/atoms/std-app-layout.lolo +55 -9
  22. package/behaviors/lolo/ui/core/atoms/std-app-search.lolo +6 -2
  23. package/behaviors/lolo/ui/core/atoms/std-billable-hour.lolo +19 -14
  24. package/behaviors/lolo/ui/core/atoms/std-board.lolo +77 -27
  25. package/behaviors/lolo/ui/core/atoms/std-browse.lolo +44 -28
  26. package/behaviors/lolo/ui/core/atoms/std-calendar.lolo +7 -3
  27. package/behaviors/lolo/ui/core/atoms/std-esign-flow.lolo +25 -13
  28. package/behaviors/lolo/ui/core/atoms/std-esign-request.lolo +5 -0
  29. package/behaviors/lolo/ui/core/atoms/std-event-log.lolo +0 -5
  30. package/behaviors/lolo/ui/core/atoms/std-export.lolo +0 -10
  31. package/behaviors/lolo/ui/core/atoms/std-file-store.lolo +7 -3
  32. package/behaviors/lolo/ui/core/atoms/std-form-advanced.lolo +1 -6
  33. package/behaviors/lolo/ui/core/atoms/std-geosearch.lolo +1 -0
  34. package/behaviors/lolo/ui/core/atoms/std-graphs.lolo +20 -4
  35. package/behaviors/lolo/ui/core/atoms/std-import.lolo +0 -5
  36. package/behaviors/lolo/ui/core/atoms/std-list.lolo +46 -32
  37. package/behaviors/lolo/ui/core/atoms/std-modal-editor.lolo +2 -2
  38. package/behaviors/lolo/ui/core/atoms/std-rating-review.lolo +12 -13
  39. package/behaviors/lolo/ui/core/atoms/std-record-detail.lolo +16 -12
  40. package/behaviors/lolo/ui/core/atoms/std-recurrence.lolo +10 -1
  41. package/behaviors/lolo/ui/core/atoms/std-role-gate.lolo +39 -0
  42. package/behaviors/lolo/ui/core/atoms/std-saved-search.lolo +78 -16
  43. package/behaviors/lolo/ui/core/atoms/std-selection.lolo +15 -10
  44. package/behaviors/lolo/ui/core/atoms/std-stats.lolo +5 -5
  45. package/behaviors/lolo/ui/core/atoms/std-tag-taxonomy.lolo +3 -0
  46. package/behaviors/lolo/ui/core/atoms/std-thread.lolo +41 -73
  47. package/behaviors/lolo/ui/core/atoms/std-version-history.lolo +20 -11
  48. package/behaviors/lolo/ui/core/atoms/std-vote.lolo +0 -4
  49. package/behaviors/lolo/ui/core/atoms/std-wizard.lolo +3 -3
  50. package/behaviors/lolo/ui/core/atoms/ui-presence.lolo +21 -0
  51. package/behaviors/lolo/ui/core/molecules/ui-breadcrumb.lolo +6 -1
  52. package/behaviors/lolo/ui/core/molecules/ui-chart.lolo +11 -1
  53. package/behaviors/lolo/ui/core/molecules/ui-code-block.lolo +13 -8
  54. package/behaviors/lolo/ui/core/molecules/ui-command-palette.lolo +7 -2
  55. package/behaviors/lolo/ui/core/molecules/ui-commit-row.lolo +2 -2
  56. package/behaviors/lolo/ui/core/molecules/ui-confirm-dialog.lolo +8 -0
  57. package/behaviors/lolo/ui/core/molecules/ui-data-grid.lolo +41 -3
  58. package/behaviors/lolo/ui/core/molecules/ui-data-list.lolo +41 -3
  59. package/behaviors/lolo/ui/core/molecules/ui-document-details.lolo +30 -9
  60. package/behaviors/lolo/ui/core/molecules/ui-document-panel.lolo +8 -3
  61. package/behaviors/lolo/ui/core/molecules/ui-document-viewer.lolo +6 -1
  62. package/behaviors/lolo/ui/core/molecules/ui-drawer.lolo +13 -0
  63. package/behaviors/lolo/ui/core/molecules/ui-floating-action-button.lolo +6 -1
  64. package/behaviors/lolo/ui/core/molecules/ui-floating-toolbar.lolo +6 -1
  65. package/behaviors/lolo/ui/core/molecules/ui-form-actions.lolo +6 -1
  66. package/behaviors/lolo/ui/core/molecules/ui-graph-canvas.lolo +6 -1
  67. package/behaviors/lolo/ui/core/molecules/ui-menu.lolo +6 -1
  68. package/behaviors/lolo/ui/core/molecules/ui-meter.lolo +6 -1
  69. package/behaviors/lolo/ui/core/molecules/ui-modal.lolo +5 -0
  70. package/behaviors/lolo/ui/core/molecules/ui-page-header.lolo +11 -1
  71. package/behaviors/lolo/ui/core/molecules/ui-page-transition.lolo +1 -1
  72. package/behaviors/lolo/ui/core/molecules/ui-swipeable-row.lolo +44 -15
  73. package/behaviors/lolo/ui/core/molecules/ui-table-view.lolo +41 -3
  74. package/behaviors/lolo/ui/core/molecules/ui-tabs.lolo +8 -2
  75. package/behaviors/lolo/ui/core/organisms/ui-detail-panel.lolo +66 -12
  76. package/behaviors/lolo/ui/core/organisms/ui-entity-cards.lolo +9 -3
  77. package/behaviors/lolo/ui/core/organisms/ui-entity-list.lolo +9 -3
  78. package/behaviors/lolo/ui/core/organisms/ui-entity-table.lolo +18 -9
  79. package/behaviors/lolo/ui/core/organisms/ui-form-section.lolo +55 -10
  80. package/behaviors/lolo/ui/core/organisms/ui-form.lolo +55 -10
  81. package/behaviors/lolo/ui/core/organisms/ui-media-gallery.lolo +8 -3
  82. package/behaviors/lolo/ui/core/organisms/ui-state-machine-view.lolo +12 -0
  83. package/behaviors/lolo/ui/core/organisms/ui-timeline.lolo +8 -3
  84. package/behaviors/lolo/ui/core/templates/ui-counter-template.lolo +2 -44
  85. package/behaviors/lolo/ui/core/templates/ui-dashboard-layout.lolo +6 -1
  86. package/behaviors/lolo/ui/core/templates/ui-generic-app-template.lolo +2 -37
  87. package/behaviors/lolo/ui/game/atoms/ui-game-menu.lolo +8 -2
  88. package/behaviors/lolo/ui/game/organisms/std-arcade-board-3d.lolo +2 -2
  89. package/behaviors/lolo/ui/game/organisms/std-crew-board-2d.lolo +0 -4
  90. package/behaviors/lolo/ui/game/organisms/std-platformer-puzzle.lolo +2 -66
  91. package/behaviors/lolo/ui/game/organisms/std-tactics-board-2d.lolo +0 -4
  92. package/behaviors/lolo/ui/game/organisms/std-worldmap-board-2d.lolo +0 -4
  93. package/behaviors/lolo/ui/learning/atoms/std-learn-stepper.lolo +6 -6
  94. package/behaviors/lolo-behavior-contracts.json +1 -1
  95. package/behaviors/registry/factory-signatures.json +1 -1
  96. package/behaviors/registry/infra/atoms/std-approval-gate.orb +124 -67
  97. package/behaviors/registry/infra/atoms/std-audit-capture.orb +0 -8
  98. package/behaviors/registry/infra/atoms/std-cache-aside.orb +0 -84
  99. package/behaviors/registry/infra/atoms/std-circuit-breaker.orb +1 -44
  100. package/behaviors/registry/infra/atoms/std-data-erasure.orb +124 -55
  101. package/behaviors/registry/infra/atoms/std-data-import.orb +12 -11
  102. package/behaviors/registry/infra/atoms/std-game-clock.orb +31 -0
  103. package/behaviors/registry/infra/atoms/std-knowledge-loop.orb +0 -57
  104. package/behaviors/registry/infra/atoms/std-lifecycle.orb +43 -0
  105. package/behaviors/registry/infra/atoms/std-mod-queue.orb +379 -103
  106. package/behaviors/registry/infra/atoms/std-notification-preferences.orb +126 -12
  107. package/behaviors/registry/infra/atoms/std-notify-on-event.orb +0 -11
  108. package/behaviors/registry/infra/atoms/std-permission-matrix.orb +128 -12
  109. package/behaviors/registry/infra/atoms/std-rate-limiter.orb +287 -72
  110. package/behaviors/registry/infra/atoms/std-status-lifecycle.orb +5 -8
  111. package/behaviors/registry/ml/atoms/std-graph-builder.orb +11 -0
  112. package/behaviors/registry/ml/atoms/std-ml-classify.orb +0 -7
  113. package/behaviors/registry/ml/atoms/std-ml-similarity.orb +0 -7
  114. package/behaviors/registry/ui/avl/atoms/ui-avl-state-machine.orb +82 -0
  115. package/behaviors/registry/ui/core/atoms/std-app-layout.orb +417 -9
  116. package/behaviors/registry/ui/core/atoms/std-app-search.orb +53 -1
  117. package/behaviors/registry/ui/core/atoms/std-billable-hour.orb +209 -19
  118. package/behaviors/registry/ui/core/atoms/std-board.orb +242 -61
  119. package/behaviors/registry/ui/core/atoms/std-browse.orb +295 -41
  120. package/behaviors/registry/ui/core/atoms/std-calendar.orb +96 -2
  121. package/behaviors/registry/ui/core/atoms/std-esign-flow.orb +122 -15
  122. package/behaviors/registry/ui/core/atoms/std-esign-request.orb +11 -0
  123. package/behaviors/registry/ui/core/atoms/std-event-log.orb +0 -8
  124. package/behaviors/registry/ui/core/atoms/std-export.orb +0 -16
  125. package/behaviors/registry/ui/core/atoms/std-file-store.orb +109 -2
  126. package/behaviors/registry/ui/core/atoms/std-form-advanced.orb +1 -43
  127. package/behaviors/registry/ui/core/atoms/std-geosearch.orb +5 -0
  128. package/behaviors/registry/ui/core/atoms/std-graphs.orb +173 -66
  129. package/behaviors/registry/ui/core/atoms/std-import.orb +0 -8
  130. package/behaviors/registry/ui/core/atoms/std-list.orb +226 -34
  131. package/behaviors/registry/ui/core/atoms/std-modal-editor.orb +10 -1
  132. package/behaviors/registry/ui/core/atoms/std-rating-review.orb +37 -19
  133. package/behaviors/registry/ui/core/atoms/std-record-detail.orb +204 -11
  134. package/behaviors/registry/ui/core/atoms/std-recurrence.orb +89 -4
  135. package/behaviors/registry/ui/core/atoms/std-role-gate.orb +217 -0
  136. package/behaviors/registry/ui/core/atoms/std-saved-search.orb +419 -19
  137. package/behaviors/registry/ui/core/atoms/std-selection.orb +140 -10
  138. package/behaviors/registry/ui/core/atoms/std-stats.orb +73 -1
  139. package/behaviors/registry/ui/core/atoms/std-tag-taxonomy.orb +3 -0
  140. package/behaviors/registry/ui/core/atoms/std-thread.orb +190 -115
  141. package/behaviors/registry/ui/core/atoms/std-version-history.orb +127 -13
  142. package/behaviors/registry/ui/core/atoms/std-vote.orb +0 -9
  143. package/behaviors/registry/ui/core/atoms/std-wizard.orb +33 -3
  144. package/behaviors/registry/ui/core/atoms/ui-presence.orb +59 -0
  145. package/behaviors/registry/ui/core/molecules/ui-breadcrumb.orb +53 -1
  146. package/behaviors/registry/ui/core/molecules/ui-chart.orb +68 -1
  147. package/behaviors/registry/ui/core/molecules/ui-code-block.orb +291 -8
  148. package/behaviors/registry/ui/core/molecules/ui-command-palette.orb +87 -2
  149. package/behaviors/registry/ui/core/molecules/ui-commit-row.orb +3 -2
  150. package/behaviors/registry/ui/core/molecules/ui-confirm-dialog.orb +32 -0
  151. package/behaviors/registry/ui/core/molecules/ui-data-grid.orb +189 -3
  152. package/behaviors/registry/ui/core/molecules/ui-data-list.orb +189 -3
  153. package/behaviors/registry/ui/core/molecules/ui-document-details.orb +81 -24
  154. package/behaviors/registry/ui/core/molecules/ui-document-panel.orb +121 -3
  155. package/behaviors/registry/ui/core/molecules/ui-document-viewer.orb +53 -1
  156. package/behaviors/registry/ui/core/molecules/ui-drawer.orb +40 -0
  157. package/behaviors/registry/ui/core/molecules/ui-floating-action-button.orb +53 -1
  158. package/behaviors/registry/ui/core/molecules/ui-floating-toolbar.orb +53 -1
  159. package/behaviors/registry/ui/core/molecules/ui-form-actions.orb +53 -1
  160. package/behaviors/registry/ui/core/molecules/ui-graph-canvas.orb +53 -1
  161. package/behaviors/registry/ui/core/molecules/ui-menu.orb +57 -1
  162. package/behaviors/registry/ui/core/molecules/ui-meter.orb +53 -1
  163. package/behaviors/registry/ui/core/molecules/ui-modal.orb +8 -0
  164. package/behaviors/registry/ui/core/molecules/ui-page-header.orb +60 -1
  165. package/behaviors/registry/ui/core/molecules/ui-page-transition.orb +1 -1
  166. package/behaviors/registry/ui/core/molecules/ui-swipeable-row.orb +393 -23
  167. package/behaviors/registry/ui/core/molecules/ui-table-view.orb +189 -3
  168. package/behaviors/registry/ui/core/molecules/ui-tabs.orb +99 -2
  169. package/behaviors/registry/ui/core/organisms/ui-detail-panel.orb +282 -20
  170. package/behaviors/registry/ui/core/organisms/ui-entity-cards.orb +130 -3
  171. package/behaviors/registry/ui/core/organisms/ui-entity-list.orb +130 -3
  172. package/behaviors/registry/ui/core/organisms/ui-entity-table.orb +367 -9
  173. package/behaviors/registry/ui/core/organisms/ui-form-section.orb +104 -13
  174. package/behaviors/registry/ui/core/organisms/ui-form.orb +104 -13
  175. package/behaviors/registry/ui/core/organisms/ui-media-gallery.orb +121 -3
  176. package/behaviors/registry/ui/core/organisms/ui-state-machine-view.orb +82 -0
  177. package/behaviors/registry/ui/core/organisms/ui-timeline.orb +121 -3
  178. package/behaviors/registry/ui/core/templates/ui-counter-template.orb +1 -172
  179. package/behaviors/registry/ui/core/templates/ui-dashboard-layout.orb +53 -1
  180. package/behaviors/registry/ui/core/templates/ui-generic-app-template.orb +1 -116
  181. package/behaviors/registry/ui/game/atoms/ui-game-menu.orb +99 -2
  182. package/behaviors/registry/ui/game/organisms/std-arcade-board-3d.orb +10 -0
  183. package/behaviors/registry/ui/game/organisms/std-crew-board-2d.orb +0 -7
  184. package/behaviors/registry/ui/game/organisms/std-platformer-puzzle.orb +1 -807
  185. package/behaviors/registry/ui/game/organisms/std-tactics-board-2d.orb +0 -7
  186. package/behaviors/registry/ui/game/organisms/std-worldmap-board-2d.orb +0 -7
  187. package/behaviors/registry/ui/learning/atoms/std-learn-stepper.orb +6 -0
  188. package/canonical-operators.json +18 -1
  189. package/dist/behaviors/exports-reader.js +7662 -3762
  190. package/dist/behaviors/functions/index.d.ts +309 -104
  191. package/dist/behaviors/functions/index.js +7651 -3762
  192. package/dist/behaviors/index.d.ts +1 -1
  193. package/dist/behaviors/index.js +7663 -3763
  194. package/dist/behaviors/query.js +7662 -3762
  195. package/dist/behaviors-embeddings.hash.json +3 -3
  196. package/dist/behaviors-embeddings.json +35 -27
  197. package/dist/behaviors-registry.json +4402 -1898
  198. package/dist/index.d.ts +3 -3
  199. package/dist/index.js +7680 -3763
  200. package/dist/knob-embeddings.hash.json +3 -3
  201. package/dist/knob-embeddings.json +612 -352
  202. package/dist/modules/anim.d.ts +1 -1
  203. package/dist/modules/array.d.ts +1 -1
  204. package/dist/modules/array.js +15 -0
  205. package/dist/modules/async.d.ts +1 -1
  206. package/dist/modules/behavior.d.ts +1 -1
  207. package/dist/modules/browser.d.ts +1 -1
  208. package/dist/modules/composition.d.ts +1 -1
  209. package/dist/modules/contract.d.ts +1 -1
  210. package/dist/modules/core.d.ts +1 -1
  211. package/dist/modules/core.js +2 -0
  212. package/dist/modules/data.d.ts +1 -1
  213. package/dist/modules/ease.d.ts +1 -1
  214. package/dist/modules/format.d.ts +1 -1
  215. package/dist/modules/geo.d.ts +1 -1
  216. package/dist/modules/graph.d.ts +1 -1
  217. package/dist/modules/grid.d.ts +1 -1
  218. package/dist/modules/index.d.ts +1 -1
  219. package/dist/modules/index.js +17 -0
  220. package/dist/modules/integration.d.ts +1 -1
  221. package/dist/modules/json.d.ts +1 -1
  222. package/dist/modules/llm.d.ts +1 -1
  223. package/dist/modules/math.d.ts +1 -1
  224. package/dist/modules/memory.d.ts +1 -1
  225. package/dist/modules/nn.d.ts +1 -1
  226. package/dist/modules/noise.d.ts +1 -1
  227. package/dist/modules/object.d.ts +1 -1
  228. package/dist/modules/os.d.ts +1 -1
  229. package/dist/modules/path.d.ts +1 -1
  230. package/dist/modules/prob.d.ts +1 -1
  231. package/dist/modules/session.d.ts +1 -1
  232. package/dist/modules/str.d.ts +1 -1
  233. package/dist/modules/tensor.d.ts +1 -1
  234. package/dist/modules/time.d.ts +1 -1
  235. package/dist/modules/trace.d.ts +1 -1
  236. package/dist/modules/train.d.ts +1 -1
  237. package/dist/modules/validate.d.ts +1 -1
  238. package/dist/modules/vector.d.ts +1 -1
  239. package/dist/modules/workspace.d.ts +1 -1
  240. package/dist/registry/factory-signatures.json +1 -1
  241. package/dist/registry.d.ts +2 -2
  242. package/dist/registry.js +17 -0
  243. package/dist/{types-Ggla7OK7.d.ts → types-DLx38UFZ.d.ts} +23 -3
  244. package/package.json +2 -2
@@ -1,5 +1,6 @@
1
1
  app std-approval-gate "1.1.0"
2
2
  "std-approval-gate — generic approval gate / approver workflow. Use when a user voices that an action must be reviewed, approved, signed off, or authorized by a privileged role before it proceeds (admin approval, supervisor sign-off, manager approval, gatekeeper review, editor approval, senior editor approval, reviewer approval, publishing approval, draft approval, content review, submit drafts then editors review and approve or reject, needs approval before going live, requires sign-off before publish). Persists ApprovalRequest rows + surfaces the PENDING ones in a review queue showing what is being approved and who asked, with Approve / Deny actions — Deny captures a written reason. approverRoles is ENFORCED by the review transitions themselves: an APPROVE/DENY from a viewer whose role is not listed does not fire. blockSelfApproval additionally stops a reviewer approving their own request (four-eyes) — DENY stays allowed as self-withdrawal. On approval emits ApprovalGranted; on denial emits ApprovalDenied (with the reason). Hosts that replay the gated action MUST route a failed replay back via APPROVAL_REPLAY_FAILED so the request reopens instead of being silently consumed. Compose onto any orbital whose action you want to gate: the target orbital emits an external event, an ApprovalRequest row is created (stamp subjectLabel/subjectId/requestedBy so reviewers see what they are judging), and downstream effects wait on ApprovalGranted. Differs from std-mod-queue, which is content-moderation-specific."
3
+ type ItemAction = { label : string!, event : event, variant : string, icon : string, roles : [string], when : SExpr }
3
4
  orbital ApprovalGateOrbital {
4
5
  uses Spinner from "std/behaviors/ui-spinner"
5
6
  uses Typography from "std/behaviors/ui-typography"
@@ -192,22 +193,7 @@ orbital ApprovalGateOrbital {
192
193
  variant: caption
193
194
  }]
194
195
  gap: sm
195
- itemActions: [{
196
- event: OPEN_SUBJECT
197
- icon: eye
198
- label: View
199
- variant: ghost
200
- }, {
201
- event: APPROVE
202
- icon: check
203
- label: Approve
204
- variant: primary
205
- }, {
206
- event: DENY
207
- icon: x
208
- label: Deny
209
- variant: danger
210
- }]
196
+ itemActions: (array/filter @config.itemActions (fn action (or (= (array/len (object/get @action roles [])) 0) (array/includes (object/get @action roles []) @config.viewerRole))))
211
197
  look: @config.tableLook
212
198
  type: data-grid
213
199
  }]
@@ -412,7 +398,6 @@ orbital ApprovalGateOrbital {
412
398
  }
413
399
 
414
400
  listens {
415
- CloseButton.CLOSE -> CLOSE
416
401
  OPEN
417
402
  @description "Summons the review queue (host nav/affordance requests it)."
418
403
  @synonyms "open, show, review, view queue, open approvals"
@@ -502,30 +487,6 @@ orbital ApprovalGateOrbital {
502
487
  @description "When on, a reviewer cannot APPROVE a request they submitted themselves (requestedBy = the viewer's id) — enforced by the APPROVE transition guard, from the button or from the bus. Requires hosts to stamp requestedBy at request creation. DENY stays allowed on your own request (denying your own request withdraws it). Off by default."
503
488
  @synonyms "self approval, self-approval, four eyes, four-eyes, separation of duties, cannot approve own, no self sign-off, dual control"
504
489
  @tier "policy"
505
- threshold : number = 0
506
- @label "Auto-approve below this value"
507
- @description "Requests whose gated value is below this threshold are auto-approved. v1.0 declarative only."
508
- @synonyms "auto approve amount, skip review under, threshold, limit"
509
- @tier "policy"
510
- autoApproveBelowThreshold : boolean = true
511
- @label "Skip review queue for low-value requests?"
512
- @description "When true, auto-approves requests below the threshold without queuing. v1.0 declarative only."
513
- @synonyms "auto approve, skip review, bypass queue, automatic approval"
514
- @tier "policy"
515
- valueField : string = ""
516
- @label "Value field"
517
- @description "Payload field name to compare against threshold (e.g. 'amount' on a RefundRequested event). v1.0 declarative only."
518
- @tier "internal"
519
- escalationHours : number = 0
520
- @label "Escalate after how many hours pending?"
521
- @description "Hours a request can sit pending before escalating. v1.0 declarative only."
522
- @synonyms "escalation time, SLA hours, pending timeout, escalate after"
523
- @tier "policy"
524
- escalationRoles : [string] = []
525
- @label "Who gets notified when a request escalates?"
526
- @description "Roles notified on escalation (compose sibling std-notify-on-event to deliver)."
527
- @synonyms "escalation contacts, escalate to, notify roles, escalated approver"
528
- @tier "policy"
529
490
  tableLook : "dense" | "spacious" | "striped" | "borderless" | "card-rows" = dense
530
491
  @label "Review queue table style"
531
492
  @description "Visual treatment for the approval-queue data table."
@@ -535,6 +496,29 @@ orbital ApprovalGateOrbital {
535
496
  @label "Review slot"
536
497
  @description "UI slot the review queue renders into. Defaults to the modal overlay so the queue never seizes the host's main content; summoned via OPEN, cleared via CLOSE."
537
498
  @tier "internal"
499
+ itemActions : [ItemAction] = [{
500
+ event: OPEN_SUBJECT
501
+ icon: eye
502
+ label: View
503
+ variant: ghost
504
+ }, {
505
+ event: APPROVE
506
+ icon: check
507
+ label: Approve
508
+ variant: primary
509
+ }, {
510
+ event: DENY
511
+ icon: x
512
+ label: Deny
513
+ variant: danger
514
+ }]
515
+ @label "Row actions"
516
+ @description "Actions offered on each row; give an item `roles` to show it only to those viewer roles."
517
+ @tier "presentation"
518
+ viewerRole : string = ""
519
+ @label "Viewer's role"
520
+ @description "The signed-in viewer's role that each action's `roles` is checked against. Bind it explicitly at the call site (e.g. `viewerRole: @user.role`) in an app whose identity carries a role; left empty, only actions with no `roles` show."
521
+ @tier "policy"
538
522
  }
539
523
  }
540
524
 
@@ -93,11 +93,6 @@ orbital AuditCaptureOrbital {
93
93
  @description "Store a full before-and-after snapshot of each change. More detail, but a larger audit log."
94
94
  @synonyms "before after, snapshot, diff, change snapshot, field diff"
95
95
  @tier "policy"
96
- retentionDays : number = 2555
97
- @label "How long should the audit log be kept (days)?"
98
- @description "Number of days to retain audit entries. Default 2555 ≈ 7 years, typical for compliance."
99
- @synonyms "log retention, keep for, audit expiry, retention period, log lifetime"
100
- @tier "policy"
101
96
  }
102
97
  }
103
98
 
@@ -254,10 +254,6 @@ orbital CacheEntryOrbital {
254
254
  }
255
255
 
256
256
  listens {
257
- FetchButton.FETCH -> FETCH
258
- InvalidateButton.INVALIDATE -> INVALIDATE
259
- RefreshButton.REFRESH -> REFRESH
260
- RetryButton.FETCH -> FETCH
261
257
  CACHED {
262
258
  data : CacheEntry
263
259
  }
@@ -281,26 +277,6 @@ orbital CacheEntryOrbital {
281
277
  }
282
278
 
283
279
  config {
284
- ttlSeconds : number = 300
285
- @label "TTL (seconds)"
286
- @description "Cache entry time-to-live before it goes stale. Default 5 minutes. Shorter = fresher/real-time data; longer = stable/long-lived caching."
287
- @synonyms "expiration, time to live, cache duration, freshness, real-time (short) vs long-lived (long)"
288
- @tier "domain"
289
- staleWhileRevalidate : boolean = true
290
- @label "Serve stale while revalidating"
291
- @description "When true, serve stale entries to consumers while a background refresh fetches fresh data. Reduces latency at the cost of brief staleness."
292
- @synonyms "SWR, stale serving"
293
- @tier "domain"
294
- evictionPolicy : "lru" | "lfu" | "fifo" | "ttl-only" = lru
295
- @label "Eviction policy"
296
- @description "How entries are evicted when the cache fills: least-recently-used, least-frequently-used, first-in-first-out, or TTL-only (never evict early)."
297
- @synonyms "cache replacement, eviction strategy"
298
- @tier "domain"
299
- maxCacheSize : number = 1000
300
- @label "Max cache entries"
301
- @description "Hard cap on cached entries before eviction. 0 = unlimited."
302
- @synonyms "cache capacity, max entries"
303
- @tier "domain"
304
280
  emptyLook : "illustrated" | "icon-only" | "text-only" | "mascot" = icon-only
305
281
  @label "Empty-state look"
306
282
  @description "Layer 2 visual treatment for the empty-state placeholder."
@@ -147,7 +147,7 @@ orbital ServiceNodeOrbital {
147
147
  INIT -> closed
148
148
  (set @entity.failureCount 0)
149
149
  (set @entity.successCount 0)
150
- (set @entity.threshold 5)
150
+ (set @entity.threshold @config.failureThreshold)
151
151
  (fetch ServiceNode {
152
152
  emit: { failure: ServiceNodeLoadFailed, success: ServiceNodeLoaded }
153
153
  })
@@ -332,7 +332,6 @@ orbital ServiceNodeOrbital {
332
332
  }
333
333
 
334
334
  listens {
335
- ResetButton.RESET -> RESET
336
335
  ServiceNodeLoadFailed {
337
336
  message : string
338
337
  }
@@ -347,21 +346,6 @@ orbital ServiceNodeOrbital {
347
346
  @description "Number of consecutive failures before the circuit opens and starts rejecting requests."
348
347
  @synonyms "open trigger, failure count"
349
348
  @tier "domain"
350
- cooldownSeconds : number = 30
351
- @label "Cooldown (seconds)"
352
- @description "Seconds the circuit stays open before transitioning to half-open and probing for recovery."
353
- @synonyms "reset timeout, open duration"
354
- @tier "domain"
355
- halfOpenRequests : number = 1
356
- @label "Half-open probe requests"
357
- @description "Probe requests allowed through in the half-open state before deciding to close or re-open. Lower = cautious single-probe recovery; higher = aggressive parallel re-validation."
358
- @synonyms "probe count, recovery test size, probe aggressiveness, recovery test volume, cautious vs fast recovery"
359
- @tier "domain"
360
- fallbackBehavior : "reject" | "cached-response" | "queue" | "static-default" = reject
361
- @label "Fallback behavior"
362
- @description "What to return to callers while the circuit is open: reject = fail-fast/strict, cached-response = graceful degrade with stale data, queue = retry-later/no data loss, static-default = safe placeholder."
363
- @synonyms "open-state response, degraded mode, fail-fast vs graceful degrade"
364
- @tier "domain"
365
349
  statLook : "elevated" | "flat" | "progress-backed" | "gauge" | "sparkline" = elevated
366
350
  @label "Stat display look"
367
351
  @description "Layer 2 visual treatment for stat / KPI cards."
@@ -1,5 +1,6 @@
1
1
  app std-data-erasure "1.0.0"
2
2
  "std-data-erasure — GDPR Art. 17 right-to-be-forgotten queue. Tracks ErasureRequest rows through pending → grace → executed lifecycle with Cancel during grace. v1.0 ships the request lifecycle UI + knob set; auto-emit of ExecuteErasure after grace lands in v1.1 (loop-with-emit gap — docs/Almadar_Std_Factories.md). Target app/ atoms then own the actual delete or piiFields scrub via an ExecuteErasure listener."
3
+ type ItemAction = { label : string!, event : event, variant : string, icon : string, roles : [string] }
3
4
  orbital DataErasureOrbital {
4
5
  uses Spinner from "std/behaviors/ui-spinner"
5
6
  uses Typography from "std/behaviors/ui-typography"
@@ -112,7 +113,7 @@ orbital DataErasureOrbital {
112
113
  })
113
114
  ExecScanLoaded -> execScanning when (and @config.enabled [">", (array/len ?data), 0])
114
115
  (set @entity.id (object/get (array/first ?data) id))
115
- (set @entity.targetEntity (object/get (array/first ?data) targetEntity))
116
+ (set @entity.targetEntity (str/default (object/get (array/first ?data) targetEntity) @config.targetEntity))
116
117
  (set @entity.subjectId (object/get (array/first ?data) subjectId))
117
118
  (emit ExecuteErasure {
118
119
  requestId: @entity.id
@@ -139,7 +140,7 @@ orbital DataErasureOrbital {
139
140
  })
140
141
  ExecScanLoaded -> execScanning when [">", (array/len ?data), 0]
141
142
  (set @entity.id (object/get (array/first ?data) id))
142
- (set @entity.targetEntity (object/get (array/first ?data) targetEntity))
143
+ (set @entity.targetEntity (str/default (object/get (array/first ?data) targetEntity) @config.targetEntity))
143
144
  (set @entity.subjectId (object/get (array/first ?data) subjectId))
144
145
  (emit ExecuteErasure {
145
146
  requestId: @entity.id
@@ -191,12 +192,7 @@ orbital DataErasureOrbital {
191
192
  variant: caption
192
193
  }]
193
194
  gap: sm
194
- itemActions: [{
195
- event: CANCEL_ERASURE
196
- icon: x
197
- label: Cancel
198
- variant: secondary
199
- }]
195
+ itemActions: (array/filter @config.itemActions (fn action (or (= (array/len (object/get @action roles [])) 0) (array/includes (object/get @action roles []) @config.viewerRole))))
200
196
  look: @config.tableLook
201
197
  type: data-grid
202
198
  }]
@@ -316,7 +312,6 @@ orbital DataErasureOrbital {
316
312
  }
317
313
 
318
314
  listens {
319
- CloseButton.CLOSE -> CLOSE
320
315
  ExecScanLoaded {
321
316
  data : [ErasureRequest]
322
317
  }
@@ -396,21 +391,6 @@ orbital DataErasureOrbital {
396
391
  @label "Target entity"
397
392
  @description "Entity name whose records erasure requests apply to (e.g. 'CustomerAccount')."
398
393
  @tier "internal"
399
- gracePeriodDays : number = 30
400
- @label "How many days before deletion is carried out?"
401
- @description "Days between request submission and execution. The subject can cancel during this window."
402
- @synonyms "grace period, cancellation window, deletion delay, days before delete"
403
- @tier "policy"
404
- anonymizeVsDelete : "anonymize" | "delete" = anonymize
405
- @label "Anonymize or fully delete the record?"
406
- @description "anonymize = scrub PII fields and keep row for audit; delete = remove the row entirely."
407
- @synonyms "deletion mode, anonymize, delete, scrub or remove, retention mode"
408
- @tier "policy"
409
- piiFields : [string] = []
410
- @label "Which fields contain personal data to scrub?"
411
- @description "Fields the target atom nulls when anonymizing (e.g. email, name, phone)."
412
- @synonyms "PII fields, personal data fields, sensitive fields, fields to scrub"
413
- @tier "policy"
414
394
  tableLook : "dense" | "spacious" | "striped" | "borderless" | "card-rows" = dense
415
395
  @label "Erasure queue table style"
416
396
  @description "Visual treatment for the erasure-requests data table."
@@ -420,6 +400,19 @@ orbital DataErasureOrbital {
420
400
  @label "Review slot"
421
401
  @description "UI slot the erasure-requests queue renders into. Defaults to the modal overlay so it never seizes the host's main content; summoned via OPEN, cleared via CLOSE."
422
402
  @tier "internal"
403
+ itemActions : [ItemAction] = [{
404
+ event: CANCEL_ERASURE
405
+ icon: x
406
+ label: Cancel
407
+ variant: secondary
408
+ }]
409
+ @label "Row actions"
410
+ @description "Actions offered on each row; give an item `roles` to show it only to those viewer roles."
411
+ @tier "presentation"
412
+ viewerRole : string = ""
413
+ @label "Viewer's role"
414
+ @description "The signed-in viewer's role that each action's `roles` is checked against. Bind it explicitly at the call site (e.g. `viewerRole: @user.role`) in an app whose identity carries a role; left empty, only actions with no `roles` show."
415
+ @tier "policy"
423
416
  }
424
417
  }
425
418
 
@@ -1,5 +1,5 @@
1
1
  app std-data-import "1.0.0"
2
- "std-data-import — staged CSV import run, source-agnostic: upload → staged review → confirm → parse+map → handoff. UPLOAD_CSV opens a run and persists an ImportBatch row (status uploaded, fieldMappingJson recorded verbatim for provenance); the host's file UI parses the CSV and answers with STAGE_ROWS, one JSON string per raw row, which the atom bulk-persists into import_rows against the batch id and presents as a staged review (row/error counts + Confirm/Discard). CONFIRM_IMPORT marks the batch confirmed, emits IMPORT_CONFIRMED { batchId, sourceName, rowCount }, and fetches the batch's staged rows; on fetch success the atom parses each rowJson via json/parse, remaps keys through the batch's mappingJson, and emits IMPORT_ROWS_PARSED { batchId, rows, failed } — the persist half is the CONSUMER organism's: it listens for IMPORT_ROWS_PARSED and persists the mapped rows into its own target entity (cross-atom persist into a consumer's entity is not expressible from here). This is deliberately the CSV-file path: the atom never calls a source service — sourceName/fieldMappingJson/targetEntity/historyWindowDays are declarative consumer configs, and any persist failure marks the batch row failed and fires IMPORT_FAILED, never a silent swallow. Compose with std-import for the file-picker menu."
2
+ "std-data-import — staged CSV import run, source-agnostic: upload → staged review → confirm → parse+map → handoff. UPLOAD_CSV opens a run and persists an ImportBatch row (status uploaded, fieldMappingJson recorded verbatim for provenance); the host's file UI parses the CSV and answers with STAGE_ROWS, one JSON string per raw row, which the atom bulk-persists into import_rows against the batch id and presents as a staged review (row/error counts + Confirm/Discard). CONFIRM_IMPORT marks the batch confirmed, emits IMPORT_CONFIRMED { batchId, sourceName, rowCount }, and fetches the batch's staged rows; on fetch success the atom parses each rowJson via json/parse, remaps keys through the batch's mappingJson, and emits IMPORT_ROWS_PARSED { batchId, rows, failed } — the persist half is the CONSUMER organism's: it listens for IMPORT_ROWS_PARSED and persists the mapped rows into its own target entity (cross-atom persist into a consumer's entity is not expressible from here). This is deliberately the CSV-file path: the atom never calls a source service — sourceName/fieldMappingJson/targetEntity are consumer configs, and any persist failure marks the batch row failed and fires IMPORT_FAILED, never a silent swallow. Compose with std-import for the file-picker menu."
3
3
  orbital DataImportOrbital {
4
4
  type DataImportFile = { name : string!, size : number, type : string, content : string }
5
5
 
@@ -218,6 +218,7 @@ orbital DataImportOrbital {
218
218
  (fn k (if (object/has (json/parse @entity.mappingJson) @k)
219
219
  (object/get (json/parse @entity.mappingJson) @k)
220
220
  @k)))))
221
+ targetEntity: @config.targetEntity
221
222
  })
222
223
  ;; Same transient-failure self-loop as in `staged` — the row fetch can
223
224
  ;; fail after the batch row was already persisted as confirmed.
@@ -284,6 +285,7 @@ orbital DataImportOrbital {
284
285
  batchId : string!
285
286
  failed : number
286
287
  rows : [Map string scalar]
288
+ targetEntity : string
287
289
  }
288
290
  @description "Confirmed rows parsed and key-mapped: each staged row's rowJson was parsed via json/parse and remapped through the batch's mappingJson; failed counts rows whose rowJson did not parse to an object (surfaced, never dropped). The consumer persists rows into its own target entity and marks them imported."
289
291
  @synonyms "rows parsed, rows mapped, import rows ready"
@@ -330,21 +332,16 @@ orbital DataImportOrbital {
330
332
  @description "Free-form name of the upstream source this import pulls from — whatever tool or file export the user names. Recorded on the batch row for provenance and echoed on IMPORT_CONFIRMED."
331
333
  @synonyms "source, origin, import from, provider name, data source"
332
334
  @tier "domain"
335
+ targetEntity : string = ""
336
+ @label "Target entity"
337
+ @description "Name of the consumer organism's entity the staged rows land in after confirm. Carried on IMPORT_ROWS_PARSED so the consumer's persist half knows where the mapped rows belong — the atom never writes the target entity itself."
338
+ @synonyms "destination, import into, target type"
339
+ @tier "domain"
333
340
  fieldMappingJson : string = "{}"
334
341
  @label "Field mapping (JSON)"
335
342
  @description "JSON object mapping source CSV column names to target field names. Stored verbatim on the batch row (mappingJson); the atom applies it when it parses staged rows into IMPORT_ROWS_PARSED, so the consumer persists already-mapped rows into the target entity."
336
343
  @synonyms "field mapping, column mapping, map columns, remap fields, csv columns"
337
344
  @tier "domain"
338
- targetEntity : string = ""
339
- @label "Target entity"
340
- @description "Name of the consumer organism's entity the staged rows land in after confirm. Declarative contract only — the atom never writes the target entity; the consumer persists on IMPORT_CONFIRMED."
341
- @synonyms "destination, import into, target type"
342
- @tier "domain"
343
- historyWindowDays : number = 0
344
- @label "Historical data range (days)"
345
- @description "How many days back an import may reach (0 = unbounded). A declared import-config knob for the consumer's staging/mapping layer — the atom stages whatever rows it is handed and never filters by date."
346
- @synonyms "history window, historical range, import range, days back, lookback period"
347
- @tier "policy"
348
345
  }
349
346
  }
350
347
 
@@ -13,6 +13,8 @@ orbital GameClockOrbital {
13
13
  initial: running
14
14
 
15
15
  state running {
16
+ INIT -> paused when (not @config.autoStart)
17
+ (set @entity.running false)
16
18
  PAUSE -> paused
17
19
  (set @entity.running false)
18
20
  RESUME -> running
@@ -269,11 +269,6 @@ orbital KnowledgeLoopOrbital {
269
269
  }
270
270
 
271
271
  listens {
272
- SurvivedButton.SURVIVED -> SURVIVED
273
- FailedButton.FAILED -> FAILED
274
- ChecksAgreeButton.CHECKS_AGREE -> CHECKS_AGREE
275
- ChecksDisagreeButton.CHECKS_DISAGREE -> CHECKS_DISAGREE
276
- ChooseNextTargetButton.CHOOSE_NEXT_TARGET -> CHOOSE_NEXT_TARGET
277
272
  CONFIRM_SCORE {
278
273
  data: ScoreCommit
279
274
  }
@@ -25,7 +25,9 @@ orbital LifecycleOrbital {
25
25
 
26
26
  state idle {
27
27
  INIT -> idle
28
- ScanRecordsLoaded -> scanning when (and @config.enabled [">", (array/len ?data), 0])
28
+ ScanRecordsLoaded -> idle when (and @config.enabled @config.dryRun [">", (array/len ?data), 0])
29
+ (notify info (str/concat "Dry run — " (array/len ?data) " record(s) would transition, nothing was written."))
30
+ ScanRecordsLoaded -> scanning when (and @config.enabled (not @config.dryRun) [">", (array/len ?data), 0])
29
31
  (set @entity.headId (object/get (array/first ?data) id))
30
32
  (set @entity.headStatus @config.toStatus)
31
33
  (emit LifecycleTransitioned { entityId: @entity.headId, status: @entity.headStatus })
@@ -1,5 +1,6 @@
1
1
  app std-mod-queue "1.0.0"
2
2
  "std-mod-queue — moderation queue for content review. Owns a ModQueueItem entity (one row per flagged target) and a single review trait that loads pending items, renders them in a data-grid with Approve / Reject / Escalate actions, and persists the reviewer's verdict back to the row."
3
+ type ItemAction = { label : string!, event : event, variant : string, icon : string, roles : [string], when : SExpr }
3
4
  orbital ModQueueItemOrbital {
4
5
  uses Spinner from "std/behaviors/ui-spinner"
5
6
  uses Typography from "std/behaviors/ui-typography"
@@ -106,7 +107,21 @@ orbital ModQueueItemOrbital {
106
107
  }
107
108
 
108
109
  state loading {
109
- ModQueueItemLoaded -> reviewing
110
+ ModQueueItemLoaded -> loading when [">", (array/len (array/filter ?data (fn row (and ["=", (object/get @row "status"), pending] [">=", (object/get @row "flagCount"), @config.autoEscalateThreshold])))), 0]
111
+ (set @entity.id (object/get (array/first (array/filter ?data (fn row (and ["=", (object/get @row "status"), pending] [">=", (object/get @row "flagCount"), @config.autoEscalateThreshold])))) id))
112
+ (persist update ModQueueItem { id: @entity.id, status: escalated } {
113
+ emit: { failure: ModQueueItemReviewFailed, success: ModQueueItemReviewed }
114
+ })
115
+ ModQueueItemReviewed -> loading
116
+ (fetch ModQueueItem {
117
+ emit: { failure: ModQueueItemLoadFailed, success: ModQueueItemLoaded }
118
+ })
119
+ ModQueueItemReviewFailed -> error
120
+ (render-ui @config.reviewSlot {
121
+ children: [@trait.ErrorAlert]
122
+ type: stack
123
+ })
124
+ ModQueueItemLoaded -> reviewing when ["=", (array/len (array/filter ?data (fn row (and ["=", (object/get @row "status"), pending] [">=", (object/get @row "flagCount"), @config.autoEscalateThreshold])))), 0]
110
125
  (render-ui @config.reviewSlot {
111
126
  children: [{
112
127
  align: center
@@ -142,22 +157,7 @@ orbital ModQueueItemOrbital {
142
157
  variant: badge
143
158
  }]
144
159
  gap: sm
145
- itemActions: [{
146
- event: APPROVE
147
- icon: check
148
- label: Approve
149
- variant: primary
150
- }, {
151
- event: REJECT
152
- icon: x
153
- label: Reject
154
- variant: danger
155
- }, {
156
- event: ESCALATE
157
- icon: alert-triangle
158
- label: Escalate
159
- variant: secondary
160
- }]
160
+ itemActions: (array/filter @config.itemActions (fn action (or (= (array/len (object/get @action roles [])) 0) (array/includes (object/get @action roles []) @config.viewerRole))))
161
161
  look: @config.tableLook
162
162
  type: data-grid
163
163
  }]
@@ -275,7 +275,6 @@ orbital ModQueueItemOrbital {
275
275
  }
276
276
 
277
277
  listens {
278
- CloseButton.CLOSE -> CLOSE
279
278
  OPEN
280
279
  @description "Summons the moderation queue (host nav/affordance requests it)."
281
280
  @synonyms "open, show, review, view queue, moderation queue"
@@ -353,6 +352,29 @@ orbital ModQueueItemOrbital {
353
352
  @label "Review slot"
354
353
  @description "UI slot the moderation queue renders into. Defaults to the modal overlay so it never seizes the host's main content; summoned via OPEN, cleared via CLOSE."
355
354
  @tier "internal"
355
+ itemActions : [ItemAction] = [{
356
+ event: APPROVE
357
+ icon: check
358
+ label: Approve
359
+ variant: primary
360
+ }, {
361
+ event: REJECT
362
+ icon: x
363
+ label: Reject
364
+ variant: danger
365
+ }, {
366
+ event: ESCALATE
367
+ icon: alert-triangle
368
+ label: Escalate
369
+ variant: secondary
370
+ }]
371
+ @label "Row actions"
372
+ @description "Actions offered on each row; give an item `roles` to show it only to those viewer roles."
373
+ @tier "presentation"
374
+ viewerRole : string = ""
375
+ @label "Viewer's role"
376
+ @description "The signed-in viewer's role that each action's `roles` is checked against. Bind it explicitly at the call site (e.g. `viewerRole: @user.role`) in an app whose identity carries a role; left empty, only actions with no `roles` show."
377
+ @tier "policy"
356
378
  }
357
379
  }
358
380
 
@@ -1,5 +1,6 @@
1
1
  app std-notification-preferences "1.0.0"
2
2
  "std-notification-preferences — per-person notification preference store plus a consultable gate. Owns NotificationPreference rows (one per person + event key: channel override in_app/email/push/slack/sms/webhook, mode instant/digest/off, quiet-hours window 'HH:MM-HH:MM' such as 22:00-07:00). The PreferencesManage trait is standard CRUD over the store (list / create / update / delete, persisted, success/failure cascade arms): a data-grid browse plus ModalRecordModal create/edit forms whose SAVE carries the full row payload (std-list daisy-chain idiom). The PreferenceGate trait is the consult half other notify traits call: emit CHECK_PREFERENCE { personId, eventKey } and the gate fetches the matching row (a row whose eventKey is blank applies to every event) and answers PREFERENCE_RESOLVED { personId, eventKey, channel, mode, suppressed } — suppressed is true only when the row's quietHours window covers the current hour; mode 'digest' rides on the verdict for the caller to defer. Default policy: no matching row — or a failed lookup — resolves fail-open to { channel: in_app, mode: instant, suppressed: false }; the absence of a preference never silences a notification."
3
+ type ItemAction = { label : string!, event : event, variant : string, icon : string, roles : [string], when : SExpr }
3
4
  orbital NotificationPreferencesOrbital {
4
5
  uses Modal from "std/behaviors/std-modal"
5
6
 
@@ -102,17 +103,7 @@ orbital NotificationPreferencesOrbital {
102
103
  variant: caption
103
104
  }]
104
105
  gap: sm
105
- itemActions: [{
106
- event: EDIT
107
- icon: pencil
108
- label: Edit
109
- variant: secondary
110
- }, {
111
- event: DELETE
112
- icon: trash-2
113
- label: Delete
114
- variant: danger
115
- }]
106
+ itemActions: (array/filter @config.itemActions (fn action (or (= (array/len (object/get @action roles [])) 0) (array/includes (object/get @action roles []) @config.viewerRole))))
116
107
  look: @config.tableLook
117
108
  type: data-grid
118
109
  }]
@@ -342,6 +333,24 @@ orbital NotificationPreferencesOrbital {
342
333
  @label "Table look"
343
334
  @description "Layer 2 visual treatment for the preference data table rendered by this atom."
344
335
  @tier "presentation"
336
+ itemActions : [ItemAction] = [{
337
+ event: EDIT
338
+ icon: pencil
339
+ label: Edit
340
+ variant: secondary
341
+ }, {
342
+ event: DELETE
343
+ icon: trash-2
344
+ label: Delete
345
+ variant: danger
346
+ }]
347
+ @label "Row actions"
348
+ @description "Actions offered on each row; give an item `roles` to show it only to those viewer roles."
349
+ @tier "presentation"
350
+ viewerRole : string = ""
351
+ @label "Viewer's role"
352
+ @description "The signed-in viewer's role that each action's `roles` is checked against. Bind it explicitly at the call site (e.g. `viewerRole: @user.role`) in an app whose identity carries a role; left empty, only actions with no `roles` show."
353
+ @tier "policy"
345
354
  }
346
355
  }
347
356
 
@@ -382,11 +382,6 @@ orbital NotifyOnEventOrbital {
382
382
  @description "Threshold compared against `guardField` when `guardOp` is not `eq` (e.g. fire when stock drops below 5)."
383
383
  @synonyms "threshold, cutoff, limit, watermark, trigger value"
384
384
  @tier "policy"
385
- listensFor : [string] = []
386
- @label "Trigger events"
387
- @description "Event names that should fire a notification. Set this to the upstream event name (e.g. OrderPlaced, CheckoutCompleted) so this atom listens for events from the orbital that emits them. The orbital owning this trait reacts whenever the named event fires anywhere in the schema."
388
- @synonyms "subscribe to event, listen for event, react to event, watch for, wire upstream event, observe event from another orbital, cross-orbital subscription, on-event trigger"
389
- @tier "internal"
390
385
  eventKey : string = ""
391
386
  @label "Event key for preferences"
392
387
  @description "Stable key naming the upstream event this listener is bound to (e.g. 'OrderPlaced'). NotificationPreference rows (std-notification-center) whose eventKey equals this key — or is blank — apply to this listener's dispatches."
@@ -1,5 +1,6 @@
1
1
  app std-permission-matrix "1.0.0"
2
2
  "std-permission-matrix — role × module permission grant table / capability matrix admin surface. Use when a user voices that permissions must be managed per role and module (permission matrix, role permissions, capability matrix, permission grants, access matrix, who can see finance, hide margins, module-level permissions, admin permission screen, grant management, finance visibility by role, restrict modules by role). Persists PermissionGrant rows (workspaceId + role + module + capability flags canReadFinance / canSeeOthersHours / canSeeMargins) with full CRUD on an admin page mounted at /admin/permissions — create/edit forms are the std-modal ModalRecordModal substrate (the corpus's two-trait CRUD shape, mirroring std-list), persists live in a sibling coordinator trait, and adminRoles is ENFORCED at the persist boundary (a viewer whose role is not listed cannot fire a write, from the button or from the bus). Ships a query trait other traits consult event-wise: CHECK_GRANT { role, module } fetches the matching grant(s) and re-emits GRANT_RESOLVED { role, module, canReadFinance, canSeeOthersHours, canSeeMargins, found }. Grant SURFACE only — entity-layer @read/@update gate integration is a recorded core gap (gates are pure @entity/@user S-expressions and cannot consult another entity's rows), so enforcement stays with the consumer until that core lands."
3
+ type ItemAction = { label : string!, event : event, variant : string, icon : string, roles : [string], when : SExpr }
3
4
  orbital PermissionMatrixOrbital {
4
5
  uses Modal from "std/behaviors/std-modal"
5
6
  uses Spinner from "std/behaviors/ui-spinner"
@@ -161,17 +162,7 @@ orbital PermissionMatrixOrbital {
161
162
  variant: caption
162
163
  }]
163
164
  gap: sm
164
- itemActions: [{
165
- event: EDIT
166
- icon: pencil
167
- label: Edit
168
- variant: ghost
169
- }, {
170
- event: DELETE
171
- icon: trash
172
- label: Delete
173
- variant: danger
174
- }]
165
+ itemActions: (array/filter @config.itemActions (fn action (or (= (array/len (object/get @action roles [])) 0) (array/includes (object/get @action roles []) @config.viewerRole))))
175
166
  type: data-grid
176
167
  }]
177
168
  direction: vertical
@@ -255,6 +246,27 @@ orbital PermissionMatrixOrbital {
255
246
  }
256
247
 
257
248
  config {}
249
+
250
+ config {
251
+ itemActions : [ItemAction] = [{
252
+ event: EDIT
253
+ icon: pencil
254
+ label: Edit
255
+ variant: ghost
256
+ }, {
257
+ event: DELETE
258
+ icon: trash
259
+ label: Delete
260
+ variant: danger
261
+ }]
262
+ @label "Row actions"
263
+ @description "Actions offered on each row; give an item `roles` to show it only to those viewer roles."
264
+ @tier "presentation"
265
+ viewerRole : string = ""
266
+ @label "Viewer's role"
267
+ @description "The signed-in viewer's role that each action's `roles` is checked against. Bind it explicitly at the call site (e.g. `viewerRole: @user.role`) in an app whose identity carries a role; left empty, only actions with no `roles` show."
268
+ @tier "policy"
269
+ }
258
270
  }
259
271
 
260
272
  ;; Create modal: configured via `config`, no effects overrides (std-list