instar 1.3.268 → 1.3.270

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 (94) hide show
  1. package/dist/commands/init.d.ts.map +1 -1
  2. package/dist/commands/init.js +3 -2
  3. package/dist/commands/init.js.map +1 -1
  4. package/dist/commands/server.d.ts.map +1 -1
  5. package/dist/commands/server.js +9 -1
  6. package/dist/commands/server.js.map +1 -1
  7. package/dist/coordination/MandateAudit.d.ts +48 -0
  8. package/dist/coordination/MandateAudit.d.ts.map +1 -0
  9. package/dist/coordination/MandateAudit.js +95 -0
  10. package/dist/coordination/MandateAudit.js.map +1 -0
  11. package/dist/coordination/MandateGate.d.ts +48 -0
  12. package/dist/coordination/MandateGate.d.ts.map +1 -0
  13. package/dist/coordination/MandateGate.js +104 -0
  14. package/dist/coordination/MandateGate.js.map +1 -0
  15. package/dist/coordination/MandateStore.d.ts +60 -0
  16. package/dist/coordination/MandateStore.d.ts.map +1 -0
  17. package/dist/coordination/MandateStore.js +106 -0
  18. package/dist/coordination/MandateStore.js.map +1 -0
  19. package/dist/coordination/conditions.d.ts +32 -0
  20. package/dist/coordination/conditions.d.ts.map +1 -0
  21. package/dist/coordination/conditions.js +54 -0
  22. package/dist/coordination/conditions.js.map +1 -0
  23. package/dist/coordination/types.d.ts +74 -0
  24. package/dist/coordination/types.d.ts.map +1 -0
  25. package/dist/coordination/types.js +17 -0
  26. package/dist/coordination/types.js.map +1 -0
  27. package/dist/core/ApprovalLedger.d.ts +132 -0
  28. package/dist/core/ApprovalLedger.d.ts.map +1 -0
  29. package/dist/core/ApprovalLedger.js +191 -0
  30. package/dist/core/ApprovalLedger.js.map +1 -0
  31. package/dist/core/SessionBuildContextStore.d.ts +33 -0
  32. package/dist/core/SessionBuildContextStore.d.ts.map +1 -0
  33. package/dist/core/SessionBuildContextStore.js +107 -0
  34. package/dist/core/SessionBuildContextStore.js.map +1 -0
  35. package/dist/core/SessionManager.d.ts +4 -0
  36. package/dist/core/SessionManager.d.ts.map +1 -1
  37. package/dist/core/SessionManager.js +44 -3
  38. package/dist/core/SessionManager.js.map +1 -1
  39. package/dist/core/types.d.ts +11 -0
  40. package/dist/core/types.d.ts.map +1 -1
  41. package/dist/core/types.js.map +1 -1
  42. package/dist/feedback-factory/migration/immutableGuard.d.ts +87 -0
  43. package/dist/feedback-factory/migration/immutableGuard.d.ts.map +1 -0
  44. package/dist/feedback-factory/migration/immutableGuard.js +163 -0
  45. package/dist/feedback-factory/migration/immutableGuard.js.map +1 -0
  46. package/dist/feedback-factory/migration/importIntegrity.d.ts +112 -0
  47. package/dist/feedback-factory/migration/importIntegrity.d.ts.map +1 -0
  48. package/dist/feedback-factory/migration/importIntegrity.js +202 -0
  49. package/dist/feedback-factory/migration/importIntegrity.js.map +1 -0
  50. package/dist/feedback-factory/monitor/parityMonitor.d.ts +75 -0
  51. package/dist/feedback-factory/monitor/parityMonitor.d.ts.map +1 -0
  52. package/dist/feedback-factory/monitor/parityMonitor.js +98 -0
  53. package/dist/feedback-factory/monitor/parityMonitor.js.map +1 -0
  54. package/dist/feedback-factory/monitor/parityMonitorStore.d.ts +44 -0
  55. package/dist/feedback-factory/monitor/parityMonitorStore.d.ts.map +1 -0
  56. package/dist/feedback-factory/monitor/parityMonitorStore.js +80 -0
  57. package/dist/feedback-factory/monitor/parityMonitorStore.js.map +1 -0
  58. package/dist/messaging/TelegramAdapter.d.ts +9 -1
  59. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  60. package/dist/messaging/TelegramAdapter.js +13 -7
  61. package/dist/messaging/TelegramAdapter.js.map +1 -1
  62. package/dist/scaffold/templates.d.ts.map +1 -1
  63. package/dist/scaffold/templates.js +11 -0
  64. package/dist/scaffold/templates.js.map +1 -1
  65. package/dist/server/AgentServer.d.ts +6 -0
  66. package/dist/server/AgentServer.d.ts.map +1 -1
  67. package/dist/server/AgentServer.js +94 -1
  68. package/dist/server/AgentServer.js.map +1 -1
  69. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  70. package/dist/server/CapabilityIndex.js +29 -0
  71. package/dist/server/CapabilityIndex.js.map +1 -1
  72. package/dist/server/DashboardRefreshDiagnostics.d.ts +12 -0
  73. package/dist/server/DashboardRefreshDiagnostics.d.ts.map +1 -0
  74. package/dist/server/DashboardRefreshDiagnostics.js +63 -0
  75. package/dist/server/DashboardRefreshDiagnostics.js.map +1 -0
  76. package/dist/server/routes.d.ts +11 -0
  77. package/dist/server/routes.d.ts.map +1 -1
  78. package/dist/server/routes.js +264 -4
  79. package/dist/server/routes.js.map +1 -1
  80. package/package.json +1 -1
  81. package/src/data/builtin-manifest.json +75 -75
  82. package/src/scaffold/templates.ts +11 -0
  83. package/upgrades/1.3.269.md +24 -0
  84. package/upgrades/1.3.270.md +106 -0
  85. package/upgrades/approval-ledger-phase2.eli16.md +56 -0
  86. package/upgrades/feedback-phase3-monitor.eli16.md +51 -0
  87. package/upgrades/feedback-phase4-integrity.eli16.md +54 -0
  88. package/upgrades/respawn-build-context-reestablishment.eli16.md +5 -0
  89. package/upgrades/side-effects/approval-ledger-phase2.md +82 -0
  90. package/upgrades/side-effects/coordination-mandate-enforcement.md +86 -0
  91. package/upgrades/side-effects/dashboard-refresh-diagnostics.md +76 -0
  92. package/upgrades/side-effects/feedback-phase3-monitor.md +37 -0
  93. package/upgrades/side-effects/feedback-phase4-integrity.md +35 -0
  94. package/upgrades/side-effects/respawn-build-context-reestablishment.md +81 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * MandateAudit — append-only, hash-chained audit of every mandate gate decision.
