@@ -115,20 +115,6 @@ function Send-MatrixText {
115115 return [string ]$response.event_id
116116}
117117
118- function Get-MatrixEvent {
119- param (
120- [Parameter (Mandatory )][string ]$RoomId ,
121- [Parameter (Mandatory )][string ]$EventId ,
122- [Parameter (Mandatory )][string ]$AuthToken
123- )
124-
125- $roomSegment = [uri ]::EscapeDataString($RoomId )
126- $eventSegment = [uri ]::EscapeDataString($EventId )
127- return Invoke-Matrix - Method Get `
128- - Path " /_matrix/client/v3/rooms/$roomSegment /event/$eventSegment " `
129- - AuthToken $AuthToken - Body $null
130- }
131-
132118function Test-ExactMarker {
133119 param (
134120 [Parameter (Mandatory )]$event ,
@@ -155,64 +141,66 @@ function Test-ExactMarker {
155141
156142function Find-StrictMarkers {
157143 param (
158- [Parameter (Mandatory )][string ] $RoomId ,
144+ [Parameter (Mandatory )][string []] $RoomIds ,
159145 [Parameter (Mandatory )][object []]$Requirements ,
160146 [Parameter (Mandatory )][string ]$AuthToken ,
161147 [Parameter (Mandatory )][long ]$StartedAtMilliseconds
162148 )
163149
164150 $found = @ {}
165- $roomSegment = [uri ]::EscapeDataString($RoomId )
166- $from = " "
167- for ($page = 0 ; $page -lt 20 ; $page ++ ) {
168- $path = " /_matrix/client/v3/rooms/$roomSegment /messages?dir=b&limit=100"
169- if (-not [string ]::IsNullOrWhiteSpace($from )) {
170- $path += " &from=$ ( [uri ]::EscapeDataString($from )) "
171- }
172- $feed = Invoke-Matrix - Method Get - Path $path `
173- - AuthToken $AuthToken - Body $null
174- $reachedStart = $false
175- foreach ($event in @ ($feed.chunk )) {
176- if (
177- $null -ne $event.origin_server_ts -and
178- $event.origin_server_ts -lt $StartedAtMilliseconds
179- ) {
180- $reachedStart = $true
151+ foreach ($roomId in $RoomIds ) {
152+ $roomSegment = [uri ]::EscapeDataString($roomId )
153+ $from = " "
154+ for ($page = 0 ; $page -lt 20 ; $page ++ ) {
155+ $path = " /_matrix/client/v3/rooms/$roomSegment /messages?dir=b&limit=100"
156+ if (-not [string ]::IsNullOrWhiteSpace($from )) {
157+ $path += " &from=$ ( [uri ]::EscapeDataString($from )) "
181158 }
182- foreach ($requirement in $Requirements ) {
159+ $feed = Invoke-Matrix - Method Get - Path $path `
160+ - AuthToken $AuthToken - Body $null
161+ $reachedStart = $false
162+ foreach ($event in @ ($feed.chunk )) {
183163 if (
184- -not $found.ContainsKey ($requirement.phase ) -and
185- (Test-ExactMarker - event $event `
186- - ExpectedSender $requirement.sender `
187- - Marker $requirement.marker `
188- - StartedAtMilliseconds $StartedAtMilliseconds )
164+ $null -ne $event.origin_server_ts -and
165+ $event.origin_server_ts -lt $StartedAtMilliseconds
189166 ) {
190- $found [$requirement.phase ] = [ordered ]@ {
191- phase = $requirement.phase
192- agentName = $requirement.agentName
193- matrixUserId = $event.sender
194- roomId = $RoomId
195- eventId = $event.event_id
196- originServerTimestamp = $event.origin_server_ts
197- bindingSha256 = $requirement.bindingSha256
167+ $reachedStart = $true
168+ }
169+ foreach ($requirement in $Requirements ) {
170+ if (
171+ -not $found.ContainsKey ($requirement.phase ) -and
172+ (Test-ExactMarker - event $event `
173+ - ExpectedSender $requirement.sender `
174+ - Marker $requirement.marker `
175+ - StartedAtMilliseconds $StartedAtMilliseconds )
176+ ) {
177+ $found [$requirement.phase ] = [ordered ]@ {
178+ phase = $requirement.phase
179+ agentName = $requirement.agentName
180+ matrixUserId = $event.sender
181+ roomId = $roomId
182+ eventId = $event.event_id
183+ originServerTimestamp = $event.origin_server_ts
184+ bindingSha256 = $requirement.bindingSha256
185+ }
198186 }
199187 }
200188 }
201- }
202- if ( $found .Count -eq $Requirements .Count -or $reachedStart ) {
203- break
204- }
205- $from = [string ]$feed .end
206- if ([ string ]::IsNullOrWhiteSpace( $from )) {
207- break
189+ if ( $reachedStart ) {
190+ break
191+ }
192+ $from = [ string ] $feed .end
193+ if ( [string ]::IsNullOrWhiteSpace( $from )) {
194+ break
195+ }
208196 }
209197 }
210198 return $found
211199}
212200
213201function Wait-StrictMarkers {
214202 param (
215- [Parameter (Mandatory )][string ] $RoomId ,
203+ [Parameter (Mandatory )][string []] $RoomIds ,
216204 [Parameter (Mandatory )][object []]$Requirements ,
217205 [Parameter (Mandatory )][string ]$AuthToken ,
218206 [Parameter (Mandatory )][long ]$StartedAtMilliseconds ,
@@ -221,7 +209,7 @@ function Wait-StrictMarkers {
221209
222210 $markers = @ {}
223211 while ([DateTimeOffset ]::UtcNow -lt $Deadline ) {
224- $markers = Find-StrictMarkers - RoomId $RoomId `
212+ $markers = Find-StrictMarkers - RoomIds $RoomIds `
225213 - Requirements $Requirements - AuthToken $AuthToken `
226214 - StartedAtMilliseconds $StartedAtMilliseconds
227215 if ($markers.Count -eq $Requirements.Count ) {
312300}
313301$matrixDomain = $manager.matrixUserID.Split (" :" , 2 )[1 ]
314302$adminMatrixUserId = " @$adminUser `:$matrixDomain "
315- if ($adminMatrixUserId -ne $manager.matrixUserID ) {
316- throw " Matrix admin identity does not match the AgentTeams Manager."
317- }
318303$login = Invoke-Matrix - Method Post - Path " /_matrix/client/v3/login" - Body @ {
319304 type = " m.login.password"
320305 identifier = @ { type = " m.id.user" ; user = $adminMatrixUserId }
@@ -324,6 +309,16 @@ $authToken = [string]$login.access_token
324309if ([string ]::IsNullOrWhiteSpace($authToken )) {
325310 throw " Matrix login did not return an access credential."
326311}
312+ $joinedRooms = Invoke-Matrix - Method Get `
313+ - Path " /_matrix/client/v3/joined_rooms" - AuthToken $authToken - Body $null
314+ $joinedRoomIds = @ ($joinedRooms.joined_rooms )
315+ if (
316+ $joinedRoomIds -notcontains $manager.roomID -or
317+ $joinedRoomIds -notcontains $team.teamRoomID
318+ ) {
319+ throw " Matrix admin cannot observe the Manager and Team rooms."
320+ }
321+ $roomIds = @ ($manager.roomID , $team.teamRoomID )
327322
328323$startedAt = [DateTimeOffset ]::UtcNow
329324$deadline = $startedAt.AddSeconds ($TimeoutSeconds )
@@ -332,61 +327,38 @@ $rollbackMarker = "[$TaskId] ROLLBACK_REQUESTED $bindingSha256"
332327$executedMarker = " [$TaskId ] ROLLBACK_EXECUTED $bindingSha256 "
333328$verifiedMarker = " [$TaskId ] ROLLBACK_VERIFIED $bindingSha256 "
334329$prompt = @"
335- $ ( $investigator .matrixUserID ) [$TaskId ] Coordinate a real AgentTeams rollback trace for the supplied L1 candidate. The independent AgentLoom host will execute the candidate and rollback after collecting your role-owned events.
330+ $ ( $manager .matrixUserID ) [$TaskId ] Run a strict AgentTeams rollback workflow through team $TeamName . Delegate coordination to $ ( $investigator .matrixUserID ) . The independent AgentLoom host will execute the candidate and rollback after collecting the role-owned events.
336331
337332Candidate SHA-256: $failedPatchSha256
338333Candidate diff:
339334$failedPatch
340335
341336Required interaction:
342- 1. Ask $ ( $verifier.matrixUserID ) to review the candidate against exact-boundary pagination behavior. The Verifier must post the exact standalone line $failureMarker from its own identity when it rejects the candidate.
343- 2. Stop and wait for the Manager's exact standalone $rollbackMarker event .
344- 3. After that Manager event, directly mention $ ( $implementer.matrixUserID ) . The Implementer acknowledges restoring the approved snapshot by posting the exact standalone line $executedMarker from its own identity.
345- 4. Only after the Implementer event, directly mention $ ( $verifier.matrixUserID ) again. The Verifier posts the exact standalone line $verifiedMarker from its own identity.
337+ 1. Investigator asks $ ( $verifier.matrixUserID ) to review the candidate against exact-boundary pagination behavior. The Verifier posts the exact standalone line $failureMarker from its own identity when it rejects the candidate, then Investigator reports that failure to Manager .
338+ 2. Only after receiving the failure report, Manager posts the exact standalone line $rollbackMarker from its own identity and directs Investigator to continue .
339+ 3. Investigator directly mentions $ ( $implementer.matrixUserID ) . The Implementer acknowledges restoring the approved snapshot by posting the exact standalone line $executedMarker from its own identity.
340+ 4. Only after the Implementer event, Investigator directly mentions $ ( $verifier.matrixUserID ) again. The Verifier posts the exact standalone line $verifiedMarker from its own identity.
346341
347- Do not claim Human approval: this is an isolated L1 snapshot restore. Do not create another task ID. Do not include any credential in messages.
342+ Never fabricate another identity's marker. Do not claim Human approval: this is an isolated L1 snapshot restore. Do not create another task ID. Do not include any credential in messages.
348343"@ .Trim()
349- $null = Send-MatrixText - RoomId $team .teamRoomID - Text $prompt `
350- - MentionUserId $investigator .matrixUserID - AuthToken $authToken
344+ $null = Send-MatrixText - RoomId $manager .roomID - Text $prompt `
345+ - MentionUserId $manager .matrixUserID - AuthToken $authToken
351346
352- $failureRequirements = @ (
347+ $requirements = @ (
353348 [ordered ]@ {
354349 phase = " VERIFICATION_FAILED"
355350 agentName = " agentloom-verifier"
356351 sender = $verifier.matrixUserID
357352 marker = $failureMarker
358353 bindingSha256 = $bindingSha256
359- }
360- )
361- $failureEvents = Wait-StrictMarkers - RoomId $team.teamRoomID `
362- - Requirements $failureRequirements - AuthToken $authToken `
363- - StartedAtMilliseconds $startedAt.ToUnixTimeMilliseconds () - Deadline $deadline
364- $failureEvent = $failureEvents.VERIFICATION_FAILED
365-
366- $managerEventId = Send-MatrixText - RoomId $team.teamRoomID `
367- - Text " $rollbackMarker `n Restore the approved snapshot and retain the failed candidate evidence." `
368- - MentionUserId $investigator.matrixUserID - AuthToken $authToken
369- $managerEvent = Get-MatrixEvent - RoomId $team.teamRoomID `
370- - EventId $managerEventId - AuthToken $authToken
371- if (
372- -not (Test-ExactMarker - event $managerEvent `
373- - ExpectedSender $manager.matrixUserID - Marker $rollbackMarker `
374- - StartedAtMilliseconds $failureEvent.originServerTimestamp ) -or
375- $managerEvent.origin_server_ts -le $failureEvent.originServerTimestamp
376- ) {
377- throw " Manager rollback request event is not ordered after the failure."
378- }
379- $managerEvidence = [ordered ]@ {
380- phase = " ROLLBACK_REQUESTED"
381- agentName = " agentloom-manager"
382- matrixUserId = $managerEvent.sender
383- roomId = $team.teamRoomID
384- eventId = $managerEvent.event_id
385- originServerTimestamp = $managerEvent.origin_server_ts
386- bindingSha256 = $bindingSha256
387- }
388-
389- $finalRequirements = @ (
354+ },
355+ [ordered ]@ {
356+ phase = " ROLLBACK_REQUESTED"
357+ agentName = " agentloom-manager"
358+ sender = $manager.matrixUserID
359+ marker = $rollbackMarker
360+ bindingSha256 = $bindingSha256
361+ },
390362 [ordered ]@ {
391363 phase = " ROLLBACK_EXECUTED"
392364 agentName = " agentloom-implementer"
@@ -402,23 +374,25 @@ $finalRequirements = @(
402374 bindingSha256 = $bindingSha256
403375 }
404376)
405- $finalEvents = Wait-StrictMarkers - RoomId $team .teamRoomID `
406- - Requirements $finalRequirements - AuthToken $authToken `
407- - StartedAtMilliseconds $managerEvent .origin_server_ts - Deadline $deadline
377+ $events = Wait-StrictMarkers - RoomIds $roomIds `
378+ - Requirements $requirements - AuthToken $authToken `
379+ - StartedAtMilliseconds $startedAt .ToUnixTimeMilliseconds () - Deadline $deadline
408380if (
409- $finalEvents.ROLLBACK_EXECUTED.originServerTimestamp -le
410- $managerEvent.origin_server_ts -or
411- $finalEvents.ROLLBACK_VERIFIED.originServerTimestamp -le
412- $finalEvents.ROLLBACK_EXECUTED.originServerTimestamp
381+ $events.ROLLBACK_REQUESTED.originServerTimestamp -le
382+ $events.VERIFICATION_FAILED.originServerTimestamp -or
383+ $events.ROLLBACK_EXECUTED.originServerTimestamp -le
384+ $events.ROLLBACK_REQUESTED.originServerTimestamp -or
385+ $events.ROLLBACK_VERIFIED.originServerTimestamp -le
386+ $events.ROLLBACK_EXECUTED.originServerTimestamp
413387) {
414388 throw " Rollback role events are not strictly chronological."
415389}
416390
417391$roleEvents = @ (
418- $failureEvent ,
419- $managerEvidence ,
420- $finalEvents .ROLLBACK_EXECUTED ,
421- $finalEvents .ROLLBACK_VERIFIED
392+ $events .VERIFICATION_FAILED ,
393+ $events .ROLLBACK_REQUESTED ,
394+ $events .ROLLBACK_EXECUTED ,
395+ $events .ROLLBACK_VERIFIED
422396)
423397$submission = [ordered ]@ {
424398 schemaVersion = " agentloom.live-rollback-submission/v1alpha1"
0 commit comments