@@ -185,7 +185,7 @@ export class OrchestratorService {
185185 orderBy : { createdAt : 'desc' } ,
186186 select : { phase : true , createdAt : true } ,
187187 } ) ,
188- this . prisma . reviewPass . count ( { where : { jobId : job . id , cycle : job . reviewCycle } } ) ,
188+ this . prisma . reviewPass . count ( { where : { jobId : job . id , cycle : job . revisionCycle } } ) ,
189189 this . prisma . queueTask . findFirst ( {
190190 where : { jobId : job . id , status : { in : [ 'PENDING' , 'RUNNING' ] } } ,
191191 orderBy : { createdAt : 'desc' } ,
@@ -196,7 +196,7 @@ export class OrchestratorService {
196196 select : { prNumber : true } ,
197197 } ) ,
198198 this . prisma . reviewPass . findFirst ( {
199- where : { jobId : job . id , cycle : job . reviewCycle } ,
199+ where : { jobId : job . id , cycle : job . revisionCycle } ,
200200 orderBy : { passNumber : 'desc' } ,
201201 select : { issues : true , verifyOk : true , dimensions : true } ,
202202 } ) ,
@@ -274,9 +274,9 @@ export class OrchestratorService {
274274 return ;
275275 }
276276
277- // /hermes revise on a PR thread: store feedback and enqueue IMPLEMENT only when
278- // the job is parked (AWAITING_PR_APPROVAL). If an agent is already running the
279- // feedback is persisted and will be picked up on the next handleImplement call.
277+ // /hermes revise on a PR thread: store feedback and open a new revision round (REVISE)
278+ // only when the job is parked (AWAITING_PR_APPROVAL). If an agent is already running the
279+ // feedback is persisted and folds into the in-flight round on the next revise call.
280280 if ( command . kind === 'revise' && job . prNumber ) {
281281 const prefix = this . config . get ( 'COMMAND_PREFIX' ) ;
282282
@@ -297,12 +297,16 @@ export class OrchestratorService {
297297 await this . safeCommentReaction ( ref , evt . commentId , 'eyes' ) ;
298298
299299 if ( job . state === 'AWAITING_PR_APPROVAL' ) {
300- await this . jobs . transition ( job . id , 'IMPLEMENTING' , {
300+ // A settled PR + new feedback = a fresh revision round: bump the round (fresh verify/
301+ // review budget) and run REVISE, scoped to this feedback — not a full re-implement.
302+ await this . jobs . update ( job . id , { revisionCycle : { increment : 1 } } ) ;
303+
304+ await this . jobs . transition ( job . id , 'REVISING' , {
301305 reason : `revision requested by @${ evt . author } ` ,
302306 actor : 'HUMAN' ,
303307 } ) ;
304308
305- await this . queue . enqueue ( { jobId : job . id , kind : 'IMPLEMENT ' } ) ;
309+ await this . queue . enqueue ( { jobId : job . id , kind : 'REVISE ' } ) ;
306310
307311 await this . safeComment (
308312 ref ,
@@ -410,13 +414,16 @@ export class OrchestratorService {
410414 } ) ;
411415
412416 if ( job . state === 'AWAITING_PR_APPROVAL' ) {
413- // The PR was settled — start a fresh revision cycle to address the feedback.
414- await this . jobs . transition ( job . id , 'IMPLEMENTING' , {
417+ // The PR was settled — open a fresh revision round (fresh verify/review budget) and
418+ // run REVISE, scoped to this feedback, rather than re-running the full IMPLEMENT.
419+ await this . jobs . update ( job . id , { revisionCycle : { increment : 1 } } ) ;
420+
421+ await this . jobs . transition ( job . id , 'REVISING' , {
415422 reason : `changes requested by @${ evt . author } ` ,
416423 actor : 'HUMAN' ,
417424 } ) ;
418425
419- await this . queue . enqueue ( { jobId : job . id , kind : 'IMPLEMENT ' } ) ;
426+ await this . queue . enqueue ( { jobId : job . id , kind : 'REVISE ' } ) ;
420427
421428 await this . safeComment (
422429 ref ,
@@ -581,6 +588,9 @@ export class OrchestratorService {
581588 data : { status : 'APPROVED' } ,
582589 } ) ;
583590
591+ // Plan approval opens revision round 1 — the first (and only) IMPLEMENT pass.
592+ await this . jobs . update ( jobId , { revisionCycle : { increment : 1 } } ) ;
593+
584594 await this . jobs . transition ( jobId , 'IMPLEMENTING' , {
585595 reason : `plan approved by ${ by } ` ,
586596 actor : 'HUMAN' ,
@@ -700,12 +710,16 @@ export class OrchestratorService {
700710
701711 await this . prisma . pullRequestFeedback . create ( { data : { jobId, author : by , body } } ) ;
702712
703- await this . jobs . transition ( jobId , 'IMPLEMENTING' , {
713+ // Settled result + new feedback = a fresh revision round (fresh verify/review budget),
714+ // addressed via a scoped REVISE rather than a full re-implement.
715+ await this . jobs . update ( jobId , { revisionCycle : { increment : 1 } } ) ;
716+
717+ await this . jobs . transition ( jobId , 'REVISING' , {
704718 reason : `changes requested by ${ by } ` ,
705719 actor : 'HUMAN' ,
706720 } ) ;
707721
708- await this . queue . enqueue ( { jobId, kind : 'IMPLEMENT ' } ) ;
722+ await this . queue . enqueue ( { jobId, kind : 'REVISE ' } ) ;
709723
710724 return { ok : true } ;
711725 }
@@ -955,10 +969,22 @@ export class OrchestratorService {
955969
956970 // PR/result feedback applies once a PR exists (GitHub) or for any dashboard job, where
957971 // "request changes" stores feedback without a PR number. Older GitHub jobs with no PR
958- // yet have nothing to fold in.
972+ // yet have nothing to fold in. Only feedback submitted *after* the last implement run is
973+ // relevant — anything older was already incorporated by that pass; re-injecting it makes a
974+ // fresh cycle re-attack already-resolved rounds (and mislabel them as current corrections).
975+ // Mirrors the same guard in handleRevise.
959976 if ( job . prNumber || job . origin === 'DASHBOARD' ) {
977+ const lastImplementRun = await this . prisma . agentRun . findFirst ( {
978+ where : { jobId, phase : 'IMPLEMENT' } ,
979+ orderBy : { createdAt : 'desc' } ,
980+ select : { createdAt : true } ,
981+ } ) ;
982+
960983 const prRevisions = await this . prisma . pullRequestFeedback . findMany ( {
961- where : { jobId } ,
984+ where : {
985+ jobId,
986+ ...( lastImplementRun ? { createdAt : { gt : lastImplementRun . createdAt } } : { } ) ,
987+ } ,
962988 orderBy : { createdAt : 'asc' } ,
963989 } ) ;
964990
@@ -1015,7 +1041,10 @@ export class OrchestratorService {
10151041 } ) ;
10161042
10171043 await this . jobs . incrementAttempts ( jobId ) ;
1018- await this . jobs . update ( jobId , { reviewCycle : { increment : 1 } } ) ;
1044+ // NB: revisionCycle is NOT incremented here. The round advances only on a human-triggered
1045+ // work episode (plan approval → round 1; each settled-PR changes request → +1), set at that
1046+ // transition. Incrementing per IMPLEMENT pass is the old coupling that forced PR feedback to
1047+ // route through IMPLEMENT just to get a fresh verify/review budget.
10191048
10201049 await this . jobs . transition ( jobId , 'VERIFYING' , {
10211050 reason : 'implementation complete' ,
@@ -1181,7 +1210,7 @@ export class OrchestratorService {
11811210 branchName : this . branchFor ( job ) ,
11821211 } ) ;
11831212
1184- const cycle = job . reviewCycle ;
1213+ const cycle = job . revisionCycle ;
11851214 const verifyCommand = await this . verifyCommandFor ( job , ws . dir ) ;
11861215
11871216 // No automated checks in the repo (yet) — nothing to run, proceed to self-review.
@@ -1283,25 +1312,28 @@ export class OrchestratorService {
12831312
12841313 const plan = await this . approvedPlan ( jobId ) ;
12851314
1286- // PR feedback is only relevant if it was submitted after the last IMPLEMENT run;
1287- // anything older was already incorporated into the code by that IMPLEMENT pass.
1288- const lastImplementRun = await this . prisma . agentRun . findFirst ( {
1289- where : { jobId, phase : 'IMPLEMENT' } ,
1315+ // PR feedback is only relevant if it was submitted after the last WORK run (IMPLEMENT or
1316+ // REVISE); anything older was already incorporated by that pass. Anchoring on either phase
1317+ // (not just IMPLEMENT) keeps each round isolated now that feedback drives REVISE, not
1318+ // IMPLEMENT — otherwise the anchor would freeze at the round-1 build and re-inject every
1319+ // prior round's feedback.
1320+ const lastWorkRun = await this . prisma . agentRun . findFirst ( {
1321+ where : { jobId, phase : { in : [ 'IMPLEMENT' , 'REVISE' ] } } ,
12901322 orderBy : { createdAt : 'desc' } ,
12911323 select : { createdAt : true } ,
12921324 } ) ;
12931325
12941326 const [ reviewPasses , prFeedback ] = await Promise . all ( [
12951327 this . prisma . reviewPass . findMany ( {
1296- where : { jobId, cycle : job . reviewCycle } ,
1328+ where : { jobId, cycle : job . revisionCycle } ,
12971329 orderBy : { passNumber : 'desc' } ,
12981330 take : 2 ,
12991331 select : { issues : true } ,
13001332 } ) ,
13011333 this . prisma . pullRequestFeedback . findMany ( {
13021334 where : {
13031335 jobId,
1304- ...( lastImplementRun ? { createdAt : { gt : lastImplementRun . createdAt } } : { } ) ,
1336+ ...( lastWorkRun ? { createdAt : { gt : lastWorkRun . createdAt } } : { } ) ,
13051337 } ,
13061338 orderBy : { createdAt : 'asc' } ,
13071339 } ) ,
@@ -1329,7 +1361,7 @@ export class OrchestratorService {
13291361 // If the most recent verify in this cycle failed, the build/tests are the priority
13301362 // fix — surface their output to the revise agent.
13311363 const lastVerify = await this . prisma . verifyRun . findFirst ( {
1332- where : { jobId, cycle : job . reviewCycle } ,
1364+ where : { jobId, cycle : job . revisionCycle } ,
13331365 orderBy : { createdAt : 'desc' } ,
13341366 select : { ok : true , command : true , output : true } ,
13351367 } ) ;
@@ -1410,7 +1442,7 @@ export class OrchestratorService {
14101442 const base = ws . baseBranch ;
14111443 const plan = await this . approvedPlan ( jobId ) ;
14121444 const maxPasses = this . review . maxPasses ;
1413- const cycle = job . reviewCycle ;
1445+ const cycle = job . revisionCycle ;
14141446
14151447 // One ordered read of this cycle's passes backs three things: the pass number, the
14161448 // immediately-preceding pass's issues (so the reviewer can verify each was resolved), and the
@@ -1673,7 +1705,7 @@ export class OrchestratorService {
16731705 await this . jobs . update ( jobId , { headSha } ) ;
16741706
16751707 const lastReview = await this . prisma . reviewPass . findFirst ( {
1676- where : { jobId, cycle : job . reviewCycle } ,
1708+ where : { jobId, cycle : job . revisionCycle } ,
16771709 orderBy : { passNumber : 'desc' } ,
16781710 } ) ;
16791711
0 commit comments