@phyzess/pappra 0.1.0-beta.13 → 0.1.0-beta.18

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 (357) hide show
  1. package/README.md +134 -15
  2. package/assets/integrations/skills/pappra/SKILL.md +28 -7
  3. package/assets/integrations/skills/pappra/references/collaboration.md +633 -0
  4. package/assets/integrations/skills/pappra/references/environment.md +360 -0
  5. package/assets/integrations/skills/pappra/references/hosts.md +20 -0
  6. package/assets/integrations/skills/pappra/references/operations.md +36 -5
  7. package/dist/adapters/pi/recovery-extension.d.ts +65 -0
  8. package/dist/adapters/pi/recovery-extension.js +238 -0
  9. package/dist/adapters/pi/session-transition-extension.d.ts +30 -0
  10. package/dist/adapters/pi/session-transition-extension.js +265 -0
  11. package/dist/app/automatic-handoff-events.d.ts +26 -0
  12. package/dist/app/automatic-handoff-events.js +134 -0
  13. package/dist/app/bounded-file.d.ts +2 -0
  14. package/dist/app/bounded-file.js +2 -0
  15. package/dist/app/capability-evidence/claude.d.ts +37 -0
  16. package/dist/app/capability-evidence/claude.js +206 -0
  17. package/dist/app/capability-evidence/codex.d.ts +35 -0
  18. package/dist/app/capability-evidence/codex.js +193 -0
  19. package/dist/app/capability-evidence/index.d.ts +33 -0
  20. package/dist/app/capability-evidence/index.js +117 -0
  21. package/dist/app/capability-evidence/pi.d.ts +73 -0
  22. package/dist/app/capability-evidence/pi.js +669 -0
  23. package/dist/app/capability-evidence/shared.d.ts +69 -0
  24. package/dist/app/capability-evidence/shared.js +195 -0
  25. package/dist/app/collab-auto-handoff.d.ts +55 -0
  26. package/dist/app/collab-auto-handoff.js +384 -0
  27. package/dist/app/collab-bindings.d.ts +57 -0
  28. package/dist/app/collab-bindings.js +1006 -0
  29. package/dist/app/collab-bootstrap-transport.d.ts +163 -0
  30. package/dist/app/collab-bootstrap-transport.js +769 -0
  31. package/dist/app/collab-bootstrap.d.ts +137 -0
  32. package/dist/app/collab-bootstrap.js +3455 -0
  33. package/dist/app/collab-handoff.d.ts +12 -0
  34. package/dist/app/collab-handoff.js +511 -0
  35. package/dist/app/collab-messages.d.ts +2 -0
  36. package/dist/app/collab-messages.js +2 -0
  37. package/dist/app/collab-notify.d.ts +156 -0
  38. package/dist/app/collab-notify.js +1208 -0
  39. package/dist/app/collab-preflight.d.ts +34 -0
  40. package/dist/app/collab-preflight.js +96 -0
  41. package/dist/app/collab-recovery-executor.d.ts +161 -0
  42. package/dist/app/collab-recovery-executor.js +1153 -0
  43. package/dist/app/collab-recovery-projection.d.ts +103 -0
  44. package/dist/app/collab-recovery-projection.js +659 -0
  45. package/dist/app/collab-recovery.d.ts +25 -0
  46. package/dist/app/collab-recovery.js +429 -0
  47. package/dist/app/collab-resources.d.ts +16 -0
  48. package/dist/app/collab-resources.js +278 -0
  49. package/dist/app/collab-role-events.d.ts +22 -0
  50. package/dist/app/collab-role-events.js +329 -0
  51. package/dist/app/collab-role-orchestration.d.ts +53 -0
  52. package/dist/app/collab-role-orchestration.js +601 -0
  53. package/dist/app/collab-role-plan.d.ts +81 -0
  54. package/dist/app/collab-role-plan.js +504 -0
  55. package/dist/app/collab-role-repair.d.ts +109 -0
  56. package/dist/app/collab-role-repair.js +821 -0
  57. package/dist/app/collab-rollover.d.ts +263 -0
  58. package/dist/app/collab-rollover.js +1112 -0
  59. package/dist/app/collab-route.d.ts +64 -0
  60. package/dist/app/collab-route.js +240 -0
  61. package/dist/app/collab-session-transition.d.ts +221 -0
  62. package/dist/app/collab-session-transition.js +3334 -0
  63. package/dist/app/collab-state.d.ts +7 -0
  64. package/dist/app/collab-state.js +162 -0
  65. package/dist/app/collab-task-store.d.ts +22 -0
  66. package/dist/app/collab-task-store.js +204 -0
  67. package/dist/app/collab-work-execution.d.ts +127 -0
  68. package/dist/app/collab-work-execution.js +1027 -0
  69. package/dist/app/collab-work-plan.d.ts +87 -0
  70. package/dist/app/collab-work-plan.js +437 -0
  71. package/dist/app/collaboration.d.ts +8 -2
  72. package/dist/app/collaboration.js +101 -12
  73. package/dist/app/doctor.js +108 -5
  74. package/dist/app/host-mcp.js +34 -8
  75. package/dist/app/host-probe.js +4 -4
  76. package/dist/app/init.d.ts +58 -4
  77. package/dist/app/init.js +768 -155
  78. package/dist/app/managed-pi-bootstrap-admission.d.ts +14 -0
  79. package/dist/app/managed-pi-bootstrap-admission.js +104 -0
  80. package/dist/app/managed-pi-bootstrap-refresh.d.ts +10 -0
  81. package/dist/app/managed-pi-bootstrap-refresh.js +78 -0
  82. package/dist/app/managed-pi-delivery.d.ts +8 -0
  83. package/dist/app/managed-pi-delivery.js +110 -0
  84. package/dist/app/managed-pi-handoff-receiver.d.ts +15 -0
  85. package/dist/app/managed-pi-handoff-receiver.js +263 -0
  86. package/dist/app/managed-pi-handoff-reference.d.ts +3 -0
  87. package/dist/app/managed-pi-handoff-reference.js +60 -0
  88. package/dist/app/managed-pi-herdr.d.ts +21 -0
  89. package/dist/app/managed-pi-herdr.js +185 -0
  90. package/dist/app/managed-pi-initial-admission.d.ts +28 -0
  91. package/dist/app/managed-pi-initial-admission.js +416 -0
  92. package/dist/app/managed-pi-initial-launch.d.ts +5 -0
  93. package/dist/app/managed-pi-initial-launch.js +61 -0
  94. package/dist/app/managed-pi-native-observation.d.ts +36 -0
  95. package/dist/app/managed-pi-native-observation.js +191 -0
  96. package/dist/app/managed-pi-readiness.d.ts +29 -0
  97. package/dist/app/managed-pi-readiness.js +288 -0
  98. package/dist/app/managed-pi-repair-stop.d.ts +21 -0
  99. package/dist/app/managed-pi-repair-stop.js +371 -0
  100. package/dist/app/managed-pi-resume-admission.d.ts +32 -0
  101. package/dist/app/managed-pi-resume-admission.js +618 -0
  102. package/dist/app/managed-pi-retirement.d.ts +28 -0
  103. package/dist/app/managed-pi-retirement.js +112 -0
  104. package/dist/app/managed-pi-sdk-control.d.ts +7 -0
  105. package/dist/app/managed-pi-sdk-control.js +169 -0
  106. package/dist/app/managed-pi-sdk-runtime.d.ts +3 -0
  107. package/dist/app/managed-pi-sdk-runtime.js +483 -0
  108. package/dist/app/managed-pi-source-admission.d.ts +14 -0
  109. package/dist/app/managed-pi-source-admission.js +323 -0
  110. package/dist/app/managed-pi-transition-host.d.ts +36 -0
  111. package/dist/app/managed-pi-transition-host.js +292 -0
  112. package/dist/app/managed-pi.d.ts +54 -0
  113. package/dist/app/managed-pi.js +248 -0
  114. package/dist/app/shell-readiness.d.ts +66 -0
  115. package/dist/app/shell-readiness.js +368 -0
  116. package/dist/app/task-pin.d.ts +2 -23
  117. package/dist/app/task-pin.js +2 -113
  118. package/dist/cli/commands/collaboration-binding.d.ts +13 -0
  119. package/dist/cli/commands/collaboration-binding.js +118 -0
  120. package/dist/cli/commands/collaboration-bootstrap.d.ts +10 -0
  121. package/dist/cli/commands/collaboration-bootstrap.js +84 -0
  122. package/dist/cli/commands/collaboration-capabilities.d.ts +13 -0
  123. package/dist/cli/commands/collaboration-capabilities.js +127 -0
  124. package/dist/cli/commands/collaboration-handoff.d.ts +13 -0
  125. package/dist/cli/commands/collaboration-handoff.js +102 -0
  126. package/dist/cli/commands/collaboration-message.d.ts +17 -0
  127. package/dist/cli/commands/collaboration-message.js +177 -0
  128. package/dist/cli/commands/collaboration-plan.d.ts +8 -0
  129. package/dist/cli/commands/collaboration-plan.js +108 -0
  130. package/dist/cli/commands/collaboration-preflight.d.ts +10 -0
  131. package/dist/cli/commands/collaboration-preflight.js +167 -0
  132. package/dist/cli/commands/collaboration-recovery-run.d.ts +46 -0
  133. package/dist/cli/commands/collaboration-recovery-run.js +224 -0
  134. package/dist/cli/commands/collaboration-recovery.d.ts +11 -0
  135. package/dist/cli/commands/collaboration-recovery.js +104 -0
  136. package/dist/cli/commands/collaboration-resources.d.ts +11 -0
  137. package/dist/cli/commands/collaboration-resources.js +96 -0
  138. package/dist/cli/commands/collaboration-role-plan.d.ts +9 -0
  139. package/dist/cli/commands/collaboration-role-plan.js +69 -0
  140. package/dist/cli/commands/collaboration-role-run.d.ts +11 -0
  141. package/dist/cli/commands/collaboration-role-run.js +128 -0
  142. package/dist/cli/commands/collaboration-rollover.d.ts +10 -0
  143. package/dist/cli/commands/collaboration-rollover.js +103 -0
  144. package/dist/cli/commands/collaboration-state.d.ts +10 -0
  145. package/dist/cli/commands/collaboration-state.js +96 -0
  146. package/dist/cli/commands/collaboration-transition.d.ts +10 -0
  147. package/dist/cli/commands/collaboration-transition.js +75 -0
  148. package/dist/cli/commands/collaboration-work-run.d.ts +34 -0
  149. package/dist/cli/commands/collaboration-work-run.js +178 -0
  150. package/dist/cli/commands/collaboration.d.ts +4 -0
  151. package/dist/cli/commands/collaboration.js +39 -4
  152. package/dist/cli/commands/continuity.js +2 -6
  153. package/dist/cli/commands/docs.d.ts +2 -0
  154. package/dist/cli/commands/docs.js +89 -15
  155. package/dist/cli/commands/host.d.ts +7 -1
  156. package/dist/cli/commands/host.js +122 -7
  157. package/dist/cli/commands/init.d.ts +20 -3
  158. package/dist/cli/commands/init.js +897 -232
  159. package/dist/cli/commands/mcp.d.ts +1 -0
  160. package/dist/cli/commands/mcp.js +11 -5
  161. package/dist/cli/commands/repair.d.ts +12 -0
  162. package/dist/cli/commands/repair.js +41 -0
  163. package/dist/cli/commands/runtime.d.ts +1 -1
  164. package/dist/cli/commands/runtime.js +139 -38
  165. package/dist/cli/commands/session.d.ts +7 -0
  166. package/dist/cli/commands/session.js +82 -0
  167. package/dist/cli/commands/task.js +19 -5
  168. package/dist/cli/run.js +866 -24
  169. package/dist/code/identity.d.ts +7 -0
  170. package/dist/code/identity.js +7 -3
  171. package/dist/code/registration.js +7 -0
  172. package/dist/code/service.d.ts +9 -0
  173. package/dist/code/service.js +16 -3
  174. package/dist/code/text.js +19 -7
  175. package/dist/collab/admission.d.ts +91 -66
  176. package/dist/collab/admission.js +21 -6
  177. package/dist/collab/canonical.d.ts +1 -1
  178. package/dist/collab/canonical.js +44 -3
  179. package/dist/collab/envelope.d.ts +2 -2
  180. package/dist/collab/envelope.js +12 -12
  181. package/dist/collab/first-work.d.ts +3 -0
  182. package/dist/collab/first-work.js +15 -0
  183. package/dist/collab/handoff.d.ts +16 -0
  184. package/dist/collab/handoff.js +39 -5
  185. package/dist/collab/index.d.ts +97 -1
  186. package/dist/collab/index.js +9 -1
  187. package/dist/collab/messages.js +126 -3
  188. package/dist/collab/persisted-messages.d.ts +123 -0
  189. package/dist/collab/persisted-messages.js +496 -0
  190. package/dist/collab/preflight.d.ts +1 -1
  191. package/dist/collab/resources.d.ts +13 -3
  192. package/dist/collab/resources.js +37 -6
  193. package/dist/collab/rollover.d.ts +311 -0
  194. package/dist/collab/rollover.js +1024 -0
  195. package/dist/collab/store.d.ts +1 -0
  196. package/dist/collab/store.js +1 -4
  197. package/dist/collab/types.d.ts +2 -354
  198. package/dist/collab/validation.d.ts +2 -10
  199. package/dist/collab/validation.js +2 -303
  200. package/dist/collab/work-plan.d.ts +105 -0
  201. package/dist/collab/work-plan.js +843 -0
  202. package/dist/continuity/context.d.ts +11 -2
  203. package/dist/continuity/context.js +100 -13
  204. package/dist/continuity/handoff-bundle.d.ts +296 -0
  205. package/dist/continuity/handoff-bundle.js +477 -0
  206. package/dist/continuity/index.d.ts +2 -0
  207. package/dist/continuity/index.js +1 -0
  208. package/dist/continuity/paths.js +10 -2
  209. package/dist/continuity/service.js +91 -15
  210. package/dist/continuity/task-pin.d.ts +24 -0
  211. package/dist/continuity/task-pin.js +590 -0
  212. package/dist/doctor.d.ts +1 -0
  213. package/dist/doctor.js +6 -0
  214. package/dist/experimental/index.d.ts +13 -0
  215. package/dist/experimental/index.js +25 -0
  216. package/dist/experimental/pi.d.ts +4 -0
  217. package/dist/experimental/pi.js +12 -0
  218. package/dist/hosts/claude/native.js +1 -1
  219. package/dist/hosts/codex/native.js +1 -1
  220. package/dist/hosts/codex/protocol.js +1 -1
  221. package/dist/hosts/integration/bootstrap-config.d.ts +58 -0
  222. package/dist/hosts/integration/bootstrap-config.js +254 -0
  223. package/dist/hosts/integration/bundle-export.d.ts +44 -0
  224. package/dist/hosts/integration/bundle-export.js +366 -3
  225. package/dist/hosts/integration/bundle.js +3 -0
  226. package/dist/hosts/integration/hook.js +36 -9
  227. package/dist/hosts/integration/pappra-bootstrap-extension.mjs +80 -0
  228. package/dist/hosts/integration/pappra-extension-runtime.mjs +59 -24631
  229. package/dist/hosts/integration/pappra-hook.mjs +61 -24749
  230. package/dist/hosts/integration/pappra-recovery-extension.mjs +259 -0
  231. package/dist/hosts/integration/pappra-session-transition-extension.mjs +276 -0
  232. package/dist/hosts/integration/pi-bootstrap-extension.d.ts +36 -0
  233. package/dist/hosts/integration/pi-bootstrap-extension.js +101 -0
  234. package/dist/hosts/integration/pi-bootstrap-guard.d.ts +125 -0
  235. package/dist/hosts/integration/pi-bootstrap-guard.js +438 -0
  236. package/dist/hosts/integration/pi-bootstrap-runtime.d.ts +63 -0
  237. package/dist/hosts/integration/pi-bootstrap-runtime.js +223 -0
  238. package/dist/hosts/integration/pi-native-events.d.ts +112 -0
  239. package/dist/hosts/integration/pi-native-events.js +348 -0
  240. package/dist/hosts/integration/pi-rollover-extension.d.ts +166 -0
  241. package/dist/hosts/integration/pi-rollover-extension.js +431 -0
  242. package/dist/hosts/integration/recovery-config.d.ts +48 -0
  243. package/dist/hosts/integration/recovery-config.js +117 -0
  244. package/dist/hosts/integration/service.d.ts +6 -1
  245. package/dist/hosts/integration/service.js +485 -35
  246. package/dist/hosts/integration/support.d.ts +7 -0
  247. package/dist/hosts/integration/support.js +9 -1
  248. package/dist/hosts/integration/templates.d.ts +3 -0
  249. package/dist/hosts/integration/templates.js +26 -3
  250. package/dist/hosts/pi/managed-host-identity.d.ts +2 -0
  251. package/dist/hosts/pi/managed-host-identity.js +40 -0
  252. package/dist/hosts/pi/managed-provider-diagnostics.d.ts +6 -0
  253. package/dist/hosts/pi/managed-provider-diagnostics.js +184 -0
  254. package/dist/hosts/pi/managed-sdk-session.d.ts +335 -0
  255. package/dist/hosts/pi/managed-sdk-session.js +1639 -0
  256. package/dist/hosts/pi/managed-session-extension.d.ts +20 -0
  257. package/dist/hosts/pi/managed-session-extension.js +84 -0
  258. package/dist/hosts/pi/managed-session.d.ts +177 -0
  259. package/dist/hosts/pi/managed-session.js +1557 -0
  260. package/dist/hosts/pi/protocol.js +1 -1
  261. package/dist/hosts/pi/query-result.js +1 -1
  262. package/dist/hosts/pi/resume-capability.d.ts +41 -0
  263. package/dist/hosts/pi/resume-capability.js +33 -0
  264. package/dist/hosts/pi/rpc.d.ts +182 -134
  265. package/dist/hosts/pi/rpc.js +230 -37
  266. package/dist/hosts/pilot.d.ts +97 -74
  267. package/dist/hosts/pilot.js +5 -1
  268. package/dist/hosts/version.d.ts +3 -0
  269. package/dist/hosts/version.js +18 -0
  270. package/dist/index.d.ts +0 -1
  271. package/dist/index.js +0 -1
  272. package/dist/infra/bounded-file.d.ts +19 -0
  273. package/dist/infra/bounded-file.js +66 -0
  274. package/dist/infra/fs.js +10 -2
  275. package/dist/infra/git.d.ts +29 -0
  276. package/dist/infra/git.js +45 -9
  277. package/dist/infra/json-property.d.ts +2 -0
  278. package/dist/infra/json-property.js +69 -0
  279. package/dist/infra/json.d.ts +4 -0
  280. package/dist/infra/json.js +24 -0
  281. package/dist/infra/owned-process-group.js +1 -1
  282. package/dist/infra/private-lock.d.ts +16 -0
  283. package/dist/infra/private-lock.js +148 -0
  284. package/dist/infra/private-state.d.ts +7 -0
  285. package/dist/infra/private-state.js +146 -0
  286. package/dist/infra/process-identity.d.ts +12 -0
  287. package/dist/infra/process-identity.js +142 -0
  288. package/dist/infra/validation.d.ts +5 -0
  289. package/dist/infra/validation.js +15 -0
  290. package/dist/init.d.ts +1 -0
  291. package/dist/init.js +6 -0
  292. package/dist/install/apply.d.ts +9 -1
  293. package/dist/install/apply.js +176 -12
  294. package/dist/install/dependencies.d.ts +38 -0
  295. package/dist/install/dependencies.js +282 -0
  296. package/dist/install/ownership.js +30 -1
  297. package/dist/install/references.d.ts +31 -0
  298. package/dist/install/references.js +208 -0
  299. package/dist/install/repair.d.ts +37 -0
  300. package/dist/install/repair.js +798 -0
  301. package/dist/install/reset-local.d.ts +16 -0
  302. package/dist/install/reset-local.js +304 -0
  303. package/dist/install/rollback.d.ts +3 -0
  304. package/dist/install/rollback.js +9 -3
  305. package/dist/install/runtime.d.ts +10 -6
  306. package/dist/install/runtime.js +299 -59
  307. package/dist/install/source-fingerprint.d.ts +2 -0
  308. package/dist/install/source-fingerprint.js +103 -0
  309. package/dist/knowledge/catalog.d.ts +1 -0
  310. package/dist/knowledge/catalog.js +143 -10
  311. package/dist/knowledge/journal.js +17 -7
  312. package/dist/knowledge/paths.js +2 -1
  313. package/dist/knowledge/refs.js +4 -0
  314. package/dist/knowledge/register-batch.d.ts +4 -0
  315. package/dist/knowledge/register-batch.js +225 -0
  316. package/dist/knowledge/relocate.d.ts +5 -0
  317. package/dist/knowledge/relocate.js +92 -0
  318. package/dist/knowledge/scan.js +103 -47
  319. package/dist/knowledge/service.d.ts +3 -0
  320. package/dist/knowledge/service.js +33 -1
  321. package/dist/knowledge/write.d.ts +4 -1
  322. package/dist/knowledge/write.js +1 -1
  323. package/dist/mcp/server.d.ts +4 -2
  324. package/dist/mcp/server.js +87 -136
  325. package/dist/schemas/collaboration-state-validation.d.ts +6 -0
  326. package/dist/schemas/collaboration-state-validation.js +342 -0
  327. package/dist/schemas/collaboration-state.d.ts +436 -0
  328. package/dist/schemas/collaboration-state.js +1 -0
  329. package/dist/schemas/collaboration.d.ts +335 -0
  330. package/dist/schemas/collaboration.js +272 -0
  331. package/dist/schemas/continuity.d.ts +8 -0
  332. package/dist/schemas/continuity.js +13 -3
  333. package/dist/schemas/doctor.d.ts +1 -0
  334. package/dist/schemas/doctor.js +1 -0
  335. package/dist/schemas/document.d.ts +61 -0
  336. package/dist/schemas/document.js +9 -0
  337. package/dist/schemas/errors.d.ts +1 -0
  338. package/dist/schemas/errors.js +1 -0
  339. package/dist/schemas/host.d.ts +24 -0
  340. package/dist/schemas/host.js +19 -0
  341. package/dist/schemas/install.d.ts +8 -2
  342. package/dist/schemas/install.js +11 -1
  343. package/dist/schemas/managed-pi-execution.d.ts +16 -0
  344. package/dist/schemas/managed-pi-execution.js +2 -0
  345. package/dist/schemas/outcome.d.ts +9 -5
  346. package/dist/workspace/config-file.js +1 -3
  347. package/dist/workspace/documents.js +12 -2
  348. package/dist/workspace/repositories.d.ts +7 -0
  349. package/dist/workspace/repositories.js +14 -5
  350. package/package.json +35 -35
  351. package/skills/pappra/SKILL.md +28 -7
  352. package/skills/pappra/references/collaboration.md +633 -0
  353. package/skills/pappra/references/environment.md +360 -0
  354. package/skills/pappra/references/hosts.md +20 -0
  355. package/skills/pappra/references/operations.md +36 -5
  356. package/dist/app/collab-from.d.ts +0 -35
  357. package/dist/app/collab-from.js +0 -84
