Merge Orchestration · cron + tick: Ticker GenServer + scheduled workflow#497
Merged
Conversation
…enServer + workflow)
The scheduling wiring that lets the merge-orchestration loop run unattended.
Two mechanisms, both off/opt-in by default, both token-free (they compute and
write the decision manifest; the .git-private-farm actuator merges).
TICK (in-brain GenServer):
* Hypatia.MergeOrchestration.Ticker -- mirrors LearningScheduler: schedule a
tick, run one guarded Scheduler.cycle, reschedule. run_now/status for manual
+ introspection. A cycle failure is rescued and recorded -- a bad store or
transient error never crashes the tick or its supervisor.
* Wired into application.ex via merge_orchestration_children(), mirroring the
existing tui_children() idiom. DEFAULT OFF; enable with
config :hypatia, :merge_orchestration, enabled: true, interval_ms: 900_000.
Cadence + cycle_opts come from that config.
CRON (GitHub Actions):
* .github/workflows/merge-orchestrate.yml -- schedule (hourly) + workflow_dispatch,
SHA-pinned setup-beam/checkout/cache/upload (mirrors tests.yml), runs the
mix hypatia.merge_orchestrate task with --store from the MERGE_ORCH_STORE repo
var (default data/verisim), uploads the merge-decisions.jsonl artifact. No
github-context interpolation in run lines.
64 ExUnit (was 61): +3 Ticker -- do_cycle records stats on success; do_cycle
rescues a mid-cycle failure (encoder raises) without raising, runs stays 0; the
GenServer run_now -> status path. 0 failures, local elixir 1.14, mix-format-clean,
scanner-clean.
The system is now fully schedulable end to end. What remains is pure owner
config/ops: flip the config to run the tick, and/or set MERGE_ORCH_STORE and let
the cron run; plus the standing owner follow-ons.
🔍 Hypatia Security ScanFindings: 42 issues detected
View findings[
{
"reason": "Repository has 5 non-main remote branch(es). Policy: single main branch only.",
"type": "GS007",
"file": ".",
"action": "delete_remote_branches",
"rule_module": "git_state",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "src/ui/gossamer/README.adoc",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "scripts/ci-tools/Cargo.toml",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "scripts/bench-tools/Cargo.toml",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "ffi/zig/README.adoc",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "docs/reports/audit/audit-2026-04-15-post.md",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "docs/integration/github-registry.adoc",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "docs/integration/github-registry.adoc",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "docs/integration/a2ml-k9.md",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
},
{
"reason": "Code scanning (Hypatia): hypatia/structural_drift/SD022 -- Hypatia structural_drift: SD022 -- 11 day(s) old",
"type": "CSA001",
"file": "docs/architecture/system-integration.md",
"action": "review",
"rule_module": "code_scanning_alerts",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Schedule the loop — cron + tick
The whole pipeline runs from one
mix hypatia.merge_orchestrate; this adds the two ways to invoke it on a schedule, so the system can run unattended. Both are off / opt-in by default and token-free (they compute and write the decision manifest; the.git-private-farmactuator re-verifies and merges).Tick — in-brain GenServer
Hypatia.MergeOrchestration.TickermirrorsLearningSchedulerexactly: schedule a tick → run one guardedScheduler.cycle→ reschedule, withrun_now/statusfor manual trigger + introspection. A cycle failure is rescued and recorded — it never crashes the tick or its supervisor.Wired into
application.exvia a newmerge_orchestration_children/0that mirrors the existingtui_children/0idiom — default OFF, so the supervision tree is unchanged unless you opt in:Cadence +
cycle_optscome from that config.Cron — GitHub Actions
.github/workflows/merge-orchestrate.yml:schedule(hourly) +workflow_dispatch, SHA-pinnedsetup-beam/checkout/cache/upload-artifact(mirrorstests.yml), runsmix hypatia.merge_orchestrate --store "$MERGE_ORCH_STORE"(store from theMERGE_ORCH_STORErepo var, defaultdata/verisim), uploads themerge-decisions.jsonlartifact (if-no-files-found: ignore). No GitHub-context interpolation inrun:lines (workflow-security gate).Testing (actual, not looks-right)
64 ExUnit, 0 failures (was 61) under Elixir 1.14, mix-format-clean, scanner-clean:
The +3 Ticker tests:
do_cycleruns a cycle and records the stats (runs: 1,last_stats.armed: 1);do_cyclerescues a mid-cycle failure (the encoder raises) without raising —runsstays0, the error is recorded (proves the tick never crashes);run_now→statuspath shows one completed run.The Ticker logic is tested against the real
Scheduler→Loop→ gate path over a tmp store (dep-free codec).Scope / safety
lib/+ a supervision-tree edit + a workflow, your review.application.exchange is additive and default-off (mirrorstui_children); mix-format also normalized the children-list indentation (semantically identical — same children, same order).Where this leaves it
The system is now fully schedulable end to end. What remains is pure owner config/ops — no code:
config :hypatia, :merge_orchestration, enabled: trueto run the in-brain tick; and/or set theMERGE_ORCH_STORErepo var (pointed at a populated store) and let the cron run — extend it with a push-to-actuator step + token if you want it fully hands-off.standardsadoption; P3 handshake +mass_squashin the actuator; the.git-private-farmActions-billing fix.Generated by Claude Code