@jinn-network/client 0.1.6 → 0.1.7-canary.0a586ca9

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 (434) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +67 -1
  3. package/deployments/deployment-jinn-mvi-l1-sepolia-fast.json +23 -4
  4. package/deployments/deployment-jinn-mvi-l1-sepolia.json +23 -4
  5. package/deployments/deployment-jinn-mvi-l2-baseSepolia.json +5 -4
  6. package/dist/adapters/mech/adapter.d.ts +57 -2
  7. package/dist/adapters/mech/adapter.js +366 -63
  8. package/dist/adapters/mech/adapter.js.map +1 -1
  9. package/dist/adapters/mech/contracts.d.ts +17 -4
  10. package/dist/adapters/mech/contracts.js +19 -4
  11. package/dist/adapters/mech/contracts.js.map +1 -1
  12. package/dist/adapters/mech/safe-revert.d.ts +20 -0
  13. package/dist/adapters/mech/safe-revert.js +12 -4
  14. package/dist/adapters/mech/safe-revert.js.map +1 -1
  15. package/dist/adapters/mech/safe.d.ts +6 -2
  16. package/dist/adapters/mech/safe.js +32 -11
  17. package/dist/adapters/mech/safe.js.map +1 -1
  18. package/dist/adapters/mech/types.d.ts +6 -1
  19. package/dist/adapters/mech/types.js.map +1 -1
  20. package/dist/adapters/mech/verdict-code.d.ts +1 -0
  21. package/dist/adapters/mech/verdict-code.js +18 -0
  22. package/dist/adapters/mech/verdict-code.js.map +1 -1
  23. package/dist/agent/operator-claude.js +8 -0
  24. package/dist/agent/operator-claude.js.map +1 -1
  25. package/dist/api/activity-events-endpoint.d.ts +14 -0
  26. package/dist/api/activity-events-endpoint.js +59 -0
  27. package/dist/api/activity-events-endpoint.js.map +1 -0
  28. package/dist/api/admin-endpoint.d.ts +15 -3
  29. package/dist/api/admin-endpoint.js +24 -2
  30. package/dist/api/admin-endpoint.js.map +1 -1
  31. package/dist/api/bootstrap-endpoint.d.ts +1 -2
  32. package/dist/api/bootstrap-endpoint.js +85 -18
  33. package/dist/api/bootstrap-endpoint.js.map +1 -1
  34. package/dist/api/codex-doctor-endpoint.d.ts +90 -0
  35. package/dist/api/codex-doctor-endpoint.js +296 -0
  36. package/dist/api/codex-doctor-endpoint.js.map +1 -0
  37. package/dist/api/discovery-endpoint.d.ts +1 -0
  38. package/dist/api/discovery-endpoint.js +26 -0
  39. package/dist/api/discovery-endpoint.js.map +1 -1
  40. package/dist/api/fleet-build.d.ts +1 -0
  41. package/dist/api/fleet-build.js +2 -1
  42. package/dist/api/fleet-build.js.map +1 -1
  43. package/dist/api/gather-status.d.ts +37 -0
  44. package/dist/api/gather-status.js +572 -19
  45. package/dist/api/gather-status.js.map +1 -1
  46. package/dist/api/hermes-doctor-endpoint.d.ts +128 -3
  47. package/dist/api/hermes-doctor-endpoint.js +265 -22
  48. package/dist/api/hermes-doctor-endpoint.js.map +1 -1
  49. package/dist/api/launcher-status.d.ts +24 -17
  50. package/dist/api/launcher-status.js +13 -11
  51. package/dist/api/launcher-status.js.map +1 -1
  52. package/dist/api/launcher-tasks.d.ts +1 -1
  53. package/dist/api/launcher-tasks.js +12 -8
  54. package/dist/api/launcher-tasks.js.map +1 -1
  55. package/dist/api/operator-artifacts-endpoint.js +73 -6
  56. package/dist/api/operator-artifacts-endpoint.js.map +1 -1
  57. package/dist/api/portfolio-v0-build.d.ts +10 -0
  58. package/dist/api/portfolio-v0-build.js +24 -5
  59. package/dist/api/portfolio-v0-build.js.map +1 -1
  60. package/dist/api/prediction-v1-build.d.ts +10 -0
  61. package/dist/api/prediction-v1-build.js +7 -1
  62. package/dist/api/prediction-v1-build.js.map +1 -1
  63. package/dist/api/server.d.ts +31 -1
  64. package/dist/api/server.js +95 -2
  65. package/dist/api/server.js.map +1 -1
  66. package/dist/api/setup-endpoints.d.ts +7 -0
  67. package/dist/api/setup-endpoints.js +67 -135
  68. package/dist/api/setup-endpoints.js.map +1 -1
  69. package/dist/api/setup-retry-endpoint.d.ts +19 -0
  70. package/dist/api/setup-retry-endpoint.js +32 -0
  71. package/dist/api/setup-retry-endpoint.js.map +1 -0
  72. package/dist/api/solvernets-endpoints.d.ts +8 -0
  73. package/dist/api/solvernets-endpoints.js +100 -105
  74. package/dist/api/solvernets-endpoints.js.map +1 -1
  75. package/dist/api/status-build.d.ts +167 -2
  76. package/dist/api/status-build.js +118 -27
  77. package/dist/api/status-build.js.map +1 -1
  78. package/dist/api/status-harness-rollup.d.ts +35 -0
  79. package/dist/api/status-harness-rollup.js +45 -0
  80. package/dist/api/status-harness-rollup.js.map +1 -0
  81. package/dist/api/task-run-routing.d.ts +7 -0
  82. package/dist/api/task-run-routing.js +12 -0
  83. package/dist/api/task-run-routing.js.map +1 -0
  84. package/dist/api/task-runs-build.d.ts +21 -0
  85. package/dist/api/task-runs-build.js +14 -1
  86. package/dist/api/task-runs-build.js.map +1 -1
  87. package/dist/build-info.json +4 -4
  88. package/dist/build-meta.json +1 -1
  89. package/dist/captures/live-publisher.js +24 -4
  90. package/dist/captures/live-publisher.js.map +1 -1
  91. package/dist/captures/publish.d.ts +1 -1
  92. package/dist/chain-read-errors.d.ts +22 -0
  93. package/dist/chain-read-errors.js +41 -1
  94. package/dist/chain-read-errors.js.map +1 -1
  95. package/dist/cli/commands/auth.js +1 -1
  96. package/dist/cli/commands/auth.js.map +1 -1
  97. package/dist/cli/commands/codedigest-revert-check.d.ts +33 -0
  98. package/dist/cli/commands/codedigest-revert-check.js +249 -0
  99. package/dist/cli/commands/codedigest-revert-check.js.map +1 -0
  100. package/dist/cli/commands/create.js +3 -2
  101. package/dist/cli/commands/create.js.map +1 -1
  102. package/dist/cli/commands/doctor.d.ts +2 -0
  103. package/dist/cli/commands/doctor.js +2 -0
  104. package/dist/cli/commands/doctor.js.map +1 -1
  105. package/dist/cli/commands/rewards.js +11 -7
  106. package/dist/cli/commands/rewards.js.map +1 -1
  107. package/dist/cli/commands/solver-nets.d.ts +1 -0
  108. package/dist/cli/commands/solver-nets.js +179 -16
  109. package/dist/cli/commands/solver-nets.js.map +1 -1
  110. package/dist/cli/commands/solver-plugins-block.d.ts +33 -0
  111. package/dist/cli/commands/solver-plugins-block.js +118 -0
  112. package/dist/cli/commands/solver-plugins-block.js.map +1 -0
  113. package/dist/cli/commands/solver-plugins-feedback.d.ts +72 -0
  114. package/dist/cli/commands/solver-plugins-feedback.js +262 -0
  115. package/dist/cli/commands/solver-plugins-feedback.js.map +1 -0
  116. package/dist/cli/commands/solver-plugins-read.d.ts +54 -0
  117. package/dist/cli/commands/solver-plugins-read.js +259 -0
  118. package/dist/cli/commands/solver-plugins-read.js.map +1 -0
  119. package/dist/cli/commands/solver-plugins.d.ts +35 -0
  120. package/dist/cli/commands/solver-plugins.js +399 -2
  121. package/dist/cli/commands/solver-plugins.js.map +1 -1
  122. package/dist/cli/commands/status.js +1 -1
  123. package/dist/cli/commands/status.js.map +1 -1
  124. package/dist/cli/commands/tasks.js +101 -11
  125. package/dist/cli/commands/tasks.js.map +1 -1
  126. package/dist/cli/commands/update.d.ts +10 -0
  127. package/dist/cli/commands/update.js +36 -0
  128. package/dist/cli/commands/update.js.map +1 -1
  129. package/dist/cli/index.js +2 -0
  130. package/dist/cli/index.js.map +1 -1
  131. package/dist/cli/introspection-context.js +5 -0
  132. package/dist/cli/introspection-context.js.map +1 -1
  133. package/dist/cli/task-native-readiness.d.ts +10 -1
  134. package/dist/cli/task-native-readiness.js +30 -6
  135. package/dist/cli/task-native-readiness.js.map +1 -1
  136. package/dist/config.d.ts +287 -235
  137. package/dist/config.js +318 -114
  138. package/dist/config.js.map +1 -1
  139. package/dist/daemon/checkpoint-loop.d.ts +48 -0
  140. package/dist/daemon/checkpoint-loop.js +76 -0
  141. package/dist/daemon/checkpoint-loop.js.map +1 -0
  142. package/dist/daemon/creator.d.ts +1 -1
  143. package/dist/daemon/creator.js +20 -3
  144. package/dist/daemon/creator.js.map +1 -1
  145. package/dist/daemon/daemon.d.ts +22 -0
  146. package/dist/daemon/daemon.js +174 -31
  147. package/dist/daemon/daemon.js.map +1 -1
  148. package/dist/daemon/eviction-loop.d.ts +40 -0
  149. package/dist/daemon/eviction-loop.js +67 -0
  150. package/dist/daemon/eviction-loop.js.map +1 -0
  151. package/dist/daemon/gate-logger.d.ts +9 -0
  152. package/dist/daemon/gate-logger.js +2 -0
  153. package/dist/daemon/gate-logger.js.map +1 -0
  154. package/dist/daemon/jinn-claim-loop-wiring.d.ts +33 -0
  155. package/dist/daemon/jinn-claim-loop-wiring.js +40 -0
  156. package/dist/daemon/jinn-claim-loop-wiring.js.map +1 -0
  157. package/dist/daemon/jinn-claim-loop.d.ts +24 -17
  158. package/dist/daemon/jinn-claim-loop.js +77 -23
  159. package/dist/daemon/jinn-claim-loop.js.map +1 -1
  160. package/dist/daemon/readiness-gate.d.ts +1 -4
  161. package/dist/daemon/readiness-gate.js.map +1 -1
  162. package/dist/daemon/skip-log-dedup.d.ts +69 -0
  163. package/dist/daemon/skip-log-dedup.js +106 -0
  164. package/dist/daemon/skip-log-dedup.js.map +1 -0
  165. package/dist/daemon/spend-cap-gate.d.ts +40 -0
  166. package/dist/daemon/spend-cap-gate.js +46 -0
  167. package/dist/daemon/spend-cap-gate.js.map +1 -0
  168. package/dist/dashboard/assets/index-BNs_ewI6.js +345 -0
  169. package/dist/dashboard/assets/index-C4huIsUW.css +32 -0
  170. package/dist/dashboard/index.html +2 -2
  171. package/dist/discovery/factory.d.ts +17 -5
  172. package/dist/discovery/factory.js +46 -18
  173. package/dist/discovery/factory.js.map +1 -1
  174. package/dist/discovery/http.js +469 -3
  175. package/dist/discovery/http.js.map +1 -1
  176. package/dist/discovery/onchain.d.ts +5 -0
  177. package/dist/discovery/onchain.js +448 -18
  178. package/dist/discovery/onchain.js.map +1 -1
  179. package/dist/discovery/types.d.ts +174 -1
  180. package/dist/discovery/types.js +8 -10
  181. package/dist/discovery/types.js.map +1 -1
  182. package/dist/discovery/with-fallback.d.ts +7 -0
  183. package/dist/discovery/with-fallback.js +37 -0
  184. package/dist/discovery/with-fallback.js.map +1 -1
  185. package/dist/earning/bootstrap.d.ts +100 -4
  186. package/dist/earning/bootstrap.js +239 -76
  187. package/dist/earning/bootstrap.js.map +1 -1
  188. package/dist/earning/contracts.d.ts +14 -0
  189. package/dist/earning/contracts.js +17 -5
  190. package/dist/earning/contracts.js.map +1 -1
  191. package/dist/earning/funding-plan.js +27 -18
  192. package/dist/earning/funding-plan.js.map +1 -1
  193. package/dist/earning/jinn-rewards.d.ts +46 -0
  194. package/dist/earning/jinn-rewards.js +32 -0
  195. package/dist/earning/jinn-rewards.js.map +1 -1
  196. package/dist/earning/safe-adapter.d.ts +2 -0
  197. package/dist/earning/safe-adapter.js +37 -11
  198. package/dist/earning/safe-adapter.js.map +1 -1
  199. package/dist/earning/store.d.ts +8 -0
  200. package/dist/earning/store.js.map +1 -1
  201. package/dist/earning/testnet-setup-migration.d.ts +12 -0
  202. package/dist/earning/testnet-setup-migration.js +27 -1
  203. package/dist/earning/testnet-setup-migration.js.map +1 -1
  204. package/dist/earning/types.d.ts +21 -6
  205. package/dist/earning/viem-clients.d.ts +11 -4
  206. package/dist/earning/viem-clients.js +14 -5
  207. package/dist/earning/viem-clients.js.map +1 -1
  208. package/dist/erc8004/identity.d.ts +19 -3
  209. package/dist/erc8004/identity.js +21 -6
  210. package/dist/erc8004/identity.js.map +1 -1
  211. package/dist/erc8004/index.d.ts +1 -1
  212. package/dist/erc8004/index.js.map +1 -1
  213. package/dist/erc8004/reputation.d.ts +8 -0
  214. package/dist/erc8004/reputation.js +22 -3
  215. package/dist/erc8004/reputation.js.map +1 -1
  216. package/dist/events/types.d.ts +2 -2
  217. package/dist/harnesses/cost-estimates.d.ts +124 -0
  218. package/dist/harnesses/cost-estimates.js +265 -0
  219. package/dist/harnesses/cost-estimates.js.map +1 -0
  220. package/dist/harnesses/engine/engine.d.ts +78 -0
  221. package/dist/harnesses/engine/engine.js +153 -11
  222. package/dist/harnesses/engine/engine.js.map +1 -1
  223. package/dist/harnesses/engine/persistence.d.ts +51 -1
  224. package/dist/harnesses/engine/persistence.js +118 -5
  225. package/dist/harnesses/engine/persistence.js.map +1 -1
  226. package/dist/harnesses/engine/work-dir-reaper.d.ts +65 -0
  227. package/dist/harnesses/engine/work-dir-reaper.js +100 -0
  228. package/dist/harnesses/engine/work-dir-reaper.js.map +1 -0
  229. package/dist/harnesses/impls/hermes-agent/adapter.js +40 -0
  230. package/dist/harnesses/impls/hermes-agent/adapter.js.map +1 -1
  231. package/dist/harnesses/impls/hermes-agent/bootstrap.d.ts +20 -0
  232. package/dist/harnesses/impls/hermes-agent/bootstrap.js +44 -8
  233. package/dist/harnesses/impls/hermes-agent/bootstrap.js.map +1 -1
  234. package/dist/harnesses/impls/hermes-agent/config-builder.d.ts +1 -1
  235. package/dist/harnesses/impls/hermes-agent/config-builder.js +4 -2
  236. package/dist/harnesses/impls/hermes-agent/config-builder.js.map +1 -1
  237. package/dist/harnesses/impls/hermes-agent/harness.d.ts +59 -1
  238. package/dist/harnesses/impls/hermes-agent/harness.js +104 -0
  239. package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
  240. package/dist/harnesses/impls/hermes-agent/prompt.d.ts +6 -6
  241. package/dist/harnesses/impls/hermes-agent/prompt.js +6 -6
  242. package/dist/harnesses/impls/index.d.ts +7 -0
  243. package/dist/harnesses/impls/index.js +16 -1
  244. package/dist/harnesses/impls/index.js.map +1 -1
  245. package/dist/harnesses/impls/learner/adapters/codex-code.d.ts +9 -0
  246. package/dist/harnesses/impls/learner/adapters/codex-code.js +30 -8
  247. package/dist/harnesses/impls/learner/adapters/codex-code.js.map +1 -1
  248. package/dist/harnesses/impls/learner/harness.d.ts +47 -4
  249. package/dist/harnesses/impls/learner/harness.js +105 -2
  250. package/dist/harnesses/impls/learner/harness.js.map +1 -1
  251. package/dist/harnesses/impls/learner/harvest.d.ts +1 -1
  252. package/dist/harnesses/impls/learner/harvest.js +23 -5
  253. package/dist/harnesses/impls/learner/harvest.js.map +1 -1
  254. package/dist/harnesses/impls/learner/plugin-path.d.ts +0 -13
  255. package/dist/harnesses/impls/learner/plugin-path.js +35 -15
  256. package/dist/harnesses/impls/learner/plugin-path.js.map +1 -1
  257. package/dist/harnesses/impls/learner/restoration-patch.d.ts +2 -2
  258. package/dist/harnesses/impls/learner/restoration-patch.js +25 -6
  259. package/dist/harnesses/impls/learner/restoration-patch.js.map +1 -1
  260. package/dist/harnesses/impls/learner/types.d.ts +11 -0
  261. package/dist/harnesses/impls/stub.d.ts +58 -0
  262. package/dist/harnesses/impls/stub.js +89 -0
  263. package/dist/harnesses/impls/stub.js.map +1 -0
  264. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.d.ts +69 -50
  265. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js +199 -94
  266. package/dist/harnesses/impls/swe-rebench-v2-evaluator/eval-runner.js.map +1 -1
  267. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.d.ts +12 -1
  268. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js +121 -7
  269. package/dist/harnesses/impls/swe-rebench-v2-evaluator/harness.js.map +1 -1
  270. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.d.ts +88 -4
  271. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js +143 -22
  272. package/dist/harnesses/impls/swe-rebench-v2-evaluator/hf-fetcher.js.map +1 -1
  273. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.d.ts +6 -0
  274. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js +1 -1
  275. package/dist/harnesses/impls/swe-rebench-v2-evaluator/index.js.map +1 -1
  276. package/dist/harnesses/readiness-registry.d.ts +7 -0
  277. package/dist/harnesses/readiness-registry.js +18 -1
  278. package/dist/harnesses/readiness-registry.js.map +1 -1
  279. package/dist/learner/revert-decision.d.ts +59 -0
  280. package/dist/learner/revert-decision.js +53 -0
  281. package/dist/learner/revert-decision.js.map +1 -0
  282. package/dist/learner/revert-stats.d.ts +24 -0
  283. package/dist/learner/revert-stats.js +44 -0
  284. package/dist/learner/revert-stats.js.map +1 -0
  285. package/dist/main.js +470 -142
  286. package/dist/main.js.map +1 -1
  287. package/dist/mcp/get-codedigest-reward.d.ts +13 -0
  288. package/dist/mcp/get-codedigest-reward.js +23 -0
  289. package/dist/mcp/get-codedigest-reward.js.map +1 -0
  290. package/dist/mcp/server.js +23 -0
  291. package/dist/mcp/server.js.map +1 -1
  292. package/dist/observability/emit-event.d.ts +3 -2
  293. package/dist/observability/emit-event.js +22 -1
  294. package/dist/observability/emit-event.js.map +1 -1
  295. package/dist/operator-errors.d.ts +7 -0
  296. package/dist/operator-errors.js +13 -1
  297. package/dist/operator-errors.js.map +1 -1
  298. package/dist/plugins/learner/.claude-plugin/plugin.json +9 -0
  299. package/dist/plugins/learner/.codex-plugin/plugin.json +39 -0
  300. package/dist/plugins/learner/AGENTS.md +40 -0
  301. package/dist/plugins/learner/CLAUDE.md +33 -0
  302. package/dist/plugins/learner/README.md +59 -0
  303. package/dist/plugins/learner/hooks/hooks.json +16 -0
  304. package/dist/plugins/learner/hooks/session-start +38 -0
  305. package/dist/plugins/learner/skills/learn/SKILL.md +412 -0
  306. package/dist/plugins/learner/skills/learn/analyst-prompt.md +68 -0
  307. package/dist/plugins/learner/skills/learn/consolidator-prompt.md +111 -0
  308. package/dist/plugins/learner/skills/learn/explorer-prompt.md +53 -0
  309. package/dist/plugins/learner/skills/learn/planner-prompt.md +87 -0
  310. package/dist/plugins/learner/skills/learn/promoter-prompt.md +184 -0
  311. package/dist/plugins/learner/skills/learn/step-worker-prompt.md +47 -0
  312. package/dist/plugins/learner/skills/learn/strategist-prompt.md +85 -0
  313. package/dist/preflight/pidfile-liveness.d.ts +44 -0
  314. package/dist/preflight/pidfile-liveness.js +103 -0
  315. package/dist/preflight/pidfile-liveness.js.map +1 -0
  316. package/dist/preflight/rpc-network.d.ts +40 -0
  317. package/dist/preflight/rpc-network.js +67 -1
  318. package/dist/preflight/rpc-network.js.map +1 -1
  319. package/dist/restart-daemon.d.ts +90 -0
  320. package/dist/restart-daemon.js +95 -0
  321. package/dist/restart-daemon.js.map +1 -0
  322. package/dist/rpc/transport.d.ts +109 -0
  323. package/dist/rpc/transport.js +220 -0
  324. package/dist/rpc/transport.js.map +1 -0
  325. package/dist/scripts/donation-consumption-acceptance.js +7 -28
  326. package/dist/scripts/donation-consumption-acceptance.js.map +1 -1
  327. package/dist/scripts/swe-rebench-v2-pytest-missing.json +16 -0
  328. package/dist/setup/halt-mode.d.ts +14 -0
  329. package/dist/setup/halt-mode.js +17 -0
  330. package/dist/setup/halt-mode.js.map +1 -0
  331. package/dist/solver-nets/prediction-operator-ux.d.ts +1 -2
  332. package/dist/solver-nets/prediction-operator-ux.js +90 -47
  333. package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
  334. package/dist/solver-nets/registry.d.ts +20 -1
  335. package/dist/solver-nets/registry.js +38 -25
  336. package/dist/solver-nets/registry.js.map +1 -1
  337. package/dist/solver-types/_swe-rebench-v2-pool-cache.d.ts +58 -0
  338. package/dist/solver-types/_swe-rebench-v2-pool-cache.js +87 -0
  339. package/dist/solver-types/_swe-rebench-v2-pool-cache.js.map +1 -0
  340. package/dist/solver-types/_swe-rebench-v2-pool.d.ts +9 -2
  341. package/dist/solver-types/_swe-rebench-v2-pool.js +15 -20
  342. package/dist/solver-types/_swe-rebench-v2-pool.js.map +1 -1
  343. package/dist/solver-types/_swe-rebench-v2-state.d.ts +15 -0
  344. package/dist/solver-types/_swe-rebench-v2-state.js +19 -0
  345. package/dist/solver-types/_swe-rebench-v2-state.js.map +1 -1
  346. package/dist/solver-types/_swe-rebench-v2-substrate.d.ts +1 -0
  347. package/dist/solver-types/_swe-rebench-v2-substrate.js +10 -0
  348. package/dist/solver-types/_swe-rebench-v2-substrate.js.map +1 -1
  349. package/dist/solver-types/_swe-rebench-v2-validated-pool.d.ts +145 -2
  350. package/dist/solver-types/_swe-rebench-v2-validated-pool.js +482 -44
  351. package/dist/solver-types/_swe-rebench-v2-validated-pool.js.map +1 -1
  352. package/dist/solver-types/swe-rebench-v2-auto.d.ts +38 -14
  353. package/dist/solver-types/swe-rebench-v2-auto.js +87 -28
  354. package/dist/solver-types/swe-rebench-v2-auto.js.map +1 -1
  355. package/dist/solver-types/swe-rebench-v2.d.ts +19 -2
  356. package/dist/solver-types/swe-rebench-v2.js +351 -96
  357. package/dist/solver-types/swe-rebench-v2.js.map +1 -1
  358. package/dist/solvernets/daemon-init.d.ts +10 -2
  359. package/dist/solvernets/daemon-init.js +22 -2
  360. package/dist/solvernets/daemon-init.js.map +1 -1
  361. package/dist/solvernets/launched-record-dispatcher.d.ts +4 -0
  362. package/dist/solvernets/launched-record-dispatcher.js +41 -7
  363. package/dist/solvernets/launched-record-dispatcher.js.map +1 -1
  364. package/dist/solvernets/registry-client-erc8004.js +11 -0
  365. package/dist/solvernets/registry-client-erc8004.js.map +1 -1
  366. package/dist/solvernets/store.d.ts +7 -2
  367. package/dist/solvernets/store.js +1 -0
  368. package/dist/solvernets/store.js.map +1 -1
  369. package/dist/spend/cost-surface-status.d.ts +10 -0
  370. package/dist/spend/cost-surface-status.js +22 -0
  371. package/dist/spend/cost-surface-status.js.map +1 -0
  372. package/dist/spend/credential.d.ts +8 -0
  373. package/dist/spend/credential.js +30 -0
  374. package/dist/spend/credential.js.map +1 -0
  375. package/dist/spend/daemon-config.d.ts +13 -0
  376. package/dist/spend/daemon-config.js +24 -0
  377. package/dist/spend/daemon-config.js.map +1 -0
  378. package/dist/spend/pricing.d.ts +16 -0
  379. package/dist/spend/pricing.js +26 -0
  380. package/dist/spend/pricing.js.map +1 -0
  381. package/dist/spend/record.d.ts +13 -0
  382. package/dist/spend/record.js +30 -0
  383. package/dist/spend/record.js.map +1 -0
  384. package/dist/spend/usage.d.ts +27 -0
  385. package/dist/spend/usage.js +113 -0
  386. package/dist/spend/usage.js.map +1 -0
  387. package/dist/store/store.d.ts +61 -0
  388. package/dist/store/store.js +302 -7
  389. package/dist/store/store.js.map +1 -1
  390. package/dist/tasks/sources.d.ts +18 -1
  391. package/dist/tasks/sources.js +33 -5
  392. package/dist/tasks/sources.js.map +1 -1
  393. package/dist/trajectory/transcript-parsers/codex-session.d.ts +12 -6
  394. package/dist/trajectory/transcript-parsers/codex-session.js +114 -13
  395. package/dist/trajectory/transcript-parsers/codex-session.js.map +1 -1
  396. package/dist/trajectory/transcript-parsers/types.d.ts +8 -8
  397. package/dist/trajectory/transcript-session-dirs.d.ts +18 -0
  398. package/dist/trajectory/transcript-session-dirs.js +85 -0
  399. package/dist/trajectory/transcript-session-dirs.js.map +1 -0
  400. package/dist/trajectory/transcript-watcher.d.ts +20 -1
  401. package/dist/trajectory/transcript-watcher.js +98 -32
  402. package/dist/trajectory/transcript-watcher.js.map +1 -1
  403. package/dist/tx-retry.d.ts +166 -19
  404. package/dist/tx-retry.js +310 -32
  405. package/dist/tx-retry.js.map +1 -1
  406. package/dist/types/payloads/portfolio-v0.d.ts +3 -3
  407. package/dist/types/payloads/prediction-apy-v0.d.ts +8 -8
  408. package/dist/types/payloads/prediction-v0.d.ts +17 -17
  409. package/dist/types/task-document.d.ts +392 -0
  410. package/dist/types/task-document.js +10 -0
  411. package/dist/types/task-document.js.map +1 -1
  412. package/dist/types/task.d.ts +28 -0
  413. package/dist/util/extract-tx-hash.d.ts +14 -0
  414. package/dist/util/extract-tx-hash.js +19 -0
  415. package/dist/util/extract-tx-hash.js.map +1 -0
  416. package/dist/vendor/@jinn-network/sdk/dist/contracts.js +1 -1
  417. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.d.ts +3 -0
  418. package/dist/vendor/@jinn-network/sdk/dist/solvernets/manifest-schema.js +1 -0
  419. package/package.json +37 -13
  420. package/plugins/learner/skills/learn/consolidator-prompt.md +18 -1
  421. package/plugins/learner/skills/learn/promoter-prompt.md +72 -1
  422. package/plugins/swe-rebench-v2-diffmin/README.md +10 -9
  423. package/plugins/swe-rebench-v2-diffmin/jinn.plugin.json +1 -1
  424. package/plugins/swe-rebench-v2-diffmin/skills/diffmin/SKILL.md +15 -10
  425. package/plugins/swe-rebench-v2-diffmin/skills/test-map/SKILL.md +10 -12
  426. package/plugins/swe-rebench-v2-runtime/.claude-plugin/plugin.json +1 -1
  427. package/plugins/swe-rebench-v2-runtime/.codex-plugin/plugin.json +3 -3
  428. package/plugins/swe-rebench-v2-runtime/README.md +6 -6
  429. package/plugins/swe-rebench-v2-runtime/jinn.plugin.json +2 -3
  430. package/plugins/swe-rebench-v2-runtime/skills/task/SKILL.md +69 -0
  431. package/dist/dashboard/assets/index-DOlzFN8a.css +0 -32
  432. package/dist/dashboard/assets/index-NkZ7CTAT.js +0 -140
  433. package/plugins/swe-rebench-v2-runtime/skills/orient/SKILL.md +0 -29
  434. package/plugins/swe-rebench-v2-runtime/skills/plan/SKILL.md +0 -53
