Commit graph hyperhive/nix
Author SHA1 Message Date
atlas
d5d77e34b7 devshell: carry vale, so the CI prose lint is a local gate too
nix/devshell.nix didn't carry vale, so
 docs/README.md
 16:51  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson
 53:49  warning  'Multiple' is too wordy.                   write-good.TooWordy
 60:33  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson
 62:14  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson
 74:12  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson
 88:12  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson

 docs/agent-lifecycle/agent-hierarchy.md
 5:59    warning  'are meant' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive
 6:24    warning  'is finished' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 7:1     warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 23:36   warning  Consider 'stops responding' instead of 'hangs'.                                                                                                 Microsoft.BiasFree
 23:59   warning  'is built' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 35:53   warning  'is required' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 68:15   warning  'are approved' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 104:12  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 107:47  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 126:3   warning  'equivalent' is too wordy.                                                                                                                      write-good.TooWordy
 135:15  warning  'be gated' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 144:26  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 153:31  warning  'is planned' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 157:32  warning  'is handled' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 217:58  warning  'be owned' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive

 docs/getting-started/setup.md
 15:17   warning  'is generated' may be passive voice. Use active voice if you can.                                                                                                                     write-good.Passive
 51:38   warning  Consider using 'the app froze', 'the app stopped responding', 'the app stopped responding to events', or 'the app became unresponsive' instead of 'hang' (which may be insensitive).  alex.Suicide
 127:25  warning  'usually' is a weasel word!                                                                                                                                                           write-good.Weasel
 134:7   warning  'whether or not' is too wordy.                                                                                                                                                        write-good.TooWordy
 148:20  warning  'it was' is too wordy.                                                                                                                                                                write-good.TooWordy
 148:23  warning  'was minted' may be passive voice. Use active voice if you can.                                                                                                                       write-good.Passive
 160:23  warning  'is needed' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 163:40  warning  'is bound' may be passive voice. Use active voice if you can.                                                                                                                         write-good.Passive
 165:51  warning  'is needed' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 177:19  warning  'is issued' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 183:36  warning  'is tracked' may be passive voice. Use active voice if you can.                                                                                                                       write-good.Passive
 200:31  warning  'are gated' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 291:26  warning  'is stored' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 297:22  warning  'is authenticated' may be passive voice. Use active voice if you can.                                                                                                                 write-good.Passive

 docs/integrations/github.md
 16:79  warning  'is needed' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/integrations/knowledge.md
 17:58  warning  'is read' may be passive voice. Use active voice if you can.     write-good.Passive
 56:61  warning  'is needed' may be passive voice. Use active voice if you can.   write-good.Passive
 94:3   warning  'is stopped' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/integrations/forge.md
 35:24   warning  'sufficient' is too wordy.                                                                                                                                     write-good.TooWordy
 109:54  warning  'are shared' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 160:19  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 171:1   warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'Disabled'.  alex.Ablist
 331:1   warning  'subsequent' is too wordy.                                                                                                                                     write-good.TooWordy

 docs/integrations/matrix.md
 34:47   warning  'be changed' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 76:16   warning  'are minted' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 172:67  warning  'is restricted' may be passive voice. Use active voice if you can.                                                                                            write-good.Passive
 200:61  warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 202:22  warning  'is trusted' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 207:61  warning  'maximum' is too wordy.                                                                                                                                       write-good.TooWordy
 221:17  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'invalid'.  alex.Ablist
 226:28  warning  'is required' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 231:26  warning  'is required' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 233:27  warning  'is required' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive

 docs/agent-lifecycle/persistence.md
 7:27    warning  Use first person (such as 'I') sparingly.                                                                                                       Microsoft.FirstPerson
 16:46   warning  'all of' is too wordy.                                                                                                                          write-good.TooWordy
 23:15   warning  'are kept' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 26:62   warning  'however' is too wordy.                                                                                                                         write-good.TooWordy
 32:33   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 92:13   warning  'are kept' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 127:17  warning  'was meant' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive
 177:23  warning  'subsequent' is too wordy.                                                                                                                      write-good.TooWordy
 185:6   warning  'modify' is too wordy.                                                                                                                          write-good.TooWordy
 249:38  warning  'is wedged' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive
 249:65  warning  'is stopped' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 278:5   warning  'is set' may be passive voice. Use active voice if you can.                                                                                     write-good.Passive
 349:12  warning  'is read' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 356:11  warning  'be confused' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 359:55  warning  'are unrelated' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 413:43  warning  'been removed' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 415:59  warning  'be deleted' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 442:9   warning  'is automigrated' may be passive voice. Use active voice if you can.                                                                            write-good.Passive
 454:58  warning  'be removed' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 480:37  warning  'subsequent' is too wordy.                                                                                                                      write-good.TooWordy
 487:19  warning  'is unaffected' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 494:18  warning  'be started' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 582:51  warning  'is set' may be passive voice. Use active voice if you can.                                                                                     write-good.Passive
 591:28  warning  'is needed' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive

 docs/agent-lifecycle/approvals.md
 34:36   warning  'all of' is too wordy.                                                                                                                          write-good.TooWordy
 141:43  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 150:42  warning  'is overloaded' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 174:44  warning  'Subsequent' is too wordy.                                                                                                                      write-good.TooWordy
 190:27  warning  'is set' may be passive voice. Use active voice if you can.                                                                                     write-good.Passive
 295:23  warning  'however' is too wordy.                                                                                                                         write-good.TooWordy
 500:47  warning  'additional' is too wordy.                                                                                                                      write-good.TooWordy
 579:9   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 615:55  warning  'previously' is too wordy.                                                                                                                      write-good.TooWordy
 618:18  warning  'was cleared' may be passive voice. Use active voice if you can.                                                                                write-good.Passive

 docs/networking/network.md
 4:20    warning  'is enabled' may be passive voice. Use active voice if you can.    write-good.Passive
 10:52   warning  'were removed' may be passive voice. Use active voice if you can.  write-good.Passive
 18:61   warning  'is untouched' may be passive voice. Use active voice if you can.  write-good.Passive
 84:33   warning  'monitor' is too wordy.                                            write-good.TooWordy
 197:50  warning  'is unchanged' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/process/pr-review-gate.md
 44:1   warning  Use first person (such as 'I') sparingly.                          Microsoft.FirstPerson
 45:36  warning  'are expected' may be passive voice. Use active voice if you can.  write-good.Passive
 50:13  warning  'be armed' may be passive voice. Use active voice if you can.      write-good.Passive

 docs/networking/snapshot-store.md
 126:49  warning  'being enabled' may be passive voice. Use active voice if you can.  write-good.Passive
 127:9   warning  'being set' may be passive voice. Use active voice if you can.      write-good.Passive
 131:15  warning  'sufficient' is too wordy.                                          write-good.TooWordy
 164:43  warning  'is discovered' may be passive voice. Use active voice if you can.  write-good.Passive
 178:5   warning  Reconsider using 'trap', it may be profane.                         alex.ProfanityMaybe
 178:67  warning  'being called' may be passive voice. Use active voice if you can.   write-good.Passive
 194:53  warning  'is wanted' may be passive voice. Use active voice if you can.      write-good.Passive
 200:1   warning  'therefore' is too wordy.                                           write-good.TooWordy
 201:5   warning  'is tracked' may be passive voice. Use active voice if you can.     write-good.Passive
 207:1   warning  'is bounded' may be passive voice. Use active voice if you can.     write-good.Passive

 docs/scheduler/ci.md
 34:1     warning  'Several' is a weasel word!                                        write-good.Weasel
 37:7     warning  'are required' may be passive voice. Use active voice if you can.  write-good.Passive
 69:27    warning  'is stuck' may be passive voice. Use active voice if you can.      write-good.Passive
 131:98   warning  'validate' is too wordy.                                           write-good.TooWordy
 146:33   warning  'is set' may be passive voice. Use active voice if you can.        write-good.Passive
 186:55   warning  'therefore' is too wordy.                                          write-good.TooWordy
 188:422  warning  'is dropped' may be passive voice. Use active voice if you can.    write-good.Passive
 193:60   warning  Reconsider using 'attack', it may be profane.                      alex.ProfanityMaybe
 193:87   warning  'eliminate' is too wordy.                                          write-good.TooWordy
 249:58   warning  'however' is too wordy.                                            write-good.TooWordy

 docs/networking/gateway.md
 22:92    warning  'is misconfigured' may be passive voice. Use active voice if you can.                                                                                          write-good.Passive
 37:518   warning  'is closed' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive
 105:40   warning  When referring to a person, consider using 'careless', 'heartless', 'indifferent', or 'insensitive' instead of 'blind to'.                                     alex.Ablist
 140:44   warning  'is unchanged' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 142:4    warning  'subsequent' is too wordy.                                                                                                                                     write-good.TooWordy
 154:38   warning  'was removed' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 169:14   warning  'is configured' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 170:48   warning  'is set' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 177:15   warning  'is covered' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 182:9    warning  Try to avoid using first-person plural like 'Let's'.                                                                                                           Microsoft.We
 190:12   warning  Try to avoid using first-person plural like 'Let's'.                                                                                                           Microsoft.We
 206:122  warning  Try to avoid using first-person plural like 'Let's'.                                                                                                           Microsoft.We
 212:153  warning  'is named' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 224:185  warning  'be wired' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 226:235  warning  'terminate' is too wordy.                                                                                                                                      write-good.TooWordy
 230:150  warning  'validate' is too wordy.                                                                                                                                       write-good.TooWordy
 230:261  warning  'be added' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 232:165  warning  'is undisturbed' may be passive voice. Use active voice if you can.                                                                                            write-good.Passive
 234:199  warning  'is wired' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 238:36   warning  Try to avoid using first-person plural like 'Let's'.                                                                                                           Microsoft.We
 276:68   warning  'was removed' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 292:49   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.                 alex.Ablist
 299:41   warning  'is privileged' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 300:30   warning  'be exposed' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 307:19   warning  'was removed' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 311:40   warning  'is required' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 358:25   warning  'is left' may be passive voice. Use active voice if you can.                                                                                                   write-good.Passive
 361:11   warning  'are opened' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 363:52   warning  'is needed' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive
 393:40   warning  'requirement' is too wordy.                                                                                                                                    write-good.TooWordy
 501:13   warning  'is broken' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive
 513:68   warning  'is required' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 528:1    warning  'is required' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 532:26   warning  'is exposed' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 550:19   warning  'is required' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 586:18   warning  'therefore' is too wordy.                                                                                                                                      write-good.TooWordy
 592:24   warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 620:7    warning  'is encrypted' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive

 docs/scheduler/jobq.md
 44:24  warning  'is done' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/process/conventions.md
 81:55   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 139:40  warning  'be handled' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 140:8   warning  'is set' may be passive voice. Use active voice if you can.                                                                                     write-good.Passive
 189:31  warning  'are scoped' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 248:13  warning  'be shown' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 274:24  warning  'are kept' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 326:17  warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 327:41  warning  'are pushed' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 394:55  warning  'Implement' is too wordy.                                                                                                                       write-good.TooWordy
 432:1   warning  'sufficient' is too wordy.                                                                                                                      write-good.TooWordy
 434:12  warning  'are factored' may be passive voice. Use active voice if you can.                                                                               write-good.Passive

 docs/process/gotchas.md
 18:46   warning  'are ignored' may be passive voice. Use active voice if you can.    write-good.Passive
 76:27   warning  'be started' may be passive voice. Use active voice if you can.     write-good.Passive
 93:3    warning  'enumerate' is too wordy.                                           write-good.TooWordy
 98:13   warning  'it was' is too wordy.                                              write-good.TooWordy
 98:16   warning  'was written' may be passive voice. Use active voice if you can.    write-good.Passive
 117:37  warning  'is needed' may be passive voice. Use active voice if you can.      write-good.Passive
 141:17  warning  Reconsider using 'trap', it may be profane.                         alex.ProfanityMaybe
 148:26  warning  'be wrapped' may be passive voice. Use active voice if you can.     write-good.Passive
 150:9   warning  'is expected' may be passive voice. Use active voice if you can.    write-good.Passive
 160:25  warning  'be reclaimed' may be passive voice. Use active voice if you can.   write-good.Passive
 161:28  warning  'are gone' may be passive voice. Use active voice if you can.       write-good.Passive
 180:36  warning  Use first person (such as 'my') sparingly.                          Microsoft.FirstPerson
 256:18  warning  'subsequent' is too wordy.                                          write-good.TooWordy
 324:46  warning  'are unused' may be passive voice. Use active voice if you can.     write-good.Passive
 355:59  warning  'was checked' may be passive voice. Use active voice if you can.    write-good.Passive
 425:29  warning  'is configured' may be passive voice. Use active voice if you can.  write-good.Passive
 438:27  warning  Use 'select' instead of the input-specific verb 'click'.            Microsoft.UIVerbs
 484:23  warning  'is rooted' may be passive voice. Use active voice if you can.      write-good.Passive

 docs/swarm/ca.md
 55:59   warning  'is expected' may be passive voice. Use active voice if you can.       write-good.Passive
 56:9    warning  'be ignored' may be passive voice. Use active voice if you can.        write-good.Passive
 65:60   warning  'are distributed' may be passive voice. Use active voice if you can.   write-good.Passive
 74:10   warning  'is issued' may be passive voice. Use active voice if you can.         write-good.Passive
 100:1   warning  'terminate' is too wordy.                                              write-good.TooWordy
 110:26  warning  'is allowed' may be passive voice. Use active voice if you can.        write-good.Passive
 145:31  warning  'is misconfigured' may be passive voice. Use active voice if you can.  write-good.Passive
 164:31  warning  'is assembled' may be passive voice. Use active voice if you can.      write-good.Passive

 docs/scheduler/coordinator.md
 19:15   warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.                                                             alex.Race
 20:61   warning  'multiple' is too wordy.                                                                                                                        write-good.TooWordy
 21:1    warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'Special'.  alex.Ablist
 22:43   warning  'is expressed' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 23:21   warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.                                                             alex.Race
 38:13   warning  'be written' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 81:268  warning  'multiple' is too wordy.                                                                                                                        write-good.TooWordy
 81:354  warning  'is typed' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 93:68   warning  'finalize' is too wordy.                                                                                                                        write-good.TooWordy
 102:17  warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 112:25  warning  'finalize' is too wordy.                                                                                                                        write-good.TooWordy
 209:51  warning  'is satisfied' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 220:31  warning  'multiple' is too wordy.                                                                                                                        write-good.TooWordy
 235:40  warning  'requirement' is too wordy.                                                                                                                     write-good.TooWordy
 241:1   warning  'exclusively' is too wordy.                                                                                                                     write-good.TooWordy
 244:5   warning  'requirement' is too wordy.                                                                                                                     write-good.TooWordy
 248:34  warning  'requirement' is too wordy.                                                                                                                     write-good.TooWordy
 256:51  warning  'acquire' is too wordy.                                                                                                                         write-good.TooWordy
 259:19  warning  'is unaffected' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 280:39  warning  'is tracked' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 343:24  warning  'be kept' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 399:67  warning  'finalize' is too wordy.                                                                                                                        write-good.TooWordy
 419:25  warning  'minimum' is too wordy.                                                                                                                         write-good.TooWordy
 424:71  warning  'subsequent' is too wordy.                                                                                                                      write-good.TooWordy
 476:21  warning  'is left' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 500:66  warning  'multiple' is too wordy.                                                                                                                        write-good.TooWordy
 558:40  warning  'is left' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 561:3   warning  'additional' is too wordy.                                                                                                                      write-good.TooWordy

 docs/swarm/secrets.md
 3:23    warning  'are generated' may be passive voice. Use active voice if you can.  write-good.Passive
 7:23    warning  'all of' is too wordy.                                              write-good.TooWordy
 17:37   warning  'is published' may be passive voice. Use active voice if you can.   write-good.Passive
 32:42   warning  'is responsible for' is too wordy.                                  write-good.TooWordy
 38:106  warning  'is generated' may be passive voice. Use active voice if you can.   write-good.Passive
 46:110  warning  'is set' may be passive voice. Use active voice if you can.         write-good.Passive
 57:139  warning  'is set' may be passive voice. Use active voice if you can.         write-good.Passive
 70:78   warning  'is made' may be passive voice. Use active voice if you can.        write-good.Passive
 80:10   warning  'is made' may be passive voice. Use active voice if you can.        write-good.Passive
 80:36   warning  'is enabled' may be passive voice. Use active voice if you can.     write-good.Passive
 81:47   warning  'is registered' may be passive voice. Use active voice if you can.  write-good.Passive
 88:67   warning  'is fed' may be passive voice. Use active voice if you can.         write-good.Passive
 120:39  warning  'are required' may be passive voice. Use active voice if you can.   write-good.Passive
 167:44  warning  'is wanted' may be passive voice. Use active voice if you can.      write-good.Passive
 187:36  warning  'be fetched' may be passive voice. Use active voice if you can.     write-good.Passive
 207:34  warning  'therefore' is too wordy.                                           write-good.TooWordy
 212:24  warning  'is built' may be passive voice. Use active voice if you can.       write-good.Passive

 docs/swarm/README.md
 6:5     warning  'additional' is too wordy.                                          write-good.TooWordy
 6:51    warning  'multiple' is too wordy.                                            write-good.TooWordy
 21:24   warning  'be qualified' may be passive voice. Use active voice if you can.   write-good.Passive
 43:67   warning  'is enabled' may be passive voice. Use active voice if you can.     write-good.Passive
 50:10   warning  'is required' may be passive voice. Use active voice if you can.    write-good.Passive
 130:62  warning  Use first person (such as 'my') sparingly.                          Microsoft.FirstPerson
 131:1   warning  'is derived' may be passive voice. Use active voice if you can.     write-good.Passive
 158:34  warning  'was removed' may be passive voice. Use active voice if you can.    write-good.Passive
 168:10  warning  'be listed' may be passive voice. Use active voice if you can.      write-good.Passive
 171:52  warning  'is tracked' may be passive voice. Use active voice if you can.     write-good.Passive
 274:1   warning  'is required' may be passive voice. Use active voice if you can.    write-good.Passive
 278:48  warning  'is documented' may be passive voice. Use active voice if you can.  write-good.Passive
 293:66  warning  'is installed' may be passive voice. Use active voice if you can.   write-good.Passive
 377:41  warning  'is opened' may be passive voice. Use active voice if you can.      write-good.Passive
 388:39  warning  'been given' may be passive voice. Use active voice if you can.     write-good.Passive
 413:27  warning  'are expected' may be passive voice. Use active voice if you can.   write-good.Passive

 docs/scheduler/observability.md
 40:23   warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 60:24   warning  'all of' is too wordy.                                                                                                                          write-good.TooWordy
 64:48   warning  'be read' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 75:60   warning  'is unchanged' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 148:51  warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 193:19  warning  'is needed' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive
 205:22  warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 215:8   warning  'additional' is too wordy.                                                                                                                      write-good.TooWordy
 221:11  warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 243:51  warning  'equivalent' is too wordy.                                                                                                                      write-good.TooWordy
 251:11  warning  'is unauthenticated' may be passive voice. Use active voice if you can.                                                                         write-good.Passive
 256:11  warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 283:18  warning  'is measured' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 284:13  warning  'are measured' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 286:33  warning  'is gone' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 311:49  warning  'equivalent' is too wordy.                                                                                                                      write-good.TooWordy
 351:59  warning  'be repeated' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 391:67  warning  'is unaffected' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 396:38  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist

 docs/tools/README.md
 45:56  warning  'multiple' is too wordy.  write-good.TooWordy

 docs/swarm/ui.md
 45:63  warning  'were supposed' may be passive voice. Use active voice if you can.  write-good.Passive
 80:61  warning  'is scoped' may be passive voice. Use active voice if you can.      write-good.Passive

 docs/swarm/services.md
 20:61    warning  'be set' may be passive voice. Use active voice if you can.         write-good.Passive
 49:55    warning  'be set' may be passive voice. Use active voice if you can.         write-good.Passive
 79:1     warning  'are created' may be passive voice. Use active voice if you can.    write-good.Passive
 102:1    warning  'be restarted' may be passive voice. Use active voice if you can.   write-good.Passive
 123:48   warning  'is configured' may be passive voice. Use active voice if you can.  write-good.Passive
 148:170  warning  'being written' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/bash.md
 26:61   warning  'is created' may be passive voice. Use active voice if you can.    write-good.Passive
 33:36   warning  'is created' may be passive voice. Use active voice if you can.    write-good.Passive
 58:53   warning  'is expected' may be passive voice. Use active voice if you can.   write-good.Passive
 128:40  warning  'is rendered' may be passive voice. Use active voice if you can.   write-good.Passive
 136:26  warning  'been removed' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/swarm/sso.md
 5:8     warning  'is declared' may be passive voice. Use active voice if you can.     write-good.Passive
 31:62   warning  'been enabled' may be passive voice. Use active voice if you can.    write-good.Passive
 70:21   warning  'multiple' is too wordy.                                             write-good.TooWordy
 98:61   warning  'is tabulated' may be passive voice. Use active voice if you can.    write-good.Passive
 118:14  warning  'is built' may be passive voice. Use active voice if you can.        write-good.Passive
 127:26  warning  'is broken' may be passive voice. Use active voice if you can.       write-good.Passive
 241:23  warning  'was verified' may be passive voice. Use active voice if you can.    write-good.Passive
 241:60  warning  'was introduced' may be passive voice. Use active voice if you can.  write-good.Passive
 257:42  warning  'are created' may be passive voice. Use active voice if you can.     write-good.Passive

 docs/tools/lifecycle.md
 16:32  warning  'is preserved' may be passive voice. Use active voice if you can.  write-good.Passive
 55:1   warning  'Subsequent' is too wordy.                                         write-good.TooWordy

 docs/tools/forge.md
 21:8     warning  'is assumed' may be passive voice. Use active voice if you can.      write-good.Passive
 28:36    warning  'validate' is too wordy.                                             write-good.TooWordy
 35:18    warning  'be seen' may be passive voice. Use active voice if you can.         write-good.Passive
 35:43    warning  'is stated' may be passive voice. Use active voice if you can.       write-good.Passive
 40:3     warning  'are removed' may be passive voice. Use active voice if you can.     write-good.Passive
 45:22    warning  'validate' is too wordy.                                             write-good.TooWordy
 137:1    warning  'Multiple' is too wordy.                                             write-good.TooWordy
 144:144  warning  'are merged' may be passive voice. Use active voice if you can.      write-good.Passive
 154:51   warning  Use first person (such as 'I') sparingly.                            Microsoft.FirstPerson
 158:8    warning  'are read' may be passive voice. Use active voice if you can.        write-good.Passive
 178:61   warning  'be run' may be passive voice. Use active voice if you can.          write-good.Passive
 313:38   warning  'are structured' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/scheduling.md
 23:1   warning  'is set' may be passive voice. Use active voice if you can.      write-good.Passive
 25:45  warning  'multiple' is too wordy.                                         write-good.TooWordy
 33:8   warning  'are left' may be passive voice. Use active voice if you can.    write-good.Passive
 34:54  warning  'previously' is too wordy.                                       write-good.TooWordy
 46:31  warning  'is removed' may be passive voice. Use active voice if you can.  write-good.Passive
 96:16  warning  'minimum' is too wordy.                                          write-good.TooWordy

 docs/tools/matrix.md
 6:9     warning  'is configured' may be passive voice. Use active voice if you can.  write-good.Passive
 31:35   warning  'is inferred' may be passive voice. Use active voice if you can.    write-good.Passive
 32:34   warning  'is sent' may be passive voice. Use active voice if you can.        write-good.Passive
 46:20   warning  'enumerate' is too wordy.                                           write-good.TooWordy
 63:43   warning  'been invited' may be passive voice. Use active voice if you can.   write-good.Passive
 70:4    warning  'Multiple' is too wordy.                                            write-good.TooWordy
 74:64   warning  'is keyed' may be passive voice. Use active voice if you can.       write-good.Passive
 111:18  warning  'multiple' is too wordy.                                            write-good.TooWordy
 113:5   warning  'Multiple' is too wordy.                                            write-good.TooWordy
 130:51  warning  'was dropped' may be passive voice. Use active voice if you can.    write-good.Passive
 141:1   warning  'is cleared' may be passive voice. Use active voice if you can.     write-good.Passive
 149:39  warning  'additional' is too wordy.                                          write-good.TooWordy

 docs/tools/subagent.md
 44:11  warning  'are meant' may be passive voice. Use active voice if you can.   write-good.Passive
 44:24  warning  'be bounded' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/hivectl.md
 46:24   warning  'is created' may be passive voice. Use active voice if you can.   write-good.Passive
 100:53  warning  'is needed' may be passive voice. Use active voice if you can.    write-good.Passive
 136:67  warning  'is hoisted' may be passive voice. Use active voice if you can.   write-good.Passive
 157:38  warning  'equivalent' is too wordy.                                        write-good.TooWordy
 205:46  warning  'previously' is too wordy.                                        write-good.TooWordy
 222:1   warning  'requirement' is too wordy.                                       write-good.TooWordy
 224:12  warning  'were added' may be passive voice. Use active voice if you can.   write-good.Passive
 231:1   warning  'therefore' is too wordy.                                         write-good.TooWordy
 244:35  warning  'be consumed' may be passive voice. Use active voice if you can.  write-good.Passive
 245:52  warning  'is required' may be passive voice. Use active voice if you can.  write-good.Passive
 246:6   warning  'is given' may be passive voice. Use active voice if you can.     write-good.Passive

 docs/tools/swarmctl-cli.md
 70:62   warning  'multiple' is too wordy.                                            write-good.TooWordy
 119:19  warning  'was generated' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/hivectl-cli.md
 250:118  warning  'is created' may be passive voice. Use active voice if you can.     write-good.Passive
 506:331  warning  'is required' may be passive voice. Use active voice if you can.    write-good.Passive
 506:357  warning  'is given' may be passive voice. Use active voice if you can.       write-good.Passive
 644:9    warning  'is staged' may be passive voice. Use active voice if you can.      write-good.Passive
 907:19   warning  'was generated' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/forge-cli.md
 146:68    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 176:192   warning  'is created' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 246:161   warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 284:48    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 296:37    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 345:51    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 351:54    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 351:90    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 352:47    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 363:43    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 363:79    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 371:37    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 401:51    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 407:87    warning  'is set' may be passive voice. Use active voice if you can.                                                                                                        write-good.Passive
 418:40    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 461:159   warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 483:78    warning  'are left' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 490:72    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 654:67    warning  'are left' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 706:161   warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 744:48    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 756:37    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 805:55    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 811:54    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 811:90    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 812:47    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 823:43    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 823:79    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 831:37    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 861:51    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 867:87    warning  'is set' may be passive voice. Use active voice if you can.                                                                                                        write-good.Passive
 878:40    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 921:159   warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 980:94    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 988:84    warning  'be cloned' may be passive voice. Use active voice if you can.                                                                                                     write-good.Passive
 1041:76   warning  'in addition' is too wordy.                                                                                                                                        write-good.TooWordy
 1041:123  warning  'is set' may be passive voice. Use active voice if you can.                                                                                                        write-good.Passive
 1042:23   warning  'Maximum' is too wordy.                                                                                                                                            write-good.TooWordy
 1139:240  warning  When referring to a person, consider using 'correct', 'adequate', 'sufficient', 'consistent', 'valid', 'coherent', 'sensible', or 'reasonable' instead of 'sane'.  alex.Ablist
 1402:19   warning  'was generated' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive

 docs/trust-boundary/boundary.md
 5:32    warning  'is tracked' may be passive voice. Use active voice if you can.   write-good.Passive
 52:64   warning  'are served' may be passive voice. Use active voice if you can.   write-good.Passive
 58:61   warning  'be bound' may be passive voice. Use active voice if you can.     write-good.Passive
 60:62   warning  'is treated' may be passive voice. Use active voice if you can.   write-good.Passive
 99:27   warning  'is shared' may be passive voice. Use active voice if you can.    write-good.Passive
 112:13  warning  'is declared' may be passive voice. Use active voice if you can.  write-good.Passive
 122:46  warning  'therefore' is too wordy.                                         write-good.TooWordy
 124:15  warning  'all of' is too wordy.                                            write-good.TooWordy
 131:21  warning  'be opened' may be passive voice. Use active voice if you can.    write-good.Passive
 151:53  warning  'is added' may be passive voice. Use active voice if you can.     write-good.Passive
 157:4   warning  'equivalent' is too wordy.                                        write-good.TooWordy

 docs/web-ui/README.md
 107:17  warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race
 131:28  warning  Use first person (such as 'I') sparingly.                                            Microsoft.FirstPerson

 docs/turn-loop/config.md
 107:8   warning  'additional' is too wordy.                                                                                                                                     write-good.TooWordy
 205:33  warning  'evaluate' is too wordy.                                                                                                                                       write-good.TooWordy
 219:21  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'Disabled'.  alex.Ablist
 263:42  warning  Use first person (such as 'I') sparingly.                                                                                                                      Microsoft.FirstPerson
 292:66  warning  'is documented' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive

 docs/trust-boundary/security.md
 13:1    warning  'is trusted' may be passive voice. Use active voice if you can.                                                  write-good.Passive
 16:25   warning  'is privileged' may be passive voice. Use active voice if you can.                                               write-good.Passive
 17:61   warning  'therefore' is too wordy.                                                                                        write-good.TooWordy
 25:64   warning  'be stopped' may be passive voice. Use active voice if you can.                                                  write-good.Passive
 39:35   warning  When referring to a person, consider using 'foolish', 'ludicrous', 'speechless', or 'silent' instead of 'dumb'.  alex.Ablist
 39:35   warning  Don't use 'dumb', it's profane.                                                                                  alex.ProfanityLikely
 39:61   warning  'is affected' may be passive voice. Use active voice if you can.                                                 write-good.Passive
 82:17   warning  'therefore' is too wordy.                                                                                        write-good.TooWordy
 91:57   warning  'equivalent' is too wordy.                                                                                       write-good.TooWordy
 196:24  warning  'therefore' is too wordy.                                                                                        write-good.TooWordy
 212:62  warning  'is tracked' may be passive voice. Use active voice if you can.                                                  write-good.Passive
 226:49  warning  'be steered' may be passive voice. Use active voice if you can.                                                  write-good.Passive
 280:26  warning  'is scoped' may be passive voice. Use active voice if you can.                                                   write-good.Passive

 docs/turn-loop/mcp.md
 117:34  warning  'equivalent' is too wordy.                                                                                                                                     write-good.TooWordy
 143:3   warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 219:8   warning  'is disallowed' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive

 docs/turn-loop/claude-invocation.md
 116:54  warning  'is gone' may be passive voice. Use active voice if you can.      write-good.Passive
 237:8   warning  'is shared' may be passive voice. Use active voice if you can.    write-good.Passive
 245:32  warning  'is set' may be passive voice. Use active voice if you can.       write-good.Passive
 247:30  warning  'are mounted' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/web-ui/css-vars.md
 36:12   warning  'all of' is too wordy.  write-good.TooWordy
 141:35  warning  'all of' is too wordy.  write-good.TooWordy

 docs/web-ui/design-guide.md
 8:30    warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race
 18:24   warning  'multiple' is too wordy.                                                             write-good.TooWordy
 19:41   warning  'multiple' is too wordy.                                                             write-good.TooWordy
 34:30   warning  'minimize' is too wordy.                                                             write-good.TooWordy
 49:67   warning  'is hidden' may be passive voice. Use active voice if you can.                       write-good.Passive
 94:56   warning  'is hidden' may be passive voice. Use active voice if you can.                       write-good.Passive
 131:61  warning  'minimum' is too wordy.                                                              write-good.TooWordy
 145:21  warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race
 149:55  warning  'consolidate' is too wordy.                                                          write-good.TooWordy
 155:26  warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race
 158:1   warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race

 docs/web-ui/shape.md
 41:17   warning  'is sanitized' may be passive voice. Use active voice if you can.    write-good.Passive
 127:51  warning  'are unaffected' may be passive voice. Use active voice if you can.  write-good.Passive
 131:46  warning  Use first person (such as 'me') sparingly.                           Microsoft.FirstPerson
 184:1   warning  'multiple' is too wordy.                                             write-good.TooWordy
 195:66  warning  'is sanitized' may be passive voice. Use active voice if you can.    write-good.Passive
 230:7   warning  'is hidden' may be passive voice. Use active voice if you can.       write-good.Passive
 232:32  warning  'are reused' may be passive voice. Use active voice if you can.      write-good.Passive
 247:43  warning  'is gone' may be passive voice. Use active voice if you can.         write-good.Passive
 253:1   warning  Use 'select' instead of the input-specific verb 'swipes'.            Microsoft.UIVerbs
 301:28  warning  'is set' may be passive voice. Use active voice if you can.          write-good.Passive

 docs/web-ui/agent.md
 49:62   warning  'multiple' is too wordy.                                                                                                                                      write-good.TooWordy
 75:21   warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 78:34   warning  Use 'select' instead of the input-specific verb 'click'.                                                                                                      Microsoft.UIVerbs
 95:59   warning  'are typed' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 131:34  warning  Reconsider using 'trap', it may be profane.                                                                                                                   alex.ProfanityMaybe
 135:43  warning  'is unchanged' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 176:36  warning  'been removed' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 270:48  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'invalid'.  alex.Ablist
 271:39  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'invalid'.  alex.Ablist
 273:12  warning  'is called' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 335:3   warning  'subsequent' is too wordy.                                                                                                                                    write-good.TooWordy
 367:35  warning  'minimum' is too wordy.                                                                                                                                       write-good.TooWordy
 377:56  warning  Use 'select' instead of the input-specific verb 'clicks'.                                                                                                     Microsoft.UIVerbs

 docs/web-ui/dashboard.md
 61:51    warning  'be confused' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 183:32   warning  'equivalent' is too wordy.                                                                                                                                     write-good.TooWordy
 251:46   warning  'is checked' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 261:35   warning  'is set' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 314:25   warning  'is unchanged' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 342:29   warning  'is tooltipped' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 386:13   warning  'however' is too wordy.                                                                                                                                        write-good.TooWordy
 447:50   warning  'is written' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 451:65   warning  'are named' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive
 466:22   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.                 alex.Ablist
 524:29   warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'Disabled'.  alex.Ablist
 537:33   warning  'originally-active' doesn't need a hyphen.                                                                                                                     Microsoft.Hyphens
 763:29   warning  'is stopped' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 771:48   warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 778:14   warning  'all of' is too wordy.                                                                                                                                         write-good.TooWordy
 798:22   warning  'is stopped' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 830:3    warning  'multiple' is too wordy.                                                                                                                                       write-good.TooWordy
 856:16   warning  'exclusively' is too wordy.                                                                                                                                    write-good.TooWordy
 951:33   warning  Reconsider using 'trap', it may be profane.                                                                                                                    alex.ProfanityMaybe
 1016:23  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 1017:22  warning  'is mixed' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 1027:22  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 1028:63  warning  'satisfy' is too wordy.                                                                                                                                        write-good.TooWordy
 1038:9   warning  'multiple' is too wordy.                                                                                                                                       write-good.TooWordy
 1075:47  warning  'is set' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 1077:57  warning  'be created' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 1109:50  warning  'is focused' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 1256:17  warning  'is written' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 1272:3   warning  'is sent' may be passive voice. Use active voice if you can.                                                                                                   write-good.Passive
 1273:15  warning  'previously' is too wordy.                                                                                                                                     write-good.TooWordy
 1286:3   warning  'is untouched' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 1391:27  warning  'is gone' may be passive voice. Use active voice if you can.                                                                                                   write-good.Passive

