feat(miner-governor): kill-switch propagation into the manage/loop subsystem (#2339) - #5057
Conversation
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | e172927 | Commit Preview URL Branch Preview URL |
Jul 11 2026, 01:04 PM |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5057 +/- ##
==========================================
+ Coverage 94.14% 94.18% +0.04%
==========================================
Files 467 468 +1
Lines 39609 39619 +10
Branches 14446 14450 +4
==========================================
+ Hits 37289 37317 +28
+ Misses 1664 1646 -18
Partials 656 656
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-11 12:58:15 UTC
✅ Suggested Action - Approve/Merge
Review summary Nits — 6 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
d5fae4d to
5cac1ab
Compare
5cac1ab to
53b3f4f
Compare
…bmission-gate.ts) #2339's own deliverable: the manage-phase submission-gate function must check the kill-switch/dry-run state as its FIRST guard, before any other logic -- flipping the kill-switch must halt any pending submission-gate check immediately, the same way it already halts the Governor chokepoint (#2340). killSwitchScope is a new REQUIRED field on SubmissionGateCandidate (not optional-with-a-permissive-default) so a caller cannot forget to resolve and pass it. Reuses isMinerKillSwitchActive (kill-switch.ts, #2341) directly -- the single shared helper #2339 asks for, not a bespoke wrapper -- rather than duplicating the check; the sibling loop-reentry-policy.ts change (next commit) consults the identical function.
…oop-reentry-policy.ts) The sibling half of #2339's own deliverable: the manage-phase loop- reentry function must ALSO check the kill-switch/dry-run state as its FIRST guard, before any other logic. killSwitchScope is a new REQUIRED field on LoopReentryCandidate, checked via the identical isMinerKillSwitchActive helper submission-gate.ts's shouldSubmit now consults (the "single shared helper, not duplicated per call site" this issue asks for) -- not a bespoke wrapper. Threads killSwitchScope through packages/gittensory-miner/lib/loop- reentry.js's attemptLoopReentry (validated fail-closed alongside its existing repoFullName/outcome checks) and into the audit event payload for traceability.
…#2339, #2336) submission-gate.ts had zero root-vitest (Codecov-visible) coverage -- only an engine-level node:test file, which Codecov cannot see. #2339's new kill-switch check (2 lines) was the first change to this file Codecov could measure, and it correctly flagged 0% patch coverage as a result. Ports the existing, already-comprehensive engine-level test suite (18 scenarios: kill-switch x3, pass/pass, fail/pass, pass/fail, both-fail, null-verdict, null-slop, both-null, observe-mode x2, isSlopBandWithinThreshold x4, barrel check) into a new root vitest file importing directly from engine source, giving 100% statement/branch/function/line coverage on the whole file, not just the newly-changed lines. Also resolves the rebase onto current main: an add/add conflict on test/unit/miner-loop-reentry.test.ts (this branch's own commit history still referenced an orphaned, pre-fix copy of the now-merged #2338 commit) and the shared build-script line conflict (package.json), both cleanly reconciled with no functional change to either.
739b132 to
6b0a998
Compare
…ing loop's handoff signal (#2337) (#5054) * chore(orb): bump manifest target version to 0.4.1 (#5075) orb-v0.4.0 was cut stable earlier today (2026-07-11), but the manifest was never bumped afterward, so orb-beta-release's due-check correctly refused to cut another 0.4.0-suffixed beta -- blocking the automated beta channel for every feat/fix merged since, including #5071/#5072. * feat(miner-governor): propagate the kill-switch into shouldSubmit (submission-gate.ts) #2339's own deliverable: the manage-phase submission-gate function must check the kill-switch/dry-run state as its FIRST guard, before any other logic -- flipping the kill-switch must halt any pending submission-gate check immediately, the same way it already halts the Governor chokepoint (#2340). killSwitchScope is a new REQUIRED field on SubmissionGateCandidate (not optional-with-a-permissive-default) so a caller cannot forget to resolve and pass it. Reuses isMinerKillSwitchActive (kill-switch.ts, #2341) directly -- the single shared helper #2339 asks for, not a bespoke wrapper -- rather than duplicating the check; the sibling loop-reentry-policy.ts change (next commit) consults the identical function. * feat(miner-governor): propagate the kill-switch into shouldReenter (loop-reentry-policy.ts) The sibling half of #2339's own deliverable: the manage-phase loop- reentry function must ALSO check the kill-switch/dry-run state as its FIRST guard, before any other logic. killSwitchScope is a new REQUIRED field on LoopReentryCandidate, checked via the identical isMinerKillSwitchActive helper submission-gate.ts's shouldSubmit now consults (the "single shared helper, not duplicated per call site" this issue asks for) -- not a bespoke wrapper. Threads killSwitchScope through packages/gittensory-miner/lib/loop- reentry.js's attemptLoopReentry (validated fail-closed alongside its existing repoFullName/outcome checks) and into the audit event payload for traceability. * feat(miner-governor): wire the gated-submission trigger into the driving loop's handoff signal Adds evaluateHarnessSubmissionTrigger (packages/gittensory-engine/src/ miner/harness-submission-trigger.ts) + evaluateAndRecordHarnessSubmis sionTrigger (packages/gittensory-miner/lib/harness-submission- trigger.js): connects shouldSubmit (#2336) to the actual driving loop's own handoff signal -- iterate-loop.ts's (#2333) HandoffPacket, produced the moment a real run's self-review reaches a clean predicted-gate pass. Not wired into any scheduler as part of this change, per the issue's own "manual owner sign-off on the wiring before this ships to any default-on profile" deliverable. Adds the session-level circuit breaker this issue's own deliverable calls for, distinct from shouldSubmit's per-candidate signal checks: N consecutive allow:false decisions in one session pauses the run entirely pending human review (checked FIRST, before ever consulting shouldSubmit -- once tripped, only a human clearing the session's own tally can un-trip it, unlike a per-candidate block a later, different candidate can clear on its own merits). Session-scoped rather than per-repo, matching "pauses the run entirely" -- distinct from #2338's loop-reentry circuit breaker, which is deliberately per-repo. Every decision (allow or block) is appended to the local event ledger with full reasons, whether or not the circuit breaker was involved. This does NOT build or invoke buildOpenPrSpec (src/mcp/local-write- tools.ts) -- that lives in the private root src/ tree, unreachable from this portable package for the same cross-package-boundary reason self-review-adapter.ts's slop injection exists. A real call site (root-side integration, wired in a later issue) consults this function's allow:true before it builds that spec itself. On the referenced "harness driving loop": the issue cites both the old M4-era gittensory-mcp harness adapter (#781, a different package) and this session's own submission-gate.ts. Wired to iterate-loop.ts's HandoffPacket instead, since that's the actual, current, same-wave driving loop #2336 was built to compose with. Test-covered per the issue's own explicit deliverable: a full candidate -> gate-check -> submit (or correctly-blocked) cycle, plus the circuit breaker tripping and resetting, and fail-closed validation. * feat(miner-governor): thread killSwitchScope through the harness submission trigger #2339 makes SubmissionGateCandidate.killSwitchScope required on shouldSubmit -- this is the coupling fixup: evaluateHarnessSubmission Trigger (#2337) constructs a shouldSubmit candidate internally, so it now requires and forwards killSwitchScope from its own candidate rather than duplicating the kill-switch check itself (shouldSubmit's own guard covers it whenever the session circuit breaker hasn't already short-circuited first). Also closes a real, pre-existing codecov gap discovered while verifying this: submission-gate.ts had ZERO root-vitest scenarios for its null-predictedGateVerdict, null-slopAssessment, slop-exceeds- threshold, and observe-mode-would-have-blocked/would-have-allowed paths -- it's only reachable from the root vitest suite through this file's own integration test, and that test never exercised them. Added all five; submission-gate.ts now measures 100% branch coverage via the actual codecov-visible path, not just the engine's own node:test suite. * fix(miner-governor): add missing as-never casts for deliberately-invalid deps assertions Two "fails closed on malformed candidate" assertions in miner-harness-submission-trigger.test.ts passed a HarnessSubmissionCandidateInput missing slopThreshold/mode without the as-never cast the four other deliberately- invalid-shape assertions in the same test already use, so tsc rejected them once the type was fully threaded through. No behavior change -- the runtime fail-closed assertions themselves were always correct. Also carries forward the same stacked-branch rebase reconciliation as the two branches this one is built on (rerere replayed the loop-reentry.test.ts resolution automatically).
Summary
Closes #2339.
Stacked on #5051 (#2338, still open) -- this PR's diff is scoped to just the kill-switch propagation; #2338's own changes are reviewed separately in its own PR.
Propagates the existing self-host kill-switch/dry-run control into the two manage-phase decision functions the sibling maintainer issues built:
shouldSubmit(submission-gate.ts, #2336) andshouldReenter(loop-reentry-policy.ts, #2338). Both now check the kill-switch as their FIRST guard, before any other logic -- flipping the kill-switch halts any pending submission-gate check or loop-reentry immediately, the same way it already halts the Governor chokepoint (#2340).Deliverables, mapped:
isMinerKillSwitchActive(kill-switch.ts, maintainer: global + per-repo kill-switch #2341) directly -- the same function the Governor chokepoint (maintainer: wire the fail-closed Governor chokepoint before every write action #2340) already consults -- rather than inventing a bespoke wrapper.killSwitchScope: MinerKillSwitchScopeis a new REQUIRED field on bothSubmissionGateCandidateandLoopReentryCandidate(not optional-with-a-permissive-default), so a caller cannot forget to resolve and pass it.countConsecutiveDisengagements/countReentriesSince(loop-reentry.js) norcountConsecutiveGateBlocks(harness-submission-trigger.js) -- the read-side tally computations both wrappers use to build their audit payloads -- ever consult the kill-switch; they keep computing real tallies for accurate logging even when the kill-switch is active, and are called unconditionally regardless of kill-switch state (there's nothing to "exempt" a pure read from -- it was never gated in the first place). Documented in loop-reentry-policy.ts's own module comment.Coupling fixups applied to the two sibling open PRs, since both
shouldSubmitandshouldReentergained a new required field their existing callers construct internally:packages/gittensory-miner/lib/loop-reentry.js'sattemptLoopReentry(maintainer: closed-loop discovery re-entry trigger #2338) -- threadskillSwitchScopethrough, validated fail-closed alongside its existing checks, included in the audit payload. This PR is stacked directly on maintainer: closed-loop discovery re-entry trigger #2338's branch, so this fixup is bundled into the SAME commit chain (see the 2nd commit).packages/gittensory-engine/src/miner/harness-submission-trigger.ts'sevaluateHarnessSubmissionTrigger(maintainer: wire the submission-gate trigger into the harness driving loop #2337, PR feat(miner-governor): wire the gated-submission trigger into the driving loop's handoff signal (#2337) #5054) -- pushed as a separate commit directly to that PR's branch, since maintainer: kill-switch propagation into the manage/loop subsystem #2339 and maintainer: wire the submission-gate trigger into the harness driving loop #2337 are independent, parallel stacks off maintainer: closed-loop discovery re-entry trigger #2338. Also closed a real, pre-existing codecov gap discovered while verifying that fixup:submission-gate.tshad zero root-vitest scenarios for several of its own branches.Validation
Measured, not assumed -- across both the engine's own
node:testsuite and the actual codecov-visible root vitest path:submission-gate.js: 100.00% lines/branch/funcs.loop-reentry-policy.js: 100.00% lines/branch/funcs.packages/gittensory-miner'snode --checkbuild script passes cleanly.test/unit/miner-loop-reentry.test.ts(the actual codecov-visible path forloop-reentry.js/loop-reentry-policy.ts): 10/10 tests pass, both files 100% branch coverage.Test plan
shouldSubmitunconditionally, even with an otherwise-clean predicted-gate pass and slop-under-threshold.shouldReenterunconditionally, even with a per-repo circuit breaker tally that would otherwise still permit re-entry (99 consecutive disengagements, checked before the circuit breaker itself).scope: "none") never itself blocks -- the underlying signals are still evaluated normally.attemptLoopReentrywithout dequeuing or moving run-state, and the block is recorded to the audit ledger with the scope that caused it.