@@ -4,11 +4,23 @@ import { privateKeyToAccount } from 'viem/accounts';
4
4
  import { base, baseSepolia } from 'viem/chains';
5
5
  import { PermanentError, parseTask } from '../../types/index.js';
6
6
  import { createClients } from './safe.js';
7
+ /**
8
+ * Coalesce a string-or-array RPC input down to the head URL for display in
9
+ * error contexts (`formatRpcError` expects a single host). The adapter
10
+ * accepts the full fallback chain at the type level; this helper exists so
11
+ * the error-formatting call sites can keep their old signature.
12
+ */
13
+ function rpcUrlForDisplay(rpcUrl) {
14
+ return Array.isArray(rpcUrl) ? rpcUrl[0] : rpcUrl;
15
+ }
7
16
  import { buildResultPayload, uploadToIpfs, cidToDigestHex, fetchFromIpfs, fetchSignedTaskFromIpfs, fetchSignedEnvelopeFromIpfs, } from './ipfs.js';
8
17
  import { canonicalJson } from '../../harnesses/engine/canonical-json.js';
9
- import { SignedEnvelopeSchema } from '../../types/envelope.js';
18
+ import { normalizeEnvelopeRole, SignedEnvelopeSchema } from '../../types/envelope.js';
10
19
  import { submitTask, claimTask as claimTaskOnchain, claimEvaluation as claimEvaluationOnchain, claimDelivery, getMechDeliveryRate, getTimeoutBounds, decodeTaskCreatedLogs, decodeSolutionDeliveryClaimedLogs, decodeDeliverLogs, findLatestDeliveryDataHexForRequest, getMarketplaceRequestDeliveryMech, getTaskCidDigest, callDeliverToMarketplace, canClaimTask, canClaimEvaluation, } from './contracts.js';