✖ 0 errors, 493 warnings and 0 suggestions in 50 files. failed
with "vale: not found" even though hive-rules says to gate locally with
the devshell — a builder had to reconstruct CI's incantation by hand.

Local command: XDG_DATA_HOME=$PWD/.vale-data nix develop -c sh -c 'vale sync && vale docs'
2026-09-13 12:25:47 +02:00
atlas
cb2c90f32e swarm: present tense + no-queue-coordinates wording
The queue's payload ceiling was justified by what the queue was about to
carry; it carries it now, so the comment says so.

The other two sites say "a hive with no queue configured". The swarm has
exactly one queue and a hive cannot lack it — only its coordinates, its
credential, or its ability to reach it. That wording is already used
everywhere else the absence is named; these two predate it.

The docs section on the agents' queue coordinates stopped at delivering
them and never said what the connection is for. It now names the subject
and the degrade rule, which is the part an operator reading an agent's
terminal at the swarm needs.

Refs #3805
2026-09-13 12:01:58 +02:00
atlas
767a863cf1 swarm-nats: grant agents their hive's terminal subject
The responder has had an agent arm since the principal was minted, but
no deployment ever passed `--agent-publish-subject`, and an empty list
is a refusal by design: `Policy::permissions` returns `None` rather than
a grant that can do nothing, so every agent was turned away at CONNECT.
The subject itself is the one this thread settled on, `$SWARM.term`
namespaced per hive.

