chrono_forge 0.9.1 → 0.11.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -1
  3. data/README.md +390 -46
  4. data/Rakefile +4 -0
  5. data/cliff.toml +62 -0
  6. data/docs/design/per-child-commit-overhead.md +213 -0
  7. data/docs/fanout-scale-test.md +247 -0
  8. data/docs/superpowers/plans/2026-06-25-chrono_forge-dashboard.md +1748 -0
  9. data/docs/superpowers/plans/2026-06-25-chrono_forge-dashboard.md.tasks.json +17 -0
  10. data/docs/superpowers/plans/2026-06-25-composite-retry-policies.md +930 -0
  11. data/docs/superpowers/plans/2026-06-25-composite-retry-policies.md.tasks.json +54 -0
  12. data/docs/superpowers/plans/2026-06-25-reserved-kwarg-guard.md +241 -0
  13. data/docs/superpowers/plans/2026-06-25-reserved-kwarg-guard.md.tasks.json +12 -0
  14. data/docs/superpowers/plans/2026-06-26-branches-spawn-merge.md +1378 -0
  15. data/docs/superpowers/plans/2026-06-26-branches-spawn-merge.md.tasks.json +67 -0
  16. data/docs/superpowers/plans/2026-06-26-deferral-continuation-race-and-catchup.md +709 -0
  17. data/docs/superpowers/plans/2026-06-26-deferral-continuation-race-and-catchup.md.tasks.json +19 -0
  18. data/docs/superpowers/plans/2026-06-30-poller-rekick-and-eta-cadence.md +205 -0
  19. data/docs/superpowers/plans/2026-06-30-poller-rekick-and-eta-cadence.md.tasks.json +33 -0
  20. data/docs/superpowers/plans/2026-07-01-workflow-definition-dag.md +1373 -0
  21. data/docs/superpowers/plans/2026-07-01-workflow-definition-dag.md.tasks.json +68 -0
  22. data/docs/superpowers/specs/2026-06-03-unified-retry-policy-design.md +226 -0
  23. data/docs/superpowers/specs/2026-06-25-chrono_forge-dashboard-design.md +190 -0
  24. data/docs/superpowers/specs/2026-06-25-composite-retry-policies-design.md +228 -0
  25. data/docs/superpowers/specs/2026-06-25-reserved-kwarg-guard-design.md +169 -0
  26. data/docs/superpowers/specs/2026-06-25-spawn-merge-branches-design.md +468 -0
  27. data/docs/superpowers/specs/2026-06-26-dashboard-branch-view-design.md +142 -0
  28. data/docs/superpowers/specs/2026-06-26-deferral-continuation-race-and-catchup-design.md +265 -0
  29. data/docs/superpowers/specs/2026-07-01-workflow-definition-dag-design.md +203 -0
  30. data/lib/chrono_forge/branch_merge_job.rb +275 -0
  31. data/lib/chrono_forge/branch_probe.rb +70 -0
  32. data/lib/chrono_forge/cleanup.rb +6 -0
  33. data/lib/chrono_forge/configuration.rb +25 -0
  34. data/lib/chrono_forge/definition.rb +37 -0
  35. data/lib/chrono_forge/definition_analyzer.rb +501 -0
  36. data/lib/chrono_forge/execution_log.rb +6 -0
  37. data/lib/chrono_forge/executor/composite_retry_policy.rb +47 -0
  38. data/lib/chrono_forge/executor/context.rb +23 -0
  39. data/lib/chrono_forge/executor/lock_strategy.rb +10 -3
  40. data/lib/chrono_forge/executor/methods/branch.rb +185 -0
  41. data/lib/chrono_forge/executor/methods/continue_if.rb +15 -6
  42. data/lib/chrono_forge/executor/methods/durably_execute.rb +36 -26
  43. data/lib/chrono_forge/executor/methods/durably_repeat.rb +148 -39
  44. data/lib/chrono_forge/executor/methods/merge_branches.rb +84 -0
  45. data/lib/chrono_forge/executor/methods/wait.rb +2 -4
  46. data/lib/chrono_forge/executor/methods/wait_until.rb +25 -25
  47. data/lib/chrono_forge/executor/methods/workflow_states.rb +50 -46
  48. data/lib/chrono_forge/executor/methods.rb +2 -0
  49. data/lib/chrono_forge/executor/retry_policy.rb +111 -0
  50. data/lib/chrono_forge/executor.rb +241 -28
  51. data/lib/chrono_forge/version.rb +1 -1
  52. data/lib/chrono_forge/workflow.rb +10 -1
  53. data/lib/chrono_forge.rb +8 -0
  54. data/lib/generators/chrono_forge/migration_actions.rb +1 -0
  55. data/lib/generators/chrono_forge/templates/add_chrono_forge_parent_execution_log.rb +38 -0
  56. data/lib/tasks/release.rake +212 -0
  57. metadata +67 -4
  58. data/lib/chrono_forge/executor/retry_strategy.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 482a39dce49e0e88ddc0f7341b2806c7893376863caa658eccdd6111c12a4d62