20
+ import { SafeInnerRevertError, formatDecodedRevert, isNonRecoverableInnerRevert, } from './safe-revert.js';
21
+ import { verdictCodeFromValue } from './verdict-code.js';
11
22
  import { manifestDigestForCid } from './digest.js';
23
+ import { emitStructured } from '../../events/emitter.js';
12
24
  import { withRecoverableRetry } from '../../tx-retry.js';
13
25
  import { formatRpcError } from '../../rpc-error-context.js';
14
26
  import { SOLUTION_ENVELOPE_CID_CONTEXT_KEY, SOLUTION_TASK_CID_CONTEXT_KEY, RESTORATION_TASK_CID_CONTEXT_KEY, } from '../../harnesses/impls/evaluation-context.js';
@@ -16,6 +28,41 @@ import { signTaskV1 } from '../../tasks/signing.js';
16
28
  const ROUTER_REQUEST_CURSOR_CONFIG_KEY = 'mech_router_request_block_cursor_v1';
17
29
  const PENDING_EVALUATION_SOLUTIONS_CONFIG_KEY = 'mech_pending_evaluation_solutions_v1';
18
30
  const DEFAULT_MECH_DELIVER_BACKFILL_LOOKBACK_BLOCKS = 100000n;
31
+ /** Yield to the event loop every N evaluation opportunities so a large retry
32
+ * backlog can't starve the HTTP API mid-cycle. */
33
+ const EVALUATION_RETRY_YIELD_EVERY = 10;
34
+ /**
35
+ * Bound the number of consecutive transient/uncaught failures for a single
36
+ * pending evaluation solution. Once exceeded, the solution is pruned from
37
+ * `pendingEvaluationSolutions` to stop unbounded log spam (#645). At default
38
+ * pollIntervalMs=5000, twenty cycles ≈ 100 s — comfortably above a normal
39
+ * transient RPC outage window, well below "spamming the log forever".
40
+ *
41
+ * The signal-driven prunes (terminal claimability, `null` delivery-envelope
42
+ * CID per #553, !isDiscoveryTaskAllowed) still fire on their own conditions;
43
+ * this counter is the backstop for failure modes that don't surface a clean
44
+ * terminal signal.
45
+ */
46
+ const MAX_EVALUATION_RETRY_ATTEMPTS = 20;
47
+ /**
48
+ * Decide whether a `canClaimEvaluation` failure means the opportunity can NEVER
49
+ * become claimable (terminal, prune it) versus one that could still clear later
50
+ * (transient, keep retrying).
51
+ *
52
+ * Classification is done on the *structured* `revertName` decoded straight from
53
+ * the inner revert data — not by regex-unformatting the operator-facing `reason`
54
+ * string. The format→regex round-trip was fragile: an arg value containing a
55
+ * `(` corrupted the strip, and the `flattenErrorMessage` fallback produced
56
+ * arbitrary text the regex mangled, silently mis-classifying opportunities.
57
+ *
58
+ * A false-keep (re-checking a dead opportunity) only costs one more RPC; a
59
+ * false-prune (dropping a still-claimable opportunity) loses real work — so
60
+ * when in doubt we keep. Anything without a known non-recoverable revert name
61
+ * is treated as transient.
62
+ */
63
+ function isTerminalEvaluationReason(revertName) {
64
+ return isNonRecoverableInnerRevert(revertName);
65
+ }
19
66
  const DEFAULT_ROUTER_LOG_CHUNK_BLOCKS = 9999n;