The value has to reach the responder with a literal dollar. systemd
substitutes `$NAME` in `ExecStart` whether or not the word is quoted,
so a single dollar expands `SWARM` — unset, therefore empty — and the
responder is handed `.term.{hive}.>`. That grant validates (it carries
the `{hive}` placeholder), is accepted, and matches nothing any agent
publishes to, so the failure surfaces as an authorization violation far
from its cause. `$$` in the unit text is the escape for one dollar.

The module-eval case reads the rendered unit rather than the module
source, because the single-dollar version renders perfectly well; the
doubled dollar is the only thing that distinguishes them before deploy.

The grant is per-hive, not per-agent: an agent's identity names its
hive, so any agent in a hive can publish as another. That is the
tradeoff ruled acceptable for now, tracked separately for tightening.

Refs #3805
2026-09-13 11:45:37 +02:00
atlas
2989c5ccdb swarm: say "no queue coordinates", never "a hive with no queue"
The swarm always has exactly one queue; a hive can only lack its
address. Reworded every prose site this PR added that stated or
implied the opposite, to name what is actually absent (coordinates,
credential, or address) instead of the queue itself.

Refs #3805
2026-09-13 11:13:17 +02:00
atlas
86652f051a swarm: wire the agents' queue coordinates and credential through the modules
The host end: `HIVE_C0RE_AGENT_QUEUE_CREDENTIAL_DIR` tells the daemon
where the reader unit put the files, and a new
`deploy.hive-controller.queue.agentNatsUrl` says where the queue is as an
agent *container* reaches it. That address defaults to the bridge one and
never to loopback — `statusPublish.natsUrl` beside it is loopback and
correct, because hive-c0re shares the host netns and an agent does not.
Paired with the swarm's token endpoint, gated together, and forwarded by
`hive_c0re::meta` as both an env var and an agent option: the harness
reads the variable at runtime, its unit is built from the option.

