chrono_forge 0.9.1 → 0.10.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/README.md +305 -44
  4. data/docs/superpowers/plans/2026-06-25-chrono_forge-dashboard.md +1748 -0
  5. data/docs/superpowers/plans/2026-06-25-chrono_forge-dashboard.md.tasks.json +17 -0
  6. data/docs/superpowers/plans/2026-06-25-composite-retry-policies.md +930 -0
  7. data/docs/superpowers/plans/2026-06-25-composite-retry-policies.md.tasks.json +54 -0
  8. data/docs/superpowers/plans/2026-06-25-reserved-kwarg-guard.md +241 -0
  9. data/docs/superpowers/plans/2026-06-25-reserved-kwarg-guard.md.tasks.json +12 -0
  10. data/docs/superpowers/plans/2026-06-26-branches-spawn-merge.md +1378 -0
  11. data/docs/superpowers/plans/2026-06-26-branches-spawn-merge.md.tasks.json +67 -0
  12. data/docs/superpowers/plans/2026-06-26-deferral-continuation-race-and-catchup.md +709 -0
  13. data/docs/superpowers/plans/2026-06-26-deferral-continuation-race-and-catchup.md.tasks.json +19 -0
  14. data/docs/superpowers/specs/2026-06-03-unified-retry-policy-design.md +226 -0
  15. data/docs/superpowers/specs/2026-06-25-chrono_forge-dashboard-design.md +190 -0
  16. data/docs/superpowers/specs/2026-06-25-composite-retry-policies-design.md +228 -0
  17. data/docs/superpowers/specs/2026-06-25-reserved-kwarg-guard-design.md +169 -0
  18. data/docs/superpowers/specs/2026-06-25-spawn-merge-branches-design.md +468 -0
  19. data/docs/superpowers/specs/2026-06-26-dashboard-branch-view-design.md +142 -0
  20. data/docs/superpowers/specs/2026-06-26-deferral-continuation-race-and-catchup-design.md +265 -0
  21. data/lib/chrono_forge/branch_merge_job.rb +138 -0
  22. data/lib/chrono_forge/branch_probe.rb +26 -0
  23. data/lib/chrono_forge/cleanup.rb +6 -0
  24. data/lib/chrono_forge/execution_log.rb +6 -0
  25. data/lib/chrono_forge/executor/composite_retry_policy.rb +47 -0
  26. data/lib/chrono_forge/executor/methods/branch.rb +185 -0
  27. data/lib/chrono_forge/executor/methods/durably_execute.rb +21 -19
  28. data/lib/chrono_forge/executor/methods/durably_repeat.rb +118 -25
  29. data/lib/chrono_forge/executor/methods/merge_branches.rb +83 -0
  30. data/lib/chrono_forge/executor/methods/wait.rb +2 -4
  31. data/lib/chrono_forge/executor/methods/wait_until.rb +25 -25
  32. data/lib/chrono_forge/executor/methods/workflow_states.rb +16 -0
  33. data/lib/chrono_forge/executor/methods.rb +2 -0
  34. data/lib/chrono_forge/executor/retry_policy.rb +111 -0
  35. data/lib/chrono_forge/executor.rb +216 -28
  36. data/lib/chrono_forge/version.rb +1 -1
  37. data/lib/chrono_forge/workflow.rb +10 -1
  38. data/lib/generators/chrono_forge/migration_actions.rb +1 -0
  39. data/lib/generators/chrono_forge/templates/add_chrono_forge_parent_execution_log.rb +38 -0
  40. metadata +42 -5
  41. data/lib/chrono_forge/executor/retry_strategy.rb +0 -29
