adispatchd 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -2
  3. package/dist/api/errors.d.ts +27 -0
  4. package/dist/api/errors.js +80 -0
  5. package/dist/api/errors.js.map +1 -0
  6. package/dist/api/index.d.ts +10 -0
  7. package/dist/api/index.js +11 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/logs.d.ts +30 -0
  10. package/dist/api/logs.js +88 -0
  11. package/dist/api/logs.js.map +1 -0
  12. package/dist/api/serialize.d.ts +65 -0
  13. package/dist/api/serialize.js +135 -0
  14. package/dist/api/serialize.js.map +1 -0
  15. package/dist/api/server.d.ts +89 -0
  16. package/dist/api/server.js +751 -0
  17. package/dist/api/server.js.map +1 -0
  18. package/dist/api/sse.d.ts +90 -0
  19. package/dist/api/sse.js +225 -0
  20. package/dist/api/sse.js.map +1 -0
  21. package/dist/app.d.ts +173 -0
  22. package/dist/app.js +488 -0
  23. package/dist/app.js.map +1 -0
  24. package/dist/cli/config-validate.d.ts +6 -0
  25. package/dist/cli/config-validate.js +39 -0
  26. package/dist/cli/config-validate.js.map +1 -0
  27. package/dist/cli/control.d.ts +31 -0
  28. package/dist/cli/control.js +186 -0
  29. package/dist/cli/control.js.map +1 -0
  30. package/dist/cli/http-client.d.ts +57 -0
  31. package/dist/cli/http-client.js +174 -0
  32. package/dist/cli/http-client.js.map +1 -0
  33. package/dist/cli/index.d.ts +14 -0
  34. package/dist/cli/index.js +14 -0
  35. package/dist/cli/index.js.map +1 -0
  36. package/dist/cli/init-templates.d.ts +20 -0
  37. package/dist/cli/init-templates.js +275 -0
  38. package/dist/cli/init-templates.js.map +1 -0
  39. package/dist/cli/init.d.ts +16 -0
  40. package/dist/cli/init.js +107 -0
  41. package/dist/cli/init.js.map +1 -0
  42. package/dist/cli/main.d.ts +2 -0
  43. package/dist/cli/main.js +25 -0
  44. package/dist/cli/main.js.map +1 -0
  45. package/dist/cli/program.d.ts +102 -0
  46. package/dist/cli/program.js +133 -0
  47. package/dist/cli/program.js.map +1 -0
  48. package/dist/cli/service.d.ts +27 -0
  49. package/dist/cli/service.js +252 -0
  50. package/dist/cli/service.js.map +1 -0
  51. package/dist/cli/start.d.ts +22 -0
  52. package/dist/cli/start.js +133 -0
  53. package/dist/cli/start.js.map +1 -0
  54. package/dist/cli/workflow-dry-run.d.ts +13 -0
  55. package/dist/cli/workflow-dry-run.js +144 -0
  56. package/dist/cli/workflow-dry-run.js.map +1 -0
  57. package/dist/config/field-catalog.d.ts +33 -0
  58. package/dist/config/field-catalog.js +172 -0
  59. package/dist/config/field-catalog.js.map +1 -0
  60. package/dist/config/filter-schema.d.ts +15 -0
  61. package/dist/config/filter-schema.js +110 -0
  62. package/dist/config/filter-schema.js.map +1 -0
  63. package/dist/config/index.d.ts +15 -0
  64. package/dist/config/index.js +16 -0
  65. package/dist/config/index.js.map +1 -0
  66. package/dist/config/issues.d.ts +27 -0
  67. package/dist/config/issues.js +37 -0
  68. package/dist/config/issues.js.map +1 -0
  69. package/dist/config/loader.d.ts +32 -0
  70. package/dist/config/loader.js +250 -0
  71. package/dist/config/loader.js.map +1 -0
  72. package/dist/config/manager.d.ts +153 -0
  73. package/dist/config/manager.js +276 -0
  74. package/dist/config/manager.js.map +1 -0
  75. package/dist/config/model.d.ts +334 -0
  76. package/dist/config/model.js +2 -0
  77. package/dist/config/model.js.map +1 -0
  78. package/dist/config/normalize.d.ts +20 -0
  79. package/dist/config/normalize.js +200 -0
  80. package/dist/config/normalize.js.map +1 -0
  81. package/dist/config/parameters.d.ts +37 -0
  82. package/dist/config/parameters.js +71 -0
  83. package/dist/config/parameters.js.map +1 -0
  84. package/dist/config/public.d.ts +6 -0
  85. package/dist/config/public.js +18 -0
  86. package/dist/config/public.js.map +1 -0
  87. package/dist/config/schemas.d.ts +538 -0
  88. package/dist/config/schemas.js +321 -0
  89. package/dist/config/schemas.js.map +1 -0
  90. package/dist/config/snapshot.d.ts +38 -0
  91. package/dist/config/snapshot.js +57 -0
  92. package/dist/config/snapshot.js.map +1 -0
  93. package/dist/config/validate.d.ts +33 -0
  94. package/dist/config/validate.js +346 -0
  95. package/dist/config/validate.js.map +1 -0
  96. package/dist/core/clock.d.ts +59 -0
  97. package/dist/core/clock.js +133 -0
  98. package/dist/core/clock.js.map +1 -0
  99. package/dist/core/duration.d.ts +19 -0
  100. package/dist/core/duration.js +93 -0
  101. package/dist/core/duration.js.map +1 -0
  102. package/dist/core/errors.d.ts +62 -0
  103. package/dist/core/errors.js +72 -0
  104. package/dist/core/errors.js.map +1 -0
  105. package/dist/core/ids.d.ts +57 -0
  106. package/dist/core/ids.js +88 -0
  107. package/dist/core/ids.js.map +1 -0
  108. package/dist/core/index.d.ts +13 -0
  109. package/dist/core/index.js +14 -0
  110. package/dist/core/index.js.map +1 -0
  111. package/dist/core/logger.d.ts +100 -0
  112. package/dist/core/logger.js +207 -0
  113. package/dist/core/logger.js.map +1 -0
  114. package/dist/core/paths.d.ts +84 -0
  115. package/dist/core/paths.js +138 -0
  116. package/dist/core/paths.js.map +1 -0
  117. package/dist/core/template.d.ts +136 -0
  118. package/dist/core/template.js +261 -0
  119. package/dist/core/template.js.map +1 -0
  120. package/dist/core/types.d.ts +544 -0
  121. package/dist/core/types.js +172 -0
  122. package/dist/core/types.js.map +1 -0
  123. package/dist/core/worker-protocol.d.ts +102 -0
  124. package/dist/core/worker-protocol.js +75 -0
  125. package/dist/core/worker-protocol.js.map +1 -0
  126. package/dist/executors/classify.d.ts +25 -0
  127. package/dist/executors/classify.js +54 -0
  128. package/dist/executors/classify.js.map +1 -0
  129. package/dist/executors/dispatcher.d.ts +35 -0
  130. package/dist/executors/dispatcher.js +68 -0
  131. package/dist/executors/dispatcher.js.map +1 -0
  132. package/dist/executors/env.d.ts +43 -0
  133. package/dist/executors/env.js +66 -0
  134. package/dist/executors/env.js.map +1 -0
  135. package/dist/executors/event-parser.d.ts +41 -0
  136. package/dist/executors/event-parser.js +106 -0
  137. package/dist/executors/event-parser.js.map +1 -0
  138. package/dist/executors/index.d.ts +12 -0
  139. package/dist/executors/index.js +13 -0
  140. package/dist/executors/index.js.map +1 -0
  141. package/dist/executors/log-capture.d.ts +57 -0
  142. package/dist/executors/log-capture.js +155 -0
  143. package/dist/executors/log-capture.js.map +1 -0
  144. package/dist/executors/process-identity.d.ts +124 -0
  145. package/dist/executors/process-identity.js +283 -0
  146. package/dist/executors/process-identity.js.map +1 -0
  147. package/dist/executors/shell-executor.d.ts +35 -0
  148. package/dist/executors/shell-executor.js +478 -0
  149. package/dist/executors/shell-executor.js.map +1 -0
  150. package/dist/executors/stream-redactor.d.ts +40 -0
  151. package/dist/executors/stream-redactor.js +89 -0
  152. package/dist/executors/stream-redactor.js.map +1 -0
  153. package/dist/executors/workspace.d.ts +10 -0
  154. package/dist/executors/workspace.js +47 -0
  155. package/dist/executors/workspace.js.map +1 -0
  156. package/dist/filters/evaluate.d.ts +77 -0
  157. package/dist/filters/evaluate.js +187 -0
  158. package/dist/filters/evaluate.js.map +1 -0
  159. package/dist/filters/fields.d.ts +35 -0
  160. package/dist/filters/fields.js +75 -0
  161. package/dist/filters/fields.js.map +1 -0
  162. package/dist/filters/index.d.ts +11 -0
  163. package/dist/filters/index.js +12 -0
  164. package/dist/filters/index.js.map +1 -0
  165. package/dist/filters/iso-date.d.ts +10 -0
  166. package/dist/filters/iso-date.js +42 -0
  167. package/dist/filters/iso-date.js.map +1 -0
  168. package/dist/filters/predicate.d.ts +24 -0
  169. package/dist/filters/predicate.js +178 -0
  170. package/dist/filters/predicate.js.map +1 -0
  171. package/dist/filters/priority.d.ts +51 -0
  172. package/dist/filters/priority.js +91 -0
  173. package/dist/filters/priority.js.map +1 -0
  174. package/dist/filters/pushdown.d.ts +12 -0
  175. package/dist/filters/pushdown.js +52 -0
  176. package/dist/filters/pushdown.js.map +1 -0
  177. package/dist/filters/shell-check.d.ts +110 -0
  178. package/dist/filters/shell-check.js +304 -0
  179. package/dist/filters/shell-check.js.map +1 -0
  180. package/dist/identities/github-app.d.ts +55 -0
  181. package/dist/identities/github-app.js +160 -0
  182. package/dist/identities/github-app.js.map +1 -0
  183. package/dist/identities/index.d.ts +6 -0
  184. package/dist/identities/index.js +7 -0
  185. package/dist/identities/index.js.map +1 -0
  186. package/dist/identities/jwt.d.ts +24 -0
  187. package/dist/identities/jwt.js +56 -0
  188. package/dist/identities/jwt.js.map +1 -0
  189. package/dist/lifecycle/context.d.ts +106 -0
  190. package/dist/lifecycle/context.js +170 -0
  191. package/dist/lifecycle/context.js.map +1 -0
  192. package/dist/lifecycle/engine.d.ts +185 -0
  193. package/dist/lifecycle/engine.js +551 -0
  194. package/dist/lifecycle/engine.js.map +1 -0
  195. package/dist/lifecycle/errors.d.ts +48 -0
  196. package/dist/lifecycle/errors.js +71 -0
  197. package/dist/lifecycle/errors.js.map +1 -0
  198. package/dist/lifecycle/index.d.ts +9 -0
  199. package/dist/lifecycle/index.js +9 -0
  200. package/dist/lifecycle/index.js.map +1 -0
  201. package/dist/lifecycle/performers.d.ts +66 -0
  202. package/dist/lifecycle/performers.js +179 -0
  203. package/dist/lifecycle/performers.js.map +1 -0
  204. package/dist/notifications/index.d.ts +6 -0
  205. package/dist/notifications/index.js +7 -0
  206. package/dist/notifications/index.js.map +1 -0
  207. package/dist/notifications/service.d.ts +115 -0
  208. package/dist/notifications/service.js +364 -0
  209. package/dist/notifications/service.js.map +1 -0
  210. package/dist/persistence/actions.d.ts +101 -0
  211. package/dist/persistence/actions.js +196 -0
  212. package/dist/persistence/actions.js.map +1 -0
  213. package/dist/persistence/blocks.d.ts +85 -0
  214. package/dist/persistence/blocks.js +140 -0
  215. package/dist/persistence/blocks.js.map +1 -0
  216. package/dist/persistence/cron-firings.d.ts +55 -0
  217. package/dist/persistence/cron-firings.js +70 -0
  218. package/dist/persistence/cron-firings.js.map +1 -0
  219. package/dist/persistence/database.d.ts +60 -0
  220. package/dist/persistence/database.js +124 -0
  221. package/dist/persistence/database.js.map +1 -0
  222. package/dist/persistence/errors.d.ts +39 -0
  223. package/dist/persistence/errors.js +67 -0
  224. package/dist/persistence/errors.js.map +1 -0
  225. package/dist/persistence/events.d.ts +72 -0
  226. package/dist/persistence/events.js +83 -0
  227. package/dist/persistence/events.js.map +1 -0
  228. package/dist/persistence/index.d.ts +18 -0
  229. package/dist/persistence/index.js +19 -0
  230. package/dist/persistence/index.js.map +1 -0
  231. package/dist/persistence/instance-lock.d.ts +26 -0
  232. package/dist/persistence/instance-lock.js +117 -0
  233. package/dist/persistence/instance-lock.js.map +1 -0
  234. package/dist/persistence/lock-keys.d.ts +16 -0
  235. package/dist/persistence/lock-keys.js +41 -0
  236. package/dist/persistence/lock-keys.js.map +1 -0
  237. package/dist/persistence/notifications.d.ts +113 -0
  238. package/dist/persistence/notifications.js +213 -0
  239. package/dist/persistence/notifications.js.map +1 -0
  240. package/dist/persistence/persistence.d.ts +46 -0
  241. package/dist/persistence/persistence.js +42 -0
  242. package/dist/persistence/persistence.js.map +1 -0
  243. package/dist/persistence/retention.d.ts +46 -0
  244. package/dist/persistence/retention.js +68 -0
  245. package/dist/persistence/retention.js.map +1 -0
  246. package/dist/persistence/runs.d.ts +215 -0
  247. package/dist/persistence/runs.js +417 -0
  248. package/dist/persistence/runs.js.map +1 -0
  249. package/dist/persistence/schema.d.ts +16 -0
  250. package/dist/persistence/schema.js +183 -0
  251. package/dist/persistence/schema.js.map +1 -0
  252. package/dist/persistence/sqlite.d.ts +49 -0
  253. package/dist/persistence/sqlite.js +131 -0
  254. package/dist/persistence/sqlite.js.map +1 -0
  255. package/dist/runs/controller.d.ts +307 -0
  256. package/dist/runs/controller.js +1078 -0
  257. package/dist/runs/controller.js.map +1 -0
  258. package/dist/runs/errors.d.ts +20 -0
  259. package/dist/runs/errors.js +26 -0
  260. package/dist/runs/errors.js.map +1 -0
  261. package/dist/runs/event-bus.d.ts +106 -0
  262. package/dist/runs/event-bus.js +105 -0
  263. package/dist/runs/event-bus.js.map +1 -0
  264. package/dist/runs/execution.d.ts +39 -0
  265. package/dist/runs/execution.js +146 -0
  266. package/dist/runs/execution.js.map +1 -0
  267. package/dist/runs/index.d.ts +12 -0
  268. package/dist/runs/index.js +13 -0
  269. package/dist/runs/index.js.map +1 -0
  270. package/dist/runs/retention.d.ts +64 -0
  271. package/dist/runs/retention.js +232 -0
  272. package/dist/runs/retention.js.map +1 -0
  273. package/dist/runs/workspace.d.ts +20 -0
  274. package/dist/runs/workspace.js +51 -0
  275. package/dist/runs/workspace.js.map +1 -0
  276. package/dist/scheduler/checks.d.ts +41 -0
  277. package/dist/scheduler/checks.js +111 -0
  278. package/dist/scheduler/checks.js.map +1 -0
  279. package/dist/scheduler/cron.d.ts +32 -0
  280. package/dist/scheduler/cron.js +83 -0
  281. package/dist/scheduler/cron.js.map +1 -0
  282. package/dist/scheduler/dry-run.d.ts +42 -0
  283. package/dist/scheduler/dry-run.js +167 -0
  284. package/dist/scheduler/dry-run.js.map +1 -0
  285. package/dist/scheduler/errors.d.ts +22 -0
  286. package/dist/scheduler/errors.js +22 -0
  287. package/dist/scheduler/errors.js.map +1 -0
  288. package/dist/scheduler/format.d.ts +3 -0
  289. package/dist/scheduler/format.js +73 -0
  290. package/dist/scheduler/format.js.map +1 -0
  291. package/dist/scheduler/index.d.ts +13 -0
  292. package/dist/scheduler/index.js +14 -0
  293. package/dist/scheduler/index.js.map +1 -0
  294. package/dist/scheduler/planner.d.ts +88 -0
  295. package/dist/scheduler/planner.js +255 -0
  296. package/dist/scheduler/planner.js.map +1 -0
  297. package/dist/scheduler/scheduler.d.ts +160 -0
  298. package/dist/scheduler/scheduler.js +680 -0
  299. package/dist/scheduler/scheduler.js.map +1 -0
  300. package/dist/scheduler/state.d.ts +26 -0
  301. package/dist/scheduler/state.js +25 -0
  302. package/dist/scheduler/state.js.map +1 -0
  303. package/dist/scheduler/types.d.ts +197 -0
  304. package/dist/scheduler/types.js +3 -0
  305. package/dist/scheduler/types.js.map +1 -0
  306. package/dist/service/index.d.ts +6 -0
  307. package/dist/service/index.js +7 -0
  308. package/dist/service/index.js.map +1 -0
  309. package/dist/service/install.d.ts +93 -0
  310. package/dist/service/install.js +250 -0
  311. package/dist/service/install.js.map +1 -0
  312. package/dist/service/unit.d.ts +50 -0
  313. package/dist/service/unit.js +171 -0
  314. package/dist/service/unit.js.map +1 -0
  315. package/dist/sources/github/adapter.d.ts +99 -0
  316. package/dist/sources/github/adapter.js +336 -0
  317. package/dist/sources/github/adapter.js.map +1 -0
  318. package/dist/sources/github/fields.d.ts +8 -0
  319. package/dist/sources/github/fields.js +72 -0
  320. package/dist/sources/github/fields.js.map +1 -0
  321. package/dist/sources/github/http.d.ts +100 -0
  322. package/dist/sources/github/http.js +288 -0
  323. package/dist/sources/github/http.js.map +1 -0
  324. package/dist/sources/github/index.d.ts +6 -0
  325. package/dist/sources/github/index.js +7 -0
  326. package/dist/sources/github/index.js.map +1 -0
  327. package/dist/sources/github/pushdown.d.ts +14 -0
  328. package/dist/sources/github/pushdown.js +47 -0
  329. package/dist/sources/github/pushdown.js.map +1 -0
  330. package/dist/sources/github/refs.d.ts +17 -0
  331. package/dist/sources/github/refs.js +61 -0
  332. package/dist/sources/github/refs.js.map +1 -0
  333. package/dist/sources/index.d.ts +6 -0
  334. package/dist/sources/index.js +7 -0
  335. package/dist/sources/index.js.map +1 -0
  336. package/dist/ui/index.d.ts +12 -0
  337. package/dist/ui/index.js +28 -0
  338. package/dist/ui/index.js.map +1 -0
  339. package/dist/ui/public/app.css +239 -0
  340. package/dist/ui/public/favicon.svg +1 -0
  341. package/dist/ui/public/index.html +27 -0
  342. package/dist/ui/public/js/client/api.js +68 -0
  343. package/dist/ui/public/js/client/app.js +146 -0
  344. package/dist/ui/public/js/client/dom.js +34 -0
  345. package/dist/ui/public/js/client/page.js +9 -0
  346. package/dist/ui/public/js/client/pages/actions.js +35 -0
  347. package/dist/ui/public/js/client/pages/blocked.js +58 -0
  348. package/dist/ui/public/js/client/pages/config.js +126 -0
  349. package/dist/ui/public/js/client/pages/dashboard.js +175 -0
  350. package/dist/ui/public/js/client/pages/run.js +367 -0
  351. package/dist/ui/public/js/client/pages/runs.js +72 -0
  352. package/dist/ui/public/js/client/pages/views.js +80 -0
  353. package/dist/ui/public/js/client/pages/workflows.js +291 -0
  354. package/dist/ui/public/js/client/types.js +1 -0
  355. package/dist/ui/public/js/client/ui.js +152 -0
  356. package/dist/ui/public/js/shared/dom.js +77 -0
  357. package/dist/ui/public/js/shared/events.js +88 -0
  358. package/dist/ui/public/js/shared/format.js +213 -0
  359. package/dist/ui/public/js/shared/logs.js +136 -0
  360. package/dist/ui/public/js/shared/params.js +90 -0
  361. package/dist/ui/public/js/shared/route.js +36 -0
  362. package/dist/ui/public/js/shared/sort.js +70 -0
  363. package/dist/ui/public/js/shared/sse.js +193 -0
  364. package/dist/ui/public/js/shared/throttle.js +65 -0
  365. package/dist/views/index.d.ts +6 -0
  366. package/dist/views/index.js +7 -0
  367. package/dist/views/index.js.map +1 -0
  368. package/dist/views/service.d.ts +131 -0
  369. package/dist/views/service.js +264 -0
  370. package/dist/views/service.js.map +1 -0
  371. package/docs/api.md +239 -0
  372. package/docs/configuration-reference.md +1785 -0
  373. package/docs/cron-semantics.md +96 -0
  374. package/docs/manual-tests/github-fixture/config.yaml +30 -0
  375. package/docs/manual-tests/github-fixture/helpers.sh +93 -0
  376. package/docs/manual-tests/github-fixture/identities.yaml +18 -0
  377. package/docs/manual-tests/github-fixture/scripts/test-worker.sh +100 -0
  378. package/docs/manual-tests/github-fixture/sources.yaml +13 -0
  379. package/docs/manual-tests/github-fixture/views/dependencies.yaml +17 -0
  380. package/docs/manual-tests/github-fixture/views/needs-maintainer.yaml +17 -0
  381. package/docs/manual-tests/github-fixture/workflows/coder-test.yaml +76 -0
  382. package/docs/manual-tests/github-fixture/workflows/commenter-test.yaml +63 -0
  383. package/docs/manual-tests/github-fixture/workflows/reviewer-test.yaml +60 -0
  384. package/docs/manual-tests/github.md +1308 -0
  385. package/docs/manual-tests/process-supervision.md +64 -0
  386. package/docs/manual-tests/systemd.md +68 -0
  387. package/docs/operations.md +271 -0
  388. package/docs/worker-protocol.md +145 -0
  389. package/examples/config/config.yaml +35 -0
  390. package/examples/config/identities.yaml +18 -0
  391. package/examples/config/sources.yaml +13 -0
  392. package/examples/config/views/needs-maintainer.yaml +15 -0
  393. package/examples/config/workflows/coder-project-a.yaml +86 -0
  394. package/examples/config/workflows/deploy.yaml +15 -0
  395. package/examples/config/workflows/nightly-maintenance.yaml +13 -0
  396. package/package.json +75 -4