@@ -0,0 +1,504 @@
1
+ import { object as isRecord } from '../infra/validation.js';
2
+ import { pathRelation } from '../collab/canonical.js';
3
+ import { WORK_PLAN_EVALUATION_SCHEMA, WORK_PLAN_SCHEMA, validateWorkPlan, } from '../collab/work-plan.js';
4
+ export const COLLAB_ROLE_PLAN_SCHEMA = 'pappra/collab-role-plan/1';
5
+ export const COLLAB_ROLE_PLAN_AGGREGATION_SCHEMA = 'pappra/collab-role-plan-aggregation/1';
6
+ const MAX_NODES = 64;
7
+ const MAX_PARTICIPANTS = 64;
8
+ const MAX_RESOURCES = 16;
9
+ const MAX_STRING = 512;
10
+ const UNCERTAIN_BLOCKERS = new Set([
11
+ 'acceptance_envelope_missing',
12
+ 'acceptance_untrusted',
13
+ 'own_uncertain',
14
+ 'uncertainty_open',
15
+ ]);
16
+ const isBoundedString = (value) => typeof value === 'string' &&
17
+ value.length > 0 &&
18
+ value.length <= MAX_STRING &&
19
+ !value.includes('\u0000');
20
+ const isRole = (value) => value === 'planner' || value === 'writer' || value === 'reviewer';
21
+ const isIdentity = (value) => isRecord(value) &&
22
+ isBoundedString(value['agent_id']) &&
23
+ isBoundedString(value['session_id']);
24
+ function roleDiagnostic(code, detail, nodeId = null) {
25
+ return { code, node_id: nodeId, detail };
26
+ }
27
+ function refusal(diagnostics) {
28
+ return {
29
+ schema: COLLAB_ROLE_PLAN_SCHEMA,
30
+ ok: false,
31
+ diagnostics,
32
+ };
33
+ }
34
+ function projectWorkPlanDiagnostics(diagnostics) {
35
+ return diagnostics.map(({ code, node_id, detail }) => ({
36
+ code,
37
+ node_id,
38
+ detail,
39
+ }));
40
+ }
41
+ function readResources(value, nodeId, diagnostics) {
42
+ if (!Array.isArray(value) || value.length === 0) {
43
+ diagnostics.push(roleDiagnostic('resources_required', 'each assignment needs an explicit non-empty resource list', nodeId));
44
+ return null;
45
+ }
46
+ if (value.length > MAX_RESOURCES) {
47
+ diagnostics.push(roleDiagnostic('resource_limit', `an assignment may declare at most ${MAX_RESOURCES} resources`, nodeId));
48
+ return null;
49
+ }
50
+ const resources = [];
51
+ for (const [index, resource] of value.entries()) {
52
+ if (!isRecord(resource) ||
53
+ !isBoundedString(resource['path']) ||
54
+ (resource['access'] !== 'read' && resource['access'] !== 'write')) {
55
+ diagnostics.push(roleDiagnostic('resource_invalid', `resource ${index} needs a bounded absolute path and read/write access`, nodeId));
56
+ return null;
57
+ }
58
+ resources.push({
59
+ path: resource['path'],
60
+ access: resource['access'],
61
+ });
62
+ }
63
+ return resources;
64
+ }
65
+ /**
66
+ * Expands an explicit role request into the existing dependency-aware WorkPlan.
67
+ * An optional planner precedes independent writers. The reviewer depends on every writer, so the existing
68
+ * evaluator—not this planner—requires each predecessor's current coordinator acceptance.
69
+ */
70
+ export function expandRolePlan(input) {
71
+ const raw = input;
72
+ if (!isRecord(raw))
73
+ return refusal([
74
+ roleDiagnostic('request_invalid', 'request must be an object'),
75
+ ]);
76
+ const diagnostics = [];
77
+ if (raw['schema'] !== COLLAB_ROLE_PLAN_SCHEMA)
78
+ diagnostics.push(roleDiagnostic('request_schema_invalid', `schema must be ${COLLAB_ROLE_PLAN_SCHEMA}`));
79
+ const planId = raw['plan_id'];
80
+ const taskId = raw['task_id'];
81
+ const ownerEpoch = raw['owner_epoch'];
82
+ if (!isBoundedString(planId) || !isBoundedString(taskId))
83
+ diagnostics.push(roleDiagnostic('request_invalid', 'plan_id and task_id are required bounded strings'));
84
+ if (typeof ownerEpoch !== 'number' ||
85
+ !Number.isSafeInteger(ownerEpoch) ||
86
+ ownerEpoch < 1)
87
+ diagnostics.push(roleDiagnostic('request_invalid', 'owner_epoch must be a positive integer'));
88
+ const rawParticipants = raw['participants'];
89
+ if (!Array.isArray(rawParticipants) || rawParticipants.length === 0) {
90
+ diagnostics.push(roleDiagnostic('participants_required', 'declare the plan participants explicitly'));
91
+ return refusal(diagnostics);
92
+ }
93
+ if (rawParticipants.length > MAX_PARTICIPANTS) {
94
+ diagnostics.push(roleDiagnostic('participant_limit', `at most ${MAX_PARTICIPANTS} participants are supported`));
95
+ return refusal(diagnostics);
96
+ }
97
+ const participants = new Map();
98
+ for (const [index, rawParticipant] of rawParticipants.entries()) {
99
+ if (!isRecord(rawParticipant)) {
100
+ diagnostics.push(roleDiagnostic('participant_invalid', `participant ${index} must be an object`));
101
+ continue;
102
+ }
103
+ const participantId = rawParticipant['participant_id'];
104
+ const role = rawParticipant['role'];
105
+ const assignee = rawParticipant['assignee'];
106
+ if (!isBoundedString(participantId) ||
107
+ !isRole(role) ||
108
+ !isIdentity(assignee)) {
109
+ diagnostics.push(roleDiagnostic('participant_invalid', `participant ${index} needs an id, planner/writer/reviewer role, and explicit assignee identity`));
110
+ continue;
111
+ }
112
+ if (participants.has(participantId)) {
113
+ diagnostics.push(roleDiagnostic('duplicate_participant_id', `participant id is repeated: ${participantId}`));
114
+ continue;
115
+ }
116
+ participants.set(participantId, {
117
+ participant_id: participantId,
118
+ role,
119
+ assignee: {
120
+ agent_id: assignee['agent_id'],
121
+ session_id: assignee['session_id'],
122
+ },
123
+ });
124
+ }
125
+ const rawAssignments = raw['assignments'];
126
+ if (!Array.isArray(rawAssignments) || rawAssignments.length === 0) {
127
+ diagnostics.push(roleDiagnostic('assignments_required', 'declare writer and reviewer assignments explicitly'));
128
+ return refusal(diagnostics);
129
+ }
130
+ if (rawAssignments.length > MAX_NODES) {
131
+ diagnostics.push(roleDiagnostic('plan_too_large', `at most ${MAX_NODES} role assignments are supported`));
132
+ return refusal(diagnostics);
133
+ }
134
+ const assignments = [];
135
+ for (const [index, rawAssignment] of rawAssignments.entries()) {
136
+ if (!isRecord(rawAssignment)) {
137
+ diagnostics.push(roleDiagnostic('assignment_invalid', `assignment ${index} must be an object`));
138
+ continue;
139
+ }
140
+ const nodeId = rawAssignment['node_id'];
141
+ const role = rawAssignment['role'];
142
+ const assignmentId = rawAssignment['assignment_id'];
143
+ const attempt = rawAssignment['attempt'];
144
+ const inputRevision = rawAssignment['input_revision'];
145
+ const participantId = rawAssignment['participant_id'];
146
+ if (!isBoundedString(nodeId) ||
147
+ !isRole(role) ||
148
+ !isBoundedString(assignmentId) ||
149
+ typeof attempt !== 'number' ||
150
+ !Number.isSafeInteger(attempt) ||
151
+ attempt < 1 ||
152
+ attempt > 1000 ||
153
+ !isBoundedString(inputRevision) ||
154
+ !isBoundedString(participantId)) {
155
+ diagnostics.push(roleDiagnostic('assignment_invalid', `assignment ${index} needs node, role, assignment, attempt, input revision, and participant pins`, isBoundedString(nodeId) ? nodeId : null));
156
+ continue;
157
+ }
158
+ const resources = readResources(rawAssignment['resources'], nodeId, diagnostics);
159
+ if (resources === null)
160
+ continue;
161
+ assignments.push({
162
+ node_id: nodeId,
163
+ role,
164
+ assignment_id: assignmentId,
165
+ attempt,
166
+ input_revision: inputRevision,
167
+ participant_id: participantId,
168
+ resources,
169
+ });
170
+ }
171
+ const usedParticipants = new Set();
172
+ for (const assignment of assignments) {
173
+ const participant = participants.get(assignment.participant_id);
174
+ if (participant === undefined) {
175
+ diagnostics.push(roleDiagnostic('participant_missing', `assignment references undeclared participant ${assignment.participant_id}`, assignment.node_id));
176
+ }
177
+ else if (participant.role !== assignment.role) {
178
+ diagnostics.push(roleDiagnostic('participant_role_mismatch', `assignment role ${assignment.role} does not match participant role ${participant.role}`, assignment.node_id));
179
+ }
180
+ else {
181
+ usedParticipants.add(participant.participant_id);
182
+ }
183
+ }
184
+ for (const participantId of participants.keys()) {
185
+ if (!usedParticipants.has(participantId))
186
+ diagnostics.push(roleDiagnostic('participant_unassigned', `declared participant ${participantId} has no matching assignment`));
187
+ }
188
+ const writers = assignments
189
+ .filter((assignment) => assignment.role === 'writer')
190
+ .sort((left, right) => left.node_id.localeCompare(right.node_id));
191
+ const reviewers = assignments.filter((assignment) => assignment.role === 'reviewer');
192
+ const planners = assignments.filter((assignment) => assignment.role === 'planner');
193
+ if (planners.length > 1)
194
+ diagnostics.push(roleDiagnostic('planner_assignment_conflict', 'at most one planner assignment is supported'));
195
+ const planner = planners[0];
196
+ if (planner) {
197
+ const identity = participants.get(planner.participant_id)?.assignee;
198
+ for (const assignment of [...writers, ...reviewers]) {
199
+ const other = participants.get(assignment.participant_id)?.assignee;
200
+ if (identity &&
201
+ other &&
202
+ identity.agent_id === other.agent_id &&
203
+ identity.session_id === other.session_id)
204
+ diagnostics.push(roleDiagnostic('planner_identity_conflict', 'planner requires a distinct agent/session identity', planner.node_id));
205
+ }
206
+ }
207
+ if (writers.length === 0)
208
+ diagnostics.push(roleDiagnostic('role_missing', 'at least one writer assignment is required'));
209
+ if (reviewers.length === 0)
210
+ diagnostics.push(roleDiagnostic('role_missing', 'one reviewer assignment is required'));
211
+ if (reviewers.length > 1)
212
+ diagnostics.push(roleDiagnostic('reviewer_assignment_conflict', 'the role plan supports exactly one reviewer assignment'));
213
+ const assignmentIds = new Set();
214
+ for (const assignment of assignments) {
215
+ if (assignmentIds.has(assignment.assignment_id))
216
+ diagnostics.push(roleDiagnostic('duplicate_assignment_id', `assignment id is repeated: ${assignment.assignment_id}`, assignment.node_id));
217
+ assignmentIds.add(assignment.assignment_id);
218
+ }
219
+ for (let leftIndex = 0; leftIndex < writers.length; leftIndex += 1) {
220
+ const left = writers[leftIndex];
221
+ for (const right of writers.slice(leftIndex + 1)) {
222
+ const conflict = left.resources.some((leftResource) => right.resources.some((rightResource) => (leftResource.access === 'write' ||
223
+ rightResource.access === 'write') &&
224
+ pathRelation(leftResource.path, rightResource.path) !== 'disjoint'));
225
+ if (conflict)
226
+ diagnostics.push(roleDiagnostic('writer_resource_conflict', `writer scopes overlap between ${left.node_id} and ${right.node_id}${left.participant_id === right.participant_id ? ` for participant ${left.participant_id}` : ''}; independent writer work must be disjoint and is not implicitly serialized`, right.node_id));
227
+ }
228
+ }
229
+ const reviewerCandidate = reviewers[0];
230
+ if (reviewerCandidate !== undefined) {
231
+ const reviewerParticipant = participants.get(reviewerCandidate.participant_id);
232
+ if (reviewerParticipant !== undefined) {
233
+ for (const writer of writers) {
234
+ const writerParticipant = participants.get(writer.participant_id);
235
+ if (writerParticipant !== undefined &&
236
+ writerParticipant.assignee.agent_id ===
237
+ reviewerParticipant.assignee.agent_id &&
238
+ writerParticipant.assignee.session_id ===
239
+ reviewerParticipant.assignee.session_id)
240
+ diagnostics.push(roleDiagnostic('reviewer_writer_identity_conflict', 'reviewer must use a different agent/session identity from every writer', reviewerCandidate.node_id));
241
+ }
242
+ }
243
+ }
244
+ if (diagnostics.length > 0)
245
+ return refusal(diagnostics);
246
+ const reviewer = reviewers[0];
247
+ const rawPlan = {
248
+ schema: WORK_PLAN_SCHEMA,
249
+ plan_id: planId,
250
+ task_id: taskId,
251
+ owner_epoch: ownerEpoch,
252
+ nodes: [
253
+ ...(planner
254
+ ? [
255
+ {
256
+ node_id: planner.node_id,
257
+ role: planner.role,
258
+ assignment_id: planner.assignment_id,
259
+ attempt: planner.attempt,
260
+ input_revision: planner.input_revision,
261
+ assignee: participants.get(planner.participant_id).assignee,
262
+ depends_on: [],
263
+ resources: planner.resources,
264
+ },
265
+ ]
266
+ : []),
267
+ ...writers.map((assignment) => {
268
+ const participant = participants.get(assignment.participant_id);
269
+ return {
270
+ node_id: assignment.node_id,
271
+ role: assignment.role,
272
+ assignment_id: assignment.assignment_id,
273
+ attempt: assignment.attempt,
274
+ input_revision: assignment.input_revision,
275
+ assignee: participant.assignee,
276
+ depends_on: planner ? [planner.node_id] : [],
277
+ resources: assignment.resources,
278
+ };
279
+ }),
280
+ {
281
+ node_id: reviewer.node_id,
282
+ role: reviewer.role,
283
+ assignment_id: reviewer.assignment_id,
284
+ attempt: reviewer.attempt,
285
+ input_revision: reviewer.input_revision,
286
+ assignee: participants.get(reviewer.participant_id).assignee,
287
+ depends_on: writers.map((assignment) => assignment.node_id),
288
+ resources: reviewer.resources,
289
+ },
290
+ ],
291
+ };
292
+ const validated = validateWorkPlan(rawPlan);
293
+ if (!validated.ok)
294
+ return refusal(projectWorkPlanDiagnostics(validated.diagnostics));
295
+ return {
296
+ schema: COLLAB_ROLE_PLAN_SCHEMA,
297
+ ok: true,
298
+ plan: validated.plan,
299
+ roles: {
300
+ ...(planner ? { planner_node_id: planner.node_id } : {}),
301
+ writer_node_ids: writers.map((assignment) => assignment.node_id),
302
+ reviewer_node_id: reviewer.node_id,
303
+ },
304
+ };
305
+ }
306
+ function isWorkNodeStatus(value) {
307
+ return (value === 'ready' ||
308
+ value === 'running' ||
309
+ value === 'awaiting_acceptance' ||
310
+ value === 'accepted' ||
311
+ value === 'blocked');
312
+ }
313
+ function readBlockerCodes(value) {
314
+ if (!Array.isArray(value))
315
+ return null;
316
+ const codes = [];
317
+ for (const blocker of value) {
318
+ if (!isRecord(blocker) || !isBoundedString(blocker['code']))
319
+ return null;
320
+ codes.push(blocker['code']);
321
+ }
322
+ return codes;
323
+ }
324
+ function unknownNode(nodeId, role, status = null, blockers = []) {
325
+ return {
326
+ node_id: nodeId,
327
+ role,
328
+ outcome: 'unknown',
329
+ work_plan_status: status,
330
+ blockers: [...blockers],
331
+ };
332
+ }
333
+ function classifyNode(nodeId, role, rawNode) {
334
+ if (!isRecord(rawNode))
335
+ return unknownNode(nodeId, role, null);
336
+ const rawStatus = rawNode['status'];
337
+ const status = typeof rawStatus === 'string' ? rawStatus : null;
338
+ const blockers = readBlockerCodes(rawNode['blockers']);
339
+ if (rawNode['node_id'] !== nodeId ||
340
+ rawNode['role'] !== role ||
341
+ !isWorkNodeStatus(rawStatus) ||
342
+ blockers === null)
343
+ return unknownNode(nodeId, role, status, blockers ?? []);
344
+ const ownAcceptance = rawNode['acceptance_blocker'];
345
+ const ownCode = isRecord(ownAcceptance) && typeof ownAcceptance['code'] === 'string'
346
+ ? ownAcceptance['code']
347
+ : null;
348
+ const rejected = 'acceptance_blocker' in rawNode
349
+ ? ownCode === 'acceptance_rejected'
350
+ : blockers.includes('acceptance_rejected');
351
+ if (rejected)
352
+ return {
353
+ node_id: nodeId,
354
+ role,
355
+ outcome: 'rejected',
356
+ work_plan_status: status,
357
+ blockers,
358
+ };
359
+ if ((ownCode !== null && UNCERTAIN_BLOCKERS.has(ownCode)) ||
360
+ blockers.some((code) => UNCERTAIN_BLOCKERS.has(code)))
361
+ return {
362
+ node_id: nodeId,
363
+ role,
364
+ outcome: 'unknown',
365
+ work_plan_status: status,
366
+ blockers,
367
+ };
368
+ if (rawStatus === 'accepted')
369
+ return {
370
+ node_id: nodeId,
371
+ role,
372
+ outcome: 'accepted',
373
+ work_plan_status: status,
374
+ blockers,
375
+ };
376
+ if (rawStatus === 'blocked')
377
+ return {
378
+ node_id: nodeId,
379
+ role,
380
+ outcome: 'blocked',
381
+ work_plan_status: status,
382
+ blockers,
383
+ };
384
+ return {
385
+ node_id: nodeId,
386
+ role,
387
+ outcome: 'pending',
388
+ work_plan_status: status,
389
+ blockers,
390
+ };
391
+ }
392
+ function aggregateOutcome(nodes) {
393
+ if (nodes.some((node) => node.outcome === 'rejected'))
394
+ return 'rejected';
395
+ if (nodes.some((node) => node.outcome === 'unknown'))
396
+ return 'unknown';
397
+ if (nodes.some((node) => node.outcome === 'missing'))
398
+ return 'missing';
399
+ if (nodes.some((node) => node.outcome === 'blocked'))
400
+ return 'blocked';
401
+ if (nodes.length > 0 && nodes.every((node) => node.outcome === 'accepted'))
402
+ return 'accepted';
403
+ return 'pending';
404
+ }
405
+ /**
406
+ * Projects the existing read-only WorkPlan evaluation. A role-plan succeeds only when every
407
+ * planned node is already accepted in that evaluation; delivery observations are not inputs.
408
+ */
409
+ export function aggregateRolePlan(expansion, evaluation) {
410
+ const diagnostics = [];
411
+ const expected = [
412
+ ...(expansion.roles.planner_node_id
413
+ ? [{ nodeId: expansion.roles.planner_node_id, role: 'planner' }]
414
+ : []),
415
+ ...expansion.roles.writer_node_ids.map((nodeId) => ({
416
+ nodeId,
417
+ role: 'writer',
418
+ })),
419
+ { nodeId: expansion.roles.reviewer_node_id, role: 'reviewer' },
420
+ ];
421
+ const rawEvaluation = evaluation;
422
+ let nodes;
423
+ if (!isRecord(rawEvaluation) || rawEvaluation['ok'] !== true) {
424
+ const refusalValue = isRecord(rawEvaluation) ? rawEvaluation : null;
425
+ const rawDiagnostics = refusalValue?.['diagnostics'];
426
+ if (Array.isArray(rawDiagnostics)) {
427
+ for (const entry of rawDiagnostics) {
428
+ if (isRecord(entry) && isBoundedString(entry['code']))
429
+ diagnostics.push(roleDiagnostic(entry['code'], isBoundedString(entry['detail'])
430
+ ? entry['detail']
431
+ : 'work-plan evaluation was refused', isBoundedString(entry['node_id']) ? entry['node_id'] : null));
432
+ }
433
+ }
434
+ if (diagnostics.length === 0)
435
+ diagnostics.push(roleDiagnostic('evaluation_unavailable', 'work-plan evaluation was refused; node outcomes remain unknown'));
436
+ nodes = expected.map(({ nodeId, role }) => unknownNode(nodeId, role));
437
+ }
438
+ else {
439
+ const metadataMatches = rawEvaluation['schema'] === WORK_PLAN_EVALUATION_SCHEMA &&
440
+ rawEvaluation['plan_id'] === expansion.plan.plan_id &&
441
+ rawEvaluation['task_id'] === expansion.plan.task_id &&
442
+ rawEvaluation['owner_epoch'] === expansion.plan.owner_epoch;
443
+ const rawNodes = rawEvaluation['nodes'];
444
+ if (!metadataMatches) {
445
+ diagnostics.push(roleDiagnostic('evaluation_mismatch', 'evaluation schema, plan id, task id, or owner epoch does not match the expanded plan'));
446
+ nodes = expected.map(({ nodeId, role }) => unknownNode(nodeId, role));
447
+ }
448
+ else if (!Array.isArray(rawNodes)) {
449
+ diagnostics.push(roleDiagnostic('evaluation_invalid', 'evaluation.nodes must be an array'));
450
+ nodes = expected.map(({ nodeId, role }) => unknownNode(nodeId, role));
451
+ }
452
+ else {
453
+ const byId = new Map();
454
+ for (const rawNode of rawNodes) {
455
+ const id = isRecord(rawNode) ? rawNode['node_id'] : null;
456
+ if (!isBoundedString(id))
457
+ continue;
458
+ const entries = byId.get(id) ?? [];
459
+ entries.push(rawNode);
460
+ byId.set(id, entries);
461
+ }
462
+ const expectedIds = new Set(expected.map((node) => node.nodeId));
463
+ for (const nodeId of byId.keys()) {
464
+ if (!expectedIds.has(nodeId))
465
+ diagnostics.push(roleDiagnostic('evaluation_node_unexpected', `evaluation contains an unplanned node ${nodeId}`, nodeId));
466
+ }
467
+ nodes = expected.map(({ nodeId, role }) => {
468
+ const entries = byId.get(nodeId) ?? [];
469
+ if (entries.length === 0)
470
+ return {
471
+ node_id: nodeId,
472
+ role,
473
+ outcome: 'missing',
474
+ work_plan_status: null,
475
+ blockers: [],
476
+ };
477
+ if (entries.length > 1) {
478
+ diagnostics.push(roleDiagnostic('evaluation_node_ambiguous', `evaluation repeats node ${nodeId}; its result is unknown`, nodeId));
479
+ return unknownNode(nodeId, role, null);
480
+ }
481
+ const result = classifyNode(nodeId, role, entries[0]);
482
+ if (result.outcome === 'unknown')
483
+ diagnostics.push(roleDiagnostic('evaluation_node_unknown', `evaluation result for ${nodeId} is malformed, uncertain, or has an unknown status`, nodeId));
484
+ return result;
485
+ });
486
+ }
487
+ }
488
+ const ids = (outcome) => nodes
489
+ .filter((node) => node.outcome === outcome)
490
+ .map((node) => node.node_id);
491
+ return {
492
+ schema: COLLAB_ROLE_PLAN_AGGREGATION_SCHEMA,
493
+ plan_id: expansion.plan.plan_id,
494
+ outcome: aggregateOutcome(nodes),
495
+ nodes,
496
+ accepted_nodes: ids('accepted'),
497
+ rejected_nodes: ids('rejected'),
498
+ unknown_nodes: ids('unknown'),
499
+ missing_nodes: ids('missing'),
500
+ pending_nodes: ids('pending'),
501
+ blocked_nodes: ids('blocked'),
502
+ diagnostics,
503
+ };
504
+ }
@@ -0,0 +1,109 @@
1
+ import type { Identity } from '../collab/types.js';
2
+ import { type RolePlanRequest, type RolePlanSuccess } from './collab-role-plan.js';
3
+ import { type WorkPlanResource } from '../collab/work-plan.js';
4
+ import type { WorkExecutionRequest } from './collab-work-execution.js';
5
+ declare const STOP_RECEIPT_SCHEMA = "pappra/collab-native-stop-receipt/1";
6
+ export interface RoleRepairCoordinatorPin {
7
+ readonly agent_id: string;
8
+ readonly session_id: string;
9
+ readonly owner_epoch: number;
10
+ }
11
+ export interface RoleRepairSourcePin {
12
+ readonly node_id: string;
13
+ readonly assignment_id: string;
14
+ readonly attempt: number;
15
+ readonly input_revision: string;
16
+ readonly resources: readonly WorkPlanResource[];
17
+ }
18
+ export interface RoleRepairNextPin {
19
+ readonly assignment_ref: string;
20
+ readonly assignment_digest: string;
21
+ readonly assignment_id: string;
22
+ readonly attempt: number;
23
+ readonly input_revision: string;
24
+ readonly participant_id: string;
25
+ readonly assignee: Identity;
26
+ readonly resources: readonly WorkPlanResource[];
27
+ }
28
+ /**
29
+ * A pre-authorized single transition. Approval pins bind the record approved by the
30
+ * coordinator to this exact source/target transition; the approval payload itself is
31
+ * passed unchanged (apart from its protocol-defined fields) to the ASSIGN envelope.
32
+ */
33
+ export interface RoleRepairAuthorization {
34
+ readonly coordinator: RoleRepairCoordinatorPin;
35
+ readonly source: RoleRepairSourcePin;
36
+ readonly next: RoleRepairNextPin;
37
+ readonly approval: {
38
+ readonly approved_by: string;
39
+ readonly reason: string;
40
+ readonly authorization_id: string;
41
+ readonly owner_epoch: number;
42
+ readonly source_attempt: number;
43
+ readonly source_input_revision: string;
44
+ readonly next_assignment_id: string;
45
+ readonly next_attempt: number;
46
+ readonly next_input_revision: string;
47
+ readonly resources_digest: string;
48
+ };
49
+ readonly next_execution?: WorkExecutionRequest;
50
+ }
51
+ export interface RoleRepairPolicy {
52
+ /** One explicit approval per repair transition; no approval is synthesized. */
53
+ readonly authorizations: readonly RoleRepairAuthorization[];
54
+ }
55
+ /** A live, source-bound stop observation supplied only by a trusted host adapter. */
56
+ export interface NativeStopReceipt {
57
+ readonly schema: typeof STOP_RECEIPT_SCHEMA;
58
+ readonly observation: 'confirmed';
59
+ readonly task_id: string;
60
+ readonly subtask_id: string;
61
+ readonly attempt: number;
62
+ readonly owner_epoch: number;
63
+ readonly assignee: Identity;
64
+ readonly evidence_ref: string;
65
+ readonly observed_at: string;
66
+ }
67
+ export interface RoleRepairRequest {
68
+ readonly task_root: string;
69
+ readonly plan_file: string;
70
+ readonly journal_file: string;
71
+ readonly event_id: string;
72
+ readonly role_plan: RolePlanRequest;
73
+ readonly execution: WorkExecutionRequest;
74
+ readonly policy: RoleRepairPolicy;
75
+ readonly rejected_node_ids: readonly string[];
76
+ readonly max_attempts: number;
77
+ readonly max_actions: number;
78
+ readonly reserved_actions: number;
79
+ }
80
+ export interface RoleRepairDependencies {
81
+ /** Must perform a live host query and return its supported receipt, never a boolean. */
82
+ readonly confirm_stopped?: (source: {
83
+ readonly task_id: string;
84
+ readonly coordinator: RoleRepairCoordinatorPin;
85
+ readonly source: RoleRepairSourcePin;
86
+ readonly assignee: Identity;
87
+ }) => Promise<NativeStopReceipt | null>;
88
+ readonly now?: () => number;
89
+ }
90
+ export interface RoleRepairOutcome {
91
+ readonly status: 'repaired' | 'repair-required' | 'repair-exhausted' | 'reconciliation-required';
92
+ readonly role_plan: RolePlanRequest | null;
93
+ readonly expansion: RolePlanSuccess | null;
94
+ readonly execution: WorkExecutionRequest | null;
95
+ readonly diagnostic: string;
96
+ }
97
+ export interface RoleRepairRecovery {
98
+ readonly role_plan: RolePlanRequest;
99
+ readonly execution: WorkExecutionRequest;
100
+ }
101
+ /** Replace only the exact rejected node selected by the bounded authorization policy. */
102
+ export declare function repairRejectedRoleNode(request: RoleRepairRequest, deps?: RoleRepairDependencies): Promise<RoleRepairOutcome>;
103
+ /**
104
+ * Read-only recovery of a caller-authorized plan. Journal data alone is never authority:
105
+ * promotion requires the live task record, current coordinator, registered assignment and
106
+ * already-published task-local WorkPlan to match the exact policy transition.
107
+ */
108
+ export declare function recoverRoleRepairPlan(rolePlan: RolePlanRequest, execution: WorkExecutionRequest, policy: RoleRepairPolicy | undefined, journalFile: string, taskRoot: string, planFile: string, maxAttempts: number): Promise<RoleRepairRecovery>;
109
+ export {};