20
67
  /**
21
68
  * Floor block for the on-chain TaskCreated backlog scan, per chain.
@@ -81,8 +128,18 @@ export class MechAdapter {
81
128
  deliveryBlockCursor = 0n;
82
129
  pendingEvaluations = new Map();
83
130
  observedTasks = new Map();
131
+ /**
132
+ * Read-through cache for `restorationAnnouncementForTaskId` — the restoration
133
+ * task body looked up *while building an evaluation opportunity*. Kept
134
+ * SEPARATE from `observedTasks` (the `watchForTasks` discovery dedup set) on
135
+ * purpose: writing the restoration body into `observedTasks` made the
136
+ * TaskCreated scan skip that taskId as a *restoration* opportunity just
137
+ * because the daemon had built an *evaluation* opportunity for someone
138
+ * else's attempt on it. That blocked the creator's own daemon from claiming
139
+ * its own attempt on a multi-attempt (`maxClaims > 1`) task it posted.
140
+ */
141
+ restorationBodyCache = new Map();
84
142
  requestKinds = new Map();
85
- claimedRestorationTaskIds = new Set();
86
143
  evaluationOpportunities = new Map();
87
144
  pendingEvaluationSolutions = new Map();
88
145
  // Original Tasks keyed by request ID (restoration and evaluation)