The agent end: `nix/agent-modules/queue.nix` declares that option pair
and, when set, has the harness unit inherit the two credentials by name.
Bare-id `LoadCredential=` is the terse form documented for inheriting
what the service manager received, and is non-fatal when the credential
is absent — which a hive whose publisher has not run yet needs.

No `HIVE_AGENT_OIDC_CA_FILE`: the meta flake already embeds the hive CA
and the swarm root into each container's trust store at build time, and
reqwest's rustls backend verifies against it.

Refs #3805
2026-09-13 11:13:17 +02:00
atlas
f8dd737456 swarm: run the agent queue credential reader before hive-c0re
Ruled: swarm-bao-queue-agent.service must run before hive-c0re.service
and be wanted (not required) by it, so no agent container renders
ahead of the reader's attempt at its credential. An unreachable store
delays hive-c0re's start by the reader's own start-limit window rather
than failing it outright.

Refs #4314
2026-09-13 11:10:00 +02:00
atlas
09d502ea34 swarm-nats: set max_payload to 8 MiB explicitly
The swarm queue's rendered settings never named max_payload, so it ran
on nats-server's upstream default of 1 MiB. That default is about to
be too small: the broker is going to carry agent terminal rows
(whole TermMsg bodies) published as complete messages rather than
split, and a publish over the limit does not truncate — the server
answers -ERR 'Maximum Payload Violation' and closes the connection,
dropping the row.

Set max_payload = 8388608 explicitly in the settings merge, with a
comment on what it bounds and what bounds it (max_pending, which
nats-server refuses to start past). Add a module-eval case that reads
the rendered container config so a future edit that drops or shadows
the key fails eval instead of surfacing as a dropped row in
production.

Refs #3805
2026-09-12 21:40:36 +02:00
atlas
b8157cb08e swarm: read the agent queue credential out of the store onto the hive host
The publisher on the authelia host has been writing
`secret/swarm/hives/<hive>/queue/agent` — the OIDC client secret agent
containers present to the swarm queue, plus the client id it belongs to —
and nothing read it. This is the reader: a oneshot `swarm-bao-queue-agent`
that logs in with the host's certificate and lands the two fields as two
files under `deploy.hive-controller.queue.agentCredentialDir`, the secret
`0600` and the client id `0644`.

Two files rather than one because that is the consumer's shape:
`swarm_queue_client::QueueConfig::from_env` takes the secret as a path and
the client id as a value, so the split here is what keeps the next slice
from parsing anything.

Same shape as the store's first reader, `glue-matrix-bao-token.nix` — a
cert login that fails loudly under `Restart=on-failure` because every state
it fails on is one a retry fixes, then reads that degrade quietly because no
retry turns "no value there" into a value. Unlike the matrix token there is
no local fallback and none is possible, so absent files mean this hive's
agents do not connect, which is the ordinary state of a swarm before the
publisher has run.

Nothing consumes the files yet and this unit is ordered `Before=` nothing.
The next slice bind-mounts them into agent containers through hive-c0re and
adds the ordering edge along with them.

Refs #3805
2026-09-12 21:05:52 +02:00
atlas
14305255f0 swarm: put the matrix registration token where the reader is granted
`swarm-bao-matrix-token` reads `secret/swarm/matrix/registration-token`
and is refused with `Code: 403 — permission denied`, measured on this
host at 16:17:49Z after a successful cert login.

path.rs makes every swarm path `swarm/<kind>/<name>/…` where Kind is a
closed set of four: agents, hives, services, controller. `matrix` sits
where a kind belongs, so policy.rs's read document — which emits exactly
`swarm/agents/*` and `swarm/hives/<hive>/*` — cannot cover it. The
module's own doc predicted this: "a misspelled kind is a 403 at provision
time rather than anything a compiler sees".

Moves the token to `swarm/hives/<hive>/matrix/registration-token`, built
through principal_prefix(Kind::Hive, …) like its per-hive sibling
queue::agent_client_path. The policy is untouched: render already grants
that prefix. mara chose this over widening the namespace.

The nix reader interpolates hyperhiveCfg.hiveName, with the no-fallback
reasoning glue-bao-tls.nix already gives at its own use of it.

path.rs's MOUNT doc justified itself by citing the old literal, which
this commit deletes; rewritten to cite the nix reader instead.

Scope: this makes the read reachable, not the value present. Nothing
writes that path yet, and a 403 says nothing about presence — the two
are separate findings and only the first is fixed here. No migration:
nothing ever wrote the old path and no read ever succeeded.

Gate: cargo fmt 0, cargo test -p swarm-secret-client 0 — 32 passed
against a 29-passed baseline with the change stashed, so the three new
tests are accounted for rather than assumed.

Refs #4308
2026-09-12 19:46:04 +02:00
atlas
2a02c76ad5 hive-c0re: name an agent container after its machine, not "nixos"
Every agent container reports the hostname `nixos`, so every log line it
ships carries that as its `_HOSTNAME`. Measured: host `muede-lpt2`,
`hive-matrix` (declared as `containers.hive-matrix`) `hive-matrix`, and
`h-atlas` `nixos`.

nixpkgs sets the hostname in the merge function of the
`containers.<name>.config` option (nixos-containers.nix:524), so it reaches
a guest evaluated through that option and nothing else. Agent containers are
`nixos-container create --flake meta#<name>` — an independent `nixosSystem`
off the meta flake, which never evaluates that submodule.

nspawn also names a container's hostname after the machine by default; that
is ruled out as the source here, because `h-atlas`'s machine name is
`h-atlas` and it reports `nixos`.

The machine name rather than the logical one: `stats/otel_metrics.rs:345`
already labels metrics `container.name = "h-<name>"`, so the logical name
would make logs say `atlas` while metrics say `h-atlas` — a prefix transform
on every join between the two signals. Declarative containers and nspawn
both use the machine name too, so this is one rule with no exception for
agents.

The emission sits next to `hyperhive.user.name = name;`, which already
derives the container's unix user from the agent name; the hostname was the
one identity attr nobody wired.

Also drops the prose in swarm-otel.nix and module-eval.nix that explained
`_MACHINE_ID` by "every container is `nixos`" — that motivating example is
what this commit removes, and the argument for `_MACHINE_ID` never depended
on it.

Checked before editing: nothing in the tree assumes the hostname is
"nixos" (0 hits across *.rs and *.nix), and nothing reads the hostname at
runtime.

Gate: cargo fmt 0, clippy -D warnings 0, cargo test -p hive-c0re meta::
0 (23 run, 22 passed, 1 ignored), nix fmt 0 changed.

Refs #4304
2026-09-12 18:19:18 +02:00
atlas
4db746a22c glue-matrix-bao-token: do not assert what the Before= ordering does
The retry comment claimed "every retry is time the homeserver may spend
waiting". That is the conservative reading, not a measured one, and argus
is right that it is probably wrong: systemd ordering typically resolves
once a unit's first start job completes, success or failure, and an
auto-restart after that is not a new ordering-relevant job.

If that holds, the container proceeds after the first failed attempt --
same timing as today -- and what the retries buy is the token file being
correct within ~60s for whatever starts next, rather than this boot's
race getting a second chance.

Both readings justify the same tight bound, for different reasons, so the
comment now says the ordering behaviour is unverified instead of picking
one. An agent container cannot reach a systemd manager to settle it.

Refs #4303
2026-09-12 16:10:45 +02:00
atlas
35c3f724f1 glue-matrix-bao-token: retry a failed login, keep degrading on an empty read
The unit treats every failure as permanent: it prints why and `exit 0`s,
with no `Restart=`, so one bad moment costs the whole boot. Two of its
failure modes deserve that and one does not.

`bao login` fails when the store is unreachable, sealed, or has not been
given this host's cert-auth role yet. All three are transient. Measured
on this morning's rebuild:

  11:24:05  Started Container 'swarm-bao'
  11:24:06  could not log in to swarm-bao with this host's certificate
  11:24:07  Success! Data written to: auth/cert/certs/swarm-secret-publisher

It lost by one second, and stayed degraded for the boot. The publisher
next to it hit the same race and recovered on its first retry, because it
has `Restart=on-failure`.

