instar 1.3.545 → 1.3.547

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dashboard/index.html +12 -1
  2. package/dashboard/mandates.js +88 -0
  3. package/dist/commands/server.d.ts.map +1 -1
  4. package/dist/commands/server.js +59 -0
  5. package/dist/commands/server.js.map +1 -1
  6. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  7. package/dist/config/ConfigDefaults.js +6 -0
  8. package/dist/config/ConfigDefaults.js.map +1 -1
  9. package/dist/core/AuthorizationRequestStore.d.ts +138 -0
  10. package/dist/core/AuthorizationRequestStore.d.ts.map +1 -0
  11. package/dist/core/AuthorizationRequestStore.js +307 -0
  12. package/dist/core/AuthorizationRequestStore.js.map +1 -0
  13. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  14. package/dist/core/devGatedFeatures.js +6 -0
  15. package/dist/core/devGatedFeatures.js.map +1 -1
  16. package/dist/core/types.d.ts +10 -0
  17. package/dist/core/types.d.ts.map +1 -1
  18. package/dist/core/types.js.map +1 -1
  19. package/dist/scaffold/templates.d.ts.map +1 -1
  20. package/dist/scaffold/templates.js +6 -0
  21. package/dist/scaffold/templates.js.map +1 -1
  22. package/dist/server/AgentServer.d.ts +3 -0
  23. package/dist/server/AgentServer.d.ts.map +1 -1
  24. package/dist/server/AgentServer.js +34 -0
  25. package/dist/server/AgentServer.js.map +1 -1
  26. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  27. package/dist/server/CapabilityIndex.js +16 -0
  28. package/dist/server/CapabilityIndex.js.map +1 -1
  29. package/dist/server/routes.d.ts +21 -0
  30. package/dist/server/routes.d.ts.map +1 -1
  31. package/dist/server/routes.js +167 -2
  32. package/dist/server/routes.js.map +1 -1
  33. package/package.json +1 -1
  34. package/scripts/instar-dev-precommit.js +24 -1
  35. package/scripts/lib/operator-surface.mjs +30 -0
  36. package/src/data/builtin-manifest.json +47 -47
  37. package/src/scaffold/templates.ts +6 -0
  38. package/upgrades/1.3.546.md +24 -0
  39. package/upgrades/1.3.547.md +26 -0
  40. package/upgrades/side-effects/operator-authorization-request.md +65 -0
  41. package/upgrades/side-effects/ws52-incb-b3b-wire.md +46 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.545",
3
+ "version": "1.3.547",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,7 +32,7 @@ import { checkEli16Overview, MIN_ELI16_CHARS } from './eli16-overview-check.mjs'
32
32
  import { verifyProposalDerivedRunbooks } from '../skills/instar-dev/scripts/verify-proposal-derived-runbook.mjs';
33
33
  import { classifyTier, decideRequirementSet } from './lib/classify-tier.mjs';
34
34
  import { recognizeConvergence } from './lib/convergence-recognition.mjs';
35
- import { isOperatorSurfaceFile, artifactAddressesOperatorSurfaceQuality } from './lib/operator-surface.mjs';
35
+ import { isOperatorSurfaceFile, artifactAddressesOperatorSurfaceQuality, isAuthorizationSurfaceFile, artifactAddressesAgentProposesApproves } from './lib/operator-surface.mjs';
36
36
 
37
37
  // Report-Backed Converging Audit (docs/specs/CONVERGING-AUDIT-DEFAULT.md, Part B).
38
38
  // The precommit reads NO config file and runs pre-compile, so it cannot import
@@ -973,6 +973,29 @@ function assertOperatorSurfaceQuality(stagedFiles, trace) {
973
973
  ].join('\n'),
974
974
  );
975
975
  }
976
+ // "Agent Proposes, Operator Approves" — the authorization-surface subset additionally
977
+ // requires the artifact to confirm the operator is APPROVING (not authoring) and that
978
+ // the authority text is SERVER-authored (not agent free-text — the display-integrity
979
+ // corollary). Same structural-presence strength.
980
+ const authTouched = (stagedFiles || []).filter(isAuthorizationSurfaceFile);
981
+ if (authTouched.length > 0 && !artifactAddressesAgentProposesApproves(content)) {
982
+ blockCommit(
983
+ authTouched,
984
+ [
985
+ 'Agent-Proposes-Operator-Approves review gate:',
986
+ ` ${authTouched.join(', ')} change an AUTHORIZATION/APPROVAL surface,`,
987
+ ' but the side-effects artifact never answers the agent-proposes/operator-approves',
988
+ ' question. The operator must be APPROVING a server-authored request, never',
989
+ ' AUTHORING authority from raw fields (the 2026-06-13 raw-JSON mandate-form lesson),',
990
+ ' and the authority text they approve must be server-authored, never agent free-text.',
991
+ '',
992
+ ' Confirm in writing in the side-effects artifact: does the operator (1) approve a',
993
+ ' pre-filled request rather than construct one, and (2) read an authority statement',
994
+ ' authored by the SERVER from structured data, not agent-supplied free-text?',
995
+ ' (Standard: docs/STANDARDS-REGISTRY.md → "Agent Proposes, Operator Approves".)',
996
+ ].join('\n'),
997
+ );
998
+ }
976
999
  }