@@ -104,7 +161,7 @@ export class MechAdapter {
104
161
  formatRpcError(message, {
105
162
  operation: 'getBlockNumber',
106
163
  chain: this.config.chainId === 84532 ? 'base-sepolia' : 'base',
107
- rpcUrl: this.config.rpcUrl,
164
+ rpcUrl: rpcUrlForDisplay(this.config.rpcUrl),
108
165
  }));
109
166
  },
110
167
  });
@@ -214,6 +271,13 @@ export class MechAdapter {
214
271
  ? item.transactionHash
215
272
  : undefined,
216
273
  blockNumber: typeof item.blockNumber === 'number' ? item.blockNumber : undefined,
274
+ // #645: clamp to a non-negative integer. A tampered or corrupted
275
+ // store row carrying a negative or fractional failedAttempts could
276
+ // otherwise underflow the prune budget (e.g. -1_000_000_000 would
277
+ // defeat the bound for ~10^9 cycles).
278
+ failedAttempts: typeof item.failedAttempts === 'number' && Number.isFinite(item.failedAttempts)
279
+ ? Math.max(0, Math.floor(item.failedAttempts))
280
+ : 0,
217
281
  };
218
282
  this.pendingEvaluationSolutions.set(solution.requestId, solution);
219
283
  }
@@ -236,6 +300,90 @@ export class MechAdapter {
236
300
  return;
237
301
  this.persistPendingEvaluationSolutions();
238
302
  }
