@@ -18,6 +18,7 @@ import {
1818 type PlannedAgentAction ,
1919} from "../../src/settings/agent-actions" ;
2020import { recordAuditEvent } from "../../src/db/repositories" ;
21+ import { upsertRepoFocusManifest } from "../../src/signals/focus-manifest-loader" ;
2122import type { GitHubPullRequestPayload } from "../../src/types" ;
2223import { createTestEnv } from "../helpers/d1" ;
2324
@@ -774,6 +775,91 @@ describe("runSelfTuneBreaker — reads recorded pr_outcome ground truth + engage
774775 expect ( await isCloseHoldOnly ( env , "owner/repo" ) ) . toBe ( false ) ; // close breaker auto-cleared
775776 } ) ;
776777
778+ describe ( "#6803: review.selftune: false opt-out is absolute for the breaker too, not just the routine tuning pass" , ( ) => {
779+ it ( "does NOT engage the merge or close breaker for an opted-out repo, even with data that would otherwise trip both" , async ( ) => {
780+ const env = createTestEnv ( ) ;
781+ await upsertRepoFocusManifest ( env , "owner/opted-out" , { review : { selftune : false } } ) ;
782+ // Same shape as the plain ENGAGES tests above -- would trip both breakers if this repo weren't opted out.
783+ for ( let i = 0 ; i < 4 ; i += 1 ) await seedDecisionAndOutcome ( env , "owner/opted-out" , i , "merge" , "merged" ) ;
784+ for ( let i = 4 ; i < 12 ; i += 1 ) await seedDecisionAndOutcome ( env , "owner/opted-out" , i , "merge" , "closed" ) ;
785+ for ( let i = 12 ; i < 16 ; i += 1 ) await seedDecisionAndOutcome ( env , "owner/opted-out" , i , "close" , "closed" ) ;
786+ for ( let i = 16 ; i < 24 ; i += 1 ) await seedDecisionAndOutcome ( env , "owner/opted-out" , i , "close" , "merged" ) ;
787+
788+ await runSelfTuneBreaker ( env ) ;
789+
790+ expect ( await isHoldOnly ( env , "owner/opted-out" ) ) . toBe ( false ) ;
791+ expect ( await isCloseHoldOnly ( env , "owner/opted-out" ) ) . toBe ( false ) ;
792+ } ) ;
793+
794+ it ( "does NOT auto-clear an already-engaged flag for an opted-out repo, even with fully recovered precision -- the opt-out is absolute, not one-directional" , async ( ) => {
795+ const env = createTestEnv ( ) ;
796+ const flags = createFlagStore ( env ) ;
797+ await flags . setFlag ( "holdonly:owner/opted-out" , true ) ;
798+ await flags . setFlag ( "closehold:owner/opted-out" , true ) ;
799+ await env . DB . prepare (
800+ "UPDATE system_flags SET updated_at = datetime('now', '-2 days') WHERE key IN ('holdonly:owner/opted-out', 'closehold:owner/opted-out')" ,
801+ ) . run ( ) ;
802+ await upsertRepoFocusManifest ( env , "owner/opted-out" , { review : { selftune : false } } ) ;
803+ // Fully recovered precision -- would auto-clear both breakers (per the AUTO-CLEARS test above) if this
804+ // repo weren't opted out.
805+ for ( let i = 0 ; i < 12 ; i += 1 ) await seedDecisionAndOutcome ( env , "owner/opted-out" , i , "merge" , "merged" ) ;
806+ for ( let i = 12 ; i < 24 ; i += 1 ) await seedDecisionAndOutcome ( env , "owner/opted-out" , i , "close" , "closed" ) ;
807+
808+ const log = vi . spyOn ( console , "log" ) . mockImplementation ( ( ) => { } ) ;
809+ await runSelfTuneBreaker ( env ) ;
810+ log . mockRestore ( ) ;
811+
812+ expect ( await isHoldOnly ( env , "owner/opted-out" ) ) . toBe ( true ) ;
813+ expect ( await isCloseHoldOnly ( env , "owner/opted-out" ) ) . toBe ( true ) ;
814+ } ) ;
815+
816+ it ( "also excludes an opted-out repo from the miner-scoped pass (#2352)" , async ( ) => {
817+ const env = createTestEnv ( ) ;
818+ await upsertRepoFocusManifest ( env , "owner/opted-out" , { review : { selftune : false } } ) ;
819+ // Miner-authored rows (miner_authored=1), same shape as the #2352 ENGAGES test: 33% precision, would
820+ // otherwise trip the holdonly:owner/opted-out:miner flag.
821+ for ( let i = 0 ; i < 4 ; i += 1 ) {
822+ await env . DB . prepare (
823+ "INSERT INTO review_audit (id, project, target_id, event_type, decision, source, head_sha, summary, miner_authored, created_at) VALUES (?, ?, ?, 'gate_decision', 'merge', 'gittensory-native', ?, NULL, 1, CURRENT_TIMESTAMP)" ,
824+ )
825+ . bind ( `gd:m:owner/opted-out#${ i } ` , "owner/opted-out" , `owner/opted-out#${ i } ` , `sha${ i } ` )
826+ . run ( ) ;
827+ await env . DB . prepare (
828+ "INSERT INTO review_audit (id, project, target_id, event_type, decision, source, head_sha, summary, created_at) VALUES (?, ?, ?, 'pr_outcome', 'merged', 'gittensory-native', NULL, NULL, CURRENT_TIMESTAMP)" ,
829+ )
830+ . bind ( `po:m:owner/opted-out#${ i } ` , "owner/opted-out" , `owner/opted-out#${ i } ` )
831+ . run ( ) ;
832+ }
833+ for ( let i = 4 ; i < 12 ; i += 1 ) {
834+ await env . DB . prepare (
835+ "INSERT INTO review_audit (id, project, target_id, event_type, decision, source, head_sha, summary, miner_authored, created_at) VALUES (?, ?, ?, 'gate_decision', 'merge', 'gittensory-native', ?, NULL, 1, CURRENT_TIMESTAMP)" ,
836+ )
837+ . bind ( `gd:m:owner/opted-out#${ i } ` , "owner/opted-out" , `owner/opted-out#${ i } ` , `sha${ i } ` )
838+ . run ( ) ;
839+ await env . DB . prepare (
840+ "INSERT INTO review_audit (id, project, target_id, event_type, decision, source, head_sha, summary, created_at) VALUES (?, ?, ?, 'pr_outcome', 'closed', 'gittensory-native', NULL, NULL, CURRENT_TIMESTAMP)" ,
841+ )
842+ . bind ( `po:m:owner/opted-out#${ i } ` , "owner/opted-out" , `owner/opted-out#${ i } ` )
843+ . run ( ) ;
844+ }
845+
846+ await runSelfTuneBreaker ( env ) ;
847+
848+ expect ( await isHoldOnly ( env , "owner/opted-out:miner" ) ) . toBe ( false ) ;
849+ } ) ;
850+
851+ it ( "does not opt out an unrelated repo (the exclusion is per-repo, not global)" , async ( ) => {
852+ const env = createTestEnv ( ) ;
853+ await upsertRepoFocusManifest ( env , "owner/opted-out" , { review : { selftune : false } } ) ;
854+ for ( let i = 0 ; i < 4 ; i += 1 ) await seedDecisionAndOutcome ( env , "owner/still-tuned" , i , "merge" , "merged" ) ;
855+ for ( let i = 4 ; i < 12 ; i += 1 ) await seedDecisionAndOutcome ( env , "owner/still-tuned" , i , "merge" , "closed" ) ;
856+
857+ await runSelfTuneBreaker ( env ) ;
858+
859+ expect ( await isHoldOnly ( env , "owner/still-tuned" ) ) . toBe ( true ) ;
860+ } ) ;
861+ } ) ;
862+
777863 it ( "never throws (fails safe) even when review_audit reads blow up" , async ( ) => {
778864 const env = createTestEnv ( ) ;
779865 const realPrepare = env . DB . prepare . bind ( env . DB ) ;
0 commit comments