@@ -0,0 +1,67 @@
1
+ {
2
+ "planPath": "docs/superpowers/plans/2026-06-26-branches-spawn-merge.md",
3
+ "tasks": [
4
+ {
5
+ "id": 1,
6
+ "subject": "Task 1: Schema — parent_execution_log_id column + index",
7
+ "status": "completed",
8
+ "description": "Add nullable parent_execution_log_id (FK type matching pk) to chrono_forge_workflows + composite (parent_execution_log_id, state) index, via an additive migration wired into the generators and applied to the test DB.\n\n```json:metadata\n{\"files\": [\"lib/generators/chrono_forge/templates/add_chrono_forge_parent_execution_log.rb\", \"lib/generators/chrono_forge/migration_actions.rb\", \"test/internal/db/migrate/20260626000001_add_chrono_forge_parent_execution_log.rb\", \"test/schema_test.rb\", \"test/generators_test.rb\"], \"verifyCommand\": \"bundle exec ruby -I test test/schema_test.rb\", \"acceptanceCriteria\": [\"parent_execution_log_id column exists\", \"(parent_execution_log_id, state) index exists\", \"migration in MIGRATIONS + generators_test\"], \"requiresUserVerification\": false}\n```"
9
+ },
10
+ {
11
+ "id": 2,
12
+ "subject": "Task 2: Model associations",
13
+ "status": "completed",
14
+ "blockedBy": [1],
15
+ "description": "Workflow belongs_to :parent_execution_log (optional); ExecutionLog has_many :spawned_workflows (fk parent_execution_log_id, dependent: :nullify).\n\n```json:metadata\n{\"files\": [\"lib/chrono_forge/workflow.rb\", \"lib/chrono_forge/execution_log.rb\", \"test/branch_associations_test.rb\"], \"verifyCommand\": \"bundle exec ruby -I test test/branch_associations_test.rb\", \"acceptanceCriteria\": [\"parent_execution_log association\", \"spawned_workflows association\"], \"requiresUserVerification\": false}\n```"
16
+ },
17
+ {
18
+ "id": 3,
19
+ "subject": "Task 3: branch block + spawn (single)",
20
+ "status": "completed",
21
+ "blockedBy": [2],
22
+ "description": "branch(name, automerge:) durable step with in-memory @open_branches registry, eager dispatch, seal-on-close, SKIP-BLOCK-WHEN-SEALED. spawn(name, klass, **kwargs) single child. spawn outside branch raises NotInBranchError. Error classes + Methods include (create empty MergeBranches stub).\n\n```json:metadata\n{\"files\": [\"lib/chrono_forge/executor/methods/branch.rb\", \"lib/chrono_forge/executor.rb\", \"lib/chrono_forge/executor/methods.rb\", \"lib/chrono_forge/executor/methods/merge_branches.rb\", \"test/branch_test.rb\", \"test/internal/app/jobs/noop_child.rb\", \"test/internal/app/jobs/single_spawn_workflow.rb\"], \"verifyCommand\": \"bundle exec ruby -I test test/branch_test.rb\", \"acceptanceCriteria\": [\"spawn creates linked child + seals branch\", \"spawn outside branch raises\", \"sealed branch skips block on replay\"], \"requiresUserVerification\": false}\n```"
23
+ },
24
+ {
25
+ "id": 4,
26
+ "subject": "Task 4: spawn_each streaming dispatch",
27
+ "status": "completed",
28
+ "blockedBy": [3],
29
+ "description": "spawn_each(name, source, of:) — AR keyset (find_in_batches start:, error_on_ignore: true) or enumerable (offset/drop), one child per item keyed name_{index}, class from block, cursor {pk,n} on branch log metadata.\n\n```json:metadata\n{\"files\": [\"lib/chrono_forge/executor/methods/branch.rb\", \"test/spawn_each_test.rb\", \"test/internal/app/jobs/spawn_each_workflow.rb\"], \"verifyCommand\": \"bundle exec ruby -I test test/spawn_each_test.rb\", \"acceptanceCriteria\": [\"one indexed child per item\", \"class from block (mixed)\", \"raises on conflicting AR order\", \"cursor persisted\"], \"requiresUserVerification\": false}\n```"
30
+ },
31
+ {
32
+ "id": 5,
33
+ "subject": "Task 5: BranchMergeJob poller",
34
+ "status": "completed",
35
+ "blockedBy": [2],
36
+ "description": "ChronoForge::BranchMergeJob (plain ActiveJob): capped-count probe per branch (limit CAP), wake parent when all sealed + pending 0, else re-kick never-started children (started_at nil older than REKICK_AFTER) and reschedule clamp(pending*FACTOR, min, max).\n\n```json:metadata\n{\"files\": [\"lib/chrono_forge/branch_merge_job.rb\", \"test/branch_merge_job_test.rb\"], \"verifyCommand\": \"bundle exec ruby -I test test/branch_merge_job_test.rb\", \"acceptanceCriteria\": [\"wakes parent when complete\", \"reschedules when incomplete\", \"capped count\", \"re-kicks never-started child\"], \"requiresUserVerification\": false}\n```"
37
+ },
38
+ {
39
+ "id": 6,
40
+ "subject": "Task 6: merge_branches / merge_branch join",
41
+ "status": "completed",
42
+ "blockedBy": [3, 5],
43
+ "description": "merge_branches(*names, min_interval:, max_interval:) + alias merge_branch — immediate done-check, else enqueue BranchMergeJob + halt; remove joined names from @open_branches on completion; raise ArgumentError for unopened name. Shared helpers branches_done?/enqueue_branch_merge_job/open_branch!.\n\n```json:metadata\n{\"files\": [\"lib/chrono_forge/executor/methods/merge_branches.rb\", \"test/merge_branches_test.rb\", \"test/internal/app/jobs/two_branch_workflow.rb\", \"test/internal/app/jobs/stalled_child_branch_workflow.rb\"], \"verifyCommand\": \"bundle exec ruby -I test test/merge_branches_test.rb\", \"acceptanceCriteria\": [\"parent resumes after branches complete\", \"halts+enqueues poller while incomplete\", \"unopened name raises\", \"Option A: stalled child parks parent until recovered\"], \"requiresUserVerification\": false}\n```"
44
+ },
45
+ {
46
+ "id": 7,
47
+ "subject": "Task 7: Completion gate — automerge + raise on unmerged",
48
+ "status": "completed",
49
+ "blockedBy": [4, 6],
50
+ "description": "enforce_branch_joins! at start of complete_workflow!: raise UnmergedBranchError for leftover non-automerge branches; for leftover automerge branches not done, enqueue BranchMergeJob + halt; else seal. Early-return when @open_branches empty.\n\n```json:metadata\n{\"files\": [\"lib/chrono_forge/executor/methods/workflow_states.rb\", \"test/automerge_test.rb\", \"test/internal/app/jobs/unmerged_branch_workflow.rb\"], \"verifyCommand\": \"bundle exec ruby -I test test/automerge_test.rb\", \"acceptanceCriteria\": [\"automerge blocks completion until children done\", \"unmerged branch raises\", \"already-merged branch no-op at gate\", \"empty @open_branches early-returns\"], \"requiresUserVerification\": false}\n```"
51
+ },
52
+ {
53
+ "id": 8,
54
+ "subject": "Task 8: Crash-recovery + scale regression tests",
55
+ "status": "completed",
56
+ "blockedBy": [7],
57
+ "description": "Prove cursor-resume (glitch mid-dispatch -> resume from metadata.cursors, exactly N children, no dupes) and bulk dispatch (insert_all issues ceil(N/of) INSERTs, not N). Do NOT assert bulk enqueue (test adapter falls back to per-job).\n\n```json:metadata\n{\"files\": [\"test/branch_recovery_test.rb\", \"test/branch_scale_test.rb\"], \"verifyCommand\": \"bundle exec ruby -I test test/branch_scale_test.rb test/branch_recovery_test.rb\", \"acceptanceCriteria\": [\"cursor resume: exactly N children, no dupes\", \"dispatch uses ceil(N/of) bulk inserts\"], \"requiresUserVerification\": false}\n```"
58
+ },
59
+ {
60
+ "id": 9,
61
+ "subject": "Task 9: activejob >= 7.1 floor + README",
62
+ "status": "completed",
63
+ "description": "Pin activejob >= 7.1 (perform_all_later) in gemspec; document Branches in README with worked example + 3 caveats (every branch joined or UnmergedBranchError; parent not replayed per poll; source stable during dispatch).\n\n```json:metadata\n{\"files\": [\"chrono_forge.gemspec\", \"README.md\"], \"verifyCommand\": \"bundle exec rake test\", \"acceptanceCriteria\": [\"activejob >= 7.1 floor\", \"README branches section + caveats\"], \"requiresUserVerification\": false}\n```"
64
+ }
65
+ ],
66
+ "lastUpdated": "2026-06-26T00:00:00Z"
67
+ }