303
+ /**
304
+ * Increment the per-solution failure counter and prune when it exceeds the
305
+ * MAX_EVALUATION_RETRY_ATTEMPTS budget. Persistence runs on every increment
306
+ * so a crash mid-cycle does not lose the count (and let a wedge resume
307
+ * log-spamming after a restart).
308
+ *
309
+ * Call sites: ONLY the two paths that fail to make progress on this specific
310
+ * solution — the transient `canClaimEvaluation` branch in
311
+ * evaluationAnnouncementForSolution, and the `catch (err)` arm of
312
+ * retryPendingEvaluationSolutions. Do NOT call from the signal-driven prune
313
+ * paths (terminal claimability, null delivery-envelope CID,
314
+ * !isDiscoveryTaskAllowed) — those already prune cleanly.
315
+ *
316
+ * Returns true when the solution was pruned (caller should stop work on it).
317
+ */
318
+ recordEvaluationFailureAndMaybePrune(solution) {
319
+ const next = (solution.failedAttempts ?? 0) + 1;
320
+ solution.failedAttempts = next;
321
+ if (next > MAX_EVALUATION_RETRY_ATTEMPTS) {
322
+ console.log(`[mech] pruning evaluation opportunity ${solution.requestId} for task ${solution.taskId}/${solution.attemptIndex}: ` +
323
+ `exceeded retry budget (${MAX_EVALUATION_RETRY_ATTEMPTS}) — pruned`);
324
+ this.forgetPendingEvaluationSolution(solution.requestId);
325
+ return true;
326
+ }
327
+ this.persistPendingEvaluationSolutions();
328
+ return false;
329
+ }
330
+ /** Prune terminal evaluation state so the poll loop stops retrying (#512). */
331
+ pruneTerminalEvaluationOpportunity(params) {
332
+ const { opportunityId, solutionRequestId, reason } = params;
333
+ const target = opportunityId ?? solutionRequestId ?? 'unknown';
334
+ console.log(`[mech] pruning evaluation opportunity ${target}: ${reason} (terminal — pruned)`);
335
+ if (opportunityId) {
336
+ this.evaluationOpportunities.delete(opportunityId);
337
+ this.observedTasks.delete(opportunityId);
338
+ }
339
+ if (solutionRequestId) {
340
+ this.forgetPendingEvaluationSolution(solutionRequestId);
341
+ }
342
+ }
343
+ async claimEvaluationWithTerminalPrune(opportunityId, evaluationOpportunity, evaluationTaskCidDigest) {
344
+ try {
345
+ return await this.claimEvaluation(evaluationOpportunity.taskId, evaluationOpportunity.attemptIndex, evaluationTaskCidDigest);
346
+ }
347
+ catch (err) {
348
+ if (err instanceof SafeInnerRevertError && isNonRecoverableInnerRevert(err.decodedName)) {
349
+ this.pruneTerminalEvaluationOpportunity({
350
+ opportunityId,
351
+ solutionRequestId: evaluationOpportunity.task.restorationRequestId,
352
+ reason: formatDecodedRevert(err.decodedName, err.decodedArgs),
353
+ });
354
+ }
355
+ throw err;
356
+ }
357
+ }
358
+ clearPendingDeliveryRecoveryState(requestId) {
359
+ this.originalStates.delete(requestId);
360
+ this.pendingEvaluations.delete(requestId);
361
+ this.requestKinds.delete(requestId);
362
+ }
363
+ recoveryDeliveryExpirySeconds(requestId) {
364
+ const task = this.originalStates.get(requestId) ?? this.pendingEvaluations.get(requestId);
365
+ const claimPolicy = task?.claimPolicy ?? DEFAULT_MECH_CLAIM_POLICY;
366
+ const normalizeTsToSeconds = (value) => {
367
+ if (value == null)
368
+ return undefined;
369
+ return value > 10_000_000_000 ? Math.floor(value / 1000) : value;
370
+ };
371
+ const submissionDeadlineSeconds = normalizeTsToSeconds(claimPolicy.submissionDeadlineTs);
372
+ if (submissionDeadlineSeconds != null)
373
+ return submissionDeadlineSeconds;
374
+ const claimWindowEndSeconds = normalizeTsToSeconds(claimPolicy.claimWindowEndTs ?? task?.window?.endTs);
375
+ if (claimWindowEndSeconds == null)
376
+ return undefined;
377
+ return claimWindowEndSeconds + claimPolicy.claimLeaseTtlSeconds;
378
+ }
379
+ shouldSkipExpiredRecoveryDelivery(requestId, currentChainTimestampSeconds, recoveryExpirySeconds) {
380
+ if (currentChainTimestampSeconds <= recoveryExpirySeconds)
381
+ return false;
382
+ console.error(`[mech] skipping recovery delivery for ${requestId}: ` +
383
+ `submission deadline expired at ${new Date(recoveryExpirySeconds * 1000).toISOString()}`);
384
+ this.clearPendingDeliveryRecoveryState(requestId);
385
+ return true;
386
+ }
239
387
  async postTask(state) {
240
388
  const restorationState = {
241
389
  ...state,
@@ -264,18 +412,21 @@ export class MechAdapter {
264
412
  const manifestDigest = keccak256(toBytes(signedTask.solverNetManifestCid));
265
413
  const policy = this.contractPolicyForTask(restorationState);
266
414
  const taskSubmission = await submitTask(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, restorationDataHex, manifestDigest, policy, deliveryRate, deliveryRate, maxTimeout, this.config.evictionRecovery);
267
- const announcement = {
268
- taskId: taskSubmission.taskId,
269
- task: {
270
- ...restorationState,
271
- signedTask,
272
- context: { ...(restorationState.context ?? {}), [SOLUTION_TASK_CID_CONTEXT_KEY]: restorationTaskCid },
273
- },
274
- taskCid: restorationTaskCid,
275
- onchainCreationTx: taskSubmission.txHash,
276
- onchainCreationBlock: taskSubmission.blockNumber,
277
- };
278
- this.observedTasks.set(taskSubmission.taskId, announcement);
415
+ // Deliberately do NOT seed `observedTasks` with the task we just posted.
416
+ // `observedTasks` is the dedup set for `watchForTasks`: the on-chain
417
+ // TaskCreated scan skips any taskId already in it (so a task is announced
418
+ // to the engine-watcher at most once). Seeding it here marked the
419
+ // creator's own task as "already announced" before it was ever yielded —
420
+ // which permanently prevented the *creator's own daemon* from discovering,
421
+ // claiming, and solving a task it posted. On a multi-attempt task
422
+ // (`maxClaims > 1`) the creator running the solver role is legitimate
423
+ // (the protocol forbids only self-*evaluation*, and that on a per-attempt
424
+ // basis), and on testnet it is the intended single-operator dogfood path
425
+ // — post → claim → solve → grade → settle from one daemon. The dedup is
426
+ // still correct: it now keys only on tasks `watchForTasks` actually
427
+ // yielded. `restorationAnnouncementForTaskId` re-hydrates from chain/IPFS
428
+ // on a cache miss, so dropping the pre-seed costs at most one redundant
429
+ // fetch if the creator later claims its own task.
279
430
  return {
280
431
  taskId: taskSubmission.taskId,
281
432
  taskCid: restorationTaskCid,
@@ -348,7 +499,14 @@ export class MechAdapter {
348
499
  maxClaimsPerOperator: claimPolicy.maxClaimsPerOperator,
349
500
  policyHook: (claimPolicy.policyHook ?? zeroAddress),
350
501
  evaluationPolicy: {
351
- requiredVerdicts: 1,
502
+ // `requiredVerdicts` defaults to 1 but is overridable via the task's
503
+ // claim policy. A value > 1 opens additional verdict claim slots per
504
+ // attempt; combined with the per-evaluator cap below (1), it
505
+ // guarantees an honest evaluator can still claim and deliver a slot
506
+ // even when other evaluators have squatted some — the structural fix
507
+ // for a shared/adversarial testnet where a non-delivering claimer
508
+ // would otherwise permanently lock a single-slot attempt.
509
+ requiredVerdicts: claimPolicy.requiredVerdicts ?? 1,
352
510
  passThreshold: 1,
353
511
  evaluationDeadline: submissionDeadline + BigInt(claimPolicy.claimLeaseTtlSeconds),
354
512
  maxVerdictsPerEvaluator: 1,
@@ -381,7 +539,11 @@ export class MechAdapter {
381
539
  };
382
540
  }
383
541
  async restorationAnnouncementForTaskId(taskId) {
384
- const cached = this.observedTasks.get(taskId);
542
+ // Read-through `restorationBodyCache` — NOT `observedTasks`. This helper is
543
+ // an evaluation-path lookup of a task's restoration body; caching it into
544
+ // the `watchForTasks` discovery dedup set would suppress the creator's own
545
+ // restoration-claim discovery for the same taskId (see field comment).
546
+ const cached = this.restorationBodyCache.get(taskId) ?? this.observedTasks.get(taskId);
385
547
  if (cached)
386
548
  return cached;
387
549
  const taskCidDigest = await getTaskCidDigest(this.publicClient, this.config.routerAddress, taskId);
@@ -394,7 +556,7 @@ export class MechAdapter {
394
556
  task,
395
557
  taskCid,
396
558
  };
397
- this.observedTasks.set(taskId, announcement);
559
+ this.restorationBodyCache.set(taskId, announcement);
398
560
  return announcement;
399
561
  }
400
562
  async restorationAnnouncementFromDigest(params) {
@@ -440,8 +602,6 @@ export class MechAdapter {
440
602
  for (const candidate of candidates) {
441
603
  if (!this.isDiscoveryTaskAllowed(candidate.taskId))
442
604
  continue;
443
- if (this.claimedRestorationTaskIds.has(candidate.taskId))
444
- continue;
445
605
  // gh #300 ghost-task floor — same floor as the on-chain TaskCreated
446
606
  // backlog scan, applied to the DiscoveryAPI path too. Without this,
447
607
  // the Ponder indexer (or onchain floor's listClaimableTasks) returns
@@ -465,19 +625,40 @@ export class MechAdapter {
465
625
  continue;
466
626
  }
467
627
  try {
628
+ // Yield every hydrated candidate per cycle rather than returning after
629
+ // the first. The engine-watcher (daemon._runEngineWatcherLoop) is the
630
+ // single point of skip-state truth — when its in-flight admission gate
631
+ // fast-skips a candidate (~30s TTL), that skip state never flows back
632
+ // into the adapter's iteration cursor. Yielding only the first
633
+ // candidate per cycle meant a fast-skipped slot starved every
634
+ // subsequent candidate in the round-robin (`fc05f686`) ordering for
635
+ // the duration of the TTL. By driving the full candidate list per
636
+ // cycle we let the engine apply its gate to each one, preserving the
637
+ // round-robin fairness across joined SolverNets. See task 212 live
638
+ // verification in the fix's commit body.
468
639
  yield await this.restorationAnnouncementFromDigest({
469
640
  taskId: candidate.taskId,
470
641
  taskCidDigest: candidate.taskCidDigest,
471
642
  transactionHash: candidate.createdAtTx,
472
643
  blockNumber: candidate.createdAtBlock,
473
644
  });
474
- return;
475
645
  }
476
646
  catch (err) {
477
647
  console.error(`[mech] failed to hydrate subgraph task ${candidate.taskId}:`, err instanceof Error ? err.message : err);
478
648
  }
479
649
  }
480
650
  }
651
+ /**
652
+ * Look up the Deliver-event envelope CID for a pending evaluation solution.
653
+ *
654
+ * Returns `null` when the Deliver event is not present in the configured
655
+ * lookback window. This is a terminal signal for the caller — re-running the
656
+ * same lookup later is deterministically futile when `solution.blockNumber`
657
+ * is set (toBlock is fixed at the SolutionDeliveryClaimed block), and is
658
+ * monotonically less likely to find the event when toBlock follows chain head
659
+ * (the window slides forward, away from any older Deliver event). Callers
660
+ * should prune the pending solution on `null` rather than retry — see #553.
661
+ */
481
662
  async deliveryEnvelopeCidForSolution(solution) {
482
663
  const deliveryMech = await getMarketplaceRequestDeliveryMech(this.publicClient, this.config.mechMarketplaceAddress, solution.requestId);
483
664
  const toBlock = solution.blockNumber != null
@@ -488,8 +669,7 @@ export class MechAdapter {
488
669
  const fromBlock = toBlock > lookback ? toBlock - lookback : 0n;
489
670
  const deliveryDataHex = await findLatestDeliveryDataHexForRequest(this.publicClient, deliveryMech, solution.requestId, fromBlock, toBlock);
490
671
  if (!deliveryDataHex) {
491
- throw new Error(`No Deliver event data found for solution ${solution.requestId} on mech ${deliveryMech} ` +
492
- `between blocks ${fromBlock} and ${toBlock}`);
672
+ return null;
493
673
  }
494
674
  const digest = deliveryDataHex.startsWith('0x') ? deliveryDataHex.slice(2) : deliveryDataHex;
495
675
  return `f01551220${digest}`;
@@ -500,14 +680,43 @@ export class MechAdapter {
500
680
  this.forgetPendingEvaluationSolution(solution.requestId);
501
681
  return undefined;
502
682
  }
503
- const restoration = await this.restorationAnnouncementForTaskId(solution.taskId);
683
+ // Cheap claimability gate FIRST — before the restoration lookup + IPFS
684
+ // fetch. A backlog of terminal opportunities (finalized / evaluation
685
+ // deadline passed / max verdicts reached) must not pay the expensive
686
+ // restoration-announcement cost on every poll cycle. Terminal reasons are
687
+ // pruned from the working set so the loop never re-scans on-chain history;
688
+ // transient reasons are left in place to be retried next cycle.
504
689
  const claimable = await canClaimEvaluation(this.publicClient, this.config.safeAddress, this.config.routerAddress, solution.taskId, solution.attemptIndex, this.config.mechContractAddress);
505
690
  if (!claimable.ok) {
506
- console.log(`[mech] skipping evaluation opportunity ${solution.requestId} for task ${solution.taskId}/${solution.attemptIndex}: ${claimable.reason}`);
507
- this.forgetPendingEvaluationSolution(solution.requestId);
691
+ const terminal = isTerminalEvaluationReason(claimable.revertName);
692
+ console.log(`[mech] skipping evaluation opportunity ${solution.requestId} for task ${solution.taskId}/${solution.attemptIndex}: ${claimable.reason}` +
693
+ (terminal ? ' (terminal — pruned)' : ' (transient — will retry)'));
694
+ if (terminal) {
695
+ this.pruneTerminalEvaluationOpportunity({
696
+ solutionRequestId: solution.requestId,
697
+ reason: claimable.reason,
698
+ });
699
+ }
700
+ else {
701
+ // #645 backstop: bound retries on transient/unclassified claimability
702
+ // failures so a wedged opportunity can't log-spam forever.
703
+ this.recordEvaluationFailureAndMaybePrune(solution);
704
+ }
508
705
  return undefined;
509
706
  }
707
+ const restoration = await this.restorationAnnouncementForTaskId(solution.taskId);
510
708
  const solutionEnvelopeCid = await this.deliveryEnvelopeCidForSolution(solution);
709
+ if (solutionEnvelopeCid == null) {
710
+ // #553: Deliver event is not within the configured lookback window. A
711
+ // retry with the same toBlock cannot reach an older event, so this is
712
+ // terminal — prune so the loop never re-pays the canClaimEvaluation +
713
+ // restoration lookup cost on a deterministically-failing opportunity.
714
+ this.pruneTerminalEvaluationOpportunity({
715
+ solutionRequestId: solution.requestId,
716
+ reason: `no Deliver event found within configured lookback for task ${solution.taskId}/${solution.attemptIndex}`,
717
+ });
718
+ return undefined;
719
+ }
511
720
  const resultPayload = await fetchFromIpfs(this.config.ipfsGatewayUrl, solutionEnvelopeCid);
512
721
  const resultData = resultPayload.data ?? JSON.stringify(resultPayload);
513
722
  const evaluationTask = this.buildEvaluationTask({
@@ -532,21 +741,39 @@ export class MechAdapter {
532
741
  task: evaluationTask,
533
742
  });
534
743
  this.observedTasks.set(opportunityId, announcement);
744
+ // #645: a successful announcement means the candidate has made progress;
745
+ // reset the transient-failure counter so that subsequent transient errors
746
+ // (e.g. IPFS hiccups in the announce → claim window) don't accumulate
747
+ // across the candidate's lifetime and silently false-prune legitimate work.
748
+ if (solution.failedAttempts) {
749
+ solution.failedAttempts = 0;
750
+ this.persistPendingEvaluationSolutions();
751
+ }
535
752
  return announcement;
536
753
  }
537
754
  async *retryPendingEvaluationSolutions() {
755
+ let processed = 0;
538
756
  for (const [requestId, solution] of Array.from(this.pendingEvaluationSolutions)) {
757
+ // Yield to the event loop periodically so a large backlog of pending
758
+ // evaluation solutions can't starve the HTTP API mid-cycle.
759
+ if (processed > 0 && processed % EVALUATION_RETRY_YIELD_EVERY === 0) {
760
+ await new Promise((resolve) => setImmediate(resolve));
761
+ }
762
+ processed++;
539
763
  try {
540
764
  const announcement = await this.evaluationAnnouncementForSolution(solution);
541
765
  if (announcement) {
542
766
  yield announcement;
543
767
  }
544
- else {
545
- this.forgetPendingEvaluationSolution(requestId);
546
- }
768
+ // No announcement does NOT mean "forget" — pruning is owned by
769
+ // evaluationAnnouncementForSolution, which only removes terminal cases.
547
770
  }
548
771
  catch (err) {
549
772
  console.error(`[mech] evaluation opportunity retry failed for ${requestId}:`, err);
773
+ // #645 backstop: bound retries on any uncaught failure so a wedged
774
+ // requestId (e.g. an RPC failure path that re-throws every cycle)
775
+ // can't log-spam forever.
776
+ this.recordEvaluationFailureAndMaybePrune(solution);
550
777
  }
551
778
  }
552
779
  }
@@ -576,7 +803,7 @@ export class MechAdapter {
576
803
  for (const { taskId, taskCidDigest, manifestDigest, transactionHash, blockNumber } of createdTasks) {
577
804
  if (!this.isDiscoveryTaskAllowed(taskId))
578
805
  continue;
579
- if (this.claimedRestorationTaskIds.has(taskId) || this.observedTasks.has(taskId))
806
+ if (this.observedTasks.has(taskId))
580
807
  continue;
581
808
  if (joinedManifestDigests.size > 0 && !joinedManifestDigests.has(manifestDigest.toLowerCase()))
582
809
  continue;
@@ -605,7 +832,7 @@ export class MechAdapter {
605
832
  console.error('[mech] Error polling for tasks:', formatRpcError(err, {
606
833
  operation: 'pollTaskCreated',
607
834
  chain: this.config.chainId === 84532 ? 'base-sepolia' : 'base',
608
- rpcUrl: this.config.rpcUrl,
835
+ rpcUrl: rpcUrlForDisplay(this.config.rpcUrl),
609
836
  contract: this.config.routerAddress,
610
837
  fromBlock: this.requestBlockCursor + 1n,
611
838
  }));
@@ -619,7 +846,7 @@ export class MechAdapter {
619
846
  const signedEvaluationTask = await this.signTaskDocument(evaluationOpportunity.task);
620
847
  const evaluationCid = await uploadToIpfs(this.config.ipfsRegistryUrl, signedEvaluationTask);
621
848
  const evaluationTaskCidDigest = cidToDigestHex(evaluationCid);
622
- const claimed = await this.claimEvaluation(evaluationOpportunity.taskId, evaluationOpportunity.attemptIndex, evaluationTaskCidDigest);
849
+ const claimed = await this.claimEvaluationWithTerminalPrune(taskId, evaluationOpportunity, evaluationTaskCidDigest);
623
850
  this.pendingEvaluations.set(claimed.requestId, evaluationOpportunity.task);
624
851
  this.originalStates.set(claimed.requestId, evaluationOpportunity.task);
625
852
  this.requestKinds.set(claimed.requestId, 'verdict');
@@ -644,7 +871,6 @@ export class MechAdapter {
644
871
  }
645
872
  const claimed = await claimTaskOnchain(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, taskId, this.config.mechContractAddress, this.config.evictionRecovery);
646
873
  const task = announcement.task;
647
- this.claimedRestorationTaskIds.add(claimed.taskId);
648
874
  this.pendingEvaluations.set(claimed.requestId, task);
649
875
  this.originalStates.set(claimed.requestId, { ...task, role: task.role ?? 'restoration' });
650
876
  this.requestKinds.set(claimed.requestId, 'solution');
@@ -676,9 +902,13 @@ export class MechAdapter {
676
902
  async submitVerdictDelivery(requestId, verdictDigest, verdictCode) {
677
903
  await claimDelivery(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, requestId, { variant: 'v3', kind: 'verdict', evidenceHash: verdictDigest, verdictCode }, this.config.evictionRecovery);
678
904
  }
679
- async evidenceHashForDelivery(requestId, deliveryDataHex) {
905
+ async deliveryClaimForDelivery(requestId, deliveryDataHex) {
906
+ const fallbackKind = this.requestKinds.get(requestId) ?? 'solution';
680
907
  if (this.config.routerClaimDeliveryVariant !== 'v2' && this.config.routerClaimDeliveryVariant !== 'v3') {
681
- return undefined;
908
+ return {
909
+ evidenceHash: undefined,
910
+ kind: fallbackKind,
911
+ };
682
912
  }
683
913
  const deliveryDigest = deliveryDataHex.startsWith('0x')
684
914
  ? deliveryDataHex.slice(2)
@@ -686,11 +916,6 @@ export class MechAdapter {
686
916
  const envelopeCid = `f01551220${deliveryDigest}`;
687
917
  const rawEnvelope = await fetchSignedEnvelopeFromIpfs(this.config.ipfsGatewayUrl, envelopeCid);
688
918
  const parsed = SignedEnvelopeSchema.parse(rawEnvelope);
689
- // Strip signature to recompute the hash over the unsigned body.
690
- //
691
- // Important: compute over the fetched wire object, not over the parsed
692
- // schema result. The schema normalizes some nested objects and may strip
693
- // extension metadata that was present when the envelope was signed.
694
919
  const rawSigned = rawEnvelope;
695
920
  const { signature: _rawSignature, ...unsignedBody } = rawSigned;
696
921
  const signature = parsed.signature;
@@ -699,22 +924,36 @@ export class MechAdapter {
699
924
  if (recomputed !== signature.hash) {
700
925
  throw new Error(`recomputed hash ${recomputed} !== envelope.signature.hash ${signature.hash}`);
701
926
  }
702
- return recomputed;
927
+ const role = normalizeEnvelopeRole(parsed.role);
928
+ if (role === 'capture') {
929
+ throw new Error(`unsupported delivery envelope role=capture for requestId ${requestId}`);
930
+ }
931
+ const kind = role === 'verdict' ? 'verdict' : 'solution';
932
+ const payload = rawSigned['payload'];
933
+ const rawVerdict = payload != null && typeof payload === 'object'
934
+ ? payload['verdict']
935
+ : undefined;
936
+ return {
937
+ evidenceHash: recomputed,
938
+ kind,
939
+ verdictCode: kind === 'verdict' ? verdictCodeFromValue(rawVerdict) : undefined,
940
+ };
703
941
  }
704
942
  async ensureDeliveryClaimed(requestId, deliveryDataHex) {
705
- let evidenceHash;
943
+ let claimOptions;
706
944
  try {
707
- evidenceHash = await this.evidenceHashForDelivery(requestId, deliveryDataHex);
945
+ claimOptions = await this.deliveryClaimForDelivery(requestId, deliveryDataHex);
708
946
  }
709
947
  catch (err) {
710
- console.error(`[mech] evidenceHash derivation failed for ${requestId} — skipping claim, will retry on next loop:`, err);
948
+ console.error(`[mech] delivery claim metadata derivation failed for ${requestId} — skipping claim, will retry on next loop:`, err);
711
949
  return 'retry';
712
950
  }
713
951
  try {
714
952
  await claimDelivery(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, requestId, {
715
953
  variant: this.config.routerClaimDeliveryVariant,
716
- kind: this.requestKinds.get(requestId) ?? 'solution',
717
- evidenceHash,
954
+ kind: claimOptions.kind,
955
+ evidenceHash: claimOptions.evidenceHash,
956
+ verdictCode: claimOptions.verdictCode,
718
957
  }, this.config.evictionRecovery);
719
958
  return 'claimed';
720
959
  }
@@ -728,22 +967,66 @@ export class MechAdapter {
728
967
  return 'already-claimed';
729
968
  }
730
969
  console.error(`[mech] claimDelivery failed for ${requestId}:`, err);
970
+ // Paired SSE signal for the operator-app `claim_failed` notification
971
+ // (OPERATOR-APP-SPEC §2.10). The early-return branches above
972
+ // (`skipped` / `already-claimed`) are not failures and intentionally do not emit.
973
+ emitStructured({
974
+ kind: 'intent',
975
+ message: 'Delivery claim failed',
976
+ requestId,
977
+ errorCode: 'claim_failed',
978
+ details: {
979
+ kind: claimOptions.kind,
980
+ source: 'mech.claimDelivery',
981
+ error: message,
982
+ },
983
+ });
731
984
  return 'retry';
732
985
  }
733
986
  }
987
+ /**
988
+ * Paginate `getLogs` over `[deliveryBlockCursor+1, currentBlock]` chunked by
989
+ * `DEFAULT_ROUTER_LOG_CHUNK_BLOCKS` to honor RPC provider block-range limits
990
+ * (Tenderly base-sepolia caps at 100k; sepolia.base.org ~1k). Advances +
991
+ * persists `deliveryBlockCursor` per chunk so a mid-scan RPC failure on a
992
+ * later chunk does not strand the cursor at the pre-poll value (#552).
993
+ *
994
+ * Yields each chunk's decoded Deliver entries so the consumer can process
995
+ * them with the live "current block" context (needed for the recovery-
996
+ * delivery timestamp cache).
997
+ */
998
+ async *scanDeliveryLogChunks(currentBlock) {
999
+ while (currentBlock > this.deliveryBlockCursor) {
1000
+ const chunkStart = this.deliveryBlockCursor + 1n;
1001
+ const chunkEnd = chunkStart + DEFAULT_ROUTER_LOG_CHUNK_BLOCKS > currentBlock
1002
+ ? currentBlock
1003
+ : chunkStart + DEFAULT_ROUTER_LOG_CHUNK_BLOCKS;
1004
+ const logs = await this.publicClient.getLogs({
1005
+ address: this.config.mechContractAddress,
1006
+ fromBlock: chunkStart,
1007
+ toBlock: chunkEnd,
1008
+ });
1009
+ // Advance + persist BEFORE yielding so partial progress is durable even
1010
+ // if a downstream throw escapes back through the for-await consumer.
1011
+ this.deliveryBlockCursor = chunkEnd;
1012
+ if (this.store) {
1013
+ this.store.setLastProcessedBlock(this.deliveryBlockCursor);
1014
+ }
1015
+ yield decodeDeliverLogs(logs);
1016
+ }
1017
+ }
734
1018
  async *watchForDeliveries() {
735
1019
  while (!this.stopped) {
736
1020
  try {
737
1021
  const currentBlock = await this.publicClient.getBlockNumber();
738
- if (currentBlock > this.deliveryBlockCursor) {
739
- const logs = await this.publicClient.getLogs({
740
- address: this.config.mechContractAddress,
741
- fromBlock: this.deliveryBlockCursor + 1n,
742
- toBlock: currentBlock,
743
- });
744
- this.deliveryBlockCursor = currentBlock;
745
- const decoded = decodeDeliverLogs(logs);
746
- for (const { requestId, deliveryDataHex, mechAddress } of decoded) {
1022
+ // Caches scoped to the whole poll iteration: the "current block"
1023
+ // reference does not change across chunks.
1024
+ const blockTimestampSecondsByNumber = new Map();
1025
+ let currentBlockTimestampSeconds;
1026
+ for await (const decoded of this.scanDeliveryLogChunks(currentBlock)) {
1027
+ if (this.stopped)
1028
+ break;
1029
+ for (const { requestId, deliveryDataHex, mechAddress, blockNumber } of decoded) {
747
1030
  // Two concerns, independent:
748
1031
  // (a) Did this Safe DELIVER this? → claim it (counter credit goes to msg.sender)
749
1032
  // The Deliver event's mechAddress is mechServiceMultisig (the Safe that owns
@@ -753,6 +1036,30 @@ export class MechAdapter {
753
1036
  const iCreatedRestoration = this.pendingEvaluations.has(requestId);
754
1037
  if (!iDelivered && !iCreatedRestoration)
755
1038
  continue;
1039
+ if (iCreatedRestoration) {
1040
+ const recoveryExpirySeconds = this.recoveryDeliveryExpirySeconds(requestId);
1041
+ if (recoveryExpirySeconds != null) {
1042
+ let deliveryTimestampSeconds;
1043
+ if (blockNumber != null) {
1044
+ deliveryTimestampSeconds = blockTimestampSecondsByNumber.get(blockNumber);
1045
+ if (deliveryTimestampSeconds == null) {
1046
+ const deliveryBlockData = await this.publicClient.getBlock({ blockNumber });
1047
+ deliveryTimestampSeconds = Number(deliveryBlockData.timestamp);
1048
+ blockTimestampSecondsByNumber.set(blockNumber, deliveryTimestampSeconds);
1049
+ }
1050
+ }
1051
+ else {
1052
+ if (currentBlockTimestampSeconds == null) {
1053
+ const currentBlockData = await this.publicClient.getBlock({ blockNumber: currentBlock });
1054
+ currentBlockTimestampSeconds = Number(currentBlockData.timestamp);
1055
+ }
1056
+ deliveryTimestampSeconds = currentBlockTimestampSeconds;
1057
+ }
1058
+ if (this.shouldSkipExpiredRecoveryDelivery(requestId, deliveryTimestampSeconds, recoveryExpirySeconds)) {
1059
+ continue;
1060
+ }
1061
+ }
1062
+ }
756
1063
  // (a) Deliverer-side claim path: if this Safe delivered the request,
757
1064
  // claim it first so router counters credit the deliverer.
758
1065
  let deliveryClaimStatus;
@@ -788,9 +1095,7 @@ export class MechAdapter {
788
1095
  deliveryMechAddress: mechAddress,
789
1096
  };
790
1097
  // Clean up after yielding
791
- this.originalStates.delete(requestId);
792
- this.pendingEvaluations.delete(requestId);
793
- this.requestKinds.delete(requestId);
1098
+ this.clearPendingDeliveryRecoveryState(requestId);
794
1099
  }
795
1100
  catch (err) {
796
1101
  console.error(`[mech] Failed to parse delivery ${requestId}:`, err);
@@ -802,15 +1107,13 @@ export class MechAdapter {
802
1107
  console.error('[mech] Error polling for deliveries:', formatRpcError(err, {
803
1108
  operation: 'pollDeliveries',
804
1109
  chain: this.config.chainId === 84532 ? 'base-sepolia' : 'base',
805
- rpcUrl: this.config.rpcUrl,
1110
+ rpcUrl: rpcUrlForDisplay(this.config.rpcUrl),
806
1111
  contract: this.config.mechContractAddress,
807
1112
  fromBlock: this.deliveryBlockCursor + 1n,
808
1113
  }));
809
1114
  }
810
- // Persist block cursor for crash recovery
811
- if (this.store && this.deliveryBlockCursor > 0n) {
812
- this.store.setLastProcessedBlock(this.deliveryBlockCursor);
813
- }
1115
+ // Cursor persistence is per-chunk inside the loop above (#552). A poll
1116
+ // that did no chunked work has no progress to persist.
814
1117
  await new Promise(r => setTimeout(r, this.config.pollIntervalMs));
815
1118
  }
816
1119
  }