@@ -0,0 +1,96 @@
1
+ # Cron-Semantik (Spec §5.5, §7, §24.7)
2
+
3
+ Gilt für Workflows mit `trigger: { type: schedule, cron, timezone }` (Default-Zeitzone `UTC`). Implementiert in
4
+ `src/scheduler/cron.ts` (Slot-Berechnung, croner 10.0.1) und `src/scheduler/scheduler.ts` (Auslösung, Protokoll).
5
+ Das DST-Verhalten ist durch Tests festgenagelt (`src/scheduler/cron.test.ts`); ein croner-Update, das es ändert,
6
+ fällt dort auf.
7
+
8
+ ## Grundregeln
9
+
10
+ - **Slot** = von croner berechneter Zeitpunkt (UTC-Instant, Sekundengenauigkeit). Syntax: croner (5 Felder, optional
11
+ 6 mit Sekunden); Validierung in `config validate` (WI-02).
12
+ - **Höchstens ein automatischer Run pro Slot.** Absicherung doppelt: Primärschlüssel `cron_firings(workflow_id,
13
+ scheduled_for)` und Lock-Key `cron:<slot>` des Runs. Eintrag und Reservierung erfolgen in **einer** Transaktion.
14
+ - **Jeder behandelte Slot bekommt höchstens einen `cron_firings`-Eintrag** mit `decision`. Ausnahme Serien:
15
+ `skipped_disabled`, `skipped_paused`, `skipped_not_ready`, `skipped_draining` werden nur für den **ersten Slot
16
+ einer Serie** geschrieben (Grund endet mit „further slots are not recorded while this state lasts“); weitere Slots
17
+ desselben Zustands schreiben nur `lastHandled` im Speicher fort. Jede andere Entscheidung (auch ein Start) beendet
18
+ die Serie, danach wird ein erneuter Zustand wieder einmal protokolliert:
19
+
20
+ | decision | Bedeutung |
21
+ |---|---|
22
+ | `started` | Run reserviert und gestartet (`run_id` gesetzt) |
23
+ | `skipped_missed` | Slot verpasst (Downtime oder zu spät behandelt) – **wird nicht nachgeholt** |
24
+ | `skipped_limit` | globales oder Workflow-`max_concurrent` erreicht (aktive Runs inkl. manueller und `recovery_pending`) |
25
+ | `skipped_condition` / `skipped_condition_unknown` | Workflow-Condition `false` (Exit 1) / `unknown` (Exit ≥ 2, Timeout, Fehler) |
26
+ | `skipped_blocked` | aktiver Retry-Block im Workflow-Scope |
27
+ | `skipped_disabled` | Workflow deaktiviert (Config oder Runtime-Override) |
28
+ | `skipped_paused` / `skipped_not_ready` / `skipped_draining` | Controller pausiert / Recovery läuft noch / Drain bzw. Shutdown |
29
+ | `skipped_lock` | Slot-Lock bereits belegt (defensiv, sollte nicht vorkommen) |
30
+ | `start_failed` | Reservierung oder Start unerwartet fehlgeschlagen (`reason`) |
31
+
32
+ - **Kein Rückstau:** Ein übersprungener Slot (egal warum) wird nie nachgeholt; der nächste Run entsteht frühestens
33
+ zum nächsten Slot. Überlappung verschiedener Slots desselben Workflows regelt `max_concurrent` (Default 1).
34
+
35
+ ## Verpasste Slots
36
+
37
+ - **Toleranz** (`cronMisfireToleranceMs`, Default 60 s): Wird ein Slot spätestens so lange nach seinem Zeitpunkt
38
+ behandelt (Timer-Latenz, kurzer Neustart), wird er normal entschieden. Ist er älter, gilt er als `skipped_missed`.
39
+ - **Nach einem Neustart** sucht der Scheduler pro Workflow ab dem jüngsten persistierten Slot (`cron_firings.latest`)
40
+ alle Slots bis „jetzt“: der jüngste wird – falls innerhalb der Toleranz – normal entschieden, alle älteren werden
41
+ `skipped_missed` mit Grund „slot passed while the orchestrator was not running“.
42
+ - Gibt es noch keinen persistierten Slot (erster Start, neu angelegter Workflow), beginnt die Planung bei „jetzt“ –
43
+ es wird nichts rückwirkend protokolliert.
44
+ - Wird ein Cron-Ausdruck/eine Zeitzone per Reload **geändert**, beginnt die Planung ebenfalls bei „jetzt“.
45
+ - Begrenzung: pro Nachhol-Prüfung werden höchstens `maxRecordedMissedSlots` (Default 100) Slots einzeln
46
+ protokolliert; ältere werden nur gezählt und im Grund des ältesten protokollierten Eintrags genannt
47
+ („+N older missed slot(s) not recorded“). Die Suche ist auf 100 000 Slots begrenzt (danach nur noch die jüngsten).
48
+ - Timer werden höchstens 1 h im Voraus gestellt und danach neu berechnet; damit wirken auch Systemzeit-Sprünge
49
+ (NTP, Suspend) spätestens nach 1 h, und übersprungene Slots werden als `skipped_missed` protokolliert.
50
+
51
+ ## Sommerzeit (DST) – beobachtetes und festgelegtes Verhalten
52
+
53
+ Beispiel `Europe/Berlin` 2026: Umstellung auf Sommerzeit 29.03. 02:00 CET → 03:00 CEST (01:00Z),
54
+ zurück auf Winterzeit 25.10. 03:00 CEST → 02:00 CET (01:00Z).
55
+
56
+ **Fehlende Lokalzeit (Frühjahr, Lücke 02:00–02:59):**
57
+
58
+ | Ausdruck | Verhalten am Umstellungstag |
59
+ |---|---|
60
+ | `30 2 * * *` (täglich, Zeitpunkt in der Lücke) | läuft **genau einmal**, um 03:30 CEST (= 01:30Z; um die Lückenlänge verschoben) |
61
+ | `0 2 * * *` | läuft einmal um 03:00 CEST (01:00Z) |
62
+ | `0 3 * * *` | läuft einmal um 03:00 CEST (01:00Z) – also zum selben Zeitpunkt wie `0 2` |
63
+ | `*/30 * * * *` | 01:30 CET, dann 03:00 CEST, 03:30 … – die nicht existierenden 02:00/02:30 entfallen ersatzlos, keine Duplikate |
64
+
65
+ Regel: Tägliche (und seltenere) Jobs mit einer Uhrzeit in der Lücke fallen **nicht** aus, sondern laufen einmal,
66
+ verschoben um die Lückenlänge. Sub-stündliche/stündliche Jobs verlieren die Slots in der Lücke (die verschobene Zeit
67
+ existiert ohnehin als regulärer Slot und läuft nur einmal).
68
+
69
+ **Doppelte Lokalzeit (Herbst, 02:00–02:59 zweimal):**
70
+
71
+ | Ausdruck | Verhalten am Umstellungstag |
72
+ |---|---|
73
+ | `30 2 * * *` | läuft **genau einmal**, beim ersten Durchlauf (02:30 CEST = 00:30Z); die zweite 02:30 (CET) läuft nicht |
74
+ | `0 * * * *` | 02:00 CEST (00:00Z), dann 03:00 CET (02:00Z) – die zweite 02:00 (CET, 01:00Z) entfällt |
75
+ | `*/30 * * * *` | 02:00, 02:30 CEST, dann 03:00 CET – Lücke von 1,5 h, die wiederholten 02:00/02:30 CET entfallen |
76
+
77
+ Regel: Jede **Wanduhrzeit** wird höchstens einmal ausgelöst – beim ersten Auftreten. Es gibt nie zwei Runs für
78
+ „02:30“ an einem Tag. Wer exakte Intervalle braucht, verwendet `timezone: UTC`.
79
+
80
+ **UTC** hat keine Umstellung; Slots sind unverändert.
81
+
82
+ ## Zusammenspiel mit anderen Regeln
83
+
84
+ - Conditions werden pro Slot ausgewertet (Workflow-Conditions mit `cache` über den TTL-Cache, sonst neu);
85
+ Item-Conditions/Filter gibt es für Schedule-Workflows nicht.
86
+ - Retry-Blocks für Schedule-Workflows sind workflowbezogen (`itemKey = null`); ein aktiver Block führt zu
87
+ `skipped_blocked`, bis er entfernt wird.
88
+ - Manuelle Starts eines Schedule-Workflows haben eigene Lock-Keys (`manual:<runId>`), erzeugen keinen
89
+ `cron_firings`-Eintrag, zählen aber zur Auslastung und können dadurch einen Slot zu `skipped_limit` machen.
90
+ - Deaktivierte Workflows werden weiter getaktet; protokolliert wird nur der erste Slot einer
91
+ `skipped_disabled`-Serie (gleiches gilt für Pause/Not-ready/Drain) – keine Zeilenflut bei `* * * * *`.
92
+ - Folge für die Downtime-Erkennung: Startet der Orchestrator neu, während bzw. nachdem eine solche Serie lief, sind
93
+ die nicht protokollierten Slots nach dem letzten Eintrag nicht von Downtime unterscheidbar; sie werden (begrenzt)
94
+ als `skipped_missed` mit Grund „… not running (or while still skipped_disabled)“ protokolliert.
95
+ - Fehler bei der Behandlung eines Slots (z. B. DB-Fehler) werden geloggt; der Timer wird **immer** neu gestellt, der
96
+ nächste Slot wird normal entschieden (der fehlgeschlagene Slot bleibt ohne Eintrag).
@@ -0,0 +1,30 @@
1
+ # Test-Konfiguration für docs/manual-tests/github.md (manuelle Tests gegen echtes GitHub).
2
+ # NICHT produktiv verwenden: kurze Intervalle und Retry-Pausen, damit die Testfälle schnell beobachtbar sind.
3
+ # Wird von src/sources/github/manual-fixture.test.ts mit dem echten Loader validiert.
4
+
5
+ server:
6
+ host: 127.0.0.1
7
+ port: 8791 # eigener Port, kollidiert nicht mit einer produktiven Instanz (8787)
8
+ allowed_hosts: []
9
+
10
+ scheduler:
11
+ polling_interval: 20s # kurz, damit „nächster Poll“ (Szenario 3) schnell sichtbar ist
12
+ max_concurrent: 4 # global; Workflow-Limit von coder-test (2) greift zuerst (Szenario 1)
13
+
14
+ workspace:
15
+ cleanup: never # Workspaces zur Analyse behalten (liegen unter <data-dir>/workspaces)
16
+
17
+ lifecycle:
18
+ action_retry:
19
+ max_attempts: 3
20
+ delay: 20s # Default 30 s; kürzer für Szenario 6
21
+
22
+ retention:
23
+ completed_runs: 7d
24
+ failed_runs: 7d
25
+ blocked_runs: 7d
26
+ cleanup_interval: 24h
27
+
28
+ notifications:
29
+ on: [retry_block_created, lifecycle_action_failed, recovery_failed]
30
+ channels: [] # optional: Webhook (z. B. https://webhook.site) für Block-/Action-Fehler eintragen
@@ -0,0 +1,93 @@
1
+ # Shell-Helfer für docs/manual-tests/github.md – NICHT vom Orchestrator ausgeführt, sondern in der eigenen
2
+ # Shell geladen (bash oder zsh), im Repo-Root:
3
+ #
4
+ # export ADISPATCH_TEST_OWNER=<account-oder-org>
5
+ # source docs/manual-tests/github-fixture/helpers.sh
6
+ #
7
+ # Benötigt: gh (angemeldet als Maintainer-Mensch, Zugriff auf alle drei Test-Repos), curl, jq, openssl, npx.
8
+
9
+ : "${ADISPATCH_TEST_OWNER:?ADISPATCH_TEST_OWNER setzen (GitHub-Account oder Org der Test-Repos)}"
10
+ export ADISPATCH_CFG="${ADISPATCH_CFG:-$PWD/tmp/orch-cfg}"
11
+ export ADISPATCH_DATA="${ADISPATCH_DATA:-$PWD/tmp/orch-data}"
12
+ export API="${API:-http://127.0.0.1:8791/api/v1}"
13
+ export GH_API_VERSION="${GH_API_VERSION:-2026-03-10}" # = GITHUB_API_VERSION in src/sources/github/http.ts
14
+
15
+ # --- Orchestrator ------------------------------------------------------------------------------------------
16
+ orch() { npx tsx src/cli/main.ts "$@"; } # CLI aus dem Checkout
17
+ api() { curl -sS "$API$1"; } # GET gegen die API
18
+ post() { # POST mit CSRF-Header
19
+ local body="${2:-}"
20
+ [ -n "$body" ] || body='{}'
21
+ curl -sS -X POST -H 'X-Adispatch-Request: 1' -H 'Content-Type: application/json' -d "$body" "$API$1"
22
+ }
23
+ runs() { # runs <workflow> [limit]
24
+ api "/runs?workflow=$1&limit=${2:-10}" |
25
+ jq -r '.runs[] | [.id, .sourceItemKey, .status, .outcome, (.businessResult // "-"), .lifecycleStatus, (.finalReason // "")] | @tsv'
26
+ }
27
+ run_of() { # run_of <source> <nr> → neueste Run-ID
28
+ api "/runs?item=$1:$2&limit=1" | jq -r '.runs[0].id // empty'
29
+ }
30
+ diag() { # diag <workflow> → letzte Planungsdiagnose
31
+ api "/workflows/$1" | jq -r '.diagnosis // {} | "status=\(.status) polled=\(.polled) error=\(.error) pushdown=\(.pushdown | tojson)",
32
+ (.candidates // [] | .[] | [.itemKey, .decision, (.reason // "")] | @tsv)'
33
+ }
34
+ actions() { # actions <run-id> → Action-Journal
35
+ api "/runs/$1" | jq -r '.actions[] | [.id, .hook, .ordinal, .type, .status, "attempts=\(.attempts)", (.externalKey // "-"), (.lastError.message // "")] | @tsv'
36
+ }
37
+ events() { api "/runs/$1/events?limit=1000" | jq -c '.events[] | {type, payload}'; } # events <run-id>
38
+ view() { # view <view-id> → Tabelle (frisch, ohne Cache)
39
+ api "/views/$1/items?refresh=true" |
40
+ jq -r '(.columns | map(.label) | @tsv), (.rows[] | .cells | map(if .known then (.value | tostring) else "?" end) | @tsv), (.errors[] | "ERROR \(.sourceId): \(.message)")'
41
+ }
42
+
43
+ # --- GitHub (als Mensch über gh) ---------------------------------------------------------------------------
44
+ repo() { printf '%s/%s' "$ADISPATCH_TEST_OWNER" "$1"; } # repo orch-test-a → owner/orch-test-a
45
+ issue_url() { printf 'https://github.com/%s/issues/%s' "$(repo "$1")" "$2"; }
46
+ mkissue() { # mkissue <repo> <titel> [label ...] → Nummer
47
+ local r="$1" title="$2" l
48
+ shift 2
49
+ local args=()
50
+ for l in "$@"; do args+=(--label "$l"); done
51
+ gh issue create -R "$(repo "$r")" --title "$title" --body "adispatchd manual test: $title" "${args[@]}" | sed 's#.*/##'
52
+ }
53
+ blockedby() { # blockedby <repo> <nr> <blocker-repo> <blocker-nr>
54
+ gh issue edit "$2" -R "$(repo "$1")" --add-blocked-by "$(issue_url "$3" "$4")"
55
+ }
56
+ blockedby_api() { # wie blockedby, über REST (issue_id = Datenbank-ID!)
57
+ local id
58
+ id="$(gh api "repos/$(repo "$3")/issues/$4" --jq .id)" || return 1
59
+ gh api -X POST "repos/$(repo "$1")/issues/$2/dependencies/blocked_by" -H "X-GitHub-Api-Version: $GH_API_VERSION" \
60
+ -F issue_id="$id" --jq '"blocked_by added: #\(.number)"'
61
+ }
62
+ unblock_api() { # unblock_api <repo> <nr> <blocker-repo> <blocker-nr>
63
+ local id
64
+ id="$(gh api "repos/$(repo "$3")/issues/$4" --jq .id)" || return 1
65
+ gh api -X DELETE "repos/$(repo "$1")/issues/$2/dependencies/blocked_by/$id" -H "X-GitHub-Api-Version: $GH_API_VERSION" --jq '.number'
66
+ }
67
+ labels() { gh issue view "$2" -R "$(repo "$1")" --json labels --jq '[.labels[].name] | sort | join(",")'; } # labels <repo> <nr>
68
+ comments() { # comments <repo> <nr> → id, Autor, Typ, App-ID, letzte Zeile
69
+ gh api --paginate "repos/$(repo "$1")/issues/$2/comments" \
70
+ --jq '.[] | [.id, .user.login, .user.type, (.performed_via_github_app.id // "-" | tostring), (.body | split("\n") | last)] | @tsv'
71
+ }
72
+
73
+ # --- GitHub (als App) --------------------------------------------------------------------------------------
74
+ probe() { npx tsx tmp/probe.ts "$@"; } # siehe github.md, Abschnitt 2.4
75
+ ghraw() { # ghraw <identity> <pfad> [curl-Optionen] → Rohantwort als App
76
+ local identity="$1" path="$2" token
77
+ shift 2
78
+ token="$(probe token "$identity" 2>/dev/null)" || { echo "kein Token für $identity" >&2; return 1; }
79
+ curl -sS -H "Authorization: Bearer $token" -H 'Accept: application/vnd.github+json' \
80
+ -H "X-GitHub-Api-Version: $GH_API_VERSION" "$@" "https://api.github.com$path"
81
+ }
82
+ app_jwt() { # app_jwt <app-id> <pem-datei> → JWT (9 min)
83
+ local now h p s
84
+ now="$(date +%s)"
85
+ h="$(printf '{"alg":"RS256","typ":"JWT"}' | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
86
+ p="$(printf '{"iat":%d,"exp":%d,"iss":"%s"}' "$((now - 60))" "$((now + 540))" "$1" | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
87
+ s="$(printf '%s.%s' "$h" "$p" | openssl dgst -sha256 -sign "$2" -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
88
+ printf '%s.%s.%s' "$h" "$p" "$s"
89
+ }
90
+ installation_id() { # installation_id <app-id> <pem-datei> <repo>
91
+ curl -sS -H "Authorization: Bearer $(app_jwt "$1" "$2")" -H 'Accept: application/vnd.github+json' \
92
+ -H "X-GitHub-Api-Version: $GH_API_VERSION" "https://api.github.com/repos/$(repo "$3")/installation" | jq '{id, app_id, app_slug, repository_selection, permissions}'
93
+ }
@@ -0,0 +1,18 @@
1
+ # Drei GitHub Apps (eine pro Rolle). Die Zahlen sind Platzhalter und werden beim Kopieren durch die echten
2
+ # App-IDs und Installation-IDs ersetzt (siehe github.md, Abschnitt 2). Private Keys NUR als Env-Variablen.
3
+ identities:
4
+ maintainer:
5
+ type: github_app
6
+ app_id: 9000001
7
+ installation_id: 9100001
8
+ private_key_env: ADISPATCH_TEST_MAINTAINER_KEY
9
+ coder:
10
+ type: github_app
11
+ app_id: 9000002
12
+ installation_id: 9100002
13
+ private_key_env: ADISPATCH_TEST_CODER_KEY
14
+ reviewer:
15
+ type: github_app
16
+ app_id: 9000003
17
+ installation_id: 9100003
18
+ private_key_env: ADISPATCH_TEST_REVIEWER_KEY
@@ -0,0 +1,100 @@
1
+ #!/bin/sh
2
+ # Test-Worker für docs/manual-tests/github.md. Simuliert je nach Issue-Label das Worker-Verhalten
3
+ # (Worker-Protokoll: docs/worker-protocol.md, Spec §8.2):
4
+ #
5
+ # (kein test:*-Label) Exit 0 + Ergebnis success → on_success
6
+ # test:slow vorher TEST_SLOW_SECONDS (Default 90) schlafen, alle 10 s ein progress-Event
7
+ # test:failure Exit 0 + Ergebnis failure (fachlich) → on_failure, kein Retry-Zähler
8
+ # test:crash Ergebnis success schreiben, dann Exit 1 → crashed (Datei wird ignoriert), on_crash
9
+ # test:invalid-result Exit 0 + ungültige Ergebnisdatei → crashed (Protokollfehler)
10
+ # test:token GH_TOKEN (execute.secrets) gegen die API prüfen; Exit 1, falls nicht HTTP 200
11
+ # test:revoke-token GH_TOKEN per DELETE /installation/token widerrufen (erzwingt Token-Erneuerung im
12
+ # Orchestrator: nächster Aufruf der Identity → 401 → invalidate → neues Token)
13
+ #
14
+ # Labels kombinierbar (z. B. test:slow + test:failure). Argumente: $1 = Issue-Nummer, $2 = owner/repo.
15
+ set -eu
16
+
17
+ number="${1:-?}"
18
+ repo="${2:-?}"
19
+ slow="${TEST_SLOW_SECONDS:-90}"
20
+
21
+ # Labels aus der Kontextdatei lesen (source.attributes.labels). node ist vorhanden, weil der Orchestrator
22
+ # damit läuft; Fallback grep (Labels stehen als JSON-Strings in der Datei).
23
+ labels=""
24
+ if command -v node >/dev/null 2>&1; then
25
+ labels="$(node -e '
26
+ const c = JSON.parse(require("fs").readFileSync(process.env.ADISPATCH_CONTEXT_FILE, "utf8"));
27
+ const l = (c.source && c.source.attributes && c.source.attributes.labels) || [];
28
+ process.stdout.write(l.join("\n"));
29
+ ')"
30
+ else
31
+ labels="$(grep -o '"test:[a-z-]*"' "${ADISPATCH_CONTEXT_FILE}" | tr -d '"' || true)"
32
+ fi
33
+ has() { printf '%s\n' "${labels}" | grep -qx "$1"; }
34
+
35
+ # Ergebnis atomar schreiben (temporäre Datei im selben Verzeichnis + mv).
36
+ write_result() { # $1 = success|failure, $2 = message
37
+ tmp="${ADISPATCH_RESULT_FILE}.tmp.$$"
38
+ msg="$(printf '%s' "$2" | sed 's/\\/\\\\/g; s/"/\\"/g')"
39
+ printf '{"schema_version":1,"result":"%s","message":"%s","details":{"repo":"%s","number":"%s"}}\n' \
40
+ "$1" "${msg}" "${repo}" "${number}" > "${tmp}"
41
+ mv "${tmp}" "${ADISPATCH_RESULT_FILE}"
42
+ }
43
+
44
+ echo "test-worker: run ${ADISPATCH_RUN_ID} workflow ${ADISPATCH_WORKFLOW_ID} item ${repo}#${number}"
45
+ echo "test-worker: labels: $(printf '%s' "${labels}" | tr '\n' ' ')"
46
+ echo "test-worker: workspace ${ADISPATCH_WORKSPACE}"
47
+ echo '@@ADISPATCH_EVENT {"type":"status","message":"test-worker gestartet"}'
48
+
49
+ if has test:token; then
50
+ code="$(curl -s -o /dev/null -w '%{http_code}' \
51
+ -H "Authorization: Bearer ${GH_TOKEN:-missing}" \
52
+ -H 'Accept: application/vnd.github+json' \
53
+ -H 'X-GitHub-Api-Version: 2026-03-10' \
54
+ "https://api.github.com/repos/${repo}/issues/${number}")"
55
+ echo "test-worker: GET issue with GH_TOKEN → HTTP ${code}"
56
+ [ "${code}" = "200" ] || { echo "test-worker: GH_TOKEN rejected" >&2; exit 1; }
57
+ fi
58
+
59
+ if has test:revoke-token; then
60
+ code="$(curl -s -o /dev/null -w '%{http_code}' -X DELETE \
61
+ -H "Authorization: Bearer ${GH_TOKEN:-missing}" \
62
+ -H 'Accept: application/vnd.github+json' \
63
+ -H 'X-GitHub-Api-Version: 2026-03-10' \
64
+ "https://api.github.com/installation/token")"
65
+ echo "test-worker: DELETE /installation/token → HTTP ${code} (expected 204)"
66
+ fi
67
+
68
+ if has test:slow; then
69
+ elapsed=0
70
+ while [ "${elapsed}" -lt "${slow}" ]; do
71
+ printf '@@ADISPATCH_EVENT {"type":"progress","value":%s}\n' "$((elapsed * 100 / slow))"
72
+ echo "test-worker: working ${elapsed}/${slow}s"
73
+ sleep 10
74
+ elapsed=$((elapsed + 10))
75
+ done
76
+ fi
77
+
78
+ if has test:crash; then
79
+ write_result success "wird ignoriert, weil Exit != 0"
80
+ echo "test-worker: simulating crash (exit 1)" >&2
81
+ exit 1
82
+ fi
83
+
84
+ if has test:invalid-result; then
85
+ tmp="${ADISPATCH_RESULT_FILE}.tmp.$$"
86
+ printf '%s\n' '{"schema_version":1,"result":"maybe"}' > "${tmp}"
87
+ mv "${tmp}" "${ADISPATCH_RESULT_FILE}"
88
+ echo "test-worker: wrote invalid result file"
89
+ exit 0
90
+ fi
91
+
92
+ if has test:failure; then
93
+ write_result failure "Simulierter fachlicher Fehler fuer ${repo}#${number}"
94
+ echo '@@ADISPATCH_EVENT {"type":"question","message":"Anforderungen unklar (simuliert)"}'
95
+ exit 0
96
+ fi
97
+
98
+ write_result success "Simulierter Erfolg fuer ${repo}#${number}"
99
+ echo '@@ADISPATCH_EVENT {"type":"progress","value":100}'
100
+ exit 0
@@ -0,0 +1,13 @@
1
+ # Zwei Test-Repos im selben Account/Org. ADISPATCH_TEST_OWNER wird beim Kopieren ersetzt (siehe github.md, Abschnitt 2).
2
+ # Das dritte Repo (orch-test-hidden) ist bewusst KEINE Source und für keine App installiert.
3
+ sources:
4
+ test_a:
5
+ type: github
6
+ owner: ADISPATCH_TEST_OWNER
7
+ repository: orch-test-a
8
+ identity: maintainer # Lesen (Polling, Dependencies, Views) mit der Maintainer-App
9
+ test_b:
10
+ type: github
11
+ owner: ADISPATCH_TEST_OWNER
12
+ repository: orch-test-b
13
+ identity: maintainer
@@ -0,0 +1,17 @@
1
+ # views/dependencies.yaml – Beobachtungswerkzeug für die Dependency-Fälle (github.md: T11–T14), ohne Runs zu starten.
2
+ # Zeigt für alle offenen Items mit Label deps-test, wie der Adapter "blocked by" auflöst.
3
+ id: dependencies
4
+ title: Dependencies (Test)
5
+ sources: [test_a, test_b]
6
+ filter:
7
+ all:
8
+ - { field: labels, operator: contains, value: deps-test }
9
+ fields:
10
+ - { field: repository, label: Repository }
11
+ - { field: number, label: Nr. }
12
+ - { field: title, label: Titel, link: url }
13
+ - { field: dependencies.status, label: Status }
14
+ - { field: dependencies.blocked_by_total, label: Blocker gesamt }
15
+ - { field: dependencies.blocked_by_open, label: Blocker offen }
16
+ - { field: dependencies.blocked, label: Blockiert }
17
+ sort: { field: number, direction: asc }
@@ -0,0 +1,17 @@
1
+ # views/needs-maintainer.yaml – Szenario 10: kombiniert beide Test-Repos (github.md: T21).
2
+ id: needs-maintainer
3
+ title: Needs Maintainer (Test)
4
+ sources: [test_a, test_b]
5
+ filter:
6
+ all:
7
+ - { field: labels, operator: contains, value: needs-maintainer }
8
+ fields:
9
+ - { field: repository, label: Repository }
10
+ - { field: number, label: Nr. }
11
+ - { field: title, label: Titel, link: url }
12
+ - { field: is_pull_request, label: PR }
13
+ - { field: run.last_workflow, label: Letzter Agent }
14
+ - { field: run.last_status, label: Status }
15
+ - { field: run.last_result.message, label: Ergebnis }
16
+ - { field: updated_at, label: Aktualisiert }
17
+ sort: { field: updated_at, direction: desc }
@@ -0,0 +1,76 @@
1
+ # workflows/coder-test.yaml – Coder-Rolle gegen orch-test-a (github.md: T3–T9, T13–T17, T20).
2
+ # Startet Issues/PRs mit Label ready-for-coding, deren native "blocked by"-Abhängigkeiten alle geschlossen sind.
3
+ # Das Verhalten des Test-Workers steuern die Labels test:* (siehe scripts/test-worker.sh).
4
+ id: coder-test
5
+ name: Coder-Test (orch-test-a)
6
+ enabled: true
7
+ priority: 50
8
+ max_concurrent: 2 # Szenario 1: zwei parallel, der dritte wartet (workflow_limit)
9
+ identity: coder # schreibende Aktionen (Labels, Kommentare) als Coder-App
10
+
11
+ trigger:
12
+ type: source
13
+ source: test_a
14
+
15
+ filter:
16
+ all:
17
+ - { field: labels, operator: contains, value: ready-for-coding } # Pushdown: ?labels=ready-for-coding
18
+ - { field: dependencies.blocked_by_open, operator: equals, value: 0 } # teuer, unknown → kein Start
19
+
20
+ item_priority:
21
+ rules:
22
+ - when: { field: labels, operator: contains, value: 'priority:high' }
23
+ value: 50
24
+ default: 0
25
+
26
+ execute:
27
+ type: shell
28
+ command: scripts/test-worker.sh # relativ zum config-dir
29
+ args: ['{item.number}', '{source.repository}']
30
+ env:
31
+ TEST_SLOW_SECONDS: '90' # Dauer bei Label test:slow
32
+ secrets:
33
+ GH_TOKEN: { identity: coder } # nur für Label test:token (Token-Prüfung im Worker)
34
+ timeout:
35
+ max_duration: 10m
36
+ idle_timeout: 5m
37
+ cancel_grace: 10s
38
+
39
+ retry:
40
+ max_technical_failures: 3 # Szenario 5: dritter Crash → Retry-Block
41
+
42
+ on_start:
43
+ - id: on_start-labels
44
+ type: source.update
45
+ labels: { add: [coding], remove: [ready-for-coding] }
46
+ on_success:
47
+ - id: on_success-labels
48
+ type: source.update
49
+ labels: { add: [ready-for-review], remove: [coding] }
50
+ - id: on_success-comment
51
+ type: source.comment
52
+ message: 'Coder-Test erfolgreich: {result.message}'
53
+ continue_on_error: true
54
+ on_failure: # fachliches failure (Ergebnisdatei) → Needs Maintainer, kein Retry-Zähler
55
+ - id: on_failure-labels
56
+ type: source.update
57
+ labels: { add: [needs-maintainer], remove: [coding] }
58
+ - id: on_failure-comment
59
+ type: source.comment
60
+ message: 'Needs maintainer: {result.message}'
61
+ on_crash: # technischer Fehler → zurück in die Warteschlange (Block stoppt nach 3×)
62
+ - id: on_crash-labels
63
+ type: source.update
64
+ labels: { add: [ready-for-coding], remove: [coding] }
65
+ on_start_error:
66
+ - id: on_start_error-labels
67
+ type: source.update
68
+ labels: { add: [ready-for-coding], remove: [coding] }
69
+ on_timeout:
70
+ - id: on_timeout-labels
71
+ type: source.update
72
+ labels: { add: [ready-for-coding], remove: [coding] }
73
+ on_cancel:
74
+ - id: on_cancel-labels
75
+ type: source.update
76
+ labels: { add: [ready-for-coding], remove: [coding] }
@@ -0,0 +1,63 @@
1
+ # workflows/commenter-test.yaml – Kommentar-Actions gegen orch-test-b (github.md: T6, T7, T18, T19).
2
+ # on_start kommentiert als REVIEWER (Action-Identity überschreibt die Workflow-Identity),
3
+ # on_success als CODER mit großzügigem Retry, damit ein kurzer Netzwerkausfall überbrückt wird (Szenario 6).
4
+ id: commenter-test
5
+ name: Kommentar-Test (orch-test-b)
6
+ enabled: true
7
+ priority: 30
8
+ max_concurrent: 1
9
+ identity: coder
10
+
11
+ trigger:
12
+ type: source
13
+ source: test_b
14
+
15
+ filter:
16
+ all:
17
+ - { field: labels, operator: contains, value: ready-for-comment }
18
+
19
+ execute:
20
+ type: shell
21
+ command: scripts/test-worker.sh
22
+ args: ['{item.number}', '{source.repository}']
23
+ env:
24
+ TEST_SLOW_SECONDS: '60'
25
+ timeout:
26
+ max_duration: 10m
27
+
28
+ on_start:
29
+ - id: on_start-labels
30
+ type: source.update
31
+ labels: { add: [commenting], remove: [ready-for-comment] }
32
+ - id: start-comment
33
+ type: source.comment
34
+ identity: reviewer
35
+ message: 'Kommentar-Test gestartet (Run {run.id}, Item {item.key}).'
36
+ on_success:
37
+ - id: done-comment
38
+ type: source.comment
39
+ message: 'Kommentar-Test fertig: {result.message}'
40
+ retry: { max_attempts: 6, delay: 20s } # ~100 s Fenster für einen Netzwerkausfall
41
+ - id: on_success-labels
42
+ type: source.update
43
+ labels: { add: [commented], remove: [commenting] }
44
+ on_failure:
45
+ - id: on_failure-labels
46
+ type: source.update
47
+ labels: { add: [needs-maintainer], remove: [commenting] }
48
+ on_crash:
49
+ - id: on_crash-labels
50
+ type: source.update
51
+ labels: { add: [ready-for-comment], remove: [commenting] }
52
+ on_start_error:
53
+ - id: on_start_error-labels
54
+ type: source.update
55
+ labels: { add: [ready-for-comment], remove: [commenting] }
56
+ on_timeout:
57
+ - id: on_timeout-labels
58
+ type: source.update
59
+ labels: { add: [ready-for-comment], remove: [commenting] }
60
+ on_cancel:
61
+ - id: on_cancel-labels
62
+ type: source.update
63
+ labels: { add: [ready-for-comment], remove: [commenting] }
@@ -0,0 +1,60 @@
1
+ # workflows/reviewer-test.yaml – Reviewer-Rolle gegen orch-test-a (github.md: T10).
2
+ # Nur Pull Requests mit Label ready-for-review und ohne offene Blocker. Ein Issue mit demselben Label
3
+ # (z. B. nach coder-test-Erfolg) wird über is_pull_request herausgefiltert.
4
+ id: reviewer-test
5
+ name: Reviewer-Test (orch-test-a, nur PRs)
6
+ enabled: true
7
+ priority: 40
8
+ max_concurrent: 1
9
+ identity: reviewer
10
+
11
+ trigger:
12
+ type: source
13
+ source: test_a
14
+
15
+ filter:
16
+ all:
17
+ - { field: labels, operator: contains, value: ready-for-review }
18
+ - { field: is_pull_request, operator: equals, value: true }
19
+ - { field: dependencies.blocked_by_open, operator: equals, value: 0 }
20
+
21
+ execute:
22
+ type: shell
23
+ command: scripts/test-worker.sh
24
+ args: ['{item.number}', '{source.repository}']
25
+ env:
26
+ TEST_SLOW_SECONDS: '60'
27
+ timeout:
28
+ max_duration: 10m
29
+
30
+ on_start:
31
+ - id: on_start-labels
32
+ type: source.update
33
+ labels: { add: [reviewing], remove: [ready-for-review] }
34
+ on_success:
35
+ - id: on_success-labels
36
+ type: source.update
37
+ labels: { add: [reviewed], remove: [reviewing] }
38
+ - id: on_success-comment
39
+ type: source.comment
40
+ message: 'Reviewer-Test ok: {result.message}'
41
+ on_failure:
42
+ - id: on_failure-labels
43
+ type: source.update
44
+ labels: { add: [needs-maintainer], remove: [reviewing] }
45
+ on_crash:
46
+ - id: on_crash-labels
47
+ type: source.update
48
+ labels: { add: [ready-for-review], remove: [reviewing] }
49
+ on_start_error:
50
+ - id: on_start_error-labels
51
+ type: source.update
52
+ labels: { add: [ready-for-review], remove: [reviewing] }
53
+ on_timeout:
54
+ - id: on_timeout-labels
55
+ type: source.update
56
+ labels: { add: [ready-for-review], remove: [reviewing] }
57
+ on_cancel:
58
+ - id: on_cancel-labels
59
+ type: source.update
60
+ labels: { add: [ready-for-review], remove: [reviewing] }