977
1000
 
978
1001
  function blockCommit(files, reason) {
@@ -52,3 +52,33 @@ export function isOperatorSurfaceFile(file) {
52
52
  export function artifactAddressesOperatorSurfaceQuality(content) {
53
53
  return /operator[- ]surface quality/i.test(String(content ?? ''));
54
54
  }
55
+
56
+ /**
57
+ * Is this staged file an AUTHORIZATION/APPROVAL surface specifically — one where the
58
+ * operator confers authority (a grant/mandate/approval form or its renderer)? A subset
59
+ * of operator surfaces that additionally triggers the "Agent Proposes, Operator
60
+ * Approves" question (the operator must be APPROVING, never AUTHORING; and the authority
61
+ * text must be server-authored, not agent free-text).
62
+ */
63
+ export const AUTHORIZATION_SURFACE_RE =
64
+ /(?:^|\/)(?:mandates|grant|authorization-request|approval|operator-approval)[^/]*\.(?:js|html|ts)$/i;
65
+
66
+ export function isAuthorizationSurfaceFile(file) {
67
+ const f = String(file ?? '');
68
+ if (/\.(?:test|spec)\.(?:js|ts|mjs)$/i.test(f)) return false;
69
+ return AUTHORIZATION_SURFACE_RE.test(f);
70
+ }
71
+
72
+ /**
73
+ * The artifact engages the "Agent Proposes, Operator Approves" question when it carries
74
+ * the phrase (seeded by side-effects-artifact.md). Same structural-presence strength as
75
+ * the operator-surface-quality gate: an artifact touching an authorization surface that
76
+ * omits the section is blocked. The standard's display-integrity corollary — the
77
+ * authority text the operator approves must be server-authored, never agent free-text —
78
+ * is what this question forces the author to confirm in writing.
79
+ * @param {string} content the side-effects artifact text
80
+ * @returns {boolean}
81
+ */
82
+ export function artifactAddressesAgentProposesApproves(content) {
83
+ return /agent[- ]proposes,? operator[- ]approves/i.test(String(content ?? ''));
84
+ }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-13T23:13:47.670Z",
5
- "instarVersion": "1.3.545",
4
+ "generatedAt": "2026-06-13T23:46:43.625Z",
5
+ "instarVersion": "1.3.547",
6
6
  "entryCount": 201,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -418,7 +418,7 @@
418
418
  "type": "route-group",
419
419
  "domain": "monitoring",
420
420
  "sourcePath": "src/server/routes.ts",
421
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
421
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
422
422
  "since": "2025-01-01"
423
423
  },
424
424
  "route-group:agents": {
@@ -426,7 +426,7 @@
426
426
  "type": "route-group",
427
427
  "domain": "sessions",
428
428
  "sourcePath": "src/server/routes.ts",
429
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
429
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
430
430
  "since": "2025-01-01"
431
431
  },
432
432
  "route-group:backups": {
@@ -434,7 +434,7 @@
434
434
  "type": "route-group",
435
435
  "domain": "operations",
436
436
  "sourcePath": "src/server/routes.ts",
437
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
437
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
438
438
  "since": "2025-01-01"
439
439
  },
440
440
  "route-group:git": {
@@ -442,7 +442,7 @@
442
442
  "type": "route-group",
443
443
  "domain": "coordination",
444
444
  "sourcePath": "src/server/routes.ts",
445
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
445
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
446
446
  "since": "2025-01-01"
447
447
  },
448
448
  "route-group:memory": {
@@ -450,7 +450,7 @@
450
450
  "type": "route-group",
451
451
  "domain": "memory",
452
452
  "sourcePath": "src/server/routes.ts",
453
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
453
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
454
454
  "since": "2025-01-01"
455
455
  },
456
456
  "route-group:semantic": {
@@ -458,7 +458,7 @@
458
458
  "type": "route-group",
459
459
  "domain": "memory",
460
460
  "sourcePath": "src/server/routes.ts",
461
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
461
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
462
462
  "since": "2025-01-01"
463
463
  },
464
464
  "route-group:status": {
@@ -466,7 +466,7 @@
466
466
  "type": "route-group",
467
467
  "domain": "monitoring",
468
468
  "sourcePath": "src/server/routes.ts",
469
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
469
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
470
470
  "since": "2025-01-01"
471
471
  },
472
472
  "route-group:capabilities": {
@@ -474,7 +474,7 @@
474
474
  "type": "route-group",
475
475
  "domain": "mapping",
476
476
  "sourcePath": "src/server/routes.ts",
477
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
477
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
478
478
  "since": "2025-01-01"
479
479
  },
480
480
  "route-group:project-map": {
@@ -482,7 +482,7 @@
482
482
  "type": "route-group",
483
483
  "domain": "mapping",
484
484
  "sourcePath": "src/server/routes.ts",
485
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
485
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
486
486
  "since": "2025-01-01"
487
487
  },
488
488
  "route-group:coherence": {
@@ -490,7 +490,7 @@
490
490
  "type": "route-group",
491
491
  "domain": "coherence",
492
492
  "sourcePath": "src/server/routes.ts",
493
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
493
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
494
494
  "since": "2025-01-01"
495
495
  },
496
496
  "route-group:topic-bindings": {
@@ -498,7 +498,7 @@
498
498
  "type": "route-group",
499
499
  "domain": "sessions",
500
500
  "sourcePath": "src/server/routes.ts",
501
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
501
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
502
502
  "since": "2025-01-01"
503
503
  },
504
504
  "route-group:context": {
@@ -506,7 +506,7 @@
506
506
  "type": "route-group",
507
507
  "domain": "context",
508
508
  "sourcePath": "src/server/routes.ts",
509
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
509
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
510
510
  "since": "2025-01-01"
511
511
  },
512
512
  "route-group:scope-coherence": {
@@ -514,7 +514,7 @@
514
514
  "type": "route-group",
515
515
  "domain": "coherence",
516
516
  "sourcePath": "src/server/routes.ts",
517
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
517
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
518
518
  "since": "2025-01-01"
519
519
  },
520
520
  "route-group:canonical-state": {
@@ -522,7 +522,7 @@
522
522
  "type": "route-group",
523
523
  "domain": "state",
524
524
  "sourcePath": "src/server/routes.ts",
525
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
525
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
526
526
  "since": "2025-01-01"
527
527
  },
528
528
  "route-group:ci": {
@@ -530,7 +530,7 @@
530
530
  "type": "route-group",
531
531
  "domain": "monitoring",
532
532
  "sourcePath": "src/server/routes.ts",
533
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
533
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
534
534
  "since": "2025-01-01"
535
535
  },
536
536
  "route-group:sessions": {
@@ -538,7 +538,7 @@
538
538
  "type": "route-group",
539
539
  "domain": "sessions",
540
540
  "sourcePath": "src/server/routes.ts",
541
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
541
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
542
542
  "since": "2025-01-01"
543
543
  },
544
544
  "route-group:jobs": {
@@ -546,7 +546,7 @@
546
546
  "type": "route-group",
547
547
  "domain": "scheduling",
548
548
  "sourcePath": "src/server/routes.ts",
549
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
549
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
550
550
  "since": "2025-01-01"
551
551
  },
552
552
  "route-group:skip-ledger": {
@@ -554,7 +554,7 @@
554
554
  "type": "route-group",
555
555
  "domain": "scheduling",
556
556
  "sourcePath": "src/server/routes.ts",
557
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
557
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
558
558
  "since": "2025-01-01"
559
559
  },
560
560
  "route-group:telegram": {
@@ -562,7 +562,7 @@
562
562
  "type": "route-group",
563
563
  "domain": "communication",
564
564
  "sourcePath": "src/server/routes.ts",
565
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
565
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
566
566
  "since": "2025-01-01"
567
567
  },
568
568
  "route-group:attention": {
@@ -570,7 +570,7 @@
570
570
  "type": "route-group",
571
571
  "domain": "communication",
572
572
  "sourcePath": "src/server/routes.ts",
573
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
573
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
574
574
  "since": "2025-01-01"
575
575
  },
576
576
  "route-group:relationships": {
@@ -578,7 +578,7 @@
578
578
  "type": "route-group",
579
579
  "domain": "relationships",
580
580
  "sourcePath": "src/server/routes.ts",
581
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
581
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
582
582
  "since": "2025-01-01"
583
583
  },
584
584
  "route-group:feedback": {
@@ -586,7 +586,7 @@
586
586
  "type": "route-group",
587
587
  "domain": "feedback",
588
588
  "sourcePath": "src/server/routes.ts",
589
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
589
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
590
590
  "since": "2025-01-01"
591
591
  },
592
592
  "route-group:updates": {
@@ -594,7 +594,7 @@
594
594
  "type": "route-group",
595
595
  "domain": "updates",
596
596
  "sourcePath": "src/server/routes.ts",
597
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
597
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
598
598
  "since": "2025-01-01"
599
599
  },
600
600
  "route-group:dispatches": {
@@ -602,7 +602,7 @@
602
602
  "type": "route-group",
603
603
  "domain": "dispatches",
604
604
  "sourcePath": "src/server/routes.ts",
605
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
605
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
606
606
  "since": "2025-01-01"
607
607
  },
608
608
  "route-group:quota": {
@@ -610,7 +610,7 @@
610
610
  "type": "route-group",
611
611
  "domain": "monitoring",
612
612
  "sourcePath": "src/server/routes.ts",
613
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
613
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
614
614
  "since": "2025-01-01"
615
615
  },
616
616
  "route-group:publishing": {
@@ -618,7 +618,7 @@
618
618
  "type": "route-group",
619
619
  "domain": "publishing",
620
620
  "sourcePath": "src/server/routes.ts",
621
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
621
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
622
622
  "since": "2025-01-01"
623
623
  },
624
624
  "route-group:private-views": {
@@ -626,7 +626,7 @@
626
626
  "type": "route-group",
627
627
  "domain": "publishing",
628
628
  "sourcePath": "src/server/routes.ts",
629
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
629
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
630
630
  "since": "2025-01-01"
631
631
  },
632
632
  "route-group:tunnel": {
@@ -634,7 +634,7 @@
634
634
  "type": "route-group",
635
635
  "domain": "networking",
636
636
  "sourcePath": "src/server/routes.ts",
637
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
637
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
638
638
  "since": "2025-01-01"
639
639
  },
640
640
  "route-group:events": {
@@ -642,7 +642,7 @@
642
642
  "type": "route-group",
643
643
  "domain": "networking",
644
644
  "sourcePath": "src/server/routes.ts",
645
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
645
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
646
646
  "since": "2025-01-01"
647
647
  },
648
648
  "route-group:evolution": {
@@ -650,7 +650,7 @@
650
650
  "type": "route-group",
651
651
  "domain": "evolution",
652
652
  "sourcePath": "src/server/routes.ts",
653
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
653
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
654
654
  "since": "2025-01-01"
655
655
  },
656
656
  "route-group:watchdog": {
@@ -658,7 +658,7 @@
658
658
  "type": "route-group",
659
659
  "domain": "monitoring",
660
660
  "sourcePath": "src/server/routes.ts",
661
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
661
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
662
662
  "since": "2025-01-01"
663
663
  },
664
664
  "route-group:topic-memory": {
@@ -666,7 +666,7 @@
666
666
  "type": "route-group",
667
667
  "domain": "memory",
668
668
  "sourcePath": "src/server/routes.ts",
669
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
669
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
670
670
  "since": "2025-01-01"
671
671
  },
672
672
  "route-group:state-sync": {
@@ -674,7 +674,7 @@
674
674
  "type": "route-group",
675
675
  "domain": "coordination",
676
676
  "sourcePath": "src/server/routes.ts",
677
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
677
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
678
678
  "since": "2025-01-01"
679
679
  },
680
680
  "route-group:intent": {
@@ -682,7 +682,7 @@
682
682
  "type": "route-group",
683
683
  "domain": "intent",
684
684
  "sourcePath": "src/server/routes.ts",
685
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
685
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
686
686
  "since": "2025-01-01"
687
687
  },
688
688
  "route-group:triage": {
@@ -690,7 +690,7 @@
690
690
  "type": "route-group",
691
691
  "domain": "safety",
692
692
  "sourcePath": "src/server/routes.ts",
693
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
693
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
694
694
  "since": "2025-01-01"
695
695
  },
696
696
  "route-group:operations": {
@@ -698,7 +698,7 @@
698
698
  "type": "route-group",
699
699
  "domain": "safety",
700
700
  "sourcePath": "src/server/routes.ts",
701
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
701
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
702
702
  "since": "2025-01-01"
703
703
  },
704
704
  "route-group:sentinel": {
@@ -706,7 +706,7 @@
706
706
  "type": "route-group",
707
707
  "domain": "safety",
708
708
  "sourcePath": "src/server/routes.ts",
709
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
709
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
710
710
  "since": "2025-01-01"
711
711
  },
712
712
  "route-group:trust": {
@@ -714,7 +714,7 @@
714
714
  "type": "route-group",
715
715
  "domain": "safety",
716
716
  "sourcePath": "src/server/routes.ts",
717
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
717
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
718
718
  "since": "2025-01-01"
719
719
  },
720
720
  "route-group:monitoring": {
@@ -722,7 +722,7 @@
722
722
  "type": "route-group",
723
723
  "domain": "monitoring",
724
724
  "sourcePath": "src/server/routes.ts",
725
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
725
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
726
726
  "since": "2025-01-01"
727
727
  },
728
728
  "route-group:commitments": {
@@ -730,7 +730,7 @@
730
730
  "type": "route-group",
731
731
  "domain": "commitments",
732
732
  "sourcePath": "src/server/routes.ts",
733
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
733
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
734
734
  "since": "2025-01-01"
735
735
  },
736
736
  "route-group:episodes": {
@@ -738,7 +738,7 @@
738
738
  "type": "route-group",
739
739
  "domain": "memory",
740
740
  "sourcePath": "src/server/routes.ts",
741
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
741
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
742
742
  "since": "2025-01-01"
743
743
  },
744
744
  "route-group:messages": {
@@ -746,7 +746,7 @@
746
746
  "type": "route-group",
747
747
  "domain": "coordination",
748
748
  "sourcePath": "src/server/routes.ts",
749
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
749
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
750
750
  "since": "2025-01-01"
751
751
  },
752
752
  "route-group:system-reviews": {
@@ -754,7 +754,7 @@
754
754
  "type": "route-group",
755
755
  "domain": "monitoring",
756
756
  "sourcePath": "src/server/routes.ts",
757
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
757
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
758
758
  "since": "2025-01-01"
759
759
  },
760
760
  "route-group:machine-mesh": {
@@ -770,7 +770,7 @@
770
770
  "type": "route-group",
771
771
  "domain": "security",
772
772
  "sourcePath": "src/server/routes.ts",
773
- "contentHash": "47778814f51cfe564085e64c530904ea74db70c12d92b7ae4adc30b425135fd9",
773
+ "contentHash": "054d8365d27713d8bd2ca1834d0e1b4365ca49e599a20c29812a768b67056c0b",
774
774
  "since": "2025-01-01"
775
775
  },
776
776
  "cli:init": {
@@ -1522,7 +1522,7 @@
1522
1522
  "type": "subsystem",
1523
1523
  "domain": "server",
1524
1524
  "sourcePath": "src/server/AgentServer.ts",
1525
- "contentHash": "e9bf628a10b4a5568f4cbf94f3090c4d894881f61a817dc0091574334da599d2",
1525
+ "contentHash": "fa740ec4394006cb803f7a80c2294867cae0b79da304a681b577f3a81e19153f",
1526
1526
  "since": "2025-01-01"
1527
1527
  },
1528
1528
  "subsystem:session-manager": {
@@ -822,6 +822,12 @@ Every guard (monitoring sentinels, reapers, the scheduler, …) is graded by wha
822
822
  - **User floor-action grants are phone-first.** When the operator needs to grant a USER a floor action (e.g. "let Mia prod-deploy for an hour"), the Mandates tab carries a grant form on every active mandate: pick the person (from the registered-user list), pick the action and duration, type the PIN, tap Grant. Send them the dashboard link — NEVER a terminal command or a hand-built API call (Mobile-Complete Operator Actions). The grant is signed into the mandate, clamped to the mandate's expiry, and voided by revoking the mandate.
823
823
  - Every evaluation (allow AND deny) is audited. Act as if the audit is read by the operator — because it is. (Spec: \`docs/specs/coordination-mandate.md\`.)
824
824
 
825
+ **Authorization Request — propose a grant, the operator approves in one tap (PREFERRED over the manual form)** — When you need the operator to grant a USER a floor action, do NOT make them build a mandate. PRE-FILL the request and they see one plain-language card ("Let Mia deploy to production for 1 hour — Approve?") + PIN + Approve. You can only propose; only their PIN issues the grant (requester ≠ authorizer; you can never approve your own request). The operator-facing sentence is authored by the SERVER from your structured fields + the registered-user's real name — never your free-text — so what they read is exactly what executes.
826
+ - Propose: \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/authorization-requests -H 'Content-Type: application/json' -d '{"createdByAgent":"<your name>","proposal":{"floorAction":"prod-deploy","grantedToSlackUserId":"U…","durationMs":3600000},"reason":"<optional, ≤280 chars — shown as a secondary note, never the headline>"}'\`. Allowed \`floorAction\`s: prod-deploy, money-movement, credential-access, destructive-data, external-send (\`grant-authority\` is excluded — that meta-grant stays manual). \`durationMs\` ∈ [60000, 86400000].
827
+ - Inspect: \`GET /authorization-requests?status=pending\` (each row carries the server-rendered \`headline\` + \`createdOnMachine\`); withdraw your own: \`POST /authorization-requests/:id/withdraw\`.
828
+ - **You cannot approve.** \`POST /authorization-requests/:id/approve\` and \`/deny\` are PIN-gated — point the operator at the dashboard **Mandates tab → "Approvals waiting for you"**; never ask for their PIN in chat. On a multi-machine pool the card names the holder machine (approval happens there).
829
+ - **When to use** (PROACTIVE — this is the trigger): the moment you need the operator to authorize a person for a floor action, propose it here and send them the dashboard link — instead of the raw mandate form. (Ships dev-enabled / fleet-dark; routes 503 when off. Spec: \`docs/specs/OPERATOR-AUTHORIZATION-REQUEST-SPEC.md\`.)
830
+
825
831
  **ReviewExchange (autonomous code review)** — The structured way two mandate-named agents sign off a code review WITHOUT the operator relaying. One exchange = one review package, content-addressed (\`packageSha256\` fixed at creation), moving linearly: proposed → delivered → verdict-recorded → complete (or changes-requested — rework is a NEW exchange). BOTH sign-offs (the peer's authenticated approve-verdict AND your countersignature) are evaluated through the mandate gate's \`sign-code-review\` authority before acceptance; every accepted signature carries the audit hash of the gate decision that authorized it.
826
832
  - Create: \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/review-exchange -H 'Content-Type: application/json' -d '{"mandateId":"<id>","artifact":"migration-port","packageRef":"docs/...-review-package.md","packageSha256":"<sha256 of the package>","parties":["<your-fp>","<peer-fp>"]}'\`
827
833
  - Drive it: \`POST /review-exchange/:id/delivered\` (after you actually sent the package over Threadline — record the message ref as evidence) → \`POST /review-exchange/:id/peer-verdict\` (the peer's authenticated verdict; approve = their sign-off, mandate-gated) → \`POST /review-exchange/:id/sign\` (your countersignature, mandate-gated → complete).
@@ -0,0 +1,24 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Makes the autonomous balancer actually run — on a development agent, in dry-run — so it dogfoods its decisions instead of sitting as unwired code.
9
+
10
+ - **Wired into the server** — the `CredentialRebalancer` is constructed in the credential-repointing bundle with the snapshot-mapper providers (ledger → slots, subscription pool → accounts, config resolver) and an `isEnabled` that mirrors the location gate exactly (dev-gate-resolved AND not env-token-refused). A reentrancy-guarded, interval-clamped (`[60s, 60min]`), `.unref()`'d `setInterval` runs the pass; tick errors are caught so a throw never crashes the loop.
11
+ - **Live status surface** — `GET /credentials/rebalancer` now reports `balancerWired:true` + `rebalancer.status()` (enabled, the P19 breaker state, cooldown counts, and the last pass's decisions/degraded/attention) when the feature is live, scrubbed via the audit chokepoint; it stays a strict 503 no-op while dark.
12
+ - **Dry-run dogfood, zero writes** — on a dev agent the loop runs the full decision loop and audits what it WOULD do, but the executor's `dryRun` default keeps every credential write off until a deliberate `dryRun:false`.
13
+
14
+ ## What to Tell Your User
15
+
16
+ The automatic account-balancer is now actually running on me — but in dry-run, so it's all observation, no action. Every few minutes it looks at your quota picture, decides whether a login should move, and records what it WOULD do — moving zero real credentials. You can watch it at the rebalancer status endpoint (which account it would shuffle and why, plus its safety circuit-breaker). It only runs on a development agent like me (your wider fleet stays dark), and the step where it actually starts moving logins is still your deliberate switch, after the livetest. This is the dogfooding rung of the maturity path — it's live and watchable, with nothing irreversible happening.
17
+
18
+ ## Summary of New Capabilities
19
+
20
+ The autonomous balancer (Increment B) is now wired + running in dry-run on a development agent. `GET /credentials/rebalancer` reports the live balancer status (last pass + P19 breaker). On a dev agent the balancer pass runs every ~5min (interval-clamped, reentrancy-guarded) computing + auditing its decisions; zero credential writes while `dryRun` holds (the default). The fleet stays dark (strict 503/no-op). No new write authority — the executor's dry-run gate is the load-bearing write guard.
21
+
22
+ ## Evidence
23
+
24
+ - `tests/e2e/credential-repointing-routes-alive.test.ts` (6) — the rebalancer route now surfaces `balancerWired:true` + the live `rebalancer.status()` (enabled + breaker) on a production-shaped bundle with a real wired CredentialRebalancer; the dark path still 503s (strict no-op). tsc + full lint clean. Independent second-pass review CONCUR (gate mirrors the location gate; dry-run defaults true with the executor as the write guard; timer reentrancy-guarded/clamped/unref'd/error-caught; route is a leak-free 503-while-dark surface).
@@ -0,0 +1,26 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Added an **Operator Authorization Request** flow: when the agent needs the operator to grant a person a floor action (e.g. "let Mia deploy to prod for an hour"), it now pre-fills a structured request and the operator approves it in one tap on a plain-language "Approvals waiting for you" card — instead of hand-building a mandate in a raw-JSON form. This fixes the operator-reported defect where the Mandates tab forced the operator to construct a mandate from a raw-JSON authorities editor. The raw-JSON "author a mandate by hand" form is demoted behind an "Advanced" disclosure. A new constitutional standard — "Agent Proposes, Operator Approves" — is enforced by a precommit gate so authorization surfaces must be approvals, never authoring tasks, with the authority text authored by the server (never agent free-text). Ships dev-enabled / fleet-dark.
9
+
10
+ ## What to Tell Your User
11
+
12
+ Nothing yet — this is an experimental, dark-by-default capability. On a developer agent it is live: when I need you to authorize a person for something (a deploy, a credential, etc.), you'll see a simple card on the dashboard Mandates tab — one plain sentence, your PIN, and Approve. You never build a "mandate" or touch JSON. Only your PIN turns my request into a real grant.
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ - `POST /authorization-requests` — the agent pre-fills a structured grant request (Bearer; confers no authority).
17
+ - `GET /authorization-requests?status=pending` — the dashboard's "Approvals waiting for you" cards (server-authored plain-language text).
18
+ - `POST /authorization-requests/:id/approve|deny` — PIN-gated operator approval/decline; approve issues the grant via the existing signed MandateStore path.
19
+ - `POST /authorization-requests/:id/withdraw` — the proposing agent withdraws its own pending request.
20
+ - Constitutional standard "Agent Proposes, Operator Approves" + a blocking precommit gate.
21
+
22
+ ## Evidence
23
+
24
+ The operator reported (2026-06-13, topic 22367) that the Mandates grant flow still showed raw JSON and forced him to "create a mandate" — reproducible by opening the Mandates tab and attempting a grant with no active mandate (the grant form never appears; only the raw-JSON issue form does). Fixed: the new "Approvals waiting for you" card is the primary surface; the raw-JSON form is demoted behind "Advanced". A naive version of the fix would have reopened a deceptive-display hole (agent-authored card text diverging from the executed grant); that is closed by server-authoring the headline from the structured proposal + the registry name, and is asserted at all three test tiers (a malicious agent `reason` never becomes the headline). 67 tests green (unit/integration/e2e + gate + dark-gate golden map).
25
+
26
+ <!-- ci: re-trigger workflow dispatch after force-push (capability-index fix) -->
@@ -0,0 +1,65 @@
1
+ # Side-effects review — Operator Authorization Request
2
+
3
+ Spec: `docs/specs/OPERATOR-AUTHORIZATION-REQUEST-SPEC.md` (converged 3 rounds / 6 reviewers, approved).
4
+
5
+ ## Summary of the change
6
+
7
+ Adds an **Authorization Request** primitive: the agent (Bearer) pre-fills a structured request to grant a user a floor action; the operator approves it with their dashboard PIN on a dead-simple "Approvals waiting for you" card; on approval the server issues the grant via the EXISTING signed `MandateStore.issue()` path. Replaces the raw-JSON "build a mandate by hand" form as the primary surface (it is demoted behind an "Advanced" disclosure). Ships dev-enabled / fleet-dark (`resolveDevAgentGate`, `enabled` omitted from ConfigDefaults).
8
+
9
+ ## Decision-point inventory
10
+
11
+ The only new authority-conferring decision point is the PIN-gated `POST /authorization-requests/:id/approve`. It routes through the existing signed `MandateStore.issue/addGrants` — it does NOT introduce a new authority primitive, modify the MandateGate deny-ladder, the GrantStore read path, or the SlackPermissionGate evaluate-path.
12
+
13
+ ## 1. Over-block
14
+ Could a legitimate operator be blocked from approving? The approve route is PIN-gated with the existing rate-limited `checkMandatePin` (5/5min per IP). A locked-out operator self-heals after the window. The feature is additive — if its store is unreadable the routes 503 and the existing manual mandate/grant path is unaffected. No new over-block on existing flows.
15
+
16
+ ## 2. Under-block
17
+ Could an agent get authority it shouldn't? No. A pending request confers ZERO authority (inert). The grant issues ONLY inside the PIN-gated approve, via the existing signed path — requester ≠ authorizer is preserved and the agent can never approve its own request (no PIN). The proposable floor-action allowlist EXCLUDES `grant-authority` (the meta-escalation stays manual). The grantee must resolve to a registered principal at create AND approve (rejects phantom/sybil ids).
18
+
19
+ ## 3. Level-of-abstraction fit
20
+ A new primitive at the right layer: it is an operator-friendly FRONT DOOR to issuing a grant, built atop the proven mandate read/issue path (one-carrier-per-grant, `meta.carrier:true`, operator-invisible). Not a parallel authority store.
21
+
22
+ ## 4. Signal vs authority compliance
23
+ The PIN-gated approve is a legitimate human authority chokepoint (the operator sees the named person + plain-language action and decides). No automated trust-policy gate is layered on top (that would re-introduce brittle blocking authority on a human authority). Foundation note: the SlackPermissionGate `FLOOR_ACTIONS` enum-as-authority (flagged 2026-06-09) is inherited UNCHANGED and explicitly NOT worsened — recorded in the spec's Foundation Audit; resolving it is a separate spec.
24
+
25
+ ## 5. Interactions
26
+ - MandateStore: approval issues a fresh per-grant carrier mandate (expiry == grant expiry); revoking one never affects another; hourly prune bounds the `activeGrant` hot-path scan.
27
+ - SlackPermissionGate: unchanged — `activeGrant` returns the issued grant and the gate flips refuse→allow with no gate change.
28
+ - Manual issue form: demoted behind "Advanced", still functional for the rare agent-pair credential/code-review case.
29
+
30
+ ## 6. External surfaces
31
+ - HTTP: 6 new `/authorization-requests` routes (Bearer for propose/list/withdraw; PIN-gated for approve/deny). 503 when the feature is off.
32
+ - Dashboard: a new "Approvals waiting for you" section + the demoted manual form (`dashboard/index.html`, `dashboard/mandates.js`).
33
+ - Audit: every issued grant lands in the existing hash-chained `MandateAudit`.
34
+
35
+ ## 6b. Operator-surface quality (Operator-Surface Quality standard)
36
+ The change touches operator surfaces (`dashboard/index.html`, `dashboard/mandates.js`). Answering the quality question in writing:
37
+ 1. **Leads with the primary action?** YES — the "Approvals waiting for you" card renders open at the top of the tab with Approve as the primary, always-visible button; the destructive/advanced paths are below and collapsed.
38
+ 2. **Exposes zero raw internals as primary content?** YES — the card shows only a server-authored plain-language sentence ("Let Mia deploy to production for 1 hour.") + an optional escaped secondary reason. No JSON, fingerprints, slugs, or the carrier mandate. The raw-JSON authorities editor is demoted behind "Advanced — author a mandate by hand".
39
+ 3. **De-emphasizes destructive actions?** YES — Decline is a quiet secondary button; there is no destructive primary.
40
+ 4. **Plain language at phone width?** YES — single-column cards, real tap targets, plain sentences; no horizontal scroll.
41
+
42
+ ## Agent Proposes, Operator Approves (the new standard)
43
+ The change touches an authorization/approval surface, so it answers the agent-proposes/operator-approves + display-integrity question:
44
+ 1. **Does the operator APPROVE a pre-filled request rather than construct one?** YES — the agent supplies only structured fields; the operator reads one sentence and taps Approve. They never assemble a mandate, pick enums, or edit JSON.
45
+ 2. **Is the authority statement SERVER-authored, not agent free-text?** YES — `renderAuthorizationCard` builds the headline from the structured proposal + the registry display name; the agent's optional `reason` is carried as a clearly-secondary, escaped note and can never become the headline. A unit + integration + e2e test each assert a malicious `reason` never appears as the authority. This closes the deceptive-summary class.
46
+
47
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
48
+ The AuthorizationRequest store is **machine-local by design** (the grant it issues lands in the holder's machine-local MandateStore). Each request stamps `createdOnMachine`. The pending-approval card on a NON-holder machine shows "Asked on <machine> — open that machine's dashboard to approve" instead of a dead Approve button (no silent cross-machine hole). Documented in FD-6.
49
+
50
+ ## 8. Rollback cost
51
+ Clean. The feature is dev-gated: setting `monitoring.authorizationRequests.enabled:false` (or fleet default) routes every route 503; nothing else changes. Disabling mid-flight leaves pending requests inert (they confer nothing) and any already-issued grants stand as normal mandate grants (revocable via the existing path). No migration to unwind (no `migrateConfig` entry; the dashboard serves from the package dir).
52
+
53
+ ## Conclusion
54
+ Loss-reducing + additive. The single safety invariant (requester ≠ authorizer; PIN-only authority) is preserved and strengthened (server-authored display). Ships dark-on-fleet behind the dev gate.
55
+
56
+ ## Evidence pointers
57
+ - Spec + convergence report: `docs/specs/OPERATOR-AUTHORIZATION-REQUEST-SPEC.md`, `docs/specs/reports/operator-authorization-request-convergence.md`.
58
+ - Tests (67 green): `tests/unit/AuthorizationRequestStore.test.ts` (20), `tests/unit/operator-surface-gate.test.ts` (13), `tests/integration/authorization-request-routes.test.ts` (7), `tests/e2e/authorization-request-lifecycle.test.ts` (3), `tests/unit/lint-dev-agent-dark-gate.test.ts` (24, golden map recomputed).
59
+ - The deceptive-summary defense is asserted at all three tiers (server-authored headline ≠ agent free-text).
60
+
61
+ ## Second-pass review (if required)
62
+ The spec passed 3-round convergence with 6 independent reviewers (security, adversarial, integration/multi-machine, decision-completeness, lessons-aware/foundation, scalability) — the multi-angle adversarial review that catches what a single pass misses. The round-1 CRITICAL (deceptive display) and round-2 HIGH (bounds-as-deception) were both closed before convergence.
63
+
64
+ ## Implementation note (CapabilityIndex)
65
+ The 6 `/authorization-requests` routes are classified in `src/server/CapabilityIndex.ts` as the agent-facing `authorizationRequest` capability (surfaced in `/capabilities`), satisfying the capabilities-discoverability ratchet.