4
- data.tar.gz: aab4017a4b0f90ff68779a0b21b660e34a10ba53a28325f7bcbb801251796ebb
3
+ metadata.gz: c2b3299dbce8cb34289b708af6e0d22d19d764de09978ae257cb87fd37322b5b
4
+ data.tar.gz: f8ca2ae0af221d262d8109b06bd4c319a679d14ea0b440404ef96997134f8b17
5
5
  SHA512:
6
- metadata.gz: 1c1a271dccf9c204633846bc81126b327efb1c176b90181c0dece715f99471a021054f8a892f1a223b11655ededeadc720d34a1a67b7e8ca7cf47a6f9749c175
7
- data.tar.gz: 72745635bb4e34011c3ed735dfa3d648e88362824463b34bd719b32727c7d36602d130044861b882abb9685633231a57ce9a223771f08855a9938b1811db8405
6
+ metadata.gz: c0e81af8116529cbcb1b13fc2f23c952c3622b13f615281f7f97c82ce41cda244316bbb77a99666c4709e8211747d931bdf31d7b02cad011119db8b49b72714d
7
+ data.tar.gz: 427469cfe3d72bd2891d156227be9a32a1879cfa1dc8f52c8c54f87bf99feeabc1b8d9dfca46fb37e58bae6cb84f560f77fca94888dcfcbd32fededfc70bd1f1
data/CHANGELOG.md CHANGED
@@ -1,4 +1,59 @@
1
- ## [Unreleased]
1
+ ## [0.11.0] - 2026-07-04
2
+
3
+ ### Bug Fixes
4
+
5
+ - Back off BranchMergeJob polling for non-progressing children
6
+ - Leave prepare uncommitted for review; publish commits
7
+ - Converge merges promptly via drain-ETA cadence and never-started-count rekick ([#12](https://github.com/radioactive-labs/chrono_forge/issues/12))
8
+ - Overlay/analyzer correctness, detail-panel XSS, and UX polish
9
+
10
+ ### Documentation
11
+
12
+ - Refresh dashboard screenshots, badges; fix upgrade note and API reference
13
+ - Restructure READMEs — promote branches, refine cadence note, dashboard cross-link
14
+ - Add ActiveJob Continuations, Rails-version, and dashboard rows to comparison
15
+ - Correct "workflow is just a Ruby method" framing
16
+ - Add ChronoForge equivalent of the step DSL; fix step-vs-workflow framing
17
+
18
+ ### Features
19
+
20
+ - Add bulk merge / merge_once for context ([#11](https://github.com/radioactive-labs/chrono_forge/issues/11))
21
+ - Workflow definition graph with static DAG and live run overlay ([#13](https://github.com/radioactive-labs/chrono_forge/issues/13))
22
+
23
+ ### Miscellaneous Tasks
24
+
25
+ - Add cliff-driven release script for both gems
26
+ - Replace bin/release with per-gem rake release flow
27
+
28
+ ### Performance
29
+
30
+ - Consolidate per-child commits and flatten log writes
31
+
32
+ ### Styling
33
+
34
+ - Apply standardrb blank-line formatting to existing files
35
+
36
+ ## [0.10.0] - 2026-06-27
37
+
38
+ ### Added
39
+
40
+ - **Concurrent sub-workflows** — `branch` blocks plus `spawn` / `spawn_each` dispatch child workflows that run in parallel, joined later with `merge_branches` (or an inline automerge at branch-block close); the completion gate raises if a branch is left unmerged. `spawn_each` streams bulk dispatch with a resumable cursor and keys AR-sourced children by record PK, so a crash mid-dispatch resumes without re-running completed children. Adds the `parent_execution_log_id` column + `[parent_execution_log_id, state]` index (additive migration, installed by the `chrono_forge:upgrade` generator), with `ExecutionLog#spawned_workflows` / `Workflow#parent_execution_log` associations. Join progress is driven by `ChronoForge::BranchMergeJob`, a lightweight poller that holds no lock and never replays the parent: it re-arms on each pass (fenced by a per-pass `poll_token` so a superseded chain stops quietly), rekicks dropped child jobs, and records observable poll state on the branch logs. Requires `activejob >= 7.1`.
41
+ - `ChronoForge::Executor::RetryPolicy` — a single, unified retry abstraction (attempt cap + exponential-with-jitter backoff + error-class predicate) used by every retry site: workflow-level uncaught errors, `durably_execute`, `durably_repeat`, and `wait_until` condition errors. Replaces the three previously-independent retry systems and two backoff algorithms.
42
+ - Class-level `retry_policy` DSL to set a workflow's default retry policy, plus a per-call `retry_policy:` keyword on `durably_execute`, `durably_repeat`, and `wait_until`. Resolution is per-call → class default → per-site built-in. `wait_until` deliberately does not inherit the class default (so a class-wide "retry everything" can't silently retry condition-evaluation bugs).
43
+ - **Composite retry policies** — pass an ordered array of `RetryPolicy` objects (per-call, or to the class-level `retry_policy` DSL as positional args) to give each error type its own independent attempt budget and backoff. The first policy whose `retry_on` matches the raised error wins (subclasses route to the policy that lists their ancestor; a trailing `retry_on: nil` is a catch-all; an unmatched error fails fast). Per-error counts are keyed by each policy's declared errors (`RetryPolicy#budget_key`) and persisted in execution-log metadata (steps) or the job args (workflow-level), so budgets are stable across replays and policy reordering. `RetryPolicy.compose(*policies)` builds one explicitly.
44
+
45
+ ### Changed
46
+
47
+ - **Performance:** completed steps are now resolved from a single bulk read per replay instead of one indexed `SELECT` each. On every resume the engine replays the whole workflow body; previously each already-completed step cost its own lookup, so a workflow with hundreds of steps paid hundreds of `SELECT`s per resume (quadratic over its lifetime). Completed steps are now plucked once into a per-pass cache and short-circuited from a readonly, unsaved stand-in (no row, no round-trip); only not-yet-completed steps still hit the database. `durably_repeat` repetition logs are deliberately excluded from the cache — they accumulate without bound yet are never replayed — so repeat-heavy workflows don't pull their history into memory.
48
+ - **BREAKING:** `durably_execute` and `durably_repeat` no longer accept `max_attempts:`; `wait_until` no longer accepts `retry_on:`. All three now take `retry_policy:` (a `RetryPolicy`). Migrate `max_attempts: N` → `retry_policy: RetryPolicy.new(max_attempts: N)` and `retry_on: [...]` → `retry_policy: RetryPolicy.new(retry_on: [...])`.
49
+ - **BREAKING:** backoff is now exponential with jitter everywhere (previously the workflow level used a fixed array declared as `[1s,5s,30s,2m,10m]` — though the `should_retry? < 3` bug meant only its first three entries `[1s,5s,30s]` were ever reached — and steps used `2**n` capped at 32s). Workflow-level retries default to 10 attempts with a tolerant window of up to ~8.5 min (≈4 min typical with jitter; cap 600s) — wide enough to ride out a transient infra blip (DB failover, deploy restart) on an uncaught `perform` error, since each such retry replays the whole workflow. A *permanently* failing workflow is now retried 10 times before reaching `failed` (vs the previous effective 4). Note this path covers only uncaught errors in `perform`; a step exhausting its own retries stalls the workflow instead.
50
+
51
+ ### Fixed
52
+
53
+ - Continuation jobs are now published only **after** the workflow lock is released. Every deferral primitive (`wait`, `wait_until`, `durably_execute` retry, `durably_repeat`, and the workflow-level retry) previously enqueued its continuation inline, while the enqueuing job still held the lock; an immediately-runnable (`delay == 0`) same-key continuation could be claimed by another worker before the lock was released, surfacing as a spurious `ConcurrentExecutionError` at lock acquisition. The continuation is now recorded during the run and flushed in the executor's `ensure` block after `release_lock`, closing the race.
54
+ - `durably_repeat` catch-up is now O(1) for the skippable run instead of O(missed intervals). When a workflow resumes far behind schedule, the **expired prefix** (ticks older than `timeout`) is fast-forwarded in closed form to the first non-expired grid tick, rather than walking one zero-delay job per missed tick. **Behavior change:** the expired prefix now produces a single summary execution log (`error_class: "TimeoutError"`, `metadata["fast_forwarded"]` = number of ticks skipped) instead of one `"Execution timed out"` row per tick — update any dashboards or alerts that key off per-tick timeout rows. Ticks still inside their `timeout` window continue to execute as normal catch-up work.
55
+ - Workflow-level retry no longer has a contradictory cap (`should_retry?` stopped at 3 while `RetryStrategy.max_attempts` was 5, making the array's `2m`/`10m` entries unreachable). The single `RetryPolicy` is now the sole decider.
56
+ - Removed the dead `retry_method:` argument that `durably_execute` passed on reschedule but `perform` never bound.
2
57
 
3
58
  ## [0.9.1] - 2026-06-25
4
59