`bao kv get` returning nothing is the opposite: the store answered, and
holds no token at that path. A retry cannot improve it, so that branch
keeps `exit 0` and the local token.

The bound is sized for this race, not for an unseal.
`swarm-bao-controller-policy` waits 2880 x 30s because a shamir unseal is
a human action and that unit blocks nothing. This one is `Before=` the
homeserver's container, so every retry is time the homeserver may spend
waiting -- 4 x 15s covers a container-start race with margin, and a store
still sealed after it degrades exactly as it does today.

`StartLimit*` are `[Unit]` settings and are ignored under `[Service]`, so
they are top-level attrs here. The module-eval case asserts the window
outlasts `RestartSec x burst`, since a burst that cannot be reached is a
unit that looks like it retries and does not.

Refs #4303
2026-09-12 16:10:45 +02:00
atlas
57aedc82ae swarm-otel: say what is measured about _HOSTNAME, not a mechanism that is wrong
The previous commit's comments explained `_HOSTNAME` being `nixos` with
"no container sets `networking.hostName`", read off a `git grep` of this
tree. That grep answers a question about our source; the default is
nixpkgs': `nixos/modules/virtualisation/nixos-containers.nix` sets
`networking.hostName = mkDefault name` for every `containers.<name>`
guest, which is how every swarm service container here is declared.

So the stated cause is wrong, and why the default does not reach these
guests is still open. What is measured is narrower: an agent container
reports `nixos`, and `_MACHINE_ID` is per-machine by construction. The
comments now claim only that, and say the rest is unresolved.

The code is unchanged — `_MACHINE_ID` in `_stream_fields` is correct
regardless of which explanation turns out to be true.

Refs #4304
2026-09-12 14:38:35 +02:00
atlas
bb38e1967c swarm-otel: key the log stream by machine, not by a hostname every container shares
`_stream_fields=_HOSTNAME,_SYSTEMD_UNIT` was chosen to give "one stream
per unit per machine", which is what the comment above it claims. It does
not: no container sets `networking.hostName`, so `_HOSTNAME` is the NixOS
default `nixos` in every one of them, and every container's stream for a
given unit name merges into a single series.

Measured from inside an agent container:

  journalctl -n1 -o json -> "_MACHINE_ID":"5d1427ea…", "_HOSTNAME":"nixos"
  cat /etc/machine-id    ->  5d1427ea…
  git grep -i hostname -- nix/  -> 20 hits, all public vhost names,
                                   zero `networking.hostName =`

`_MACHINE_ID` is written by journald per machine and is already on every
entry, so adding it to the stream key makes the partition what its own
comment says it is. That merge is also why the host collector and the
containerised one were one series: both log to
`opentelemetry-collector.service`, and the field meant to separate them
was a constant.

The second comment touched here asserted a reader "can still tell the
origins apart" from `_HOSTNAME`/`_SYSTEMD_UNIT`/`_MACHINE_ID`. True only
of the last one; it now says so.

Not a full fix for attribution: `_MACHINE_ID` is opaque hex and nothing
maps it to a container name. Naming is the other half and is a separate
change.

Refs #4304
2026-09-12 14:14:11 +02:00
atlas
5e9b79a719 swarm: log in to bao before reading or writing a secret
`BAO_CLIENT_CERT` decides which certificate the TLS handshake presents. It is
not an identity: cert auth is a login, and a `bao kv` call without a token asks
its token helper for one instead — a `sh` neither unit carries on `path`.

Measured on this host, from `swarm-bao-matrix-token.service`:

  swarm-bao did not return secret/swarm/matrix/registration-token
  failed to get token helper: error expanding config path "":
    exec: "sh": executable file not found in $PATH

So the first credential meant to travel through the store never has, and the
publisher added last week would not have either.

`-token-only` rather than a plain login: storing is the default, and it stores
through that same helper, so the obvious form reproduces the failure one line
further down. It is `-field=token -no-store`, which keeps the token on stdout
and out of the filesystem.

The two units degrade differently on purpose, and that is preserved. The matrix
fetch is `Wants=`-only and must not hold up the homeserver, so a refused login
reports why and keeps the token already in place. The publisher is
`Restart=on-failure`, where a store that cannot authenticate this host is worth
retrying and "published 0" would read as an ordinary quiet day.

