@telora/daemon 0.22.169 → 0.22.187

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 (254) hide show
  1. package/build-info.json +9 -3
  2. package/dist/audit/audit-floor-policy.d.ts +188 -0
  3. package/dist/audit/audit-floor-policy.d.ts.map +1 -0
  4. package/dist/audit/audit-floor-policy.js +353 -0
  5. package/dist/audit/audit-floor-policy.js.map +1 -0
  6. package/dist/audit/audit-prompt.d.ts +4 -177
  7. package/dist/audit/audit-prompt.d.ts.map +1 -1
  8. package/dist/audit/audit-prompt.js +6 -329
  9. package/dist/audit/audit-prompt.js.map +1 -1
  10. package/dist/completion/commit-verdict-release.d.ts +37 -1
  11. package/dist/completion/commit-verdict-release.d.ts.map +1 -1
  12. package/dist/completion/commit-verdict-release.js +90 -15
  13. package/dist/completion/commit-verdict-release.js.map +1 -1
  14. package/dist/completion/escalations.d.ts.map +1 -1
  15. package/dist/completion/escalations.js +3 -1
  16. package/dist/completion/escalations.js.map +1 -1
  17. package/dist/completion/review-exit-verdict-gate.d.ts +11 -5
  18. package/dist/completion/review-exit-verdict-gate.d.ts.map +1 -1
  19. package/dist/completion/review-exit-verdict-gate.js +6 -3
  20. package/dist/completion/review-exit-verdict-gate.js.map +1 -1
  21. package/dist/delivery/commit-verdict-hold.d.ts.map +1 -1
  22. package/dist/delivery/commit-verdict-hold.js +2 -1
  23. package/dist/delivery/commit-verdict-hold.js.map +1 -1
  24. package/dist/directive/stranded-review-reroute.js +1 -1
  25. package/dist/directive/stranded-review-reroute.js.map +1 -1
  26. package/dist/focus/focus-executor.d.ts.map +1 -1
  27. package/dist/focus/focus-executor.js +2 -0
  28. package/dist/focus/focus-executor.js.map +1 -1
  29. package/dist/focus/pending-review-approved-head.d.ts +1 -1
  30. package/dist/focus/pending-review-approved-head.d.ts.map +1 -1
  31. package/dist/focus/pending-review-approved-head.js +4 -3
  32. package/dist/focus/pending-review-approved-head.js.map +1 -1
  33. package/dist/focus/session-health.d.ts.map +1 -1
  34. package/dist/focus/session-health.js +2 -1
  35. package/dist/focus/session-health.js.map +1 -1
  36. package/dist/focus-stage-lifecycle/planning-release.d.ts +52 -17
  37. package/dist/focus-stage-lifecycle/planning-release.d.ts.map +1 -1
  38. package/dist/focus-stage-lifecycle/planning-release.js +58 -70
  39. package/dist/focus-stage-lifecycle/planning-release.js.map +1 -1
  40. package/dist/focus-stage-lifecycle/ratify-bar-gate.d.ts +108 -0
  41. package/dist/focus-stage-lifecycle/ratify-bar-gate.d.ts.map +1 -0
  42. package/dist/focus-stage-lifecycle/ratify-bar-gate.js +174 -0
  43. package/dist/focus-stage-lifecycle/ratify-bar-gate.js.map +1 -0
  44. package/dist/git/merge-to-main.d.ts.map +1 -1
  45. package/dist/git/merge-to-main.js.map +1 -1
  46. package/dist/nexus/index.d.ts.map +1 -1
  47. package/dist/nexus/index.js +2 -1
  48. package/dist/nexus/index.js.map +1 -1
  49. package/dist/nexus/intake-prompt-sections.d.ts +70 -0
  50. package/dist/nexus/intake-prompt-sections.d.ts.map +1 -0
  51. package/dist/nexus/intake-prompt-sections.js +145 -0
  52. package/dist/nexus/intake-prompt-sections.js.map +1 -0
  53. package/dist/nexus/intake-spawn.d.ts +49 -13
  54. package/dist/nexus/intake-spawn.d.ts.map +1 -1
  55. package/dist/nexus/intake-spawn.js +45 -122
  56. package/dist/nexus/intake-spawn.js.map +1 -1
  57. package/dist/nexus/intake.d.ts +55 -0
  58. package/dist/nexus/intake.d.ts.map +1 -1
  59. package/dist/nexus/intake.js +62 -1
  60. package/dist/nexus/intake.js.map +1 -1
  61. package/dist/prd/arm-readiness.d.ts +93 -0
  62. package/dist/prd/arm-readiness.d.ts.map +1 -0
  63. package/dist/prd/arm-readiness.js +254 -0
  64. package/dist/prd/arm-readiness.js.map +1 -0
  65. package/dist/prd/arm-refusal.d.ts +149 -0
  66. package/dist/prd/arm-refusal.d.ts.map +1 -0
  67. package/dist/prd/arm-refusal.js +219 -0
  68. package/dist/prd/arm-refusal.js.map +1 -0
  69. package/dist/prd/controller-shared.d.ts +111 -0
  70. package/dist/prd/controller-shared.d.ts.map +1 -1
  71. package/dist/prd/controller-shared.js +3 -1
  72. package/dist/prd/controller-shared.js.map +1 -1
  73. package/dist/prd/controller.d.ts +16 -10
  74. package/dist/prd/controller.d.ts.map +1 -1
  75. package/dist/prd/controller.js +28 -35
  76. package/dist/prd/controller.js.map +1 -1
  77. package/dist/prd/frontier-arming.d.ts +151 -0
  78. package/dist/prd/frontier-arming.d.ts.map +1 -0
  79. package/dist/prd/frontier-arming.js +315 -0
  80. package/dist/prd/frontier-arming.js.map +1 -0
  81. package/dist/prd/index.d.ts +10 -1
  82. package/dist/prd/index.d.ts.map +1 -1
  83. package/dist/prd/index.js +9 -1
  84. package/dist/prd/index.js.map +1 -1
  85. package/dist/prd/scoping-prompt.d.ts +68 -0
  86. package/dist/prd/scoping-prompt.d.ts.map +1 -0
  87. package/dist/prd/scoping-prompt.js +86 -0
  88. package/dist/prd/scoping-prompt.js.map +1 -0
  89. package/dist/prompt/prompt-contradictions.d.ts +20 -1
  90. package/dist/prompt/prompt-contradictions.d.ts.map +1 -1
  91. package/dist/prompt/prompt-contradictions.js +35 -0
  92. package/dist/prompt/prompt-contradictions.js.map +1 -1
  93. package/dist/prompt/team-prompt-base.d.ts +18 -0
  94. package/dist/prompt/team-prompt-base.d.ts.map +1 -1
  95. package/dist/prompt/team-prompt-base.js +56 -11
  96. package/dist/prompt/team-prompt-base.js.map +1 -1
  97. package/dist/prompt-sections/persona-sections.d.ts +36 -13
  98. package/dist/prompt-sections/persona-sections.d.ts.map +1 -1
  99. package/dist/prompt-sections/persona-sections.js +93 -16
  100. package/dist/prompt-sections/persona-sections.js.map +1 -1
  101. package/dist/prompt-sections/scoping-sections.d.ts +19 -5
  102. package/dist/prompt-sections/scoping-sections.d.ts.map +1 -1
  103. package/dist/prompt-sections/scoping-sections.js +45 -38
  104. package/dist/prompt-sections/scoping-sections.js.map +1 -1
  105. package/dist/prompt-sections/shared.d.ts +8 -0
  106. package/dist/prompt-sections/shared.d.ts.map +1 -1
  107. package/dist/prompt-sections/shared.js.map +1 -1
  108. package/dist/queries/delivery-gate-state.js +1 -1
  109. package/dist/queries/focus-criteria-standing.d.ts +170 -7
  110. package/dist/queries/focus-criteria-standing.d.ts.map +1 -1
  111. package/dist/queries/focus-criteria-standing.js +143 -8
  112. package/dist/queries/focus-criteria-standing.js.map +1 -1
  113. package/dist/queries/focus-ratify-release.d.ts +43 -0
  114. package/dist/queries/focus-ratify-release.d.ts.map +1 -0
  115. package/dist/queries/focus-ratify-release.js +45 -0
  116. package/dist/queries/focus-ratify-release.js.map +1 -0
  117. package/dist/queries/focuses.d.ts +0 -10
  118. package/dist/queries/focuses.d.ts.map +1 -1
  119. package/dist/queries/focuses.js +2 -15
  120. package/dist/queries/focuses.js.map +1 -1
  121. package/dist/queries/prd.d.ts +31 -0
  122. package/dist/queries/prd.d.ts.map +1 -1
  123. package/dist/queries/prd.js +26 -1
  124. package/dist/queries/prd.js.map +1 -1
  125. package/dist/queries/shared.js +1 -1
  126. package/dist/resolvers/focus-criteria-standing.d.ts.map +1 -1
  127. package/dist/resolvers/focus-criteria-standing.js +324 -25
  128. package/dist/resolvers/focus-criteria-standing.js.map +1 -1
  129. package/dist/resolvers/shared/review-window-commits.d.ts.map +1 -1
  130. package/dist/resolvers/shared/review-window-commits.js +2 -1
  131. package/dist/resolvers/shared/review-window-commits.js.map +1 -1
  132. package/dist/security/security-auto-inject.d.ts +51 -0
  133. package/dist/security/security-auto-inject.d.ts.map +1 -1
  134. package/dist/security/security-auto-inject.js +101 -11
  135. package/dist/security/security-auto-inject.js.map +1 -1
  136. package/dist/security/security-scan-engine.d.ts +4 -4
  137. package/dist/security/security-scan-engine.d.ts.map +1 -1
  138. package/dist/security/security-scan-engine.js +6 -0
  139. package/dist/security/security-scan-engine.js.map +1 -1
  140. package/dist/session/session-lineage.d.ts.map +1 -1
  141. package/dist/session/session-lineage.js +2 -0
  142. package/dist/session/session-lineage.js.map +1 -1
  143. package/dist/shell/constants.d.ts +5 -0
  144. package/dist/shell/constants.d.ts.map +1 -1
  145. package/dist/shell/constants.js +5 -0
  146. package/dist/shell/constants.js.map +1 -1
  147. package/dist/shell/daemon-instance.d.ts +74 -64
  148. package/dist/shell/daemon-instance.d.ts.map +1 -1
  149. package/dist/shell/daemon-instance.js +16 -121
  150. package/dist/shell/daemon-instance.js.map +1 -1
  151. package/dist/shell/health-events.js +1 -1
  152. package/dist/shell/health-events.js.map +1 -1
  153. package/dist/shell/instance-liveness.d.ts +112 -0
  154. package/dist/shell/instance-liveness.d.ts.map +1 -0
  155. package/dist/shell/instance-liveness.js +205 -0
  156. package/dist/shell/instance-liveness.js.map +1 -0
  157. package/dist/shell/schema-version-gate.d.ts +22 -0
  158. package/dist/shell/schema-version-gate.d.ts.map +1 -1
  159. package/dist/shell/schema-version-gate.js +116 -6
  160. package/dist/shell/schema-version-gate.js.map +1 -1
  161. package/dist/shell/worker-pidfile.d.ts +21 -8
  162. package/dist/shell/worker-pidfile.d.ts.map +1 -1
  163. package/dist/shell/worker-pidfile.js +38 -9
  164. package/dist/shell/worker-pidfile.js.map +1 -1
  165. package/dist/spawn/lead-launch.d.ts.map +1 -1
  166. package/dist/spawn/lead-launch.js +2 -1
  167. package/dist/spawn/lead-launch.js.map +1 -1
  168. package/dist/spawn/one-shot-scoping-spawn.d.ts +51 -0
  169. package/dist/spawn/one-shot-scoping-spawn.d.ts.map +1 -0
  170. package/dist/spawn/one-shot-scoping-spawn.js +156 -0
  171. package/dist/spawn/one-shot-scoping-spawn.js.map +1 -0
  172. package/dist/spawn/process-spawn.d.ts +12 -0
  173. package/dist/spawn/process-spawn.d.ts.map +1 -1
  174. package/dist/spawn/process-spawn.js +1 -1
  175. package/dist/spawn/process-spawn.js.map +1 -1
  176. package/dist/spawn/prompt-assembly.d.ts +8 -0
  177. package/dist/spawn/prompt-assembly.d.ts.map +1 -1
  178. package/dist/spawn/prompt-assembly.js +15 -3
  179. package/dist/spawn/prompt-assembly.js.map +1 -1
  180. package/dist/spawn/worktree-session.d.ts +24 -6
  181. package/dist/spawn/worktree-session.d.ts.map +1 -1
  182. package/dist/spawn/worktree-session.js +37 -14
  183. package/dist/spawn/worktree-session.js.map +1 -1
  184. package/dist/testing/arm-coverage-model.d.ts +75 -0
  185. package/dist/testing/arm-coverage-model.d.ts.map +1 -0
  186. package/dist/testing/arm-coverage-model.js +114 -0
  187. package/dist/testing/arm-coverage-model.js.map +1 -0
  188. package/dist/testing/fixtures/index.js +1 -1
  189. package/dist/types/index.js +1 -1
  190. package/dist/verify/commit-gate-configured.d.ts.map +1 -1
  191. package/dist/verify/commit-gate-configured.js +1 -1
  192. package/dist/verify/commit-gate-configured.js.map +1 -1
  193. package/dist/verify/commit-verdict-pull.d.ts +48 -0
  194. package/dist/verify/commit-verdict-pull.d.ts.map +1 -0
  195. package/dist/verify/commit-verdict-pull.js +148 -0
  196. package/dist/verify/commit-verdict-pull.js.map +1 -0
  197. package/dist/verify/commit-verdict-record.js +1 -1
  198. package/dist/verify/credit-rearm.js +1 -1
  199. package/dist/verify/credit-rearm.js.map +1 -1
  200. package/dist/verify/default-on-guards.d.ts +74 -0
  201. package/dist/verify/default-on-guards.d.ts.map +1 -0
  202. package/dist/verify/default-on-guards.js +305 -0
  203. package/dist/verify/default-on-guards.js.map +1 -0
  204. package/dist/verify/explicit-rearm.d.ts.map +1 -1
  205. package/dist/verify/explicit-rearm.js +1 -0
  206. package/dist/verify/explicit-rearm.js.map +1 -1
  207. package/dist/verify/gate-run-registry.d.ts.map +1 -1
  208. package/dist/verify/gate-run-registry.js +1 -0
  209. package/dist/verify/gate-run-registry.js.map +1 -1
  210. package/dist/verify/judged-ancestor.d.ts +41 -0
  211. package/dist/verify/judged-ancestor.d.ts.map +1 -0
  212. package/dist/verify/judged-ancestor.js +101 -0
  213. package/dist/verify/judged-ancestor.js.map +1 -0
  214. package/dist/verify/no-own-delta-verdict.d.ts +7 -2
  215. package/dist/verify/no-own-delta-verdict.d.ts.map +1 -1
  216. package/dist/verify/no-own-delta-verdict.js +14 -17
  217. package/dist/verify/no-own-delta-verdict.js.map +1 -1
  218. package/dist/verify/rework-attribution.d.ts +71 -0
  219. package/dist/verify/rework-attribution.d.ts.map +1 -0
  220. package/dist/verify/rework-attribution.js +263 -0
  221. package/dist/verify/rework-attribution.js.map +1 -0
  222. package/dist/verify/shortfall-rulings.d.ts.map +1 -1
  223. package/dist/verify/shortfall-rulings.js +3 -2
  224. package/dist/verify/shortfall-rulings.js.map +1 -1
  225. package/dist/verify/verification-boundary-env.d.ts +70 -17
  226. package/dist/verify/verification-boundary-env.d.ts.map +1 -1
  227. package/dist/verify/verification-boundary-env.js +88 -14
  228. package/dist/verify/verification-boundary-env.js.map +1 -1
  229. package/dist/verify/verification-commit-sharing.d.ts.map +1 -1
  230. package/dist/verify/verification-commit-sharing.js +2 -1
  231. package/dist/verify/verification-commit-sharing.js.map +1 -1
  232. package/dist/verify/verification-config.d.ts.map +1 -1
  233. package/dist/verify/verification-config.js +1 -0
  234. package/dist/verify/verification-config.js.map +1 -1
  235. package/dist/verify/verification-default-on.d.ts +0 -32
  236. package/dist/verify/verification-default-on.d.ts.map +1 -1
  237. package/dist/verify/verification-default-on.js +10 -234
  238. package/dist/verify/verification-default-on.js.map +1 -1
  239. package/dist/verify/verification-deps-default.d.ts.map +1 -1
  240. package/dist/verify/verification-deps-default.js +9 -0
  241. package/dist/verify/verification-deps-default.js.map +1 -1
  242. package/dist/verify/verification-engine.d.ts +2 -1
  243. package/dist/verify/verification-engine.d.ts.map +1 -1
  244. package/dist/verify/verification-engine.js +12 -4
  245. package/dist/verify/verification-engine.js.map +1 -1
  246. package/dist/verify/verification-feedback.d.ts +1 -1
  247. package/dist/verify/verification-feedback.d.ts.map +1 -1
  248. package/dist/verify/verification-feedback.js +5 -0
  249. package/dist/verify/verification-feedback.js.map +1 -1
  250. package/dist/verify/verification-rework-issue.d.ts +48 -7
  251. package/dist/verify/verification-rework-issue.d.ts.map +1 -1
  252. package/dist/verify/verification-rework-issue.js +111 -9
  253. package/dist/verify/verification-rework-issue.js.map +1 -1
  254. package/package.json +2 -2
