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,47 @@
1
+ // SourceAwareClaimAppender — Slice-08b.
2
+ //
3
+ // Implements AcceptedClaimAppender using SourceAwareFactStore + SourceRegistry.
4
+ // PROPOSAL_ACCEPT_USES_SOURCE_AWARE_FACTSTORE_001: all acceptance writes go through
5
+ // SourceAwareFactStore, which calls assertCanAppend() on every append.
6
+ //
7
+ // Atomicity (InMemory):
8
+ // Phase 1 — Pre-validate all claims synchronously via registry.assertCanAppend().
9
+ // If any fails, throw immediately with no writes.
10
+ // Phase 2 — Write all claims sequentially via SourceAwareFactStore.append().
11
+ // For InMemory, writes are infallible after Phase 1 validation.
12
+ // For SQLite, a transaction would be required — defer to SQLiteProposalQueue.
13
+ //
14
+ // PROPOSAL_CONTEXT_CAPABILITIES_NOT_AUTHORITATIVE_001: this class does not inspect
15
+ // AgentConsentContext.capabilities. Source validation comes from SourceRegistry.
16
+ export class SourceAwareClaimAppender {
17
+ _store;
18
+ _registry;
19
+ _uow;
20
+ constructor(_store, _registry, _uow) {
21
+ this._store = _store;
22
+ this._registry = _registry;
23
+ this._uow = _uow;
24
+ }
25
+ async appendAll(ctx, claims) {
26
+ if (claims.length === 0)
27
+ return [];
28
+ // Phase 1: pre-validate ALL claims (synchronous, throws before any write)
29
+ // PROPOSAL_ACCEPT_ATOMIC_ROLLBACK_001: if any claim fails here, none are written.
30
+ for (const claim of claims) {
31
+ this._registry.assertCanAppend(claim);
32
+ }
33
+ // Phase 2: write all atomically — UNIT_OF_WORK_PROPOSAL_ACCEPT_ATOMIC_001 /
34
+ // UNIT_OF_WORK_NO_PARTIAL_ACCEPTED_CLAIMS_001.
35
+ // For InMemory, Phase 2 is infallible after Phase 1 (NoopUnitOfWork is sufficient).
36
+ // For SQLite, inject SQLiteUnitOfWork to guarantee BEGIN/COMMIT/ROLLBACK.
37
+ return this._uow.run(async () => {
38
+ const ids = [];
39
+ for (const claim of claims) {
40
+ const { claimId } = await this._store.append(claim, ctx);
41
+ ids.push(claimId);
42
+ }
43
+ return ids;
44
+ });
45
+ }
46
+ }
47
+ //# sourceMappingURL=source-aware-claim-appender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-aware-claim-appender.js","sourceRoot":"","sources":["../../src/proposal/source-aware-claim-appender.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,EAAE;AACF,gFAAgF;AAChF,oFAAoF;AACpF,uEAAuE;AACvE,EAAE;AACF,wBAAwB;AACxB,oFAAoF;AACpF,8DAA8D;AAC9D,+EAA+E;AAC/E,4EAA4E;AAC5E,0FAA0F;AAC1F,EAAE;AACF,mFAAmF;AACnF,iFAAiF;AASjF,MAAM,OAAO,wBAAwB;IAEhB;IACA;IACA;IAHnB,YACmB,MAA+B,EAC/B,SAAyB,EACzB,IAAqB;QAFrB,WAAM,GAAN,MAAM,CAAyB;QAC/B,cAAS,GAAT,SAAS,CAAgB;QACzB,SAAI,GAAJ,IAAI,CAAiB;IACrC,CAAC;IAEJ,KAAK,CAAC,SAAS,CAAC,GAAkB,EAAE,MAAuC;QACzE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEnC,0EAA0E;QAC1E,kFAAkF;QAClF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACxC,CAAC;QAED,4EAA4E;QAC5E,+CAA+C;QAC/C,oFAAoF;QACpF,0EAA0E;QAC1E,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAC9B,MAAM,GAAG,GAAc,EAAE,CAAC;YAC1B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBACzD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ import type { Database } from "better-sqlite3";
2
+ import type { ProposalId } from "../types/ids.js";
3
+ import type { AgentConsentContext, AccessContext } from "../types/access-context.js";
4
+ import type { AcceptOptions, Proposal, ProposalDecider, ProposalFilter, ProposalInput } from "../types/proposal.js";
5
+ import type { AcceptedClaimAppender } from "./accepted-claim-appender.js";
6
+ import type { FactoryCompatibleProposalQueue } from "./proposal-queue.js";
7
+ import type { SourceRegistry } from "../source/source-registry.js";
8
+ import type { CryptoBoundary } from "../crypto/types.js";
9
+ import { GrantRegistry } from "../consent/grant-registry.js";
10
+ export declare class SQLiteProposalQueue implements FactoryCompatibleProposalQueue {
11
+ private readonly _db;
12
+ private readonly _crypto;
13
+ private readonly _appender;
14
+ private readonly _grantRegistry;
15
+ private readonly _sourceRegistry;
16
+ private readonly _cache;
17
+ readonly factoryCompatible: "durable-proposal-queue";
18
+ private constructor();
19
+ static open(db: Database, crypto: CryptoBoundary, appender: AcceptedClaimAppender, grantRegistry: GrantRegistry, sourceRegistry: SourceRegistry): Promise<SQLiteProposalQueue>;
20
+ createProposal(ctx: AgentConsentContext, input: ProposalInput): Promise<Proposal>;
21
+ getProposal(ctx: AccessContext, proposalId: ProposalId): Proposal | undefined;
22
+ listProposals(ctx: AccessContext, filter?: ProposalFilter): Proposal[];
23
+ acceptProposal(ctx: ProposalDecider, proposalId: ProposalId, options: AcceptOptions): Promise<Proposal>;
24
+ rejectProposal(ctx: ProposalDecider, proposalId: ProposalId, reason: string): Promise<Proposal>;
25
+ private _getExistingPending;
26
+ }
@@ -0,0 +1,282 @@
1
+ // SQLiteProposalQueue — Production-06b.
2
+ //
3
+ // PROPOSAL_QUEUE_DURABLE_REQUIRED_001: proposals survive process restart (proposals table, schema v7).
4
+ // PROPOSAL_QUEUE_REOPEN_PRESERVES_STATUS_001: status + decision fields restored across reopen via
5
+ // eager cache load in SQLiteProposalQueue.open().
6
+ // PROPOSAL_QUEUE_CANDIDATES_NOT_CLAIMS_UNTIL_ACCEPT_001: candidateClaims remain outside FactStore
7
+ // until acceptProposal succeeds; all sensitive payload is encrypted before SQLite write.
8
+ // PROPOSAL_QUEUE_ACCEPTANCE_PROVENANCE_PRESERVED_001: resultingClaimIds + decidedBy preserved in
9
+ // encrypted_payload, restoring full acceptance provenance after reopen.
10
+ //
11
+ // createProposal / rejectProposal / acceptProposal are async — encryption must complete before the
12
+ // SQLite write. getProposal and listProposals are sync (served from in-memory cache loaded at open).
13
+ //
14
+ // Production-06d-b-a: ProposalQueue interface was migrated to async (A1 decision). SQLiteProposalQueue
15
+ // now satisfies ProposalQueue directly via FactoryCompatibleProposalQueue (which extends ProposalQueue).
16
+ // The structural incompatibility that previously prevented implements ProposalQueue is resolved.
17
+ //
18
+ // Usage:
19
+ // const queue = await SQLiteProposalQueue.open(db, crypto, appender, grantRegistry, sourceRegistry);
20
+ // const proposal = await queue.createProposal(agentCtx, input);
21
+ import { asISOTime, asProposalId } from "../types/ids.js";
22
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
23
+ function isDecider(ctx) {
24
+ return ctx.kind === "owner" || ctx.kind === "system_projection" || ctx.kind === "test";
25
+ }
26
+ function rowToProposal(row, payload) {
27
+ const result = {
28
+ id: row.proposal_id,
29
+ proposedBy: Object.freeze({
30
+ agentId: row.proposed_by_agent,
31
+ grantId: row.under_grant,
32
+ purpose: payload.proposedByPurpose,
33
+ }),
34
+ underGrant: row.under_grant,
35
+ candidateClaims: Object.freeze([...payload.candidateClaims]),
36
+ status: row.status,
37
+ createdAt: row.created_at,
38
+ };
39
+ if (payload.rationale !== undefined)
40
+ result["rationale"] = payload.rationale;
41
+ if (row.decided_at !== null)
42
+ result["decidedAt"] = row.decided_at;
43
+ if (payload.decidedBy !== undefined)
44
+ result["decidedBy"] = Object.freeze({ ...payload.decidedBy });
45
+ if (payload.rejectionReason !== undefined)
46
+ result["rejectionReason"] = payload.rejectionReason;
47
+ if (payload.resultingClaimIds !== undefined)
48
+ result["resultingClaimIds"] = Object.freeze([...payload.resultingClaimIds]);
49
+ return Object.freeze(result);
50
+ }
51
+ // ─── SQLiteProposalQueue ──────────────────────────────────────────────────────
52
+ export class SQLiteProposalQueue {
53
+ _db;
54
+ _crypto;
55
+ _appender;
56
+ _grantRegistry;
57
+ _sourceRegistry;
58
+ _cache;
59
+ // PROPOSAL_QUEUE_FACTORY_COMPATIBLE_001: durable capability marker.
60
+ // Proves encrypted SQLite-backed proposal storage; does not prove LifeApiImpl assembly compat.
61
+ factoryCompatible = "durable-proposal-queue";
62
+ constructor(_db, _crypto, _appender, _grantRegistry, _sourceRegistry, _cache) {
63
+ this._db = _db;
64
+ this._crypto = _crypto;
65
+ this._appender = _appender;
66
+ this._grantRegistry = _grantRegistry;
67
+ this._sourceRegistry = _sourceRegistry;
68
+ this._cache = _cache;
69
+ }
70
+ // Load all existing proposals from proposals table, decrypt each, populate cache.
71
+ static async open(db, crypto, appender, grantRegistry, sourceRegistry) {
72
+ const cache = new Map();
73
+ const rows = db.prepare("SELECT * FROM proposals").all();
74
+ for (const row of rows) {
75
+ const blob = JSON.parse(row.encrypted_payload);
76
+ const payload = await crypto.decryptJson(blob);
77
+ const p = rowToProposal(row, payload);
78
+ cache.set(p.id, p);
79
+ }
80
+ return new SQLiteProposalQueue(db, crypto, appender, grantRegistry, sourceRegistry, cache);
81
+ }
82
+ // ── createProposal ──────────────────────────────────────────────────────────
83
+ async createProposal(ctx, input) {
84
+ const grant = this._grantRegistry.lookup(ctx.grantId);
85
+ if (grant === undefined) {
86
+ throw new Error("PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant not found in registry — " +
87
+ `grantId "${ctx.grantId}" has not been registered`);
88
+ }
89
+ if (grant.grantedTo.agentId !== ctx.agentId) {
90
+ throw new Error("PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant belongs to a different agent — " +
91
+ `grant.grantedTo.agentId="${grant.grantedTo.agentId}", ctx.agentId="${ctx.agentId}"`);
92
+ }
93
+ if (grant.purpose !== ctx.purpose) {
94
+ throw new Error(`PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: purpose mismatch — ` +
95
+ `grant.purpose="${grant.purpose}", ctx.purpose="${ctx.purpose}"`);
96
+ }
97
+ if (!grant.capabilities.includes("propose")) {
98
+ throw new Error("PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant lacks 'propose' capability — " +
99
+ `capabilities=${JSON.stringify(grant.capabilities)}`);
100
+ }
101
+ const now = Date.now();
102
+ if (new Date(grant.notAfter).getTime() <= now) {
103
+ throw new Error(`PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant is expired (notAfter="${grant.notAfter}")`);
104
+ }
105
+ if (new Date(grant.notBefore).getTime() > now) {
106
+ throw new Error(`PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant is not yet active (notBefore="${grant.notBefore}")`);
107
+ }
108
+ if (grant.revokedAt !== undefined) {
109
+ throw new Error(`PROPOSAL_ACCEPT_REQUIRES_VALID_GRANT_001: grant has been revoked (revokedAt="${grant.revokedAt}")`);
110
+ }
111
+ if (input.candidateClaims.length === 0) {
112
+ throw new Error("PROPOSAL_QUEUE_EXISTS_001: candidateClaims must not be empty");
113
+ }
114
+ const id = asProposalId(`prop_${globalThis.crypto.randomUUID()}`);
115
+ const nowIso = asISOTime(new Date().toISOString());
116
+ const encPayload = {
117
+ version: 1,
118
+ candidateClaims: [...input.candidateClaims],
119
+ proposedByPurpose: ctx.purpose,
120
+ };
121
+ if (input.rationale !== undefined)
122
+ encPayload["rationale"] = input.rationale;
123
+ const blob = await this._crypto.encryptJson(encPayload);
124
+ const blobJson = JSON.stringify(blob);
125
+ this._db.prepare(`INSERT INTO proposals
126
+ (proposal_id, status, proposed_by_agent, under_grant,
127
+ encrypted_payload, payload_key_id, created_at, updated_at, decided_at)
128
+ VALUES (?, 'pending', ?, ?, ?, ?, ?, ?, NULL)`).run(id, ctx.agentId, ctx.grantId, blobJson, blob.keyId, nowIso, nowIso);
129
+ const result = {
130
+ id,
131
+ proposedBy: Object.freeze({ agentId: ctx.agentId, grantId: ctx.grantId, purpose: ctx.purpose }),
132
+ underGrant: ctx.grantId,
133
+ candidateClaims: Object.freeze([...input.candidateClaims]),
134
+ status: "pending",
135
+ createdAt: nowIso,
136
+ };
137
+ if (input.rationale !== undefined)
138
+ result["rationale"] = input.rationale;
139
+ const proposal = Object.freeze(result);
140
+ this._cache.set(id, proposal);
141
+ return proposal;
142
+ }
143
+ // ── getProposal ─────────────────────────────────────────────────────────────
144
+ getProposal(ctx, proposalId) {
145
+ if (ctx == null)
146
+ throw new TypeError("AccessContext is required");
147
+ return this._cache.get(proposalId);
148
+ }
149
+ // ── listProposals ───────────────────────────────────────────────────────────
150
+ listProposals(ctx, filter) {
151
+ if (ctx == null)
152
+ throw new TypeError("AccessContext is required");
153
+ let proposals = Array.from(this._cache.values());
154
+ if (filter?.status !== undefined)
155
+ proposals = proposals.filter((p) => p.status === filter.status);
156
+ if (filter?.proposedByAgent !== undefined)
157
+ proposals = proposals.filter((p) => p.proposedBy.agentId === filter.proposedByAgent);
158
+ if (filter?.underGrant !== undefined)
159
+ proposals = proposals.filter((p) => p.underGrant === filter.underGrant);
160
+ return proposals;
161
+ }
162
+ // ── acceptProposal ──────────────────────────────────────────────────────────
163
+ async acceptProposal(ctx, proposalId, options) {
164
+ if (!isDecider(ctx)) {
165
+ throw new Error("PROPOSAL_AGENT_CANNOT_ACCEPT_001: AgentConsentContext and AuditContext cannot accept proposals");
166
+ }
167
+ const proposal = this._getExistingPending(proposalId, "accept");
168
+ const source = this._sourceRegistry.getSource(ctx, options.sourceId);
169
+ if (source === undefined) {
170
+ throw new Error(`SOURCE_UNKNOWN_REJECTED_001: sourceId "${options.sourceId}" is not registered`);
171
+ }
172
+ if (source.status !== "active") {
173
+ throw new Error(`SOURCE_INACTIVE_REJECTED_001: sourceId "${options.sourceId}" is inactive`);
174
+ }
175
+ const meta = source.metadata;
176
+ if (meta === undefined || !("acceptedFromProposalId" in meta)) {
177
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001: acceptance source "${options.sourceId}" must have metadata.acceptedFromProposalId`);
178
+ }
179
+ if (meta["acceptedFromProposalId"] !== proposal.id) {
180
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_PROPOSAL_001: metadata.acceptedFromProposalId "${String(meta["acceptedFromProposalId"])}" does not match proposal.id "${proposal.id}"`);
181
+ }
182
+ if (!("proposedBy" in meta)) {
183
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001: acceptance source "${options.sourceId}" must have metadata.proposedBy`);
184
+ }
185
+ if (meta["proposedBy"] !== proposal.proposedBy.agentId) {
186
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_AGENT_001: metadata.proposedBy "${String(meta["proposedBy"])}" does not match proposal.proposedBy.agentId "${proposal.proposedBy.agentId}"`);
187
+ }
188
+ if (!("underGrant" in meta)) {
189
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_REQUIRED_001: acceptance source "${options.sourceId}" must have metadata.underGrant`);
190
+ }
191
+ if (meta["underGrant"] !== proposal.underGrant) {
192
+ throw new Error(`PROPOSAL_ACCEPT_SOURCE_METADATA_MATCHES_GRANT_001: metadata.underGrant "${String(meta["underGrant"])}" does not match proposal.underGrant "${proposal.underGrant}"`);
193
+ }
194
+ const finalClaims = proposal.candidateClaims.map((c) => ({ ...c, sourceId: options.sourceId }));
195
+ // PROPOSAL_ACCEPT_ATOMIC_ROLLBACK_001: status update only after appendAll succeeds.
196
+ const claimIds = await this._appender.appendAll(ctx, finalClaims);
197
+ const nowIso = asISOTime(new Date().toISOString());
198
+ const encPayload = {
199
+ version: 1,
200
+ candidateClaims: [...proposal.candidateClaims],
201
+ proposedByPurpose: proposal.proposedBy.purpose,
202
+ resultingClaimIds: [...claimIds],
203
+ decidedBy: { ...ctx },
204
+ };
205
+ if (proposal.rationale !== undefined)
206
+ encPayload["rationale"] = proposal.rationale;
207
+ const blob = await this._crypto.encryptJson(encPayload);
208
+ const blobJson = JSON.stringify(blob);
209
+ this._db.prepare(`UPDATE proposals
210
+ SET status = 'accepted', encrypted_payload = ?, payload_key_id = ?,
211
+ updated_at = ?, decided_at = ?
212
+ WHERE proposal_id = ?`).run(blobJson, blob.keyId, nowIso, nowIso, proposalId);
213
+ const result = {
214
+ id: proposal.id,
215
+ proposedBy: proposal.proposedBy,
216
+ underGrant: proposal.underGrant,
217
+ candidateClaims: proposal.candidateClaims,
218
+ status: "accepted",
219
+ createdAt: proposal.createdAt,
220
+ decidedAt: nowIso,
221
+ decidedBy: Object.freeze({ ...ctx }),
222
+ resultingClaimIds: Object.freeze([...claimIds]),
223
+ };
224
+ if (proposal.rationale !== undefined)
225
+ result["rationale"] = proposal.rationale;
226
+ const accepted = Object.freeze(result);
227
+ this._cache.set(proposalId, accepted);
228
+ return accepted;
229
+ }
230
+ // ── rejectProposal ──────────────────────────────────────────────────────────
231
+ async rejectProposal(ctx, proposalId, reason) {
232
+ if (!isDecider(ctx)) {
233
+ throw new Error("PROPOSAL_AGENT_CANNOT_REJECT_001: AgentConsentContext and AuditContext cannot reject proposals");
234
+ }
235
+ const proposal = this._getExistingPending(proposalId, "reject");
236
+ const nowIso = asISOTime(new Date().toISOString());
237
+ const encPayload = {
238
+ version: 1,
239
+ candidateClaims: [...proposal.candidateClaims],
240
+ proposedByPurpose: proposal.proposedBy.purpose,
241
+ rejectionReason: reason,
242
+ decidedBy: { ...ctx },
243
+ };
244
+ if (proposal.rationale !== undefined)
245
+ encPayload["rationale"] = proposal.rationale;
246
+ const blob = await this._crypto.encryptJson(encPayload);
247
+ const blobJson = JSON.stringify(blob);
248
+ this._db.prepare(`UPDATE proposals
249
+ SET status = 'rejected', encrypted_payload = ?, payload_key_id = ?,
250
+ updated_at = ?, decided_at = ?
251
+ WHERE proposal_id = ?`).run(blobJson, blob.keyId, nowIso, nowIso, proposalId);
252
+ const result = {
253
+ id: proposal.id,
254
+ proposedBy: proposal.proposedBy,
255
+ underGrant: proposal.underGrant,
256
+ candidateClaims: proposal.candidateClaims,
257
+ status: "rejected",
258
+ createdAt: proposal.createdAt,
259
+ decidedAt: nowIso,
260
+ decidedBy: Object.freeze({ ...ctx }),
261
+ rejectionReason: reason,
262
+ };
263
+ if (proposal.rationale !== undefined)
264
+ result["rationale"] = proposal.rationale;
265
+ const rejected = Object.freeze(result);
266
+ this._cache.set(proposalId, rejected);
267
+ return rejected;
268
+ }
269
+ // ── Private helpers ─────────────────────────────────────────────────────────
270
+ _getExistingPending(proposalId, action) {
271
+ const proposal = this._cache.get(proposalId);
272
+ if (proposal === undefined) {
273
+ throw new Error(`PROPOSAL_QUEUE_EXISTS_001: proposal "${proposalId}" not found`);
274
+ }
275
+ if (proposal.status !== "pending") {
276
+ throw new Error(`PROPOSAL_STATUS_IMMUTABLE_AFTER_DECISION_001: proposal "${proposalId}" is ` +
277
+ `"${proposal.status}" and cannot be ${action}ed again`);
278
+ }
279
+ return proposal;
280
+ }
281
+ }
282
+ //# sourceMappingURL=sqlite-proposal-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-proposal-queue.js","sourceRoot":"","sources":["../../src/proposal/sqlite-proposal-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ClaimMeta, ClaimPredicate } from "../types/claim.js";
2
+ import type { TrustProfile } from "./trust-profile.js";
3
+ import type { ResolutionResult } from "./types.js";
4
+ export declare function resolveClaims(claims: ReadonlyArray<ClaimMeta>, trust: TrustProfile, predicate: ClaimPredicate): ResolutionResult;
@@ -0,0 +1,101 @@
1
+ // Slice-02/02b: Claim-level resolution — pure function, no I/O, no mutation.
2
+ //
3
+ // Invariants (see docs/INVARIANTS.md):
4
+ // TRUST_PREDICATE_SPECIFIC_001 — trust scored per (source, predicate) pair
5
+ // TRUST_UNKNOWN_LOW_001 — unregistered pair → LOW
6
+ // RESOLUTION_TIE_DISPUTED_001 — equal-priority tie → "disputed", never silent winner
7
+ // RESOLUTION_USER_OVERRIDE_EXPLICIT_001 — overrides field wins by policy (not just HIGH trust)
8
+ // RESOLUTION_USER_OVERRIDE_RETRACTABLE_001— retracted override → fallback to trust-based
9
+ // RESOLUTION_DETERMINISTIC_001 — output invariant to input array order
10
+ // RESOLUTION_RETRACTED_CANNOT_WIN_001 — retracted claims excluded from live set
11
+ // RESOLUTION_SUPERSEDED_CANNOT_WIN_001 — live superseder removes original from live set
12
+ // RESOLUTION_SUPERSEDE_RETRACTION_POLICY_001 — retracted superseder → original resurrects (Policy A)
13
+ // RESOLUTION_CONFLICTS_VISIBLE_001 — all live non-winners in competingClaimIds
14
+ // RESOLUTION_NO_MUTATION_001 — never mutates input array or claims
15
+ // RESOLUTION_REASON_CODES_001 — typed reasonCode on every result
16
+ //
17
+ // See docs/RESOLUTION_POLICY.md for policy decisions.
18
+ import { TRUST_ORDER } from "./types.js";
19
+ const POLICY_ID = "trust-then-seq-v1";
20
+ const POLICY_VERSION = "1";
21
+ export function resolveClaims(claims, trust, predicate) {
22
+ // Deterministic base: sort by recordedSeq ascending so every downstream
23
+ // operation is order-independent. (RESOLUTION_DETERMINISTIC_001)
24
+ // recordedSeq is ONLY used for ordering — never as a tiebreaker that picks a winner.
25
+ const sorted = [...claims].sort((a, b) => a.recordedSeq - b.recordedSeq);
26
+ const allIds = sorted.map((c) => c.id);
27
+ // ── Step 1: Find retracted claim IDs ────────────────────────────────────────
28
+ // A claim C is retracted if any claim has `retracts === C.id`.
29
+ // (RESOLUTION_RETRACTED_CANNOT_WIN_001)
30
+ const retractedIds = new Set(sorted.flatMap((c) => (c.retracts !== undefined ? [c.retracts] : [])));
31
+ // ── Step 2: Retraction markers ────────────────────────────────────────────
32
+ // Claims that carry `retracts` are lifecycle operations, not value assertions.
33
+ // They cannot win. (Note: claims with `supersedes` or `overrides` CAN win.)
34
+ const retractionMarkerIds = new Set(sorted.flatMap((c) => (c.retracts !== undefined ? [c.id] : [])));
35
+ // ── Step 3: Find superseded claim IDs ───────────────────────────────────────
36
+ // A claim X is superseded if any NON-retracted claim S has `S.supersedes === X.id`.
37
+ // Retracted supersede chains are broken — the original resurrects. (Policy A —
38
+ // RESOLUTION_SUPERSEDE_RETRACTION_POLICY_001, docs/RESOLUTION_POLICY.md)
39
+ const supersededIds = new Set(sorted.flatMap((c) => c.supersedes !== undefined && !retractedIds.has(c.id) ? [c.supersedes] : []));
40
+ // ── Step 4: Determine live claims for this predicate ────────────────────────
41
+ // A claim is "live" if:
42
+ // - its predicate matches the resolution target
43
+ // - it has not been retracted
44
+ // - it has not been superseded by a live (non-retracted) claim
45
+ // - it is not itself a retraction marker
46
+ // Note: claims with `overrides` set ARE live assertions (they win by policy, not by removal).
47
+ const liveClaims = sorted.filter((c) => c.predicate === predicate &&
48
+ !retractedIds.has(c.id) &&
49
+ !supersededIds.has(c.id) &&
50
+ !retractionMarkerIds.has(c.id));
51
+ // ── Step 5: Edge case — no live claims ──────────────────────────────────────
52
+ if (liveClaims.length === 0) {
53
+ return result("disputed", "NO_LIVE_CLAIMS", undefined, [], allIds, "no-live-claims");
54
+ }
55
+ // ── Step 6: Trivial case — single live claim ─────────────────────────────────
56
+ if (liveClaims.length === 1) {
57
+ return result("resolved", "ONLY_LIVE_CLAIM", liveClaims[0].id, [], allIds, "single-live-claim");
58
+ }
59
+ // ── Step 7: UserOverride policy — BEFORE trust comparison ───────────────────
60
+ // A live claim with `overrides` set wins by policy, regardless of trust level.
61
+ // The override TARGET stays in the live set (visible in competingClaimIds).
62
+ // (RESOLUTION_USER_OVERRIDE_EXPLICIT_001, Policy B — docs/RESOLUTION_POLICY.md)
63
+ const liveOverrides = liveClaims.filter((c) => c.overrides !== undefined);
64
+ if (liveOverrides.length === 1) {
65
+ const winner = liveOverrides[0];
66
+ const competing = liveClaims.filter((c) => c.id !== winner.id).map((c) => c.id);
67
+ return result("resolved", "USER_OVERRIDE_WIN", winner.id, competing, allIds, "user-override-policy");
68
+ }
69
+ if (liveOverrides.length > 1) {
70
+ // Multiple live overrides conflict with each other → disputed
71
+ return result("disputed", "DISPUTED_EQUAL_PRIORITY", undefined, liveClaims.map((c) => c.id), allIds, "multiple-live-overrides");
72
+ }
73
+ // ── Step 8: Trust-based resolution ──────────────────────────────────────────
74
+ // (TRUST_PREDICATE_SPECIFIC_001 — score is per-pair, not per-source)
75
+ const scored = liveClaims.map((c) => ({
76
+ claim: c,
77
+ trustScore: TRUST_ORDER[trust.trustFor(c.sourceId, predicate)],
78
+ }));
79
+ const maxScore = Math.max(...scored.map((s) => s.trustScore));
80
+ const topClaims = scored.filter((s) => s.trustScore === maxScore);
81
+ if (topClaims.length === 1) {
82
+ const winner = topClaims[0].claim;
83
+ const competing = liveClaims.filter((c) => c.id !== winner.id).map((c) => c.id);
84
+ const levelName = trustLevelName(maxScore);
85
+ return result("resolved", "TRUST_WIN", winner.id, competing, allIds, `highest-trust:${levelName}`);
86
+ }
87
+ // ── Step 9: Genuine tie — disputed ──────────────────────────────────────────
88
+ // (RESOLUTION_TIE_DISPUTED_001 — equal priority → no silent winner)
89
+ return result("disputed", "DISPUTED_EQUAL_PRIORITY", undefined, liveClaims.map((c) => c.id), allIds, `trust-tie:${trustLevelName(maxScore)}`);
90
+ }
91
+ // ─── private helpers ──────────────────────────────────────────────────────────
92
+ function result(status, reasonCode, winningClaimId, competingClaimIds, allConsideredClaimIds, reason) {
93
+ return winningClaimId !== undefined
94
+ ? { status, reasonCode, winningClaimId, competingClaimIds, allConsideredClaimIds, reason, policyId: POLICY_ID, policyVersion: POLICY_VERSION }
95
+ : { status, reasonCode, competingClaimIds, allConsideredClaimIds, reason, policyId: POLICY_ID, policyVersion: POLICY_VERSION };
96
+ }
97
+ function trustLevelName(score) {
98
+ return Object.keys(TRUST_ORDER)
99
+ .find((k) => TRUST_ORDER[k] === score) ?? "UNKNOWN";
100
+ }
101
+ //# sourceMappingURL=resolve-claims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-claims.js","sourceRoot":"","sources":["../../src/resolution/resolve-claims.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { SourceId } from "../types/ids.js";
2
+ import type { ClaimPredicate } from "../types/claim.js";
3
+ import type { TrustLevel } from "./types.js";
4
+ export interface TrustProfile {
5
+ trustFor(sourceId: SourceId, predicate: ClaimPredicate): TrustLevel;
6
+ }
7
+ export declare class StaticTrustTable implements TrustProfile {
8
+ private readonly _table;
9
+ set(sourceId: SourceId, predicate: ClaimPredicate, level: TrustLevel): this;
10
+ trustFor(sourceId: SourceId, predicate: ClaimPredicate): TrustLevel;
11
+ static empty(): StaticTrustTable;
12
+ }
@@ -0,0 +1,23 @@
1
+ // Slice-02: TrustProfile — predicate-specific trust lookup.
2
+ // TRUST_PREDICATE_SPECIFIC_001: trust is (sourceId × predicate), never source alone.
3
+ // TRUST_UNKNOWN_LOW_001: unknown pair → LOW, never MEDIUM or HIGH.
4
+ // StaticTrustTable — explicit (source, predicate) → TrustLevel table.
5
+ // All entries are explicit; no glob or wildcard matching.
6
+ // Entries not in the table → LOW. (TRUST_UNKNOWN_LOW_001)
7
+ export class StaticTrustTable {
8
+ _table = new Map();
9
+ set(sourceId, predicate, level) {
10
+ this._table.set(compositeKey(sourceId, predicate), level);
11
+ return this;
12
+ }
13
+ trustFor(sourceId, predicate) {
14
+ return this._table.get(compositeKey(sourceId, predicate)) ?? "LOW";
15
+ }
16
+ static empty() {
17
+ return new StaticTrustTable();
18
+ }
19
+ }
20
+ function compositeKey(sourceId, predicate) {
21
+ return `${sourceId}::${predicate}`;
22
+ }
23
+ //# sourceMappingURL=trust-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-profile.js","sourceRoot":"","sources":["../../src/resolution/trust-profile.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,qFAAqF;AACrF,mEAAmE;AAUnE,sEAAsE;AACtE,0DAA0D;AAC1D,0DAA0D;AAC1D,MAAM,OAAO,gBAAgB;IACV,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;IAExD,GAAG,CAAC,QAAkB,EAAE,SAAyB,EAAE,KAAiB;QAClE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ,CAAC,QAAkB,EAAE,SAAyB;QACpD,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,IAAI,KAAK,CAAC;IACrE,CAAC;IAED,MAAM,CAAC,KAAK;QACV,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAChC,CAAC;CACF;AAED,SAAS,YAAY,CAAC,QAAkB,EAAE,SAAyB;IACjE,OAAO,GAAG,QAAQ,KAAK,SAAS,EAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { ClaimId } from "../types/ids.js";
2
+ export type TrustLevel = "HIGH" | "MEDIUM" | "LOW";
3
+ export declare const TRUST_ORDER: Readonly<Record<TrustLevel, number>>;
4
+ export type ResolutionStatus = "resolved" | "disputed";
5
+ export type ResolutionReasonCode = "ONLY_LIVE_CLAIM" | "TRUST_WIN" | "USER_OVERRIDE_WIN" | "DISPUTED_EQUAL_PRIORITY" | "NO_LIVE_CLAIMS";
6
+ export interface ResolutionResult {
7
+ readonly status: ResolutionStatus;
8
+ readonly reasonCode: ResolutionReasonCode;
9
+ readonly winningClaimId?: ClaimId;
10
+ readonly competingClaimIds: ReadonlyArray<ClaimId>;
11
+ readonly allConsideredClaimIds: ReadonlyArray<ClaimId>;
12
+ readonly reason: string;
13
+ readonly policyId: string;
14
+ readonly policyVersion: string;
15
+ }
@@ -0,0 +1,8 @@
1
+ // Slice-02: Resolution types.
2
+ // See docs/INVARIANTS.md for invariant IDs.
3
+ export const TRUST_ORDER = Object.freeze({
4
+ HIGH: 2,
5
+ MEDIUM: 1,
6
+ LOW: 0,
7
+ });
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/resolution/types.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,4CAA4C;AAQ5C,MAAM,CAAC,MAAM,WAAW,GAAyC,MAAM,CAAC,MAAM,CAAC;IAC7E,IAAI,EAAI,CAAC;IACT,MAAM,EAAE,CAAC;IACT,GAAG,EAAK,CAAC;CACV,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { BackendContextMintingBoundary } from "../auth/backend-context-minting-boundary.js";
2
+ import { InMemoryTenantBoundary } from "../auth/in-memory-tenant-boundary.js";
3
+ import { InMemoryGrantResolver } from "../auth/in-memory-grant-resolver.js";
4
+ import type { LifeApi } from "./life-api.js";
5
+ import type { TenantMembership } from "../auth/in-memory-tenant-boundary.js";
6
+ import type { GrantRecord } from "../auth/in-memory-grant-resolver.js";
7
+ import type { AuthAdapter, Clock } from "../auth/types.js";
8
+ /** @remarks TEST/DEV ONLY — not for production use. */
9
+ export interface BackendIntegratedTestFactoryConfig {
10
+ readonly memberships?: ReadonlyArray<TenantMembership>;
11
+ readonly grants?: ReadonlyArray<GrantRecord>;
12
+ readonly clock?: Clock;
13
+ readonly adapter?: AuthAdapter;
14
+ }
15
+ /** @remarks TEST/DEV ONLY — not for production use. */
16
+ export interface BackendIntegratedTestFactoryOutput {
17
+ readonly api: LifeApi;
18
+ readonly auth: BackendContextMintingBoundary;
19
+ readonly tenantBoundary: InMemoryTenantBoundary;
20
+ readonly grantResolver: InMemoryGrantResolver;
21
+ }
22
+ /** @remarks TEST/DEV ONLY — not for production use. NOT exported from src/index.ts. */
23
+ export declare function createBackendIntegratedLifeApiForTest(config?: BackendIntegratedTestFactoryConfig): Promise<BackendIntegratedTestFactoryOutput>;