`swarm-bao.nix` is untouched: it authenticates with the bootstrap token from a
file, which is a real identity and not a cert exchange. Its shape is where the
export idiom here comes from.
2026-09-12 12:27:33 +02:00
iris
9ad700a1a1 swarm-ui: make it installable as a PWA
Closes #4282. mara: "scope looks good" — approving the plan posted
there (manifest + icons + minimal shell-only service worker + iOS meta
tags) and both explicit questions (network-first-with-offline-fallback,
never cache /api/*).

docs/web-ui/design-guide.md's "Layout & viewport" section already
asserted swarm-ui is installable as a PWA — this is what actually backs
it.

- manifest.webmanifest: name/icons/start_url/standalone display, theme
  #cba6f7 / background #1e1e2e matching the mocha --purple/--bg values.
- sw.js: plain JS, not TypeScript — the DOM lib swarm-ui's own tsconfig
  uses and the WebWorker lib a service worker's globals need are
  mutually exclusive in one tsc program, not worth a second tsconfig for
  a self-contained ~100-line file. Scoped to the app shell only, never
  touches /api/* at all, network-first with offline-fallback-to-cache
  (not cache-first) since main.js/main.css are unhashed filenames and a
  cache-first SW would risk wedging an operator on stale JS after a
  deploy.
- index.html: manifest link, theme-color meta, iOS
  apple-mobile-web-app-* tags (Safari ignores the manifest spec).
- main.tsx: feature-detected SW registration.
- branding/hyperhive-maskable.svg: hyperhive.svg's own artwork already
  fills nearly its whole canvas, so a maskable icon needs a padded
  variant or an OS mask crops the outer ring/corner brackets — embeds
  the original via a scaled <image> ref rather than duplicating markup.
- nix/packages/swarm-ui.nix: rasterizes icon-192/512/512-maskable.png
  from the branding SVGs at build time via librsvg, rather than
  checking in static PNGs.

Verified for real: typecheck+build green, and a real headless-chromium
tab driven over CDP confirms the service worker registers and becomes
the active controller, and a simulated-offline reload still serves the
full cached shell rather than a browser error page. nix build .#swarm-ui
also verified green, including the rasterized icon output.
2026-09-12 11:30:20 +02:00
atlas
d6a79b4e63 module-eval: cover the secret publisher, and catch that it cannot evaluate
Five cases: the leaf and the pairing that points at it, that the push
hands bao a path rather than the secret, a path per hive in the roster,
that a publisher holding an identity renders on a host with no store,
and the control that renders none without an identity.

They fail on this branch, and that is the finding. The suite was green
at 100 cases with the publisher already committed, because no fixture
enabled both authelia and a store identity — so the module's `config`
never activated and its script was never evaluated. An imported module
whose config never fires is as unmeasured as an unimported one.

What they surface: `swarm.authelia.agentClientSuffix` does not exist on
main. The agent principal these secrets belong to is minted by the PR
for the agent queue principal, whose branch adds both the option and the
`agentClients` list authelia mints from. Delivery of a secret nothing
mints cannot evaluate, let alone run — so that PR lands first and this
one rebases onto it.

The argv case strips comments before matching, which it earned: a
`script` renders its own comments into the text, and this unit's
comments name the hazard verbatim so the next editor does not
reintroduce it. Matching the raw text read that warning and failed —
a check the artifact defeats by describing the thing it is checked for.

Refs #3853
2026-09-12 11:22:33 +02:00
atlas
eaa52ef200 swarm: publish minted OIDC client secrets into the swarm store
A hive that does not host authelia has no path to its own agent queue
client secret. The mint writes the plaintext to a host directory whose
other reader lives in a different container, so the host that mints is
the only place both trees are addressable — which is where this unit
runs.

Four pieces, in the order they depend on each other: the leaf
(glue-bao-tls.nix signs it, because the thing that owns a private key
owns issuing from it), the module declaring its own cert/key options,
the one-pairing glue file pointing them at that leaf, and the imports.

The unit is gated on holding a client identity, never on
deploy.bao.enable — that option is the co-location assumption itself,
and the publisher is the case that assumption excludes.

The secret is passed to bao as `value=@<path>`, never as an argv
element: bao is an external binary, so an argument is world-readable in
/proc for the life of the call.

Refs #3853
2026-09-12 11:22:33 +02:00
atlas
98f2a94d82 swarm-bao: write the secret publisher's policy and cert-auth role
A sibling unit rather than more script in swarm-bao-controller-policy, because
that unit's name is an operator-facing string: docs/getting-started/setup.md
tells a reader to run `systemctl status swarm-bao-controller-policy`. Widening
it to two principals makes the name wrong; renaming it makes the instruction
wrong.

`after` and not `requires`. The controller's unit creates the KV and cert-auth
mounts this one writes into, so the ordering is real — but a failed oneshot
still counts as finished, so `requires` would neither wait for its success nor
re-run this unit when the sibling's own retry eventually lands. Ordering plus
this unit's `Restart=on-failure` is what converges.

Four module-eval cases, because the unit arrived with every claim about it in
prose and the suite still reporting the same count: the grant is write-only and
reaches the hive prefix alone (pinned as the whole capability list, since an
added capability is what a presence check misses, with negative arms for the
agent prefix, the bare swarm prefix and the policy path); it is ordered after
the unit that creates the mounts; it renders on the host; and the control, that
it does not render inside the store's container.

Refs #3853
2026-09-12 10:56:50 +02:00
atlas
a597b6bb1c swarm-bao: the secret publisher's policy — one grant, under the hive prefix only
Write-only `create`/`update` on `secret/data/swarm/hives/*`, and nothing else.
It copies secrets in and never reads one back; a read capability would let a
file-copier recover every hive's credentials rather than merely replace them.

`hives/` and not `swarm/*` because this principal has no business with an
agent's or a service's credentials, and the hive prefix is the only one whose
paths it produces. `secret/data/` is KV v2's ACL prefix, inserted by the engine
rather than written by the caller — the same trap the controller's grant
documents one binding up.

Named outside `hive-*`: the controller may create policies under that prefix,
and a policy it can rewrite is not a constraint on it.

The unit that writes this lands next. Refs #3853
2026-09-12 10:56:50 +02:00
atlas
e8ff633c6b swarm-bao, swarm: give the secret publisher its own subject, reserved like the controller's
The unit that will copy authelia's minted OIDC client secrets into the store
needs an identity of its own. Not the controller's: that grant includes
rewriting every hive's policy and login role, which a unit whose whole job is
copying one file has no business holding.

The subject joins `certAuthCns`, so it is unrepresentable as a hive name for
the same reason the controller's is — cert auth trusts the CA, and a hive's
own leaf carries its name as the CN.

The module-eval case collides with the SECOND list element and leaves the
controller's subject at its default. A list with one consulted element and one
dead one is indistinguishable from the first element's case, so without this
the addition could be inert and nothing would say so.

Refs #3853
2026-09-12 10:56:50 +02:00
iris
d34c6618df grafana: switch the CLAUDE.md-size panel from a snapshot bar to a time series
mara, PR review: "i want to see it over time - sounds like you built
bar chart?" — correct, it was a bargauge (instant/lastNotNull). Switched
to timeseries, matching the CPU/memory-by-agent panels' own treatment of
a plain live gauge (raw value plotted across the range, no rate()/
increase() since it's not a cumulative counter).
2026-09-12 10:34:57 +02:00
iris
93ed6a977f grafana: add a CLAUDE.md-size-by-agent panel to the agents dashboard
Closes #4284. hyperhive.agent.claude_md.lines is already exported (see
hive-agent's claude_md_watch module) but had no dashboard panel — this
is the display half.

Same bargauge shape as the two sibling per-agent gauges already in this
file (container storage, active time): sum by (agent), instant query,
lastNotNull reduction, since it's a continuously-live gauge rather than
a cumulative counter. Metric name uses the dotted OTLP form per this
file's own documented convention for this store.
2026-09-12 10:34:57 +02:00
atlas
98945d4c5a otel: scrape each collector's own loss counters
A collector's `refused` / `failed` / queue-depth counters are the only
signal that says telemetry is being dropped, and nothing read them at
any tier — so a collector losing records looked exactly like a quiet
system.

The hive tier could not be scraped without first naming its port. 8888
is the collector's built-in default and appeared in no config, which is
also why nothing comparing configured ports could see it clash with a
co-located collector — swarm-otel.nix sidesteps 8888 by hand for that
reason, and says so. Declaring the port and binding it explicitly makes
the value comparable; wiring the scrape is then one entry per tier.

Extending the port-collision assertion to cover it is deliberately left
out: that belongs with the other port work, and coupling a collision
fix to a scraping fix makes both harder to review.

Gate: 101 module properties hold, was 95. The six cases pin the rendered
scrape job rather than the option; the metrics pipeline naming the
prometheus receiver, a path never emitted on any hive before this since
the hive tier's scrapeTargets was empty everywhere; the `readers`
spelling, with a control so a missing telemetry block cannot pass the
port check vacuously; the swarm tier's own entry; the two tiers not
claiming the same port; and the absence arm, a hive with no collector
declaring no target.

scrapeTargets' description said "Empty by default, and that is the
shipped case". This makes that false, so the paragraph moves with it.
2026-09-12 10:34:06 +02:00
atlas
780df10d9d swarm: name the agent client after its hive, not after "agent"
`agent-<hive>` reads as "the agent named <hive>" — which is the one thing that
identity does not carry, since it is minted per hive. It becomes
`hive-<hive>-agent`: the hive's own id, extended.

The rename is not a string swap. `hive-foo-agent` satisfies the hive parse too
(it strips to a hive named `foo-agent`), so the responder's agent rule now runs
BEFORE its hive rule — most specific wins. Hive-first would have handed every
agent its hive's grant, including writing that hive's status key, with nothing
to report it: the client authenticates and is merely able to do more than it
should.

`Policy::new`'s overlap check goes with the prefix it was written for. The
invariant the suffix form needs instead is that the suffix is non-empty: an
empty one makes `strip_suffix` succeed on every hive id, so the two principals
become one string and whichever arm runs first answers for both.

The suffix form also introduces a collision the prefix form did not have: a hive
genuinely named `foo-agent` mints `hive-foo-agent`, which is hive `foo`'s agent
id. The responder cannot see it — it has no roster, deliberately — so
`swarm-authelia.nix` asserts at eval that no hive name ends with the suffix. The
existing duplicate-id assertion does not cover this: it fires only when both
`foo` and `foo-agent` are on the roster, and with `foo-agent` alone there is no
duplicate, just a hive quietly receiving its agents' grant.

A test written by analogy with `the_prefix_alone_names_no_hive` failed, correctly
— `hive--agent` is a hive named `-agent` under the hive parse, which this module
cannot rule out. It now asserts only the part this module owns: no empty hive
name is ever expanded into a subject.
2026-09-12 10:33:06 +02:00
atlas
fe9417ae52 swarm: give agent containers their own queue principal
Agents have authelia *users*; they had no machine identity at all, so an
agent could not authenticate to the swarm queue as anything. This mints
one `agent-<hive>` OIDC client per hive beside the existing
`hive-<hive>` one, teaches the auth-callout responder an agent arm, and
opens the queue's client port on the bridge so a container can reach it.

One client per HIVE, not per agent: agents are created at runtime, and a
per-agent client would make creating one a config change plus an
authelia reload. The cost is that agents on a hive are indistinguishable
to the broker, which is deliberate and tracked separately.

The agent grant is deny-by-default twice over. An agent id matches no
hive rule, so it gets a hive's status-key grant from neither; and with
no agent subject configured the responder returns no grant at all rather
than an empty publish list, which would be a denial wearing a grant's
shape. What an agent may publish is a deployment's decision, taken
through `--agent-publish-subject` the same way `--hive-publish-subject`
already works.

`Policy::new` now refuses two prefixes where one contains the other. The
arms are tried in order, so that overlap does not error at match time -
it silently hands one principal the other's grant.

Not shipped here, and neither is reachable without it: no subject is
configured for agents anywhere in nix, and nothing yet delivers
`agent-<hive>.secret` into an agent container. Both belong to the stream
that will be the first consumer.
2026-09-12 10:33:06 +02:00
atlas
d7ca8d922b glue-matrix-bao-token: say why the store returned nothing
The reader had one failure branch, and it could not fail. It named three
states — the store holds nothing, the store is sealed, the store is
unreachable — treated all three as success, and sent bao's stderr to
/dev/null, which is the only thing that tells them apart.

The degraded mode is right and is unchanged: a missing registration token
means new agent accounts cannot be provisioned and nothing else breaks,
so this still exits 0 and leaves the local token alone. What changes is
that the journal now carries the store's own message instead of a
sentence of ours asserting all three at once.

Deliberately not branching on that message. Distinguishing "no value
found" from "permission denied" programmatically would mean matching
prose from an external tool that I cannot reach a live instance of to
confirm, which is inventing a discriminator rather than reporting one.

Nothing asserted this script before — eleven module-eval cases cover the
unit's existence and its ordering, none its contents, which is how the
branch stayed. The case added here covers the property that was missing.

Gated: `96 module properties hold`, exit 0 (95 on the base commit, +1 =
the case added). `nix fmt` reported 0 changed over 723 files emitted in a
fresh worktree. Tracker-tag, comment-block and doc-pointer lints all exit
0 after staging.
2026-09-12 03:43:38 +02:00
atlas
f1e0d9c20e swarm-bao: the CN-collision comments describe a hazard that is now guarded
Both places that warned about a hive named after the controller's cert-auth
subject still told the reader it was unmitigated, and the option's description
recommended a migration — "change this to something outside the hive-name
grammar, at the cost of a role rename in any store that has already run the
granting unit" — that is no longer the answer and is not cheap.

swarm.nix now feeds the subject into the guard on `swarm.hives`, so a
colliding roster fails evaluation. Both paragraphs get SHORTER saying so: a
guarded hazard needs the consequence ("reserved as a hive name") rather than
the threat model, and the write-site keeps only the sentence the next person
needs — a role added beside this one must join that list.

Found by sweeping for the claim rather than for the symbol: the change that
made these stale touched swarm.nix, swarm-otel.nix and module-eval.nix, so no
diff-context or doc-comment rule covers a paragraph two files away. Grepping
the tree for "would satisfy" and for prose about a hive named after a subject
turned up exactly these two and nothing in docs/.
2026-09-11 22:43:25 +02:00
atlas
bb62bf1aa9 swarm: guard hive names where the roster is declared, and reserve the cert subjects
The two hive-name guards lived in swarm-otel.nix, inside its
`config = lib.mkIf (… && deployCfg.swarm-otel.enable)`. A swarm running the
secret store and the controller but no collector therefore had no hive-name
check at all, while the names were still composed into OIDC client ids, bao
policies and cert-auth roles exactly the same way. They move to swarm.nix,
which declares `swarm.hives` and is unconditional. swarm-otel keeps the
assertion that its own entry is still in the shared list — that one is about
this module's stake in a file it no longer controls.

The equality guard also takes the store's cert-auth subjects now. Cert auth
trusts the CA, so `allowed_common_names` is the whole of what narrows a role
to one identity, and the same CA signs every hive's leaf with the hive's name
as its CN. A hive named after a role's subject presents a certificate that
role accepts, which for the controller is write access to every hive's
credentials and policies.

A list rather than the one string, because the next role added beside it
widens what a hive name must not collide with, and because the subject is an
option an operator sets — a literal deny entry covers the default and nothing
else.

Four module-eval cases, two of them controls. The fixture overrides the
subject to `ctl` on purpose: the default contains `swarm`, which the substring
guard catches whatever the new arm does, so a fixture using it could not tell
the two apart. The controls are that a legal roster trips neither guard, and
that all three fixtures really do have the collector disabled — without the
second, every case would pass while testing the arrangement they exist to
rule out.
2026-09-11 22:28:44 +02:00
atlas
2979fcf5d5 swarm-secret-client: give the store one namespace instead of one prefix
The crate had a single path convention and it was per-agent:
`swarm/agents/<agent>/matrix/<account>`. The secrets still to move into the
store do not fit it — one belongs to a hive, one to a swarm service, one to
the controller itself — so each would have picked its own shape, and each
would have been a separate grant to get wrong.

mara ruled the scheme on the epic: `swarm/<kind>/<name>/<secret>`, over
`agents`, `hives`, `services` and `controller`. This lands it.

`Kind` is an enum rather than free strings for one reason: the store's grant
is written in nix and cannot be reached from Rust, so a misspelled kind is a
403 at provision time and not a compile error. `Kind::ALL` lets a test
enumerate the set instead of restating it, which is what makes adding a kind
a deliberate edit rather than an accidental grant.

Note `Kind` sits beside `checked_segment`'s existing `kind` argument, which
means something else entirely — the label of the name being validated. They
are not the same concept and should not be merged.

Nothing about the rendered policy changes. `policy::render` still grants read
on the agent kind alone; the other kinds are absent on purpose, because what a
hive may read of its own kind is a boundary question and not a consequence of
the namespace growing. The controller's write grant likewise stays scoped to
`agents/` — it widens when a path outside it gains a writer, not when the
kinds are declared.

Verified: `cargo test -p swarm-secret-client` 23 passed, 0 failed. The two
tests pinning the rendered strings (`the_document_grants_read_over_the_whole_agent_prefix`
and matrix's path assertion) still assert the same literals they did before,
which is what shows this is a faithful port rather than a reshape. `nix fmt`
710 emitted, 10 formatted, 0 changed; the three scripts/check-*.sh lints pass
with the change staged. No reference to the removed `path::AGENT_PREFIX`
survives in the crate or in nix — checked with a scoped pattern, because the
unqualified name also belongs to hive-host-sock's container prefix and greps
for it are answering a different question.
2026-09-11 20:19:47 +02:00
atlas
47d53f5c23 hive-c0re: one binding for /run/hyperhive's mode
The mode was declared twice in this file — the service unit's
RuntimeDirectoryMode and the socket unit's DirectoryMode — with only a
prose "must match" note tying them. Whichever unit activates first creates
the directory, so they cannot be allowed to disagree.

Both literals are in one file, so they become a `let`. Deleting a copy
beats checking it, and unlike rendering the mode into hive-priv it costs no
config knob for a value nobody should ever set.

hive-priv's tmpfiles.d entry for the same path is a third declaration that
cannot read this binding, and is left in step by hand. An earlier revision
of this branch added a CI check for exactly that pair; mara pointed out it
was keyed to one path rather than to the class, and looking for the general
case found two more paths declared by more than one mechanism — including
/run/hive-agent, where hive-gateway's tmpfiles rule and hive-priv's
generated one disagreed on the owner and the winner depended on systemd's
read order. That check is being reworked as a general one, tracked
separately, so nothing about it rides in here.

Verified: nix fmt (713 traversed, 5 formatted, 0 changed); the three
scripts/check-*.sh lints all exit 0 with the tree staged; .forgejo/ is now
byte-identical to main and the diff is this one file. checks.module-eval
reported 91 module properties hold on the previous revision of this branch
— the only nix change since is comment text inside the same let block,
which cannot affect evaluation.
2026-09-11 19:35:36 +02:00
atlas
72635832b7 swarm-grafana: grafana requires SSO, so the login form goes unconditionally
`auth.disable_login_form` was gated on `ssoLocal` — `grafana.enable &&
authelia.enable`, i.e. "both of them run on THIS host". With authelia
elsewhere in the swarm that is false, so a deployment that is very much
using SSO still rendered grafana with its local login form enabled, on a
vhost the gateway publishes, for a product that ships an `admin`/`admin`
account.

The reason that matters was already in the module, three lines up
("Grafana ships an `admin`/`admin` account, and this vhost is on the
public gateway") — it was just attached to a conditional. Whether a
password box sits on a public login page is not a per-host question.

Per mara on the docs PR for this: "grafana requires sso - no local
login". The OIDC block below stays gated on locality; making that follow
the same swarm-wide question is a larger change with its own tracking.

The module-eval suite already had the fixture this needed: `grafanaOldPath`
enables grafana and not authelia, which is exactly the shape the login
form stayed enabled in, so the regression case needs no new hive. 90 -> 91
properties.

Closes #4218.
2026-09-11 18:23:51 +02:00
atlas
5af1f6a8e5 docs, mcp.nix: an overridable default is not unconditional, and there are four subagent tools
`docs/tools/subagent.md` and `docs/tools/bash.md` both described their MCP
server as injected "unconditionally". Both entries are `lib.mkDefault`, and
the module says why one line above each: "so an agent.nix can still
override/disable the entry", "so the operator's own agent.nix can override
the entry".

The word matters for the subagent one in particular. The same comment block
records the framing that it is default-on for now and should become a real
capability gate later, so "can I turn this off today?" is a question an
operator has — and "unconditionally" answers it as "patch nix/" when the
answer is one override in agent.nix.

Both pages now say default, and say what the default yields to.

The other direction on the same page: `subagentHttpPort`'s option
description and the unit comment beside it both listed three tools,
`start`/`continue`/`interrupt`. The daemon serves four. #4101, which
introduced it, is titled with the three-verb phrasing, so `status` landed
afterwards and never reached either description — while `subagent.md` had
the full set all along. The option description renders into the generated
options doc, so it is the one an operator reads.

Closes #4231.
2026-09-11 16:58:12 +02:00
atlas
f918cea957 module-eval: evaluate the swarm.peers removal shim
`nix/host-modules/swarm-peers-removed.nix` exists to turn an "option does
not exist" error into a warning that says where the entries went. That
warning is its whole deliverable, and no fixture set `swarm.peers` — the
string appeared 0 times in module-eval.nix, so the shim was never
evaluated by anything.

It differs from its ten siblings in what a broken shim looks like. The
others re-route a value, so a failure shows up as a wrong rendered
config. This one renders prose nothing reads back, so a `mkIf` that
stops matching or a rename of the `swarm.hives` it points at fails
silently, and lands on the one operator who needed it.

The check already carries an old-path fixture for ten migrated
namespaces (wireguard, forge, matrix, nats, authelia, controller, ui,
stores, grafana, statusPublish). `swarm.peers` was the eleventh and the
only uncovered one.

Two peers, only one carrying `caCert`, because the module emits a second
warning filtered on exactly that attribute — with a single peer the
filtered list and `attrNames` are the same list, so a `withCaCert` that
had collapsed into `attrNames` would still read green. The third case is
the control: a hive that never set `peers` must get neither warning,
without which the other two pass on any config whose warning list
happens to carry the string.

Closes #4188.
2026-09-11 13:32:09 +02:00
atlas
dd9e0bf0b0 module-eval: pin which switch enables each swarm-wide service
`deploy.allSwarmServices` derives nine service enables and appeared
nowhere in the check, so the tier a service sits on was prose only. The
tenth, the swarm controller, already had this exact pair of cases — it
rides `singleHostSwarm` instead, and swarm-ui follows the controller.

Four cases: the switch turns its nine on, a hive that does not host them
runs none, an operator placing one elsewhere still wins over the
`mkDefault`, and hosting the shared services does not make a hive the
swarm's control plane.

The roster is counted before it is read: `lib.all` over an empty set
holds vacuously, so a roster that lost a member would otherwise turn the
case green by measuring nothing.

Closes #4186
2026-09-11 09:05:49 +02:00
atlas
07639fd364 otel: evaluate the agent log forwarder in module-eval
Nothing in this suite evaluated nix/agent-modules/ at all: every fixture
was a host, so a typo in a rendered container config surfaced on a real
deploy and nowhere else. This adds an `agent` constructor beside `hive`,
off the same `nixosModules.agent-base` the meta flake hands a container.

It also adds the suite's first two-hive fixture. Every existing one
declares `swarm.hives.h1` alone, so a per-hive arm written against those
passes on a hardcoded literal — which is exactly what the new per-hive
logs pipeline needed covering.

Eight cases, each paired with the control that makes it mean something:
the absence arms with a presence half, the per-hive arm with a roster
length check, because `lib.all` over an empty roster holds vacuously.

Each was then shown to fail. Eight mutations across the three files —
`directory` back to the runtime default, a pipeline naming no receiver,
an exporter aimed at a loopback literal, an exporter name that stops
reading `protocol`, a missing hive-tier logs pipeline, the metrics-only
processor inside it, a per-hive pipeline hardcoded to one hive, and logs
pipelines exporting to the metrics store — all caught, none survived,
none skipped, each run's baseline green.

Part of #3940.
2026-09-11 09:03:49 +02:00
atlas
68711796ef otel: forward each agent container's journal to its hive collector
An agent container writes a complete journal — 991 MB and nine days deep
on this hive — that nothing outside it can read: the host-side
per-container journal directory is an id-mapped bind mount, and journald
writes nothing into it. So the reader has to run inside the container,
and the path it would push to did not exist.

Three tiers, one vertical slice, because any two of them alone are
silent:

- the agent container gains an `opentelemetry-collector` with a
  `journald` receiver aimed at its own journal and an exporter aimed at
  the same base address every in-process producer already exports to.
- the hive collector gains `service.pipelines.logs`. Without it the
  `otlp` receiver answers 404 on `/v1/logs` — measured, and
  indistinguishable from a route that was never meant to exist.
- the swarm collector gains a per-hive `logs/<hive>` pipeline beside
  `metrics/<hive>`. Without it the push is accepted, answered 200, and
  routed nowhere.

The receiver's `directory` is stated rather than inherited, and that is
the load-bearing line: its default is the RUNTIME journal
(`/run/log/journal`), which in an agent container is empty. Left at the
default this whole path validates, starts, reports healthy and forwards
nothing. The assertion beside it covers the same silence from the other
end — a `volatile` or `none` journald storage empties the directory the
receiver reads.

Attribution follows the tier that can prove it. The forwarder stamps
`agent`, which no host-side reader could supply; `hive` is deliberately
left to the swarm tier, which upserts it from whichever receiver
accepted the sample, precisely so the label comes from something the
sender cannot write.

No `units` allowlist, unlike the swarm tier's journald receiver. That
one needs one because the host's journal also holds an operator's own
session; a container's journal is the harness and what the harness
spawns. Measured volume is 20827 entries / 6.3 MB per agent per day,
with nothing logging below `info` — so the receiver's `info` default
filters nothing and there is no bill to justify a knob.

Agent containers only, per the ruling on the issue: swarm services need
one forwarder per service container and get re-measured once this works.

Part of #3940.
2026-09-11 09:03:49 +02:00
atlas
48e6a0b88f swarm-bao: create the KV mount the controller writes credentials through
The bootstrap unit writes a policy granting `secret/data/swarm/agents/*` and
nothing creates that engine. A fresh OpenBao has no `secret/` — only a dev-mode
one does — so `swarm-controller`'s first credential write answers `no handler
for route "secret/data/swarm/agents/<agent>/matrix/<name>". route entry not
found.` Measured on the live host at 21:27:27Z; #4171.

`git grep` for `secrets enable`, `kv-v2`, `kv_v2` and `sys/mounts` returned zero
across the whole tree. Control, so the zero means something: `auth enable` in
this same file returns 2 — the same defect was already found and fixed once, for
the cert auth mount, with a comment that states the principle. This is the other
half of it.

The mount name is now bound once and interpolated into both the policy text and
the new step, because a grant and a mount that disagree is exactly the failure
being fixed.

Placed outside the client-CA block: the controller writes *through* this mount
regardless of whether anything can log in by certificate. `module-eval` asserts
that, since one indentation level decides it.

Grants, measured against a real openbao 2.6.2 rather than derived:
`-output-policy` asks for `sys/mounts/secret` create+update, and a token holding
exactly `sys/mounts` read + `sys/mounts/<path>` create/update enabled the engine
— **no `sudo`**, unlike `sys/auth/cert`. Negative control: the same token on an
ungranted path got 403, so the grant is what made it work. `setup.md`'s
documented policy gains those two.

Also from that session, each deciding how this is written: re-enabling an
existing path errors (exit 2), so this asks first like the auth mount does;
`secrets list -format=json` keys look like `"secret/"`, so the `case` idiom
ports over; and `kv put -mount=<p>` reports `<p>/data/...`, confirming v2 — the
prefix the policy grants and the client writes.

setup.md also drops a check that cannot work: it told the operator to confirm
with `bao read auth/cert/…`, which 403s because the host wrapper carries no
token. `systemctl status swarm-bao-controller-policy` needs no credential and
names the three success lines. The first-attempt-after-rebuild race is now
written down too — the store is still coming up, and the 30s retry is what
lands.

Refs #4171.
2026-09-11 00:16:46 +02:00
atlas
4bb44daf03 swarm-nats, swarm-victorialogs: correct two comments that describe a topology we do not have
Both claims are load-bearing prose, and both are wrong in a way nothing in
the tree reads (#4168).

swarm-nats says the queue is "reachable from every agent container on the
hive" because the container shares the host netns — in a comment, and again
in the operator-facing `calloutUserPublicKey` description, which renders into
the options doc. Agent containers do not share it: `PRIVATE_NETWORK=1` is
written unconditionally (hive-priv/src/main.rs, and hive-priv-sock says
"isolation is the only supported mode"), and hive-network.nix states the
shared-netns mode was removed. The bridge firewall opens 53/67/80/443 plus
`exposeHostPorts`, whose only consumer tree-wide is otel — the queue's port is
in none of them, and no gateway route exists either (`grep -c nats` in
hive-gateway/default.nix -> 0; control `forge` -> 3, so the zero means
something). Its actual clients are host-side: HIVE_C0RE_NATS_URL and
SWARM_CONTROLLER_NATS_URL, both 127.0.0.1 on a single-host swarm, plus each
remote hive dialling a routable address.

swarm-victorialogs says the ingest endpoint has "no authentication of its
own". Upstream offers Basic Auth via -httpAuth.username / -httpAuth.password
(and -metricsAuthKey / -deleteAuthKey / -pprofAuthKey); this module sets none
of it. "The software offers nothing" and "we configure nothing" send a later
reader to different places, so the wording now says the second one.

Neither conclusion changes. The queue must still refuse everyone until the
callout responder exists, and the logs endpoint must still be pinned to
loopback — only the reasons were false.

Checked while here: swarm-authelia's identical "no authentication of its own"
is TRUE (upstream's telemetry.metrics has exactly enabled, address, buffers,
timeouts), and otel.nix's "reachable from agent containers and nowhere else"
is true and better-founded than it claims — the receiver binds the bridge IP,
not just a firewall hole.

Refs #4168.
2026-09-10 23:18:40 +02:00
atlas
16182c670e swarm-bao: write the first grant from the host, not the container
`swarm-bao-controller-policy` creates the `swarm-controller` policy and
cert-auth role — the credential every hive logs in with. It has never
succeeded on any deployment, and the reason is where it ran.

Inside the container it had neither of the two things the store demands.
Its `BAO_ADDR` was the public DNS name, which from that netns resolves to
the hive bridge: `dial tcp 10.42.0.1:8200: connect: connection refused`.
And every API listener carries `tls_require_and_verify_client_cert`, while
`tlsDir` holds the server's leaf and the CA that signs clients — no client
identity at all. Fixing only the address moves the failure one hop.

The comment above the unit asserted the opposite — that in there the store
is "reachable without a client certificate at all, which is the point". The
listener config decides that, and says otherwise. That belief is what put
the unit in the container, so it goes with it.

On the host all four coordinates already exist: `baoCli` carries the
address, the CA, the certificate and the key, so the unit needs no
`environment` block at all. `bootstrapTokenFile` was always a host path —
the container only saw it through a bind mount. Nothing new crosses the
boundary; the mount gets no wider.

The retry bound is resized with it. 10 attempts at 30s is five minutes,
and under `seal = "shamir"` an operator unseals by hand, so it would give
up before a human arrived — permanently, because `start-limit-hit` does
not self-heal. That is the same silent no-bootstrap this issue is about.
2880 × 30s covers a day, inside a 25h window.

module-eval follows the unit to the host and gains an arm asserting it is
NOT rendered inside the container: the move is the fix, so the side it
landed on is worth pinning.
2026-09-10 22:19:48 +02:00
atlas
20da007351 swarm-bao: bound the granting unit's restarts for real
`StartLimitBurst` sat in `serviceConfig`, so it rendered into `[Service]`,
where systemd silently ignores it — the unit retried every 30s forever.
Measured on a live store: the journal reports `restart counter is at 18`
against a burst of 10.

This repo already states the rule and pins it with a test:
`hive-priv/src/main.rs` renders its drop-in with `StartLimit*` under
`[Unit]` and says why — "systemd silently ignores them under `[Service]`,
so a bound that moved sections would look configured and do nothing".
That is exactly what happened here, in another module.

Moving the burst alone would not have fixed it. systemd's default window
is 10s while `RestartSec = 30`, so at most one restart falls inside it and
a burst of 10 is unreachable; the interval has to exceed `RestartSec` times
the burst. 600 matches the value hive-priv already uses.

Uses the NixOS service-level options rather than a hand-written
`unitConfig`: nixpkgs renders `startLimitBurst` / `startLimitIntervalSec`
into `unitConfig` itself (`nixos/lib/systemd-lib.nix`), and `hive-ci.nix`
already sets `startLimitIntervalSec` that way.

The module-eval case asserts placement where nixpkgs puts it, and that
`serviceConfig` does not carry it — so moving it back fails the build.
2026-09-10 22:19:48 +02:00
atlas
c24dd03485 swarm-bao: put a wrapped bao on the host, with this store's coordinates
Reading a role out of the store took four round-trips of environment
guessing: the certificate has no IP SAN so loopback cannot verify, the
DNS name resolves to the bridge from inside the container, and the CA
the client needs lives on the host, which had no `bao` at all.

The wrapper carries the address, the server CA and — where the PKI glue
minted one — the reader's own leaf, so cert-auth login needs nothing
typed. `--set-default` throughout: an operator pointing BAO_ADDR
elsewhere still wins.

Only the wrapper reaches PATH. `wrapProgram` renames the real binary,
so there is no unwrapped `bao` to reach by accident, and the module-eval
case asserting the package's absence is what keeps a later "install it
too" from undoing that.
2026-09-10 14:56:26 +02:00
atlas
c22db5eb57 swarm-bao-tls: drop the unreachable CN fallback
`clientCn` fell back to `cfg.domain` when `hiveName` was unset. That branch
cannot run: `hive-network.nix` asserts `hiveName != null` under
`mkIf services.hyperhive.enable`, and this file's `config` is gated on the same
predicate, so any host that evaluates the conditional has already failed the
assertion.

Worse than dead, it read as a second supported spelling of a hive's identity —
which is what a cert-auth role matches on. It was not even the hive's own
domain: `cfg` here is `services.hyperhive.swarm.bao`, so the fallback resolved
to the store's address, one string shared by every hive in the swarm and the
same CN the server leaf carries.

Reading the option directly matches what other modules needing the name already
do (`hive-c0re/environment.nix`).
2026-09-10 00:25:07 +02:00
atlas
7f9e65e923 swarm-controller: hand the daemon the authority hives are issued from
Creating a hive's cert-auth role means writing the authority into the role
by value -- the store matches a presented certificate against the role's own
copy -- and nothing gave this daemon that file.

Named separately from deploy.bao.clientCaFile rather than read off it: that
option is the store's, saying which readers the store trusts on the host
that runs it, while a controller runs anywhere. The glue module supplies it
where the two are co-located, which is the same split baoClientCertFile
already makes against the hive reader's leaf.

Gated on the identity as well as the CA. Without a leaf there is nothing to
write a role with, so the file would reach a daemon that cannot act on it.

The module-eval arm needed a fixture of its own: a deployment that
self-signs both ends points clientCaFile and serverCaFile at one file, so on
the existing fixture the two authorities are the same string and wiring
either into the other's slot passes. controllerTwoCas is where they differ.
2026-09-10 00:25:07 +02:00
damocles
561bd09618 subagent: close the start/continue TOCTOU race with an atomic reservation 2026-09-09 23:45:12 +02:00
damocles
c280664d74 nix: wire the independent hive-subagent-daemon systemd unit and MCP server 2026-09-09 23:45:12 +02:00
atlas
cc8fb0ee44 swarm-bao: let the controller write agent credentials, and gate that it can
Closes #4124.

The controller's policy granted only the bootstrap paths -- hive cert-auth
roles and hive ACLs. #4113 then made it a secret WRITER, and nothing related
the grants to the paths the code writes, so every matrix token provision
answered 403. The two halves landed on different issues and neither looked
wrong on its own.

`secret/data/` is KV v2's ACL prefix and is absent from the path the code
passes, so matching `swarm-secret-client`'s spelling literally would have
granted nothing. Write-only: the controller mints these and never reads one
back, and a read capability would let it recover every agent's credentials
rather than only replace them.

The gate is the point. Two module-eval arms -- the grant exists and is not
a broader wildcard, and its capability list is pinned whole, because an
ADDED capability is what a presence check misses -- plus a test in path.rs
pinning MOUNT/AGENT_PREFIX and naming the nix file, since renaming either
constant is a silent 403 rather than a compile error.

setup.md carried two warnings this makes false: that nothing in the tree had
ever authenticated to the store, and that no deployment shape mints a leaf
whose CN reads swarm-controller. glue-bao-tls.nix has minted one since #3726
item 1.
2026-09-09 01:19:57 +02:00
atlas
0d88ca5e7f swarm-controller: accept an agent's external matrix account and put it in the store
The swarm UI had nowhere to POST an external matrix account to: this daemon
had no matrix-account code at all and no `swarm-secret-client` dependency, so
the last leg of #3726 — a credential reaching an agent — had no entry point.

`PUT /api/hives/{hive}/agents/{agent}/matrix-accounts/{account}` writes the
credential to the store under the agent's own path and publishes a
`CredentialNotice` on that hive's credential subject. All three path names are
load-bearing: agent + account locate the secret, hive routes the notice. The
account is a path segment rather than a body field so that splitting the 1:1
account-to-agent mapping later is a new route, not a changed payload.

Store first, notify second, and the order cannot be swapped: a notice that
overtakes its own write reaches a hive that reads nothing, and the hive
deliberately does not retry. The publish is followed by a flush for the reason
`publish_deploy` flushes — `publish` hands the message to the connection's
write buffer and returns, so the response could otherwise outrun the notice it
reports as sent.

The store client is built per request rather than held in `AppState`, matching
what the hive side does inside `deliver`: a login that expires is not worth
caching for a route this cold.

`swarm_hive` is `declaration_target`'s two name checks, extracted so this
handler makes them identically rather than in a second copy free to drift.
`declaration_target` still tests the writer first, so a deployment with no
queue answers 503 whatever the caller spelled.

## The nix half

#4081 minted the controller's leaf and gave it `baoClientCertFile` /
`baoClientKeyFile`, deliberately stopping there — the leaf is minted whether or
not a controller runs on that host. Nothing consumed those options, so the
identity never reached the process. Measured before writing: `git grep
baoClientCertFile` returned 5 sites and zero consumers, against a control
(`tokenEndpoint`, 4 hits in the same file) proving the search can see
consumption where it exists.

The unit now gets `BAO_ADDR` / `BAO_CLIENT_CERT` / `BAO_CLIENT_KEY` /
`BAO_CACERT` and the matching `LoadCredential` entries, following
`hive-c0re/environment.nix`'s `%d` credential shape.

The gate is `deploy.swarm-controller.baoClientCertFile`, NOT
`deploy.bao.clientCertFile`. The latter is the hive reader's identity and its
policy scopes a hive's own secrets; wiring it here would evaluate, deploy, and
fail only when the daemon tried to write an agent's credential.

Two `module-eval` arms cover exactly that. The presence arm asserts the
`LoadCredential` *source path* (`…:/var/lib/swarm-bao-pki/controller.pem`) and
not just the `%d` name, because a `%d`-only assertion passes while the daemon
holds the wrong policy. The absence arm (`controllerNoStore`) is what makes the
presence arm mean anything.

`RestrictAddressFamilies` already covers the store client; its own comment asks
for the family to be added with the client, and AF_INET/AF_INET6 are present.

Contributes to #3726
2026-09-08 15:53:50 +02:00
atlas
a204b5f457 grafana: show which sources are shipping, not just that the store is up
The log-store board reports rows ingested, disk size, free disk and errors —
every one of them a fact about VictoriaLogs itself. None of them can say
whether a particular unit or host is contributing, so aggregate ingestion
reads healthy on host-tier units while a whole tier ships nothing, and there
was no way to tell those apart from a dashboard.

Add four panels to that board rather than a second one. Every other board here
is per service — agents, authelia, openbao, forge, queue, the two stores — so
a second board about the same service would have made an operator guess which
of the two answers their question.

Nothing in the new panels names a unit: both breakdowns discover their rows
from the data, so a source that starts shipping appears without an edit, and
one that never existed is simply not there.

The ungrouped total is a control, not a summary. An empty breakdown renders
the same whether the query is malformed or the source genuinely never shipped;
with the total beside it, nonzero-and-empty is a broken query and
zero-and-empty is an empty store. Being on one board buys a second reading it
could not have alone: that total and `Log rows ingested` are the same quantity
measured by querying and from the store's own metrics, so the two disagreeing
means rows arrived that no query can reach — which is the failure this
pipeline actually had once.

The two breakdowns are bargauges rather than tables. A `stats` query returns
one frame per group, and a table panel renders one frame at a time behind a
series picker; bargauge consumes multi-series natively, for the same reason
the timeseries beside it always did. The alternative was a table plus
labelsToFields plus merge plus organize — three assumptions where this needs
none, in a spot I cannot render to check.

Series are named by their label rather than `rows{_SYSTEMD_UNIT="x.service"}`,
which also cleans up the timeseries legend. The datasource supports
legendFormat; its query editor's own placeholder is `{{label}}`.

These are the first panels to query the logs datasource at all; the other
eight boards are prometheus, including this one until now, which reads
VictoriaLogs' self-metrics out of VictoriaMetrics. So `renderDashboard` grows
a `@logsDatasourceUid@` substitution alongside the metrics one. The binding it
points at already existed, and its comment claiming a dashboard panel named it
only becomes true with this commit.

The uid is unchanged, so existing links and bookmarks still resolve; only the
title widens to match what the board now covers.

The query model was read out of the plugin in the store rather than guessed:
`queryType` is one of hits/instant/logs/stats/statsRange, and Stats/StatsRange
are the two that consume `expr`. The stream field names come from the module
that builds them — swarm-otel.nix's `_stream_fields=_HOSTNAME,_SYSTEMD_UNIT`.
The queries themselves are confirmed against the live store: mara ran the
by-unit one over seven days and it returned rows.

Refs #4084
2026-09-08 00:43:23 +02:00
damocles
66c3138dd1 hive-c0re: grant hive-admin group a polkit rule for choom 2026-09-07 23:27:15 +02:00