@@ -0,0 +1,254 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/focus-stage-lifecycle/ratify-bar-gate.test.ts,
3
+ // packages/daemon/src/prd/prd-arm-readiness.test.ts,
4
+ // packages/daemon/src/prd/prd-frontier-arm-covers-stated-effects.test.ts,
5
+ // packages/daemon/src/prd/prd-frontier-arm-refused.test.ts,
6
+ // packages/daemon/src/prd/prd-frontier-arming.test.ts
7
+ // PINNED-BY-END
8
+ /**
9
+ * "Is this focus scoped enough to arm?" -- the question the PRD controller must
10
+ * answer BEFORE it spends the PRD's Play on a frontier focus.
11
+ *
12
+ * An arm covers the effects the focus held when the go-signal was given, and
13
+ * the database fixes that set AT THE ARM (`armed_baseline_target_node_ids`). So
14
+ * an arm placed on an empty focus covers nothing, permanently: every delivery
15
+ * scoped afterwards rests at `planning`, invisible to the running team, until
16
+ * someone arms again. The controller therefore asks this first.
17
+ *
18
+ * THE BAR: the focus holds at least ONE anchored, non-cancelled delivery whose
19
+ * injection names at least one target, and EVERY one of that injection's
20
+ * targets carries an `frt_statement`. An anchor says which cause the delivery
21
+ * changes; the restatement says what the world reads as once it has. A target
22
+ * with no restatement states no future, so an arm covering it covers nothing a
23
+ * later verify can check -- which is the whole failure this module exists to
24
+ * prevent.
25
+ *
26
+ * PREFER `criteria_standing` ONCE IT LANDS. A sibling delivery is adding a
27
+ * `criteria_standing` read that answers exactly this question for an un-armed
28
+ * focus, derived live at the edge. When it lands, this module's IO half
29
+ * (`readFocusArmReadiness`) should become a call to it and the local derivation
30
+ * below should be deleted -- a second definition of "scoped enough" is exactly
31
+ * the drift the arm-coverage work exists to remove. It has NOT landed yet, so
32
+ * the derivation here is direct and deliberately narrow.
33
+ *
34
+ * FAIL CLOSED = DO NOT ARM. Every unreadable input answers "not ready" with the
35
+ * reason. That is the safe direction here and the opposite of verify's: verify
36
+ * holds a delivery to every target when it cannot prove coverage, because
37
+ * judging one target too many costs a re-work cycle; arming on an unproven
38
+ * scope costs the human's go-signal itself, which only a new arm restores.
39
+ *
40
+ * TWO QUESTIONS LIVE HERE, AND THEY ARE NOT THE SAME BAR. Read the one you
41
+ * mean:
42
+ *
43
+ * `assessArmReadiness` -- "is there a delivery worth spending the PRD's Play
44
+ * on?" PER-DELIVERY: one anchored delivery whose own injection's targets all
45
+ * state futures is enough. The PRD frontier asks this because it chooses
46
+ * WHETHER to arm.
47
+ *
48
+ * `assessFocusStatesABar` -- the DATABASE's rule, restated: across the whole
49
+ * covered set, at least one undesired effect, and NOT ONE of them unstated.
50
+ * `stamp_focus_arm_baseline()` (migration 20260922173056) refuses on exactly
51
+ * this, at both go-signals -- the role arm, and the read_only TRUE -> FALSE
52
+ * ratify crossing of an audit focus. A caller about to cross one of those
53
+ * asks THIS one, so the refusal never has to arrive mid-crossing.
54
+ *
55
+ * The second is strictly the stricter: a focus with one stated delivery and one
56
+ * unstated one passes the first and is refused by the second. That is why they
57
+ * are separate functions rather than one with a flag -- they answer different
58
+ * questions, and collapsing them would silently move the PRD frontier's bar.
59
+ */
60
+ import { DELIVERY_STATUS } from '@telora/daemon-core';
61
+ import { getFocusDeliveries } from '../queries/focuses.js';
62
+ import { fetchInjectionBundles } from '../resolvers/shared/loop.js';
63
+ import { createLogger } from '../shell/log.js';
64
+ const log = createLogger({ module: 'prd-controller' });
65
+ /** Does this injection's target set state a future? */
66
+ function targetsStateAFuture(targets) {
67
+ if (targets.length === 0)
68
+ return false;
69
+ return targets.every((t) => (t.frtStatement ?? '').trim().length > 0);
70
+ }
71
+ /**
72
+ * The bar, PURE. `targetsByInjectionId` maps each anchored delivery's injection
73
+ * to the effects it promises to flip.
74
+ *
75
+ * A delivery is COUNTED when it is anchored, not cancelled, and its injection's
76
+ * targets all carry a restatement. An injection with NO targets is not counted:
77
+ * "every target carries a restatement" is vacuously true of an empty set, and
78
+ * an arm over an empty set is precisely the zero-effect arm this check refuses.
79
+ */
80
+ export function assessArmReadiness(deliveries, targetsByInjectionId) {
81
+ const live = deliveries.filter((d) => d.executionStatus !== DELIVERY_STATUS.CANCELLED);
82
+ if (live.length === 0) {
83
+ return { ready: false, reason: 'the focus holds no non-cancelled delivery', readyDeliveryIds: [] };
84
+ }
85
+ const anchored = live.filter((d) => (d.injectionId ?? '').length > 0);
86
+ if (anchored.length === 0) {
87
+ return {
88
+ ready: false,
89
+ reason: `${live.length} delivery/deliveries, none anchored to an injection`,
90
+ readyDeliveryIds: [],
91
+ };
92
+ }
93
+ const readyDeliveryIds = anchored
94
+ .filter((d) => targetsStateAFuture(targetsByInjectionId.get(d.injectionId) ?? []))
95
+ .map((d) => d.id);
96
+ if (readyDeliveryIds.length === 0) {
97
+ return {
98
+ ready: false,
99
+ reason: `${anchored.length} anchored delivery/deliveries, but none whose injection targets ` +
100
+ 'all carry an frt_statement (an arm over them would cover no stated effect)',
101
+ readyDeliveryIds: [],
102
+ };
103
+ }
104
+ return {
105
+ ready: true,
106
+ reason: `${readyDeliveryIds.length} of ${anchored.length} anchored delivery/deliveries state their targets' futures`,
107
+ readyDeliveryIds,
108
+ };
109
+ }
110
+ /** Default: the focus's deliveries, narrowed to the fields the bar reads. */
111
+ async function defaultLoadDeliveries(focusId) {
112
+ const deliveries = await getFocusDeliveries(focusId);
113
+ return deliveries.map((d) => ({
114
+ id: d.id,
115
+ name: d.name,
116
+ executionStatus: d.executionStatus,
117
+ injectionId: d.injectionId ?? null,
118
+ }));
119
+ }
120
+ /**
121
+ * Default: the injection-context read's `nowTargets` -- per targeted undesired
122
+ * effect, its current statement and the `frt_statement` it becomes.
123
+ *
124
+ * `nowTargets` reports the UDE targets, which is exactly the set this bar is
125
+ * about: those are the effects an injection PROMISES TO FLIP, and the ones a
126
+ * later verify reconciles against. An injection that targets only a cause
127
+ * entity reports none here and is not counted -- it states no effect, so an arm
128
+ * over it covers nothing checkable. A backend predating the field omits it,
129
+ * which reads the same way: not ready, never a silent pass.
130
+ */
131
+ async function defaultLoadTargets(injectionIds) {
132
+ const bundles = await fetchInjectionBundles(injectionIds);
133
+ const out = new Map();
134
+ for (const [injectionId, bundle] of bundles) {
135
+ out.set(injectionId, (bundle.nowTargets ?? [])
136
+ .filter((t) => typeof t.nodeId === 'string' && t.nodeId.length > 0)
137
+ .map((t) => ({ nodeId: t.nodeId, frtStatement: t.target })));
138
+ }
139
+ return out;
140
+ }
141
+ /**
142
+ * Read a focus's arm readiness. NEVER throws: an unreadable input answers "not
143
+ * ready" with the failure as its reason, and the caller logs it and re-tries on
144
+ * a later tick. Nothing is escalated -- an unscoped focus is a waiting state,
145
+ * not an incident.
146
+ */
147
+ export async function readFocusArmReadiness(focusId, deps = {}) {
148
+ const loadDeliveries = deps.loadDeliveries ?? defaultLoadDeliveries;
149
+ const loadTargets = deps.loadTargetsByInjectionId ?? defaultLoadTargets;
150
+ try {
151
+ const deliveries = await loadDeliveries(focusId);
152
+ const injectionIds = deliveries
153
+ .filter((d) => d.executionStatus !== DELIVERY_STATUS.CANCELLED)
154
+ .map((d) => d.injectionId)
155
+ .filter((id) => typeof id === 'string' && id.length > 0);
156
+ const targets = injectionIds.length > 0 ? await loadTargets(injectionIds) : new Map();
157
+ return assessArmReadiness(deliveries, targets);
158
+ }
159
+ catch (err) {
160
+ const message = err.message;
161
+ log.warn(`[prd-controller] arm-readiness read failed for focus ${focusId}: ${message}`);
162
+ return {
163
+ ready: false,
164
+ reason: `arm-readiness could not be read (${message}) -- holding the arm`,
165
+ readyDeliveryIds: [],
166
+ };
167
+ }
168
+ }
169
+ /**
170
+ * The database's rule, PURE, over the same inputs `assessArmReadiness` reads.
171
+ *
172
+ * Mirrors `stamp_focus_arm_baseline()` / `focus_arm_baseline_snapshot()`: the
173
+ * covered set is the union of every non-cancelled anchored delivery's injection
174
+ * targets (the injection-context read's `nowTargets`, which reports the
175
+ * UNDESIRED EFFECT targets -- the same node type the trigger counts), it must be
176
+ * non-empty, and every member must carry a non-blank restatement.
177
+ *
178
+ * It is a PRE-CHECK, never the authority: the trigger derives its own answer at
179
+ * the instant of the write, and the two are read seconds apart. A caller still
180
+ * handles the refusal arriving anyway.
181
+ */
182
+ export function assessFocusStatesABar(deliveries, targetsByInjectionId) {
183
+ const covered = new Map();
184
+ for (const delivery of deliveries) {
185
+ if (delivery.executionStatus === DELIVERY_STATUS.CANCELLED)
186
+ continue;
187
+ const injectionId = delivery.injectionId ?? '';
188
+ if (injectionId === '')
189
+ continue;
190
+ for (const target of targetsByInjectionId.get(injectionId) ?? []) {
191
+ covered.set(target.nodeId, target);
192
+ }
193
+ }
194
+ if (covered.size === 0) {
195
+ return {
196
+ statesABar: false,
197
+ readable: true,
198
+ reason: 'the focus covers no undesired effect (no non-cancelled delivery anchored to an ' +
199
+ 'injection that targets one), so it states no future to judge the work against',
200
+ coveredEffectCount: 0,
201
+ unstatedNodeIds: [],
202
+ };
203
+ }
204
+ const unstatedNodeIds = [...covered.values()]
205
+ .filter((t) => (t.frtStatement ?? '').trim().length === 0)
206
+ .map((t) => t.nodeId);
207
+ if (unstatedNodeIds.length > 0) {
208
+ return {
209
+ statesABar: false,
210
+ readable: true,
211
+ reason: `${unstatedNodeIds.length} of ${covered.size} covered undesired effect(s) state no ` +
212
+ `future (frt_statement null or blank): ${unstatedNodeIds.join(', ')}`,
213
+ coveredEffectCount: covered.size,
214
+ unstatedNodeIds,
215
+ };
216
+ }
217
+ return {
218
+ statesABar: true,
219
+ readable: true,
220
+ reason: `${covered.size} covered undesired effect(s), every one of them stating its future`,
221
+ coveredEffectCount: covered.size,
222
+ unstatedNodeIds: [],
223
+ };
224
+ }
225
+ /**
226
+ * Read whether a focus states a bar, live. NEVER throws: an unreadable input
227
+ * answers `{ statesABar: false, readable: false }` with the failure as its
228
+ * reason, so the caller holds rather than crossing on an unproven bar.
229
+ */
230
+ export async function readFocusStatesABar(focusId, deps = {}) {
231
+ const loadDeliveries = deps.loadDeliveries ?? defaultLoadDeliveries;
232
+ const loadTargets = deps.loadTargetsByInjectionId ?? defaultLoadTargets;
233
+ try {
234
+ const deliveries = await loadDeliveries(focusId);
235
+ const injectionIds = deliveries
236
+ .filter((d) => d.executionStatus !== DELIVERY_STATUS.CANCELLED)
237
+ .map((d) => d.injectionId)
238
+ .filter((id) => typeof id === 'string' && id.length > 0);
239
+ const targets = injectionIds.length > 0 ? await loadTargets(injectionIds) : new Map();
240
+ return assessFocusStatesABar(deliveries, targets);
241
+ }
242
+ catch (err) {
243
+ const message = err.message;
244
+ log.warn(`[prd-controller] bar-standing read failed for focus ${focusId}: ${message}`);
245
+ return {
246
+ statesABar: false,
247
+ readable: false,
248
+ reason: `the focus's covered effects could not be read (${message})`,
249
+ coveredEffectCount: 0,
250
+ unstatedNodeIds: [],
251
+ };
252
+ }
253
+ }
254
+ //# sourceMappingURL=arm-readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arm-readiness.js","sourceRoot":"","sources":["../../src/prd/arm-readiness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * A refused arm, SURVIVED: classify it, and record it where an operator reads it.
3
+ *
4
+ * WHAT REFUSES, AND WHY THE MACHINE MUST EXPECT IT. The arm edge
5
+ * (`stamp_focus_arm_baseline()`, migration 20260922173056) RAISES when the arm
6
+ * would cover no undesired effect, or would cover one that states no future --
7
+ * `check_violation` with a message beginning `arm_criteria_required:`, carrying
8
+ * the offending NODES by seq and statement. The product-api answers 400 with
9
+ * that message verbatim and `code: 'arm_criteria_required'`. So the daemon's own
10
+ * readiness gate (`prd/arm-readiness.ts`) is no longer the last word on whether
11
+ * an arm lands: the database is. This module is the BACKSTOP for the case where
12
+ * the daemon thought the focus was ready and the database disagreed -- the two
13
+ * read different things (the readiness gate reads the injection bundle's
14
+ * `nowTargets`; the trigger reads `targets` edges on the live tree), and they
15
+ * are read seconds apart, so they CAN disagree without either being wrong.
16
+ *
17
+ * WHY EVERY ARM FAILURE IS CAUGHT, NOT ONLY THE RECOGNIZED REFUSAL. This
18
+ * delivery exists to remove the PRD frontier's dependence on DEPLOY ORDER, and
19
+ * the deploy-order window is exactly the window in which the refusal is NOT
20
+ * recognizable: with the migration live and the edge function not, the same
21
+ * refused arm comes back as a generic 500 `backend_error` carrying none of the
22
+ * database's text. Catching only the recognized shape would leave the tick
23
+ * aborting in precisely the window the catch was written for. So the frontier
24
+ * catches whatever the arm throws, records what it can name, and continues; the
25
+ * frontier recomputes every tick, so the arm is naturally re-attempted.
26
+ *
27
+ * WHERE THE RECORD GOES, AND WHY THERE. A `focus_debug_artifacts` section, one
28
+ * row per (focus, section_kind), rendered on the focus Debug tab with its own
29
+ * "Updated ..." stamp, read by NOTHING in the machine's decision path -- so
30
+ * recording a refusal cannot misroute a delivery -- and cleared by DELETING the
31
+ * row, which is exactly the shape "until an arm succeeds" wants. It is the same
32
+ * surface, for the same reasons, that `integration_sync` (20260920152723) and
33
+ * `directive_undelivered` (20260920202553) already use; the second of those was
34
+ * written because "the ONLY trace was a log warn" is how a focus goes quiet for
35
+ * 51 minutes with nobody able to learn what it was owed. A log warn alone would
36
+ * repeat that here: the operator who needs this fact is looking at a PRD whose
37
+ * frontier is not advancing, not at a daemon host's journal. The log warn stays
38
+ * as the FLOOR -- it is what a failed record degrades to.
39
+ *
40
+ * NOTHING HERE ESCALATES. A refused arm is a recoverable state the machine
41
+ * re-tries, not a question for a human queue: the fix is a restatement on a
42
+ * tree node, and the scoping agent the frontier re-spawns is the actor that
43
+ * writes it.
44
+ */
45
+ import { type CallApiDeps } from '../queries/shared.js';
46
+ /** The wire code the product-api answers a refused arm with. */
47
+ export declare const ARM_CRITERIA_REQUIRED_CODE = "arm_criteria_required";
48
+ /**
49
+ * The prefix the DATABASE declares as the contract (the prose after it is not).
50
+ * Matched as well as the wire code so a refusal that reaches us through a
51
+ * transport that dropped the code -- or an older edge that never set one -- is
52
+ * still recognized by the text the trigger wrote.
53
+ */
54
+ export declare const ARM_CRITERIA_REQUIRED_PREFIX = "arm_criteria_required:";
55
+ /** The focus_debug_artifacts section this record lives in. */
56
+ export declare const ARM_REFUSAL_SECTION_KIND = "arm_refused";
57
+ /** The line carrying the first-observed timestamp across re-records. */
58
+ export declare const REFUSED_SINCE_PREFIX = "Refused since: ";
59
+ /** What an arm failure was, once classified. */
60
+ export interface ArmFailure {
61
+ /**
62
+ * 'criteria_required' -- positively the arm-criteria refusal: the database
63
+ * refused because the arm states no future to judge the work against, and
64
+ * `detail` carries its node list. 'unclassified' -- any other arm failure,
65
+ * including the deploy-order window's opaque 500.
66
+ */
67
+ kind: 'criteria_required' | 'unclassified';
68
+ /** The wire code the failure carried, or null when it carried none. */
69
+ code: string | null;
70
+ /**
71
+ * The refusal text VERBATIM from its prefix onward (or the raw error message
72
+ * when there is no prefix). Never parsed or re-worded: the node list -- which
73
+ * effects are covered, or which of them state no future -- is the half a
74
+ * human needs and only the database could resolve.
75
+ */
76
+ detail: string;
77
+ }
78
+ /**
79
+ * Classify whatever `armFocus` threw. TOTAL: every input yields a record, so a
80
+ * caller never has to decide whether an unrecognized failure is reportable.
81
+ */
82
+ export declare function classifyArmFailure(err: unknown): ArmFailure;
83
+ /** Everything the rendered record names. */
84
+ export interface ArmRefusalRecord {
85
+ focusId: string;
86
+ /** The overcome node whose focus this is (the frontier's own label for it). */
87
+ nodeId: string;
88
+ prdId: string;
89
+ prdTitle: string;
90
+ failure: ArmFailure;
91
+ /** The daemon's own readiness verdict at the moment it decided to arm. */
92
+ readinessReason: string;
93
+ /** ISO timestamp of THIS observation. */
94
+ observedAt: string;
95
+ }
96
+ /** The `Refused since:` value in a stored artifact, or null when absent. */
97
+ export declare function parseRefusedSince(content: string | undefined): string | null;
98
+ /**
99
+ * Render the human-facing record. PURE.
100
+ *
101
+ * The first-observed timestamp is the one line a re-record must be able to find
102
+ * again, so it is emitted on its own line with a fixed prefix: the frontier
103
+ * re-attempts the arm every tick, so `updated_at` alone would always read "just
104
+ * now" and hide a frontier that has been refused for a day.
105
+ */
106
+ export declare function renderArmRefusalArtifact(record: ArmRefusalRecord, since: string): string;
107
+ /**
108
+ * Record a refused arm, carrying forward the first-observed timestamp when one
109
+ * is already on record.
110
+ *
111
+ * NEVER THROWS. The record is the operator's view of a waiting state, not a
112
+ * step in the tick: a recording failure (the section kind not yet deployed, the
113
+ * API down) must not cost the tick that survived the refusal. It degrades to
114
+ * the log warn, which carries the same code and node list.
115
+ */
116
+ export declare function recordArmRefusal(record: ArmRefusalRecord, deps?: CallApiDeps): Promise<void>;
117
+ /**
118
+ * Write the `arm_refused` section, carrying the first-observed timestamp
119
+ * forward. The IO half of the record, with the RENDERING left to the caller.
120
+ *
121
+ * Two crossings can be refused for stating no bar -- the role arm (the PRD
122
+ * frontier's, rendered above) and the audit focus's ratify crossing
123
+ * (`focus-stage-lifecycle/ratify-bar-gate.ts`) -- and they are refusals of
124
+ * DIFFERENT acts, so they read differently to an operator. What they share is
125
+ * the section they live in, the since-when line and the never-throws contract;
126
+ * that is what lives here, so there is one writer of the row rather than two
127
+ * that must be kept in step.
128
+ *
129
+ * NEVER THROWS. The record is the operator's view of a waiting state, not a
130
+ * step in the tick: a recording failure (the section kind not yet deployed, the
131
+ * API down) must not cost the tick that survived the refusal. It degrades to
132
+ * the log warn, which carries the same detail.
133
+ */
134
+ export declare function recordArmRefusalSection(args: {
135
+ focusId: string;
136
+ /** ISO timestamp of THIS observation; the since-when when none is stored. */
137
+ observedAt: string;
138
+ /** What the refusal said -- the floor the log warn degrades to. */
139
+ detail: string;
140
+ /** Render the artifact, given the first-observed timestamp to carry. */
141
+ render: (since: string) => string;
142
+ }, deps?: CallApiDeps): Promise<void>;
143
+ /**
144
+ * Clear the record. Idempotent (deleting a section that is not there is a
145
+ * no-op) and, like the record, never throws: a failed clear leaves a stale
146
+ * record on a focus that IS armed, which is a stale note -- not a wedge.
147
+ */
148
+ export declare function clearArmRefusal(focusId: string, deps?: CallApiDeps): Promise<void>;
149
+ //# sourceMappingURL=arm-refusal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arm-refusal.d.ts","sourceRoot":"","sources":["../../src/prd/arm-refusal.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKjE,gEAAgE;AAChE,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,2BAA2B,CAAC;AAErE,8DAA8D;AAC9D,eAAO,MAAM,wBAAwB,gBAAgB,CAAC;AAEtD,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AAEtD,gDAAgD;AAChD,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,IAAI,EAAE,mBAAmB,GAAG,cAAc,CAAC;IAC3C,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAc3D;AAQD,4CAA4C;AAC5C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,CAAC;IACpB,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAS5E;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,GACZ,MAAM,CA4BR;AASD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,gBAAgB,EACxB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACnC,EACD,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -0,0 +1,219 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/prd/prd-frontier-arm-refused.test.ts
3
+ // PINNED-BY-END
4
+ /**
5
+ * A refused arm, SURVIVED: classify it, and record it where an operator reads it.
6
+ *
7
+ * WHAT REFUSES, AND WHY THE MACHINE MUST EXPECT IT. The arm edge
8
+ * (`stamp_focus_arm_baseline()`, migration 20260922173056) RAISES when the arm
9
+ * would cover no undesired effect, or would cover one that states no future --
10
+ * `check_violation` with a message beginning `arm_criteria_required:`, carrying
11
+ * the offending NODES by seq and statement. The product-api answers 400 with
12
+ * that message verbatim and `code: 'arm_criteria_required'`. So the daemon's own
13
+ * readiness gate (`prd/arm-readiness.ts`) is no longer the last word on whether
14
+ * an arm lands: the database is. This module is the BACKSTOP for the case where
15
+ * the daemon thought the focus was ready and the database disagreed -- the two
16
+ * read different things (the readiness gate reads the injection bundle's
17
+ * `nowTargets`; the trigger reads `targets` edges on the live tree), and they
18
+ * are read seconds apart, so they CAN disagree without either being wrong.
19
+ *
20
+ * WHY EVERY ARM FAILURE IS CAUGHT, NOT ONLY THE RECOGNIZED REFUSAL. This
21
+ * delivery exists to remove the PRD frontier's dependence on DEPLOY ORDER, and
22
+ * the deploy-order window is exactly the window in which the refusal is NOT
23
+ * recognizable: with the migration live and the edge function not, the same
24
+ * refused arm comes back as a generic 500 `backend_error` carrying none of the
25
+ * database's text. Catching only the recognized shape would leave the tick
26
+ * aborting in precisely the window the catch was written for. So the frontier
27
+ * catches whatever the arm throws, records what it can name, and continues; the
28
+ * frontier recomputes every tick, so the arm is naturally re-attempted.
29
+ *
30
+ * WHERE THE RECORD GOES, AND WHY THERE. A `focus_debug_artifacts` section, one
31
+ * row per (focus, section_kind), rendered on the focus Debug tab with its own
32
+ * "Updated ..." stamp, read by NOTHING in the machine's decision path -- so
33
+ * recording a refusal cannot misroute a delivery -- and cleared by DELETING the
34
+ * row, which is exactly the shape "until an arm succeeds" wants. It is the same
35
+ * surface, for the same reasons, that `integration_sync` (20260920152723) and
36
+ * `directive_undelivered` (20260920202553) already use; the second of those was
37
+ * written because "the ONLY trace was a log warn" is how a focus goes quiet for
38
+ * 51 minutes with nobody able to learn what it was owed. A log warn alone would
39
+ * repeat that here: the operator who needs this fact is looking at a PRD whose
40
+ * frontier is not advancing, not at a daemon host's journal. The log warn stays
41
+ * as the FLOOR -- it is what a failed record degrades to.
42
+ *
43
+ * NOTHING HERE ESCALATES. A refused arm is a recoverable state the machine
44
+ * re-tries, not a question for a human queue: the fix is a restatement on a
45
+ * tree node, and the scoping agent the frontier re-spawns is the actor that
46
+ * writes it.
47
+ */
48
+ import { callApi } from '../queries/shared.js';
49
+ import { createLogger } from '../shell/log.js';
50
+ const log = createLogger({ module: 'prd-controller' });
51
+ /** The wire code the product-api answers a refused arm with. */
52
+ export const ARM_CRITERIA_REQUIRED_CODE = 'arm_criteria_required';
53
+ /**
54
+ * The prefix the DATABASE declares as the contract (the prose after it is not).
55
+ * Matched as well as the wire code so a refusal that reaches us through a
56
+ * transport that dropped the code -- or an older edge that never set one -- is
57
+ * still recognized by the text the trigger wrote.
58
+ */
59
+ export const ARM_CRITERIA_REQUIRED_PREFIX = 'arm_criteria_required:';
60
+ /** The focus_debug_artifacts section this record lives in. */
61
+ export const ARM_REFUSAL_SECTION_KIND = 'arm_refused';
62
+ /** The line carrying the first-observed timestamp across re-records. */
63
+ export const REFUSED_SINCE_PREFIX = 'Refused since: ';
64
+ /** The wire code an ApiError carries, when the thrown value is one. */
65
+ function readWireCode(err) {
66
+ const code = err?.wireCode;
67
+ return typeof code === 'string' && code.length > 0 ? code : null;
68
+ }
69
+ /**
70
+ * Classify whatever `armFocus` threw. TOTAL: every input yields a record, so a
71
+ * caller never has to decide whether an unrecognized failure is reportable.
72
+ */
73
+ export function classifyArmFailure(err) {
74
+ const message = err?.message ?? String(err);
75
+ const code = readWireCode(err);
76
+ const at = message.indexOf(ARM_CRITERIA_REQUIRED_PREFIX);
77
+ if (code === ARM_CRITERIA_REQUIRED_CODE || at !== -1) {
78
+ return {
79
+ kind: 'criteria_required',
80
+ code: code ?? ARM_CRITERIA_REQUIRED_CODE,
81
+ // Slice from the prefix when it is present: that drops any transport
82
+ // preamble while keeping every word the database wrote.
83
+ detail: at !== -1 ? message.slice(at) : message,
84
+ };
85
+ }
86
+ return { kind: 'unclassified', code, detail: message };
87
+ }
88
+ /** The `Refused since:` value in a stored artifact, or null when absent. */
89
+ export function parseRefusedSince(content) {
90
+ if (!content)
91
+ return null;
92
+ for (const line of content.split('\n')) {
93
+ if (line.startsWith(REFUSED_SINCE_PREFIX)) {
94
+ const value = line.slice(REFUSED_SINCE_PREFIX.length).trim();
95
+ if (value)
96
+ return value;
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+ /**
102
+ * Render the human-facing record. PURE.
103
+ *
104
+ * The first-observed timestamp is the one line a re-record must be able to find
105
+ * again, so it is emitted on its own line with a fixed prefix: the frontier
106
+ * re-attempts the arm every tick, so `updated_at` alone would always read "just
107
+ * now" and hide a frontier that has been refused for a day.
108
+ */
109
+ export function renderArmRefusalArtifact(record, since) {
110
+ const { focusId, nodeId, prdId, prdTitle, failure, readinessReason, observedAt } = record;
111
+ const headline = failure.kind === 'criteria_required'
112
+ ? 'Arm refused: this focus states no future to judge the work against'
113
+ : 'Arm failed: the focus could not be armed';
114
+ return [
115
+ `# ${headline}`,
116
+ '',
117
+ 'The PRD frontier materialized this focus and tried to arm it. The write was',
118
+ 'refused, so the focus stays materialized and UN-ARMED. Nothing is lost and',
119
+ 'nothing is frozen: the frontier recomputes every tick and re-attempts the arm,',
120
+ 'and this record clears the moment one lands.',
121
+ '',
122
+ `Refusal code: ${failure.code ?? '(none carried)'}`,
123
+ `${REFUSED_SINCE_PREFIX}${since}`,
124
+ `Last refused: ${observedAt}`,
125
+ `PRD: ${prdTitle} (${prdId})`,
126
+ `Overcome node: ${nodeId}`,
127
+ `Focus: ${focusId}`,
128
+ '',
129
+ '## What the database said',
130
+ '',
131
+ failure.detail,
132
+ '',
133
+ '## What the daemon thought before it asked',
134
+ '',
135
+ readinessReason,
136
+ ].join('\n');
137
+ }
138
+ /** The first-observed timestamp already on record for this focus, or null. */
139
+ async function readRefusedSince(focusId, api) {
140
+ const result = await api('focus_debug_get', { focusId });
141
+ const section = (result?.sections ?? []).find(s => s.sectionKind === ARM_REFUSAL_SECTION_KIND);
142
+ return parseRefusedSince(section?.content);
143
+ }
144
+ /**
145
+ * Record a refused arm, carrying forward the first-observed timestamp when one
146
+ * is already on record.
147
+ *
148
+ * NEVER THROWS. The record is the operator's view of a waiting state, not a
149
+ * step in the tick: a recording failure (the section kind not yet deployed, the
150
+ * API down) must not cost the tick that survived the refusal. It degrades to
151
+ * the log warn, which carries the same code and node list.
152
+ */
153
+ export async function recordArmRefusal(record, deps = {}) {
154
+ await recordArmRefusalSection({
155
+ focusId: record.focusId,
156
+ observedAt: record.observedAt,
157
+ detail: record.failure.detail,
158
+ render: (since) => renderArmRefusalArtifact(record, since),
159
+ }, deps);
160
+ }
161
+ /**
162
+ * Write the `arm_refused` section, carrying the first-observed timestamp
163
+ * forward. The IO half of the record, with the RENDERING left to the caller.
164
+ *
165
+ * Two crossings can be refused for stating no bar -- the role arm (the PRD
166
+ * frontier's, rendered above) and the audit focus's ratify crossing
167
+ * (`focus-stage-lifecycle/ratify-bar-gate.ts`) -- and they are refusals of
168
+ * DIFFERENT acts, so they read differently to an operator. What they share is
169
+ * the section they live in, the since-when line and the never-throws contract;
170
+ * that is what lives here, so there is one writer of the row rather than two
171
+ * that must be kept in step.
172
+ *
173
+ * NEVER THROWS. The record is the operator's view of a waiting state, not a
174
+ * step in the tick: a recording failure (the section kind not yet deployed, the
175
+ * API down) must not cost the tick that survived the refusal. It degrades to
176
+ * the log warn, which carries the same detail.
177
+ */
178
+ export async function recordArmRefusalSection(args, deps = {}) {
179
+ const api = deps.callApi ?? callApi;
180
+ let since = null;
181
+ try {
182
+ since = await readRefusedSince(args.focusId, api);
183
+ }
184
+ catch {
185
+ // A failed read costs the ORIGINAL since-when, never the record itself.
186
+ since = null;
187
+ }
188
+ try {
189
+ await api('focus_debug_set', {
190
+ focusId: args.focusId,
191
+ fields: {
192
+ sectionKind: ARM_REFUSAL_SECTION_KIND,
193
+ content: args.render(since ?? args.observedAt),
194
+ },
195
+ });
196
+ }
197
+ catch (err) {
198
+ log.warn(`[prd-controller] could not record the arm refusal for focus ${args.focusId} ` +
199
+ `(${err.message}) -- the refusal itself: ${args.detail}`);
200
+ }
201
+ }
202
+ /**
203
+ * Clear the record. Idempotent (deleting a section that is not there is a
204
+ * no-op) and, like the record, never throws: a failed clear leaves a stale
205
+ * record on a focus that IS armed, which is a stale note -- not a wedge.
206
+ */
207
+ export async function clearArmRefusal(focusId, deps = {}) {
208
+ const api = deps.callApi ?? callApi;
209
+ try {
210
+ await api('focus_debug_clear', {
211
+ focusId,
212
+ fields: { sectionKind: ARM_REFUSAL_SECTION_KIND },
213
+ });
214
+ }
215
+ catch (err) {
216
+ log.debug(`[prd-controller] could not clear the arm-refusal record for focus ${focusId}: ${err.message}`);
217
+ }
218
+ }
219
+ //# sourceMappingURL=arm-refusal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arm-refusal.js","sourceRoot":"","sources":["../../src/prd/arm-refusal.ts"],"names":[],"mappings":"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"}