life-as-api 0.2.0

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 (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +377 -0
  3. package/dist/agent/finance-agent.d.ts +44 -0
  4. package/dist/agent/finance-agent.js +75 -0
  5. package/dist/agent/finance-agent.js.map +1 -0
  6. package/dist/agent/legal-agent.d.ts +44 -0
  7. package/dist/agent/legal-agent.js +76 -0
  8. package/dist/agent/legal-agent.js.map +1 -0
  9. package/dist/agent/medical-agent.d.ts +44 -0
  10. package/dist/agent/medical-agent.js +75 -0
  11. package/dist/agent/medical-agent.js.map +1 -0
  12. package/dist/agent/trusted-agent-registry.d.ts +53 -0
  13. package/dist/agent/trusted-agent-registry.js +57 -0
  14. package/dist/agent/trusted-agent-registry.js.map +1 -0
  15. package/dist/audit/audit-chain-verifier.d.ts +10 -0
  16. package/dist/audit/audit-chain-verifier.js +67 -0
  17. package/dist/audit/audit-chain-verifier.js.map +1 -0
  18. package/dist/audit/audit-log.d.ts +48 -0
  19. package/dist/audit/audit-log.js +74 -0
  20. package/dist/audit/audit-log.js.map +1 -0
  21. package/dist/audit/sqlite-audit-log.d.ts +29 -0
  22. package/dist/audit/sqlite-audit-log.js +142 -0
  23. package/dist/audit/sqlite-audit-log.js.map +1 -0
  24. package/dist/auth/access-context-issuer.d.ts +18 -0
  25. package/dist/auth/access-context-issuer.js +88 -0
  26. package/dist/auth/access-context-issuer.js.map +1 -0
  27. package/dist/auth/assert-authorized-for-subject.d.ts +2 -0
  28. package/dist/auth/assert-authorized-for-subject.js +20 -0
  29. package/dist/auth/assert-authorized-for-subject.js.map +1 -0
  30. package/dist/auth/backend-context-minting-boundary.d.ts +23 -0
  31. package/dist/auth/backend-context-minting-boundary.js +281 -0
  32. package/dist/auth/backend-context-minting-boundary.js.map +1 -0
  33. package/dist/auth/default-authorization-policy.d.ts +7 -0
  34. package/dist/auth/default-authorization-policy.js +64 -0
  35. package/dist/auth/default-authorization-policy.js.map +1 -0
  36. package/dist/auth/fake-auth-adapter.d.ts +7 -0
  37. package/dist/auth/fake-auth-adapter.js +27 -0
  38. package/dist/auth/fake-auth-adapter.js.map +1 -0
  39. package/dist/auth/http-client.d.ts +12 -0
  40. package/dist/auth/http-client.js +7 -0
  41. package/dist/auth/http-client.js.map +1 -0
  42. package/dist/auth/in-memory-grant-resolver.d.ts +21 -0
  43. package/dist/auth/in-memory-grant-resolver.js +73 -0
  44. package/dist/auth/in-memory-grant-resolver.js.map +1 -0
  45. package/dist/auth/in-memory-tenant-boundary.d.ts +16 -0
  46. package/dist/auth/in-memory-tenant-boundary.js +37 -0
  47. package/dist/auth/in-memory-tenant-boundary.js.map +1 -0
  48. package/dist/auth/jwks-key-ring-auth-adapter.d.ts +38 -0
  49. package/dist/auth/jwks-key-ring-auth-adapter.js +123 -0
  50. package/dist/auth/jwks-key-ring-auth-adapter.js.map +1 -0
  51. package/dist/auth/jwks-key-ring.d.ts +25 -0
  52. package/dist/auth/jwks-key-ring.js +111 -0
  53. package/dist/auth/jwks-key-ring.js.map +1 -0
  54. package/dist/auth/jwt-auth-adapter.d.ts +15 -0
  55. package/dist/auth/jwt-auth-adapter.js +59 -0
  56. package/dist/auth/jwt-auth-adapter.js.map +1 -0
  57. package/dist/auth/jwt-core.d.ts +32 -0
  58. package/dist/auth/jwt-core.js +226 -0
  59. package/dist/auth/jwt-core.js.map +1 -0
  60. package/dist/auth/jwt-key-ring-auth-adapter.d.ts +16 -0
  61. package/dist/auth/jwt-key-ring-auth-adapter.js +58 -0
  62. package/dist/auth/jwt-key-ring-auth-adapter.js.map +1 -0
  63. package/dist/auth/oidc-discovery.d.ts +15 -0
  64. package/dist/auth/oidc-discovery.js +46 -0
  65. package/dist/auth/oidc-discovery.js.map +1 -0
  66. package/dist/auth/production-scoped-life-api.d.ts +58 -0
  67. package/dist/auth/production-scoped-life-api.js +802 -0
  68. package/dist/auth/production-scoped-life-api.js.map +1 -0
  69. package/dist/auth/proposal-scope-inspector.d.ts +3 -0
  70. package/dist/auth/proposal-scope-inspector.js +42 -0
  71. package/dist/auth/proposal-scope-inspector.js.map +1 -0
  72. package/dist/auth/proposal-scoped-life-api.d.ts +21 -0
  73. package/dist/auth/proposal-scoped-life-api.js +168 -0
  74. package/dist/auth/proposal-scoped-life-api.js.map +1 -0
  75. package/dist/auth/rate-limited-context-minting-boundary.d.ts +27 -0
  76. package/dist/auth/rate-limited-context-minting-boundary.js +77 -0
  77. package/dist/auth/rate-limited-context-minting-boundary.js.map +1 -0
  78. package/dist/auth/revocation-aware-auth-adapter.d.ts +21 -0
  79. package/dist/auth/revocation-aware-auth-adapter.js +88 -0
  80. package/dist/auth/revocation-aware-auth-adapter.js.map +1 -0
  81. package/dist/auth/sqlite-grant-resolver.d.ts +8 -0
  82. package/dist/auth/sqlite-grant-resolver.js +78 -0
  83. package/dist/auth/sqlite-grant-resolver.js.map +1 -0
  84. package/dist/auth/sqlite-tenant-boundary.d.ts +7 -0
  85. package/dist/auth/sqlite-tenant-boundary.js +41 -0
  86. package/dist/auth/sqlite-tenant-boundary.js.map +1 -0
  87. package/dist/auth/static-jwt-key-ring.d.ts +13 -0
  88. package/dist/auth/static-jwt-key-ring.js +73 -0
  89. package/dist/auth/static-jwt-key-ring.js.map +1 -0
  90. package/dist/auth/subject-scoped-life-api.d.ts +14 -0
  91. package/dist/auth/subject-scoped-life-api.js +51 -0
  92. package/dist/auth/subject-scoped-life-api.js.map +1 -0
  93. package/dist/auth/test-context-minting-boundary.d.ts +13 -0
  94. package/dist/auth/test-context-minting-boundary.js +74 -0
  95. package/dist/auth/test-context-minting-boundary.js.map +1 -0
  96. package/dist/auth/types.d.ts +77 -0
  97. package/dist/auth/types.js +16 -0
  98. package/dist/auth/types.js.map +1 -0
  99. package/dist/compliance/subject-data-report.d.ts +43 -0
  100. package/dist/compliance/subject-data-report.js +155 -0
  101. package/dist/compliance/subject-data-report.js.map +1 -0
  102. package/dist/consent/consent-guard.d.ts +4 -0
  103. package/dist/consent/consent-guard.js +37 -0
  104. package/dist/consent/consent-guard.js.map +1 -0
  105. package/dist/consent/grant-registry.d.ts +7 -0
  106. package/dist/consent/grant-registry.js +13 -0
  107. package/dist/consent/grant-registry.js.map +1 -0
  108. package/dist/consent/intersect-selector.d.ts +3 -0
  109. package/dist/consent/intersect-selector.js +66 -0
  110. package/dist/consent/intersect-selector.js.map +1 -0
  111. package/dist/contract/diagnostics.d.ts +32 -0
  112. package/dist/contract/diagnostics.js +112 -0
  113. package/dist/contract/diagnostics.js.map +1 -0
  114. package/dist/contract/project-contracts.d.ts +5 -0
  115. package/dist/contract/project-contracts.js +159 -0
  116. package/dist/contract/project-contracts.js.map +1 -0
  117. package/dist/contract/types.d.ts +32 -0
  118. package/dist/contract/types.js +5 -0
  119. package/dist/contract/types.js.map +1 -0
  120. package/dist/crypto/aes-gcm.d.ts +11 -0
  121. package/dist/crypto/aes-gcm.js +78 -0
  122. package/dist/crypto/aes-gcm.js.map +1 -0
  123. package/dist/crypto/claim-serializer.d.ts +26 -0
  124. package/dist/crypto/claim-serializer.js +59 -0
  125. package/dist/crypto/claim-serializer.js.map +1 -0
  126. package/dist/crypto/sha256.d.ts +12 -0
  127. package/dist/crypto/sha256.js +40 -0
  128. package/dist/crypto/sha256.js.map +1 -0
  129. package/dist/crypto/static-key.d.ts +11 -0
  130. package/dist/crypto/static-key.js +60 -0
  131. package/dist/crypto/static-key.js.map +1 -0
  132. package/dist/crypto/types.d.ts +20 -0
  133. package/dist/crypto/types.js +8 -0
  134. package/dist/crypto/types.js.map +1 -0
  135. package/dist/datasource/trusted-data-source-registry.d.ts +51 -0
  136. package/dist/datasource/trusted-data-source-registry.js +57 -0
  137. package/dist/datasource/trusted-data-source-registry.js.map +1 -0
  138. package/dist/erasure/tombstone.d.ts +13 -0
  139. package/dist/erasure/tombstone.js +20 -0
  140. package/dist/erasure/tombstone.js.map +1 -0
  141. package/dist/evidence/evidence-backed-claim-creator.d.ts +48 -0
  142. package/dist/evidence/evidence-backed-claim-creator.js +107 -0
  143. package/dist/evidence/evidence-backed-claim-creator.js.map +1 -0
  144. package/dist/evidence/in-memory-raw-document-store.d.ts +26 -0
  145. package/dist/evidence/in-memory-raw-document-store.js +84 -0
  146. package/dist/evidence/in-memory-raw-document-store.js.map +1 -0
  147. package/dist/evidence/raw-document-store.d.ts +12 -0
  148. package/dist/evidence/raw-document-store.js +8 -0
  149. package/dist/evidence/raw-document-store.js.map +1 -0
  150. package/dist/evidence/source-evidence-validator.d.ts +4 -0
  151. package/dist/evidence/source-evidence-validator.js +14 -0
  152. package/dist/evidence/source-evidence-validator.js.map +1 -0
  153. package/dist/evidence/sqlite-raw-document-store.d.ts +19 -0
  154. package/dist/evidence/sqlite-raw-document-store.js +122 -0
  155. package/dist/evidence/sqlite-raw-document-store.js.map +1 -0
  156. package/dist/guardian/guardian-registry.d.ts +96 -0
  157. package/dist/guardian/guardian-registry.js +95 -0
  158. package/dist/guardian/guardian-registry.js.map +1 -0
  159. package/dist/index.d.ts +44 -0
  160. package/dist/index.js +72 -0
  161. package/dist/index.js.map +1 -0
  162. package/dist/observability/health.d.ts +12 -0
  163. package/dist/observability/health.js +16 -0
  164. package/dist/observability/health.js.map +1 -0
  165. package/dist/observability/logger.d.ts +21 -0
  166. package/dist/observability/logger.js +40 -0
  167. package/dist/observability/logger.js.map +1 -0
  168. package/dist/observability/metrics.d.ts +15 -0
  169. package/dist/observability/metrics.js +52 -0
  170. package/dist/observability/metrics.js.map +1 -0
  171. package/dist/persistence/backup.d.ts +24 -0
  172. package/dist/persistence/backup.js +251 -0
  173. package/dist/persistence/backup.js.map +1 -0
  174. package/dist/persistence/decryptability-scan.d.ts +10 -0
  175. package/dist/persistence/decryptability-scan.js +144 -0
  176. package/dist/persistence/decryptability-scan.js.map +1 -0
  177. package/dist/persistence/in-memory-unit-of-work.d.ts +11 -0
  178. package/dist/persistence/in-memory-unit-of-work.js +32 -0
  179. package/dist/persistence/in-memory-unit-of-work.js.map +1 -0
  180. package/dist/persistence/key-availability.d.ts +9 -0
  181. package/dist/persistence/key-availability.js +125 -0
  182. package/dist/persistence/key-availability.js.map +1 -0
  183. package/dist/persistence/sqlite/migrations.d.ts +9 -0
  184. package/dist/persistence/sqlite/migrations.js +535 -0
  185. package/dist/persistence/sqlite/migrations.js.map +1 -0
  186. package/dist/persistence/sqlite/schema.d.ts +10 -0
  187. package/dist/persistence/sqlite/schema.js +101 -0
  188. package/dist/persistence/sqlite/schema.js.map +1 -0
  189. package/dist/persistence/sqlite/sqlite-fact-store.d.ts +24 -0
  190. package/dist/persistence/sqlite/sqlite-fact-store.js +207 -0
  191. package/dist/persistence/sqlite/sqlite-fact-store.js.map +1 -0
  192. package/dist/persistence/sqlite/sqlite-source-registry.d.ts +17 -0
  193. package/dist/persistence/sqlite/sqlite-source-registry.js +132 -0
  194. package/dist/persistence/sqlite/sqlite-source-registry.js.map +1 -0
  195. package/dist/persistence/sqlite/sqlite-unit-of-work.d.ts +8 -0
  196. package/dist/persistence/sqlite/sqlite-unit-of-work.js +41 -0
  197. package/dist/persistence/sqlite/sqlite-unit-of-work.js.map +1 -0
  198. package/dist/persistence/sqlite/types.d.ts +24 -0
  199. package/dist/persistence/sqlite/types.js +28 -0
  200. package/dist/persistence/sqlite/types.js.map +1 -0
  201. package/dist/persistence/unit-of-work.d.ts +6 -0
  202. package/dist/persistence/unit-of-work.js +15 -0
  203. package/dist/persistence/unit-of-work.js.map +1 -0
  204. package/dist/proposal/accepted-claim-appender.d.ts +7 -0
  205. package/dist/proposal/accepted-claim-appender.js +16 -0
  206. package/dist/proposal/accepted-claim-appender.js.map +1 -0
  207. package/dist/proposal/in-memory-proposal-queue.d.ts +21 -0
  208. package/dist/proposal/in-memory-proposal-queue.js +218 -0
  209. package/dist/proposal/in-memory-proposal-queue.js.map +1 -0
  210. package/dist/proposal/policy-aware-proposal-queue.d.ts +23 -0
  211. package/dist/proposal/policy-aware-proposal-queue.js +162 -0
  212. package/dist/proposal/policy-aware-proposal-queue.js.map +1 -0
  213. package/dist/proposal/proposal-policy.d.ts +37 -0
  214. package/dist/proposal/proposal-policy.js +72 -0
  215. package/dist/proposal/proposal-policy.js.map +1 -0
  216. package/dist/proposal/proposal-queue.d.ts +13 -0
  217. package/dist/proposal/proposal-queue.js +15 -0
  218. package/dist/proposal/proposal-queue.js.map +1 -0
  219. package/dist/proposal/source-aware-claim-appender.d.ts +13 -0
  220. package/dist/proposal/source-aware-claim-appender.js +47 -0
  221. package/dist/proposal/source-aware-claim-appender.js.map +1 -0
  222. package/dist/proposal/sqlite-proposal-queue.d.ts +26 -0
  223. package/dist/proposal/sqlite-proposal-queue.js +282 -0
  224. package/dist/proposal/sqlite-proposal-queue.js.map +1 -0
  225. package/dist/resolution/resolve-claims.d.ts +4 -0
  226. package/dist/resolution/resolve-claims.js +101 -0
  227. package/dist/resolution/resolve-claims.js.map +1 -0
  228. package/dist/resolution/trust-profile.d.ts +12 -0
  229. package/dist/resolution/trust-profile.js +23 -0
  230. package/dist/resolution/trust-profile.js.map +1 -0
  231. package/dist/resolution/types.d.ts +15 -0
  232. package/dist/resolution/types.js +8 -0
  233. package/dist/resolution/types.js.map +1 -0
  234. package/dist/sdk/create-backend-integrated-life-api-for-test.d.ts +23 -0
  235. package/dist/sdk/create-backend-integrated-life-api-for-test.js +240 -0
  236. package/dist/sdk/create-backend-integrated-life-api-for-test.js.map +1 -0
  237. package/dist/sdk/create-life-api.d.ts +55 -0
  238. package/dist/sdk/create-life-api.js +251 -0
  239. package/dist/sdk/create-life-api.js.map +1 -0
  240. package/dist/sdk/create-sqlite-life-api.d.ts +33 -0
  241. package/dist/sdk/create-sqlite-life-api.js +654 -0
  242. package/dist/sdk/create-sqlite-life-api.js.map +1 -0
  243. package/dist/sdk/life-api.d.ts +27 -0
  244. package/dist/sdk/life-api.js +17 -0
  245. package/dist/sdk/life-api.js.map +1 -0
  246. package/dist/sdk/validation.d.ts +8 -0
  247. package/dist/sdk/validation.js +216 -0
  248. package/dist/sdk/validation.js.map +1 -0
  249. package/dist/source/in-memory-source-registry.d.ts +15 -0
  250. package/dist/source/in-memory-source-registry.js +104 -0
  251. package/dist/source/in-memory-source-registry.js.map +1 -0
  252. package/dist/source/source-aware-fact-store.d.ts +19 -0
  253. package/dist/source/source-aware-fact-store.js +40 -0
  254. package/dist/source/source-aware-fact-store.js.map +1 -0
  255. package/dist/source/source-kind-predicate-policy.d.ts +4 -0
  256. package/dist/source/source-kind-predicate-policy.js +62 -0
  257. package/dist/source/source-kind-predicate-policy.js.map +1 -0
  258. package/dist/source/source-registry.d.ts +11 -0
  259. package/dist/source/source-registry.js +12 -0
  260. package/dist/source/source-registry.js.map +1 -0
  261. package/dist/store/in-memory-fact-store.d.ts +25 -0
  262. package/dist/store/in-memory-fact-store.js +192 -0
  263. package/dist/store/in-memory-fact-store.js.map +1 -0
  264. package/dist/surface/context-query.d.ts +21 -0
  265. package/dist/surface/context-query.js +113 -0
  266. package/dist/surface/context-query.js.map +1 -0
  267. package/dist/surface/evidence-backed-context-query.d.ts +62 -0
  268. package/dist/surface/evidence-backed-context-query.js +240 -0
  269. package/dist/surface/evidence-backed-context-query.js.map +1 -0
  270. package/dist/types/access-context.d.ts +25 -0
  271. package/dist/types/access-context.js +6 -0
  272. package/dist/types/access-context.js.map +1 -0
  273. package/dist/types/claim.d.ts +48 -0
  274. package/dist/types/claim.js +5 -0
  275. package/dist/types/claim.js.map +1 -0
  276. package/dist/types/consent.d.ts +41 -0
  277. package/dist/types/consent.js +3 -0
  278. package/dist/types/consent.js.map +1 -0
  279. package/dist/types/crypto-boundary.d.ts +12 -0
  280. package/dist/types/crypto-boundary.js +15 -0
  281. package/dist/types/crypto-boundary.js.map +1 -0
  282. package/dist/types/evidence.d.ts +31 -0
  283. package/dist/types/evidence.js +8 -0
  284. package/dist/types/evidence.js.map +1 -0
  285. package/dist/types/fact-store.d.ts +24 -0
  286. package/dist/types/fact-store.js +12 -0
  287. package/dist/types/fact-store.js.map +1 -0
  288. package/dist/types/ids.d.ts +36 -0
  289. package/dist/types/ids.js +11 -0
  290. package/dist/types/ids.js.map +1 -0
  291. package/dist/types/proposal.d.ts +38 -0
  292. package/dist/types/proposal.js +7 -0
  293. package/dist/types/proposal.js.map +1 -0
  294. package/dist/types/source.d.ts +33 -0
  295. package/dist/types/source.js +6 -0
  296. package/dist/types/source.js.map +1 -0
  297. package/dist/types/trust.d.ts +24 -0
  298. package/dist/types/trust.js +5 -0
  299. package/dist/types/trust.js.map +1 -0
  300. package/dist/utilities/deep-freeze.d.ts +1 -0
  301. package/dist/utilities/deep-freeze.js +17 -0
  302. package/dist/utilities/deep-freeze.js.map +1 -0
  303. package/package.json +55 -0
@@ -0,0 +1,218 @@
1
+ // InMemoryProposalQueue — Slice-08c hardened.
2
+ //
3
+ // PROPOSAL_QUEUE_EXISTS_001: sole mechanism for agent-authored claim proposals.
4
+ // PROPOSAL_AGENT_CAN_CREATE_001: createProposal requires valid GrantRegistry entry.
5
+ // PROPOSAL_CREATE_USES_GRANT_REGISTRY_001: grant validation uses GrantRegistry, not
6
+ // AgentConsentContext.capabilities (which is non-authoritative per
7
+ // PROPOSAL_CONTEXT_CAPABILITIES_NOT_AUTHORITATIVE_001).
8
+ // PROPOSAL_AGENT_CANNOT_ACCEPT_001 + PROPOSAL_AGENT_CANNOT_REJECT_001: enforced here.
9
+ // PROPOSAL_CANDIDATE_CLAIMS_NOT_LOGGED_BEFORE_ACCEPT_001: _appender never called in createProposal.
10
+ // PROPOSAL_ACCEPT_NO_RAW_FACTSTORE_001: constructor takes AcceptedClaimAppender, not FactStore.
11
+ // PROPOSAL_ACCEPT_ATOMIC_ROLLBACK_001: proposal status updated only AFTER appendAll() succeeds.
12
+ // PROPOSAL_DENIED_CREATE_STORES_NOTHING_001: _proposals.set() only called after all checks pass.
13
+ // PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001: acceptance source must carry all 3 provenance fields.
14
+ // PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_PROPOSAL_001: metadata.acceptedFromProposalId === proposal.id.
15
+ // PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_AGENT_001: metadata.proposedBy === proposal.proposedBy.agentId.
16
+ // PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_GRANT_001: metadata.underGrant === proposal.underGrant.
17
+ //
18
+ // PROPOSAL_ACCEPT_ATOMICITY_MVP_LIMITATION_001 (InMemory):
19
+ // Source metadata validation + proposal status update bracket appendAll() synchronously.
20
+ // If appendAll() throws, _proposals retains "pending" (no partial acceptance).
21
+ // This is single-process best-effort atomicity — not a database transaction.
22
+ // SQLite ProposalQueue with transactional guarantees is deferred.
23
+ import { asISOTime, asProposalId } from "../types/ids.js";
24
+ function deepFreezeProposal(p) {
25
+ const frozen = {
26
+ ...p,
27
+ proposedBy: Object.freeze({ ...p.proposedBy }),
28
+ candidateClaims: Object.freeze([...p.candidateClaims]),
29
+ ...(p.decidedBy !== undefined ? { decidedBy: Object.freeze({ ...p.decidedBy }) } : {}),
30
+ ...(p.resultingClaimIds !== undefined ? { resultingClaimIds: Object.freeze([...p.resultingClaimIds]) } : {}),
31
+ };
32
+ return Object.freeze(frozen);
33
+ }
34
+ function isDecider(ctx) {
35
+ return ctx.kind === "owner" || ctx.kind === "system_projection" || ctx.kind === "test";
36
+ }
37
+ export class InMemoryProposalQueue {
38
+ _appender;
39
+ _grantRegistry;
40
+ _sourceRegistry;
41
+ _proposals = new Map();
42
+ // PROPOSAL_ACCEPT_NO_RAW_FACTSTORE_001: AcceptedClaimAppender (not raw FactStore).
43
+ // PROPOSAL_CREATE_USES_GRANT_REGISTRY_001: GrantRegistry is the auth source for createProposal.
44
+ // PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001: SourceRegistry is needed to resolve acceptance
45
+ // source and validate its provenance metadata before any writes.
46
+ constructor(_appender, _grantRegistry, _sourceRegistry) {
47
+ this._appender = _appender;
48
+ this._grantRegistry = _grantRegistry;
49
+ this._sourceRegistry = _sourceRegistry;
50
+ }
51
+ // ── createProposal ──────────────────────────────────────────────────────────
52
+ // PROPOSAL_QUEUE_ASYNC_INTEGRATION_DECIDED_001: async to satisfy updated ProposalQueue interface.
53
+ // No I/O here — the async wrapper has no behavioral effect on InMemoryProposalQueue.
54
+ async createProposal(ctx, input) {
55
+ // PROPOSAL_CREATE_USES_GRANT_REGISTRY_001: resolve grant from registry — ctx is untrusted.
56
+ const grant = this._grantRegistry.lookup(ctx.grantId);
57
+ if (grant === undefined) {
58
+ throw new Error("PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant not found in registry — " +
59
+ `grantId "${ctx.grantId}" has not been registered`);
60
+ }
61
+ if (grant.grantedTo.agentId !== ctx.agentId) {
62
+ throw new Error("PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant belongs to a different agent — " +
63
+ `grant.grantedTo.agentId="${grant.grantedTo.agentId}", ctx.agentId="${ctx.agentId}"`);
64
+ }
65
+ if (grant.purpose !== ctx.purpose) {
66
+ throw new Error(`PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: purpose mismatch — ` +
67
+ `grant.purpose="${grant.purpose}", ctx.purpose="${ctx.purpose}"`);
68
+ }
69
+ if (!grant.capabilities.includes("propose")) {
70
+ throw new Error("PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant lacks 'propose' capability — " +
71
+ `capabilities=${JSON.stringify(grant.capabilities)}`);
72
+ }
73
+ const now = Date.now();
74
+ if (new Date(grant.notAfter).getTime() <= now) {
75
+ throw new Error(`PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant is expired (notAfter="${grant.notAfter}")`);
76
+ }
77
+ if (new Date(grant.notBefore).getTime() > now) {
78
+ throw new Error(`PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant is not yet active (notBefore="${grant.notBefore}")`);
79
+ }
80
+ if (grant.revokedAt !== undefined) {
81
+ throw new Error(`PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant has been revoked (revokedAt="${grant.revokedAt}")`);
82
+ }
83
+ if (input.candidateClaims.length === 0) {
84
+ throw new Error("PROPOSAL_QUEUE_EXISTS_001: candidateClaims must not be empty");
85
+ }
86
+ // PROPOSAL_DENIED_CREATE_STORES_NOTHING_001: only reach _proposals.set after all checks pass.
87
+ const id = asProposalId(`prop_${globalThis.crypto.randomUUID()}`);
88
+ const proposal = deepFreezeProposal({
89
+ id,
90
+ proposedBy: { agentId: ctx.agentId, grantId: ctx.grantId, purpose: ctx.purpose },
91
+ underGrant: ctx.grantId,
92
+ candidateClaims: [...input.candidateClaims],
93
+ ...(input.rationale !== undefined ? { rationale: input.rationale } : {}),
94
+ status: "pending",
95
+ createdAt: asISOTime(new Date().toISOString()),
96
+ });
97
+ this._proposals.set(id, proposal);
98
+ return proposal;
99
+ }
100
+ // ── getProposal ─────────────────────────────────────────────────────────────
101
+ getProposal(ctx, proposalId) {
102
+ if (ctx == null)
103
+ throw new TypeError("AccessContext is required");
104
+ return this._proposals.get(proposalId);
105
+ }
106
+ // ── listProposals ───────────────────────────────────────────────────────────
107
+ listProposals(ctx, filter) {
108
+ if (ctx == null)
109
+ throw new TypeError("AccessContext is required");
110
+ let proposals = Array.from(this._proposals.values());
111
+ if (filter?.status !== undefined)
112
+ proposals = proposals.filter((p) => p.status === filter.status);
113
+ if (filter?.proposedByAgent !== undefined)
114
+ proposals = proposals.filter((p) => p.proposedBy.agentId === filter.proposedByAgent);
115
+ if (filter?.underGrant !== undefined)
116
+ proposals = proposals.filter((p) => p.underGrant === filter.underGrant);
117
+ return proposals;
118
+ }
119
+ // ── acceptProposal ──────────────────────────────────────────────────────────
120
+ async acceptProposal(ctx, proposalId, options) {
121
+ // PROPOSAL_AGENT_CANNOT_ACCEPT_001
122
+ if (!isDecider(ctx)) {
123
+ throw new Error("PROPOSAL_AGENT_CANNOT_ACCEPT_001: AgentConsentContext and AuditContext cannot accept proposals");
124
+ }
125
+ const proposal = this._getExistingPending(proposalId, "accept");
126
+ // PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001 / MATCHES_*: resolve source and validate
127
+ // provenance metadata before any writes. These checks are part of the atomic pre-validation
128
+ // phase (PROPOSAL_ACCEPT_ATOMICITY_MVP_LIMITATION_001) — failure here leaves proposal "pending".
129
+ const source = this._sourceRegistry.getSource(ctx, options.sourceId);
130
+ if (source === undefined) {
131
+ throw new Error(`SOURCE_UNKNOWN_REJECTED_001: sourceId "${options.sourceId}" is not registered`);
132
+ }
133
+ if (source.status !== "active") {
134
+ throw new Error(`SOURCE_INACTIVE_REJECTED_001: sourceId "${options.sourceId}" is inactive`);
135
+ }
136
+ const meta = source.metadata;
137
+ if (meta === undefined || !("acceptedFromProposalId" in meta)) {
138
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001: acceptance source "${options.sourceId}" must have metadata.acceptedFromProposalId`);
139
+ }
140
+ if (meta["acceptedFromProposalId"] !== proposal.id) {
141
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_PROPOSAL_001: metadata.acceptedFromProposalId "${String(meta["acceptedFromProposalId"])}" does not match proposal.id "${proposal.id}"`);
142
+ }
143
+ if (!("proposedBy" in meta)) {
144
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001: acceptance source "${options.sourceId}" must have metadata.proposedBy`);
145
+ }
146
+ if (meta["proposedBy"] !== proposal.proposedBy.agentId) {
147
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_AGENT_001: metadata.proposedBy "${String(meta["proposedBy"])}" does not match proposal.proposedBy.agentId "${proposal.proposedBy.agentId}"`);
148
+ }
149
+ if (!("underGrant" in meta)) {
150
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001: acceptance source "${options.sourceId}" must have metadata.underGrant`);
151
+ }
152
+ if (meta["underGrant"] !== proposal.underGrant) {
153
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_GRANT_001: metadata.underGrant "${String(meta["underGrant"])}" does not match proposal.underGrant "${proposal.underGrant}"`);
154
+ }
155
+ // Override sourceId for every candidate claim before appending.
156
+ // candidateClaims may carry agent_proposal sourceId — acceptance source replaces it.
157
+ const finalClaims = proposal.candidateClaims.map((c) => ({ ...c, sourceId: options.sourceId }));
158
+ // PROPOSAL_ACCEPT_ATOMIC_ROLLBACK_001: appendAll is the atomic write gate.
159
+ // If this throws, no claims are written and proposal remains "pending" (not mutated below).
160
+ // PROPOSAL_ACCEPT_USES_SOURCE_AWARE_FACTSTORE_001: enforced by AcceptedClaimAppender contract.
161
+ const claimIds = await this._appender.appendAll(ctx, finalClaims);
162
+ // Update status only AFTER successful appendAll.
163
+ const accepted = deepFreezeProposal({
164
+ ...this._spreadProposal(proposal),
165
+ status: "accepted",
166
+ decidedAt: asISOTime(new Date().toISOString()),
167
+ decidedBy: ctx,
168
+ resultingClaimIds: claimIds,
169
+ });
170
+ this._proposals.set(proposalId, accepted);
171
+ return accepted;
172
+ }
173
+ // ── rejectProposal ──────────────────────────────────────────────────────────
174
+ // PROPOSAL_QUEUE_ASYNC_INTEGRATION_DECIDED_001: async to satisfy updated ProposalQueue interface.
175
+ async rejectProposal(ctx, proposalId, reason) {
176
+ // PROPOSAL_AGENT_CANNOT_REJECT_001
177
+ if (!isDecider(ctx)) {
178
+ throw new Error("PROPOSAL_AGENT_CANNOT_REJECT_001: AgentConsentContext and AuditContext cannot reject proposals");
179
+ }
180
+ const proposal = this._getExistingPending(proposalId, "reject");
181
+ const rejected = deepFreezeProposal({
182
+ ...this._spreadProposal(proposal),
183
+ status: "rejected",
184
+ decidedAt: asISOTime(new Date().toISOString()),
185
+ decidedBy: ctx,
186
+ rejectionReason: reason,
187
+ });
188
+ this._proposals.set(proposalId, rejected);
189
+ return rejected;
190
+ }
191
+ // ── Private helpers ─────────────────────────────────────────────────────────
192
+ _getExistingPending(proposalId, action) {
193
+ const proposal = this._proposals.get(proposalId);
194
+ if (proposal === undefined) {
195
+ throw new Error(`PROPOSAL_QUEUE_EXISTS_001: proposal "${proposalId}" not found`);
196
+ }
197
+ if (proposal.status !== "pending") {
198
+ throw new Error(`PROPOSAL_STATUS_IMMUTABLE_AFTER_DECISION_001: proposal "${proposalId}" is ` +
199
+ `"${proposal.status}" and cannot be ${action}ed again`);
200
+ }
201
+ return proposal;
202
+ }
203
+ // Spread a Proposal to a mutable base, excluding optional decision fields.
204
+ // Needed because Object.freeze + spread can include absent optional keys as undefined,
205
+ // which would violate exactOptionalPropertyTypes.
206
+ _spreadProposal(p) {
207
+ return {
208
+ id: p.id,
209
+ proposedBy: p.proposedBy,
210
+ underGrant: p.underGrant,
211
+ candidateClaims: p.candidateClaims,
212
+ status: p.status,
213
+ createdAt: p.createdAt,
214
+ ...(p.rationale !== undefined ? { rationale: p.rationale } : {}),
215
+ };
216
+ }
217
+ }
218
+ //# sourceMappingURL=in-memory-proposal-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory-proposal-queue.js","sourceRoot":"","sources":["../../src/proposal/in-memory-proposal-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { AgentConsentContext, AccessContext } from "../types/access-context.js";
2
+ import type { AcceptOptions, Proposal, ProposalDecider, ProposalFilter, ProposalInput } from "../types/proposal.js";
3
+ import type { ProposalId } from "../types/ids.js";
4
+ import type { FactoryCompatibleProposalQueue } from "./proposal-queue.js";
5
+ import type { ProposalPolicy } from "./proposal-policy.js";
6
+ import type { SourceRegistry } from "../source/source-registry.js";
7
+ import type { AuditLog } from "../audit/audit-log.js";
8
+ export declare class PolicyAwareProposalQueue implements FactoryCompatibleProposalQueue {
9
+ private readonly _inner;
10
+ private readonly _policy;
11
+ private readonly _sourceRegistry;
12
+ private readonly _auditLog;
13
+ readonly factoryCompatible: "durable-proposal-queue";
14
+ constructor(_inner: FactoryCompatibleProposalQueue, _policy: ProposalPolicy, _sourceRegistry: SourceRegistry, _auditLog: AuditLog);
15
+ getProposal(ctx: AccessContext, proposalId: ProposalId): Proposal | undefined;
16
+ listProposals(ctx: AccessContext, filter?: ProposalFilter): Proposal[];
17
+ acceptProposal(ctx: ProposalDecider, proposalId: ProposalId, options: AcceptOptions): Promise<Proposal>;
18
+ rejectProposal(ctx: ProposalDecider, proposalId: ProposalId, reason: string): Promise<Proposal>;
19
+ createProposal(ctx: AgentConsentContext, input: ProposalInput): Promise<Proposal>;
20
+ private _evaluateCombined;
21
+ private _autoReject;
22
+ private _autoAccept;
23
+ }
@@ -0,0 +1,162 @@
1
+ // Platform-02 — PolicyAwareProposalQueue (factory-internal decorator).
2
+ //
3
+ // PROPOSAL_AUTO_ACCEPTED_BY_POLICY_001: auto-accepted proposals produce a durable audit
4
+ // event with reasonCode PROPOSAL_AUTO_ACCEPTED_BY_POLICY and the resulting claim ids.
5
+ // PROPOSAL_AUTO_REJECTED_BY_POLICY_001: same for auto-reject, decision "deny".
6
+ // PROPOSAL_POLICY_AUTO_ACCEPT_FAILURE_FALLS_BACK_TO_MANUAL_001: accept-path failure leaves
7
+ // the proposal pending; createProposal does not throw.
8
+ // PROPOSAL_POLICY_EVALUATED_AFTER_CREATE_VALIDATION_001: policy runs only after the inner
9
+ // queue's grant/capability validation succeeded; an invalid grant still throws exactly
10
+ // as before.
11
+ // PROPOSAL_POLICY_SCOPE_DERIVED_FROM_PREDICATE_001: scope string is "write:<predicate>";
12
+ // combination rule: any auto-reject → reject; all auto-accept → accept; else manual.
13
+ // PROPOSAL_POLICY_ACCEPTANCE_SOURCE_PER_PROPOSAL_001: auto-accept registers a fresh
14
+ // document_upload source "policy-accept:<proposalId>" carrying the three provenance
15
+ // metadata fields.
16
+ //
17
+ // NOT exported from src/index.ts — factory-internal wiring only.
18
+ import { buildAuditEvent } from "../audit/audit-log.js";
19
+ import { asSourceId, asISOTime } from "../types/ids.js";
20
+ // Module-private system decider: auto-decisions (auto-accept / auto-reject) are system
21
+ // decisions made by the configured ProposalPolicy, not by a human owner. The inner queue
22
+ // validates decider kind via ProposalDecider (owner | system_projection | test).
23
+ const SYSTEM_DECIDER = { kind: "system_projection" };
24
+ export class PolicyAwareProposalQueue {
25
+ _inner;
26
+ _policy;
27
+ _sourceRegistry;
28
+ _auditLog;
29
+ // Truthful marker: this decorator delegates all durable writes to the inner
30
+ // durable-proposal-queue; it adds no separate storage of its own.
31
+ factoryCompatible = "durable-proposal-queue";
32
+ constructor(_inner, _policy, _sourceRegistry, _auditLog) {
33
+ this._inner = _inner;
34
+ this._policy = _policy;
35
+ this._sourceRegistry = _sourceRegistry;
36
+ this._auditLog = _auditLog;
37
+ }
38
+ getProposal(ctx, proposalId) {
39
+ return this._inner.getProposal(ctx, proposalId);
40
+ }
41
+ listProposals(ctx, filter) {
42
+ return this._inner.listProposals(ctx, filter);
43
+ }
44
+ acceptProposal(ctx, proposalId, options) {
45
+ return this._inner.acceptProposal(ctx, proposalId, options);
46
+ }
47
+ rejectProposal(ctx, proposalId, reason) {
48
+ return this._inner.rejectProposal(ctx, proposalId, reason);
49
+ }
50
+ // PROPOSAL_POLICY_EVALUATED_AFTER_CREATE_VALIDATION_001: all existing grant/capability
51
+ // validation happens inside _inner.createProposal — if it throws, policy is never consulted.
52
+ async createProposal(ctx, input) {
53
+ const proposal = await this._inner.createProposal(ctx, input);
54
+ const disposition = await this._evaluateCombined(ctx, proposal);
55
+ if (disposition === "manual") {
56
+ // PROPOSAL_POLICY_OPTIONAL_NO_CHECK_WHEN_ABSENT_001 backward-compat is handled at
57
+ // factory level (queue not wrapped at all). Manual here means today's behavior.
58
+ return proposal;
59
+ }
60
+ if (disposition === "auto-reject") {
61
+ return this._autoReject(ctx, proposal);
62
+ }
63
+ // disposition === "auto-accept"
64
+ return this._autoAccept(ctx, proposal);
65
+ }
66
+ // PROPOSAL_POLICY_SCOPE_DERIVED_FROM_PREDICATE_001: evaluate per candidate claim and
67
+ // combine — any auto-reject wins; else all auto-accept required; else manual.
68
+ async _evaluateCombined(ctx, proposal) {
69
+ const dispositions = [];
70
+ for (const claim of proposal.candidateClaims) {
71
+ let disposition;
72
+ try {
73
+ disposition = await this._policy.evaluate({
74
+ sourceId: ctx.agentId,
75
+ scope: "write:" + claim.predicate,
76
+ subjectId: claim.subject,
77
+ });
78
+ }
79
+ catch {
80
+ // PROPOSAL_POLICY_FAIL_SAFE_MANUAL_001: policy exception → treat as manual.
81
+ disposition = "manual";
82
+ }
83
+ dispositions.push(disposition);
84
+ }
85
+ if (dispositions.some((d) => d === "auto-reject"))
86
+ return "auto-reject";
87
+ if (dispositions.length > 0 && dispositions.every((d) => d === "auto-accept"))
88
+ return "auto-accept";
89
+ return "manual";
90
+ }
91
+ async _autoReject(ctx, proposal) {
92
+ const rejected = await this._inner.rejectProposal(SYSTEM_DECIDER, proposal.id, "PROPOSAL_AUTO_REJECTED_BY_POLICY_001: proposal auto-rejected by configured ProposalPolicy");
93
+ // Audit-write failure on this success path propagates — fail-closed,
94
+ // AUDIT_FAIL_CLOSED_001-consistent.
95
+ await this._auditLog.write(buildAuditEvent({
96
+ actor: ctx.agentId,
97
+ grantId: ctx.grantId,
98
+ purpose: ctx.purpose,
99
+ decision: "deny",
100
+ reasonCode: "PROPOSAL_AUTO_REJECTED_BY_POLICY",
101
+ selectorFingerprint: "proposal-policy:" + proposal.id,
102
+ resultCount: 0,
103
+ resultClaimIds: [],
104
+ now: asISOTime(new Date().toISOString()),
105
+ }));
106
+ return rejected;
107
+ }
108
+ async _autoAccept(ctx, proposal) {
109
+ try {
110
+ // PROPOSAL_POLICY_ACCEPTANCE_SOURCE_PER_PROPOSAL_001
111
+ const sourceId = asSourceId("policy-accept:" + proposal.id);
112
+ this._sourceRegistry.registerSource(SYSTEM_DECIDER, {
113
+ id: sourceId,
114
+ kind: "document_upload",
115
+ label: "Policy auto-accept from trusted source " + ctx.agentId,
116
+ metadata: {
117
+ acceptedFromProposalId: proposal.id,
118
+ proposedBy: proposal.proposedBy.agentId,
119
+ underGrant: proposal.underGrant,
120
+ },
121
+ });
122
+ const accepted = await this._inner.acceptProposal(SYSTEM_DECIDER, proposal.id, { sourceId });
123
+ // Audit-write failure on this success path propagates — fail-closed,
124
+ // AUDIT_FAIL_CLOSED_001-consistent.
125
+ await this._auditLog.write(buildAuditEvent({
126
+ actor: ctx.agentId,
127
+ grantId: ctx.grantId,
128
+ purpose: ctx.purpose,
129
+ decision: "allow",
130
+ reasonCode: "PROPOSAL_AUTO_ACCEPTED_BY_POLICY",
131
+ selectorFingerprint: "proposal-policy:" + proposal.id,
132
+ resultCount: accepted.resultingClaimIds?.length ?? 0,
133
+ resultClaimIds: accepted.resultingClaimIds ?? [],
134
+ now: asISOTime(new Date().toISOString()),
135
+ }));
136
+ return accepted;
137
+ }
138
+ catch {
139
+ // PROPOSAL_POLICY_AUTO_ACCEPT_FAILURE_FALLS_BACK_TO_MANUAL_001: fallback to manual
140
+ // review — never fail the caller's createProposal. Audit failure in THIS catch path
141
+ // only is swallowed (best-effort).
142
+ try {
143
+ await this._auditLog.write(buildAuditEvent({
144
+ actor: ctx.agentId,
145
+ grantId: ctx.grantId,
146
+ purpose: ctx.purpose,
147
+ decision: "deny",
148
+ reasonCode: "PROPOSAL_AUTO_ACCEPT_FAILED_MANUAL_FALLBACK",
149
+ selectorFingerprint: "proposal-policy:" + proposal.id,
150
+ resultCount: 0,
151
+ resultClaimIds: [],
152
+ now: asISOTime(new Date().toISOString()),
153
+ }));
154
+ }
155
+ catch {
156
+ // Best-effort — swallow audit failure in this catch path only.
157
+ }
158
+ return proposal;
159
+ }
160
+ }
161
+ }
162
+ //# sourceMappingURL=policy-aware-proposal-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-aware-proposal-queue.js","sourceRoot":"","sources":["../../src/proposal/policy-aware-proposal-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { TrustedDataSourceRegistry } from "../datasource/trusted-data-source-registry.js";
2
+ export type ProposalDisposition = "auto-accept" | "manual" | "auto-reject";
3
+ export interface ProposalPolicyInput {
4
+ /** Proposing institution — equals the proposing agent's agentId. */
5
+ readonly sourceId: string;
6
+ /** "write:<predicate>" derived from a candidate claim. */
7
+ readonly scope: string;
8
+ /** Candidate claim subject (PersonId as string). */
9
+ readonly subjectId: string;
10
+ }
11
+ export interface ProposalPolicy {
12
+ evaluate(input: ProposalPolicyInput): Promise<ProposalDisposition>;
13
+ }
14
+ /** Always "manual" — matches pre-Platform-02 behavior when no policy is configured. */
15
+ export declare class DefaultProposalPolicy implements ProposalPolicy {
16
+ evaluate(_input: ProposalPolicyInput): Promise<ProposalDisposition>;
17
+ }
18
+ /**
19
+ * Evaluation order:
20
+ * 1. sourceId in reject-list → "auto-reject" (PROPOSAL_POLICY_REJECT_LIST_PRECEDENCE_001).
21
+ * 2. registry.isSourceTrusted(sourceId, scope) === true AND subjectId not deny-listed
22
+ * → "auto-accept".
23
+ * 3. everything else → "manual" (untrusted, deny-listed subject, or registry threw —
24
+ * PROPOSAL_POLICY_FAIL_SAFE_MANUAL_001; NEVER auto-accept on error).
25
+ */
26
+ export declare class RegistryBackedProposalPolicy implements ProposalPolicy {
27
+ private readonly _registry;
28
+ private readonly _rejectListedSourceIds;
29
+ private readonly _denyListedSubjectIds;
30
+ constructor(registry: TrustedDataSourceRegistry, opts?: {
31
+ readonly rejectListedSourceIds?: Iterable<string>;
32
+ readonly denyListedSubjectIds?: Iterable<string>;
33
+ });
34
+ evaluate(input: ProposalPolicyInput): Promise<ProposalDisposition>;
35
+ addSourceToRejectList(id: string): this;
36
+ addSubjectToDenyList(id: string): this;
37
+ }
@@ -0,0 +1,72 @@
1
+ // Platform-02 — ProposalPolicy.
2
+ //
3
+ // PROPOSAL_POLICY_MANUAL_DEFAULT_001: DefaultProposalPolicy and every unknown/uncertain
4
+ // case → "manual"; identical to pre-Platform-02 behavior.
5
+ // PROPOSAL_POLICY_FAIL_SAFE_MANUAL_001: policy/registry exception during evaluation →
6
+ // "manual", never "auto-accept".
7
+ // PROPOSAL_POLICY_REJECT_LIST_PRECEDENCE_001: explicit reject-list wins over trust — a
8
+ // reject-listed source is auto-rejected even if the registry would trust it.
9
+ // PROPOSAL_POLICY_SUBJECT_DENY_LIST_BLOCKS_AUTO_ACCEPT_001: deny-listed subject downgrades
10
+ // auto-accept to manual (not auto-reject).
11
+ // ─── DefaultProposalPolicy ────────────────────────────────────────────────────────
12
+ /** Always "manual" — matches pre-Platform-02 behavior when no policy is configured. */
13
+ export class DefaultProposalPolicy {
14
+ async evaluate(_input) {
15
+ return "manual";
16
+ }
17
+ }
18
+ // ─── RegistryBackedProposalPolicy ─────────────────────────────────────────────────
19
+ /**
20
+ * Evaluation order:
21
+ * 1. sourceId in reject-list → "auto-reject" (PROPOSAL_POLICY_REJECT_LIST_PRECEDENCE_001).
22
+ * 2. registry.isSourceTrusted(sourceId, scope) === true AND subjectId not deny-listed
23
+ * → "auto-accept".
24
+ * 3. everything else → "manual" (untrusted, deny-listed subject, or registry threw —
25
+ * PROPOSAL_POLICY_FAIL_SAFE_MANUAL_001; NEVER auto-accept on error).
26
+ */
27
+ export class RegistryBackedProposalPolicy {
28
+ _registry;
29
+ _rejectListedSourceIds = new Set();
30
+ _denyListedSubjectIds = new Set();
31
+ constructor(registry, opts) {
32
+ this._registry = registry;
33
+ if (opts?.rejectListedSourceIds !== undefined) {
34
+ for (const id of opts.rejectListedSourceIds)
35
+ this._rejectListedSourceIds.add(id);
36
+ }
37
+ if (opts?.denyListedSubjectIds !== undefined) {
38
+ for (const id of opts.denyListedSubjectIds)
39
+ this._denyListedSubjectIds.add(id);
40
+ }
41
+ }
42
+ async evaluate(input) {
43
+ // PROPOSAL_POLICY_REJECT_LIST_PRECEDENCE_001: reject-list wins over trust.
44
+ if (this._rejectListedSourceIds.has(input.sourceId)) {
45
+ return "auto-reject";
46
+ }
47
+ let trusted;
48
+ try {
49
+ trusted = await this._registry.isSourceTrusted(input.sourceId, input.scope);
50
+ }
51
+ catch {
52
+ // PROPOSAL_POLICY_FAIL_SAFE_MANUAL_001: registry exception → manual, never auto-accept.
53
+ return "manual";
54
+ }
55
+ if (!trusted)
56
+ return "manual";
57
+ // PROPOSAL_POLICY_SUBJECT_DENY_LIST_BLOCKS_AUTO_ACCEPT_001
58
+ if (this._denyListedSubjectIds.has(input.subjectId)) {
59
+ return "manual";
60
+ }
61
+ return "auto-accept";
62
+ }
63
+ addSourceToRejectList(id) {
64
+ this._rejectListedSourceIds.add(id);
65
+ return this;
66
+ }
67
+ addSubjectToDenyList(id) {
68
+ this._denyListedSubjectIds.add(id);
69
+ return this;
70
+ }
71
+ }
72
+ //# sourceMappingURL=proposal-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-policy.js","sourceRoot":"","sources":["../../src/proposal/proposal-policy.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,EAAE;AACF,wFAAwF;AACxF,4DAA4D;AAC5D,sFAAsF;AACtF,mCAAmC;AACnC,uFAAuF;AACvF,+EAA+E;AAC/E,2FAA2F;AAC3F,6CAA6C;AAqB7C,qFAAqF;AAErF,uFAAuF;AACvF,MAAM,OAAO,qBAAqB;IAChC,KAAK,CAAC,QAAQ,CAAC,MAA2B;QACxC,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED,qFAAqF;AAErF;;;;;;;GAOG;AACH,MAAM,OAAO,4BAA4B;IACtB,SAAS,CAA4B;IACrC,sBAAsB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC3C,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAC;IAE3D,YACE,QAAmC,EACnC,IAGC;QAED,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,IAAI,EAAE,qBAAqB,KAAK,SAAS,EAAE,CAAC;YAC9C,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,qBAAqB;gBAAE,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnF,CAAC;QACD,IAAI,IAAI,EAAE,oBAAoB,KAAK,SAAS,EAAE,CAAC;YAC7C,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,oBAAoB;gBAAE,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAA0B;QACvC,2EAA2E;QAC3E,IAAI,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpD,OAAO,aAAa,CAAC;QACvB,CAAC;QAED,IAAI,OAAgB,CAAC;QACrB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9E,CAAC;QAAC,MAAM,CAAC;YACP,wFAAwF;YACxF,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,IAAI,CAAC,OAAO;YAAE,OAAO,QAAQ,CAAC;QAE9B,2DAA2D;QAC3D,IAAI,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YACpD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,qBAAqB,CAAC,EAAU;QAC9B,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB,CAAC,EAAU;QAC7B,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { ProposalId } from "../types/ids.js";
2
+ import type { AgentConsentContext, AccessContext } from "../types/access-context.js";
3
+ import type { AcceptOptions, Proposal, ProposalDecider, ProposalFilter, ProposalInput } from "../types/proposal.js";
4
+ export interface ProposalQueue {
5
+ createProposal(ctx: AgentConsentContext, input: ProposalInput): Promise<Proposal>;
6
+ getProposal(ctx: AccessContext, proposalId: ProposalId): Proposal | undefined;
7
+ listProposals(ctx: AccessContext, filter?: ProposalFilter): Proposal[];
8
+ acceptProposal(ctx: ProposalDecider, proposalId: ProposalId, options: AcceptOptions): Promise<Proposal>;
9
+ rejectProposal(ctx: ProposalDecider, proposalId: ProposalId, reason: string): Promise<Proposal>;
10
+ }
11
+ export interface FactoryCompatibleProposalQueue extends ProposalQueue {
12
+ readonly factoryCompatible: "durable-proposal-queue";
13
+ }
@@ -0,0 +1,15 @@
1
+ // ProposalQueue interface — Slice-08 / Production-06d-b-a.
2
+ //
3
+ // PROPOSAL_AGENT_CAN_CREATE_001: AgentConsentContext may create proposals — validated via GrantRegistry.
4
+ // PROPOSAL_CREATE_USES_GRANT_REGISTRY_001: GrantRegistry is authoritative; ctx.capabilities is ignored.
5
+ // PROPOSAL_AGENT_CANNOT_ACCEPT_001: AgentConsentContext cannot accept proposals.
6
+ // PROPOSAL_AGENT_CANNOT_REJECT_001: AgentConsentContext cannot reject proposals.
7
+ // PROPOSAL_ACCEPT_OWNER_ONLY_001: acceptProposal is restricted to Owner / System / Test contexts.
8
+ // PROPOSAL_REJECT_OWNER_ONLY_001: rejectProposal is restricted to Owner / System / Test contexts.
9
+ //
10
+ // PROPOSAL_QUEUE_ASYNC_INTEGRATION_DECIDED_001 (Production-06d-b-a): createProposal / rejectProposal /
11
+ // acceptProposal are all async. Encryption is required before every durable write —
12
+ // AesGcmCryptoBoundary.encryptJson() uses WebCrypto; no synchronous path exists.
13
+ // getProposal / listProposals remain sync (in-memory cache / Map reads).
14
+ export {};
15
+ //# sourceMappingURL=proposal-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-queue.js","sourceRoot":"","sources":["../../src/proposal/proposal-queue.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,yGAAyG;AACzG,wGAAwG;AACxG,iFAAiF;AACjF,iFAAiF;AACjF,kGAAkG;AAClG,kGAAkG;AAClG,EAAE;AACF,uGAAuG;AACvG,oFAAoF;AACpF,iFAAiF;AACjF,yEAAyE"}
@@ -0,0 +1,13 @@
1
+ import type { ClaimId } from "../types/ids.js";
2
+ import type { AppendClaimInput } from "../types/claim.js";
3
+ import type { AcceptedClaimAppender, AppendDecider } from "./accepted-claim-appender.js";
4
+ import type { SourceRegistry } from "../source/source-registry.js";
5
+ import { SourceAwareFactStore } from "../source/source-aware-fact-store.js";
6
+ import type { UnitOfWork } from "../persistence/unit-of-work.js";
7
+ export declare class SourceAwareClaimAppender implements AcceptedClaimAppender {
8
+ private readonly _store;
9
+ private readonly _registry;
10
+ private readonly _uow;
11
+ constructor(_store: SourceAwareFactStore, _registry: SourceRegistry, _uow: UnitOfWork);
12
+ appendAll(ctx: AppendDecider, claims: ReadonlyArray<AppendClaimInput>): Promise<ReadonlyArray<ClaimId>>;
13
+ }