3
+ *
4
+ * Every gate decision (ALLOW and DENY alike) is recorded. The hash chain (each
5
+ * entry embeds the hash of the previous one) makes a deletion or edit detectable
6
+ * (threat-model T8): break any link and `verifyChain()` reports the first broken
7
+ * index. The chain head is surfaced read-only for the operator. An external,
8
+ * out-of-process sink is a follow-on hardening, called out in the spec.
9
+ *
10
+ * Accountability after the fact is what makes ahead-of-time delegation safe: a
11
+ * misbehaving mandate is killable AND every action it authorized is reconstructable.
12
+ */
13
+ import type { MandateAuditEntry, MandateDecision } from './types.js';
14
+ /** Canonical bytes an entry's hash covers — field-ordered, hash EXCLUDED. */
15
+ export declare function canonicalAuditEntry(e: Omit<MandateAuditEntry, 'hash'>): string;
16
+ export interface MandateAuditDeps {
17
+ filePath: string;
18
+ now?: () => number;
19
+ }
20
+ export declare class MandateAudit {
21
+ private readonly d;
22
+ constructor(deps: MandateAuditDeps);
23
+ /** Append a decision, chaining it to the current head. Returns the new entry. */
24
+ record(input: {
25
+ mandateId: string;
26
+ agentFp: string;
27
+ action: string;
28
+ decision: MandateDecision;
29
+ reason: string;
30
+ conditionResult?: boolean | null;
31
+ }): MandateAuditEntry;
32
+ /** All entries (oldest→newest). Tolerant of a missing file / a torn trailing line. */
33
+ all(): MandateAuditEntry[];
34
+ /** The current chain head hash ('' when empty). */
35
+ headHash(): string;
36
+ /**
37
+ * Verify the hash chain end-to-end. Returns `{ ok: true }` when intact, else
38
+ * `{ ok: false, brokenAt }` with the index of the first entry whose recomputed
39
+ * hash (or prevHash linkage) does not match — the tamper signal.
40
+ */
41
+ verifyChain(): {
42
+ ok: true;
43
+ } | {
44
+ ok: false;
45
+ brokenAt: number;
46
+ };
47
+ }
48
+ //# sourceMappingURL=MandateAudit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MandateAudit.d.ts","sourceRoot":"","sources":["../../src/coordination/MandateAudit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,GAAG,MAAM,CAK9E;AAMD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAmB;gBACzB,IAAI,EAAE,gBAAgB;IAIlC,iFAAiF;IACjF,MAAM,CAAC,KAAK,EAAE;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,eAAe,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KAClC,GAAG,iBAAiB;IAmBrB,sFAAsF;IACtF,GAAG,IAAI,iBAAiB,EAAE;IAW1B,mDAAmD;IACnD,QAAQ,IAAI,MAAM;IAKlB;;;;OAIG;IACH,WAAW,IAAI;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;CAY9D"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * MandateAudit — append-only, hash-chained audit of every mandate gate decision.
3
+ *
4
+ * Every gate decision (ALLOW and DENY alike) is recorded. The hash chain (each
5
+ * entry embeds the hash of the previous one) makes a deletion or edit detectable
6
+ * (threat-model T8): break any link and `verifyChain()` reports the first broken
7
+ * index. The chain head is surfaced read-only for the operator. An external,
8
+ * out-of-process sink is a follow-on hardening, called out in the spec.
9
+ *
10
+ * Accountability after the fact is what makes ahead-of-time delegation safe: a
11
+ * misbehaving mandate is killable AND every action it authorized is reconstructable.
12
+ */
13
+ import fs from 'node:fs';
14
+ import path from 'node:path';
15
+ import { createHash } from 'node:crypto';
16
+ /** Canonical bytes an entry's hash covers — field-ordered, hash EXCLUDED. */
17
+ export function canonicalAuditEntry(e) {
18
+ return JSON.stringify([
19
+ e.ts, e.mandateId, e.agentFp, e.action, e.decision, e.reason,
20
+ e.conditionResult, e.prevHash,
21
+ ]);
22
+ }
23
+ function sha256(s) {
24
+ return createHash('sha256').update(s).digest('hex');
25
+ }
26
+ export class MandateAudit {
27
+ d;
28
+ constructor(deps) {
29
+ this.d = deps;
30
+ }
31
+ /** Append a decision, chaining it to the current head. Returns the new entry. */
32
+ record(input) {
33
+ const prevHash = this.headHash();
34
+ const ts = new Date(this.d.now ? this.d.now() : Date.now()).toISOString();
35
+ const unsigned = {
36
+ ts,
37
+ mandateId: input.mandateId,
38
+ agentFp: input.agentFp,
39
+ action: input.action,
40
+ decision: input.decision,
41
+ reason: input.reason,
42
+ conditionResult: input.conditionResult ?? null,
43
+ prevHash,
44
+ };
45
+ const entry = { ...unsigned, hash: sha256(prevHash + canonicalAuditEntry(unsigned)) };
46
+ fs.mkdirSync(path.dirname(this.d.filePath), { recursive: true });
47
+ fs.appendFileSync(this.d.filePath, JSON.stringify(entry) + '\n');
48
+ return entry;
49
+ }
50
+ /** All entries (oldest→newest). Tolerant of a missing file / a torn trailing line. */
51
+ all() {
52
+ let content;
53
+ try {
54
+ content = fs.readFileSync(this.d.filePath, 'utf8');
55
+ }
56
+ catch { /* @silent-fallback-ok — audit file may not exist yet; empty history is the natural default */
57
+ return [];
58
+ }
59
+ const out = [];
60
+ for (const line of content.split('\n')) {
61
+ if (!line.trim())
62
+ continue;
63
+ try {
64
+ out.push(JSON.parse(line));
65
+ }
66
+ catch { /* @silent-fallback-ok — torn-trailing-line tolerance; a crash mid-append must not poison reads */ }
67
+ }
68
+ return out;
69
+ }
70
+ /** The current chain head hash ('' when empty). */
71
+ headHash() {
72
+ const all = this.all();
73
+ return all.length ? all[all.length - 1].hash : '';
74
+ }
75
+ /**
76
+ * Verify the hash chain end-to-end. Returns `{ ok: true }` when intact, else
77
+ * `{ ok: false, brokenAt }` with the index of the first entry whose recomputed
78
+ * hash (or prevHash linkage) does not match — the tamper signal.
79
+ */
80
+ verifyChain() {
81
+ const all = this.all();
82
+ let prevHash = '';
83
+ for (let i = 0; i < all.length; i++) {
84
+ const { hash, ...unsigned } = all[i];
85
+ if (unsigned.prevHash !== prevHash)
86
+ return { ok: false, brokenAt: i };
87
+ const expected = sha256(prevHash + canonicalAuditEntry(unsigned));
88
+ if (expected !== hash)
89
+ return { ok: false, brokenAt: i };
90
+ prevHash = hash;
91
+ }
92
+ return { ok: true };
93
+ }
94
+ }
95
+ //# sourceMappingURL=MandateAudit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MandateAudit.js","sourceRoot":"","sources":["../../src/coordination/MandateAudit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * MandateGate — the deny-by-default enforcement point for autonomous A2A actions.
3
+ *
4
+ * `evaluate()` runs the spec's ordered checks (§4) and AUDITS every decision (allow
5
+ * AND deny). With NO valid mandate loaded the gate denies everything — so the system
6
+ * is inert (weakens nothing) until Justin authors a mandate through the PIN-gated path.
7
+ *
8
+ * Order (any miss → deny, audited):
9
+ * 1. mandate exists
10
+ * 2. authorship valid (T1/T2)
11
+ * 3. not expired (T4)
12
+ * 4. not revoked (T5)
13
+ * 5. caller is a named party (T6/T9)
14
+ * 6. an Authority matches `action` AND `params` are within `bounds`
15
+ * 7. if the Authority requires a condition, it evaluates true from REAL state (T7/T10)
16
+ * 8. → allow
17
+ *
18
+ * The agent's "judgment" never authorizes anything — the mandate (a human-authored
19
+ * policy) and the objective conditions do. This is `requester ≠ authorizer` preserved.
20
+ */
21
+ import type { MandateStore } from './MandateStore.js';
22
+ import type { ConditionsRegistry } from './conditions.js';
23
+ import type { MandateAudit } from './MandateAudit.js';
24
+ import type { MandateEvaluation, MandateAuditEntry } from './types.js';
25
+ export interface MandateGateResult {
26
+ decision: 'allow' | 'deny';
27
+ reason: string;
28
+ conditionResult: boolean | null;
29
+ audit: MandateAuditEntry;
30
+ }
31
+ /** Every key in `bounds` must be present in `params` with a deeply-equal value.
32
+ * `params` MAY carry extra keys — the bounds only constrain the keys they name. */
33
+ export declare function paramsSatisfyBounds(params: Record<string, unknown>, bounds: Record<string, unknown>): boolean;
34
+ export interface MandateGateDeps {
35
+ store: MandateStore;
36
+ conditions: ConditionsRegistry;
37
+ audit: MandateAudit;
38
+ now?: () => number;
39
+ }
40
+ export declare class MandateGate {
41
+ private readonly d;
42
+ constructor(deps: MandateGateDeps);
43
+ private nowMs;
44
+ private deny;
45
+ private allow;
46
+ evaluate(ev: MandateEvaluation): MandateGateResult;
47
+ }
48
+ //# sourceMappingURL=MandateGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MandateGate.d.ts","sourceRoot":"","sources":["../../src/coordination/MandateGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAa,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAElF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAUD;oFACoF;AACpF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAM7G;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAkB;gBACxB,IAAI,EAAE,eAAe;IAIjC,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,KAAK;IAQb,QAAQ,CAAC,EAAE,EAAE,iBAAiB,GAAG,iBAAiB;CAmDnD"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * MandateGate — the deny-by-default enforcement point for autonomous A2A actions.
3
+ *
4
+ * `evaluate()` runs the spec's ordered checks (§4) and AUDITS every decision (allow
5
+ * AND deny). With NO valid mandate loaded the gate denies everything — so the system
6
+ * is inert (weakens nothing) until Justin authors a mandate through the PIN-gated path.
7
+ *
8
+ * Order (any miss → deny, audited):
9
+ * 1. mandate exists
10
+ * 2. authorship valid (T1/T2)
11
+ * 3. not expired (T4)
12
+ * 4. not revoked (T5)
13
+ * 5. caller is a named party (T6/T9)
14
+ * 6. an Authority matches `action` AND `params` are within `bounds`
15
+ * 7. if the Authority requires a condition, it evaluates true from REAL state (T7/T10)
16
+ * 8. → allow
17
+ *
18
+ * The agent's "judgment" never authorizes anything — the mandate (a human-authored
19
+ * policy) and the objective conditions do. This is `requester ≠ authorizer` preserved.
20
+ */
21
+ /** Deterministic, key-sorted serialization for value comparison. */
22
+ function stableStringify(value) {
23
+ if (value === null || typeof value !== 'object')
24
+ return JSON.stringify(value);
25
+ if (Array.isArray(value))
26
+ return '[' + value.map(stableStringify).join(',') + ']';
27
+ const obj = value;
28
+ return '{' + Object.keys(obj).sort().map((k) => JSON.stringify(k) + ':' + stableStringify(obj[k])).join(',') + '}';
29
+ }
30
+ /** Every key in `bounds` must be present in `params` with a deeply-equal value.
31
+ * `params` MAY carry extra keys — the bounds only constrain the keys they name. */
32
+ export function paramsSatisfyBounds(params, bounds) {
33
+ for (const key of Object.keys(bounds)) {
34
+ if (!(key in params))
35
+ return false;
36
+ if (stableStringify(params[key]) !== stableStringify(bounds[key]))
37
+ return false;
38
+ }
39
+ return true;
40
+ }
41
+ export class MandateGate {
42
+ d;
43
+ constructor(deps) {
44
+ this.d = deps;
45
+ }
46
+ nowMs() {
47
+ return this.d.now ? this.d.now() : Date.now();
48
+ }
49
+ deny(ev, reason, conditionResult = null) {
50
+ const audit = this.d.audit.record({
51
+ mandateId: ev.mandateId, agentFp: ev.agentFp, action: ev.action,
52
+ decision: 'deny', reason, conditionResult,
53
+ });
54
+ return { decision: 'deny', reason, conditionResult, audit };
55
+ }
56
+ allow(ev, reason, conditionResult) {
57
+ const audit = this.d.audit.record({
58
+ mandateId: ev.mandateId, agentFp: ev.agentFp, action: ev.action,
59
+ decision: 'allow', reason, conditionResult,
60
+ });
61
+ return { decision: 'allow', reason, conditionResult, audit };
62
+ }
63
+ evaluate(ev) {
64
+ // 1. exists
65
+ const mandate = this.d.store.get(ev.mandateId);
66
+ if (!mandate)
67
+ return this.deny(ev, `mandate "${ev.mandateId}" not found`);
68
+ // 2. authorship valid
69
+ if (!this.d.store.verifyAuthorship(mandate)) {
70
+ return this.deny(ev, 'mandate authorship proof is invalid (forged or edited)');
71
+ }
72
+ // 3. not expired
73
+ if (this.nowMs() > Date.parse(mandate.expiresAt)) {
74
+ return this.deny(ev, `mandate expired at ${mandate.expiresAt}`);
75
+ }
76
+ // 4. not revoked
77
+ if (mandate.revoked) {
78
+ return this.deny(ev, `mandate revoked at ${mandate.revoked.at}: ${mandate.revoked.reason}`);
79
+ }
80
+ // 5. caller is a named party
81
+ if (!mandate.agents.includes(ev.agentFp)) {
82
+ return this.deny(ev, `agent ${ev.agentFp} is not a named party to this mandate`);
83
+ }
84
+ // 6. an authority matches action + params within bounds
85
+ const matching = mandate.authorities.find((a) => a.action === ev.action && paramsSatisfyBounds(ev.params, a.bounds));
86
+ if (!matching) {
87
+ const sameAction = mandate.authorities.some((a) => a.action === ev.action);
88
+ return this.deny(ev, sameAction
89
+ ? `params exceed the bounds of authority "${ev.action}"`
90
+ : `no authority for action "${ev.action}" in this mandate`);
91
+ }
92
+ // 7. condition (if any) evaluates true from real state
93
+ if (matching.requiresCondition) {
94
+ const ok = this.d.conditions.evaluate(matching.requiresCondition);
95
+ if (!ok) {
96
+ return this.deny(ev, `objective condition "${matching.requiresCondition}" not met`, false);
97
+ }
98
+ return this.allow(ev, `authority "${ev.action}" granted (condition "${matching.requiresCondition}" met)`, true);
99
+ }
100
+ // 8. allow (no condition)
101
+ return this.allow(ev, `authority "${ev.action}" granted`, null);
102
+ }
103
+ }
104
+ //# sourceMappingURL=MandateGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MandateGate.js","sourceRoot":"","sources":["../../src/coordination/MandateGate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * MandateStore — persists Coordination Mandates and verifies their authorship.
3
+ *
4
+ * A mandate is valid only if its `authProof` verifies (threat-model T1/T2): the proof
5
+ * is produced ONLY by the PIN-gated issuance path (the human-authenticated surface,
6
+ * Justin's decision A on issuance), so an agent holding only its Bearer token cannot
7
+ * mint or widen a mandate. The proof covers the AUTHORED, immutable fields; `revoked`
8
+ * is a store-managed flag (a later mutation), so it is excluded from the proof and
9
+ * checked separately on every gate evaluation.
10
+ *
11
+ * The signer/verifier are INJECTED (like the other signed stores): tests use a
12
+ * deterministic stub; production uses an HMAC over the server's issuance secret.
13
+ *
14
+ * Trust boundary (stated, not hidden): integrity of the on-disk mandate + revocation
15
+ * flag against an attacker with LOCAL write access is the same trust root as today
16
+ * (threat-model T12, out of scope) — the proof stops a forged/edited AUTHORED mandate;
17
+ * local-file tamper of server-managed state is the baseline trust boundary.
18
+ */
19
+ import type { Authority, CoordinationMandate } from './types.js';
20
+ /** Canonical bytes the authProof covers — the AUTHORED fields only (proof + revoked excluded). */
21
+ export declare function canonicalMandate(m: Omit<CoordinationMandate, 'authProof' | 'revoked'>): string;
22
+ export interface MandateStoreDeps {
23
+ /** Absolute path to the mandates JSON file. */
24
+ filePath: string;
25
+ /** Sign the canonical mandate bytes (HMAC over the issuance secret in production). */
26
+ sign: (canonical: string) => string;
27
+ /** Verify a proof against the canonical mandate bytes. */
28
+ verifySig: (canonical: string, proof: string) => boolean;
29
+ now?: () => number;
30
+ /** Mandate id generator (default: random). Injected for deterministic tests. */
31
+ genId?: () => string;
32
+ }
33
+ export interface IssueMandateInput {
34
+ scope: string;
35
+ agents: [string, string];
36
+ authorities: Authority[];
37
+ author: string;
38
+ expiresAt: string;
39
+ id?: string;
40
+ createdAt?: string;
41
+ }
42
+ export declare class MandateStore {
43
+ private readonly d;
44
+ constructor(deps: MandateStoreDeps);
45
+ private nowIso;
46
+ private readAll;
47
+ private writeAll;
48
+ /**
49
+ * Issue (author) a mandate. ONLY the PIN-gated route should call this. Signs the
50
+ * authored bytes, persists, returns the mandate.
51
+ */
52
+ issue(input: IssueMandateInput): CoordinationMandate;
53
+ /** Verify a mandate's authorship proof (T1/T2). */
54
+ verifyAuthorship(m: CoordinationMandate): boolean;
55
+ get(id: string): CoordinationMandate | undefined;
56
+ list(): CoordinationMandate[];
57
+ /** Revoke a mandate (idempotent). Returns the updated mandate, or undefined if absent. */
58
+ revoke(id: string, reason: string): CoordinationMandate | undefined;
59
+ }
60
+ //# sourceMappingURL=MandateStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MandateStore.d.ts","sourceRoot":"","sources":["../../src/coordination/MandateStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAYjE,kGAAkG;AAClG,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,GAAG,SAAS,CAAC,GAAG,MAAM,CAM9F;AAED,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,sFAAsF;IACtF,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,0DAA0D;IAC1D,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACzD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAmB;gBACzB,IAAI,EAAE,gBAAgB;IAIlC,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,QAAQ;IAKhB;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,iBAAiB,GAAG,mBAAmB;IAkBpD,mDAAmD;IACnD,gBAAgB,CAAC,CAAC,EAAE,mBAAmB,GAAG,OAAO;IAKjD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIhD,IAAI,IAAI,mBAAmB,EAAE;IAI7B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;CAUpE"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * MandateStore — persists Coordination Mandates and verifies their authorship.
3
+ *
4
+ * A mandate is valid only if its `authProof` verifies (threat-model T1/T2): the proof
5
+ * is produced ONLY by the PIN-gated issuance path (the human-authenticated surface,
6
+ * Justin's decision A on issuance), so an agent holding only its Bearer token cannot
7
+ * mint or widen a mandate. The proof covers the AUTHORED, immutable fields; `revoked`
8
+ * is a store-managed flag (a later mutation), so it is excluded from the proof and
9
+ * checked separately on every gate evaluation.
10
+ *
11
+ * The signer/verifier are INJECTED (like the other signed stores): tests use a
12
+ * deterministic stub; production uses an HMAC over the server's issuance secret.
13
+ *
14
+ * Trust boundary (stated, not hidden): integrity of the on-disk mandate + revocation
15
+ * flag against an attacker with LOCAL write access is the same trust root as today
16
+ * (threat-model T12, out of scope) — the proof stops a forged/edited AUTHORED mandate;
17
+ * local-file tamper of server-managed state is the baseline trust boundary.
18
+ */
19
+ import fs from 'node:fs';
20
+ import path from 'node:path';
21
+ /** Deterministic, key-sorted serialization so the proof survives JSON round-trips
22
+ * and key reordering. */
23
+ function stableStringify(value) {
24
+ if (value === null || typeof value !== 'object')
25
+ return JSON.stringify(value);
26
+ if (Array.isArray(value))
27
+ return '[' + value.map(stableStringify).join(',') + ']';
28
+ const obj = value;
29
+ const keys = Object.keys(obj).sort();
30
+ return '{' + keys.map((k) => JSON.stringify(k) + ':' + stableStringify(obj[k])).join(',') + '}';
31
+ }
32
+ /** Canonical bytes the authProof covers — the AUTHORED fields only (proof + revoked excluded). */
33
+ export function canonicalMandate(m) {
34
+ return stableStringify([
35
+ m.id, m.scope, m.agents,
36
+ m.authorities.map((a) => [a.action, a.bounds, a.requiresCondition ?? '']),
37
+ m.author, m.createdAt, m.expiresAt,
38
+ ]);
39
+ }
40
+ export class MandateStore {
41
+ d;
42
+ constructor(deps) {
43
+ this.d = deps;
44
+ }
45
+ nowIso() {
46
+ return new Date(this.d.now ? this.d.now() : Date.now()).toISOString();
47
+ }
48
+ readAll() {
49
+ try {
50
+ const raw = JSON.parse(fs.readFileSync(this.d.filePath, 'utf8'));
51
+ return Array.isArray(raw) ? raw : [];
52
+ }
53
+ catch { /* @silent-fallback-ok — mandates file may not exist yet; an empty store is DENY-BY-DEFAULT (the safe state) */
54
+ return [];
55
+ }
56
+ }
57
+ writeAll(mandates) {
58
+ fs.mkdirSync(path.dirname(this.d.filePath), { recursive: true });
59
+ fs.writeFileSync(this.d.filePath, JSON.stringify(mandates, null, 2));
60
+ }
61
+ /**
62
+ * Issue (author) a mandate. ONLY the PIN-gated route should call this. Signs the
63
+ * authored bytes, persists, returns the mandate.
64
+ */
65
+ issue(input) {
66
+ const id = input.id ?? (this.d.genId ? this.d.genId() : `mandate-${Math.random().toString(36).slice(2, 10)}`);
67
+ const createdAt = input.createdAt ?? this.nowIso();
68
+ const authored = {
69
+ id, scope: input.scope, agents: input.agents, authorities: input.authorities,
70
+ author: input.author, createdAt, expiresAt: input.expiresAt,
71
+ };
72
+ const mandate = {
73
+ ...authored,
74
+ revoked: null,
75
+ authProof: this.d.sign(canonicalMandate(authored)),
76
+ };
77
+ const all = this.readAll().filter((m) => m.id !== id);
78
+ all.push(mandate);
79
+ this.writeAll(all);
80
+ return mandate;
81
+ }
82
+ /** Verify a mandate's authorship proof (T1/T2). */
83
+ verifyAuthorship(m) {
84
+ const { authProof, revoked, ...authored } = m;
85
+ return this.d.verifySig(canonicalMandate(authored), authProof);
86
+ }
87
+ get(id) {
88
+ return this.readAll().find((m) => m.id === id);
89
+ }
90
+ list() {
91
+ return this.readAll();
92
+ }
93
+ /** Revoke a mandate (idempotent). Returns the updated mandate, or undefined if absent. */
94
+ revoke(id, reason) {
95
+ const all = this.readAll();
96
+ const idx = all.findIndex((m) => m.id === id);
97
+ if (idx < 0)
98
+ return undefined;
99
+ if (!all[idx].revoked) {
100
+ all[idx].revoked = { at: this.nowIso(), reason };
101
+ this.writeAll(all);
102
+ }
103
+ return all[idx];
104
+ }
105
+ }
106
+ //# sourceMappingURL=MandateStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MandateStore.js","sourceRoot":"","sources":["../../src/coordination/MandateStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Conditions registry — named, objective predicates that gate high-risk authorities.
3
+ *
4
+ * Structure > Willpower applied to delegation: a conditioned authority (e.g. a
5
+ * future `execute-cutover`) fires ONLY when its named condition evaluates true from
6
+ * REAL state — `integrity-gate-pass` ← `runIntegrityGate().passed`,
7
+ * `parity-zero-divergence` ← `ParityMonitor.gate().cleared`. The agent's assertion
8
+ * that "it's safe" is NEVER the input; the objective check is (threat-model T7/T10).
9
+ *
10
+ * Resolvers are INJECTED so this module stays decoupled from the integrity/parity
11
+ * machinery. A condition with no wired resolver evaluates **false** (deny-safe): an
12
+ * un-evaluable gate must never fall open. The first mandate (Justin's A/A/B) carries
13
+ * NO conditioned authority, so nothing here is exercised yet — it is built for the
14
+ * future cutover authority and tested on both sides of the boundary.
15
+ */
16
+ /** A resolver returns the live truth of a condition from real state. */
17
+ export type ConditionResolver = () => boolean;
18
+ export declare class ConditionsRegistry {
19
+ private readonly resolvers;
20
+ /** Register (or replace) the resolver for a named condition. */
21
+ register(name: string, resolver: ConditionResolver): this;
22
+ /** True iff the condition is registered. */
23
+ has(name: string): boolean;
24
+ /**
25
+ * Evaluate a (possibly compound) condition. A `+`-joined expression
26
+ * (e.g. 'integrity-gate-pass+parity-zero-divergence') is the AND of its parts —
27
+ * ALL must resolve true. An unregistered part → false (deny-safe). Any resolver
28
+ * that throws → false (deny-safe).
29
+ */
30
+ evaluate(expr: string): boolean;
31
+ }
32
+ //# sourceMappingURL=conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../../src/coordination/conditions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,wEAAwE;AACxE,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC;AAE9C,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAElE,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAKzD,4CAA4C;IAC5C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAYhC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Conditions registry — named, objective predicates that gate high-risk authorities.
3
+ *
4
+ * Structure > Willpower applied to delegation: a conditioned authority (e.g. a
5
+ * future `execute-cutover`) fires ONLY when its named condition evaluates true from
6
+ * REAL state — `integrity-gate-pass` ← `runIntegrityGate().passed`,
7
+ * `parity-zero-divergence` ← `ParityMonitor.gate().cleared`. The agent's assertion
8
+ * that "it's safe" is NEVER the input; the objective check is (threat-model T7/T10).
9
+ *
10
+ * Resolvers are INJECTED so this module stays decoupled from the integrity/parity
11
+ * machinery. A condition with no wired resolver evaluates **false** (deny-safe): an
12
+ * un-evaluable gate must never fall open. The first mandate (Justin's A/A/B) carries
13
+ * NO conditioned authority, so nothing here is exercised yet — it is built for the
14
+ * future cutover authority and tested on both sides of the boundary.
15
+ */
16
+ export class ConditionsRegistry {
17
+ resolvers = new Map();
18
+ /** Register (or replace) the resolver for a named condition. */
19
+ register(name, resolver) {
20
+ this.resolvers.set(name, resolver);
21
+ return this;
22
+ }
23
+ /** True iff the condition is registered. */
24
+ has(name) {
25
+ return this.resolvers.has(name);
26
+ }
27
+ /**
28
+ * Evaluate a (possibly compound) condition. A `+`-joined expression
29
+ * (e.g. 'integrity-gate-pass+parity-zero-divergence') is the AND of its parts —
30
+ * ALL must resolve true. An unregistered part → false (deny-safe). Any resolver
31
+ * that throws → false (deny-safe).
32
+ */
33
+ evaluate(expr) {
34
+ const parts = expr.split('+').map((p) => p.trim()).filter(Boolean);
35
+ if (parts.length === 0)
36
+ return false;
37
+ for (const part of parts) {
38
+ const resolver = this.resolvers.get(part);
39
+ if (!resolver)
40
+ return false;
41
+ let result;
42
+ try {
43
+ result = resolver() === true;
44
+ }
45
+ catch {
46
+ result = false;
47
+ }
48
+ if (!result)
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+ }
54
+ //# sourceMappingURL=conditions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditions.js","sourceRoot":"","sources":["../../src/coordination/conditions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,MAAM,OAAO,kBAAkB;IACZ,SAAS,GAAG,IAAI,GAAG,EAA6B,CAAC;IAElE,gEAAgE;IAChE,QAAQ,CAAC,IAAY,EAAE,QAA2B;QAChD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4CAA4C;IAC5C,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,IAAY;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,CAAC,QAAQ;gBAAE,OAAO,KAAK,CAAC;YAC5B,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBAAC,MAAM,GAAG,QAAQ,EAAE,KAAK,IAAI,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,MAAM,GAAG,KAAK,CAAC;YAAC,CAAC;YAC/D,IAAI,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAC;QAC5B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}