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,4 @@
1
+ import type { AgentConsentContext } from "../types/access-context.js";
2
+ import type { ConsentGrant, ConsentDecision, Capability } from "../types/consent.js";
3
+ import type { ISOTime } from "../types/ids.js";
4
+ export declare function evaluateGrant(grant: ConsentGrant | undefined, ctx: AgentConsentContext, requiredCapability: Capability, now: ISOTime): ConsentDecision;
@@ -0,0 +1,37 @@
1
+ // Slice-03: Grant validation — checks purpose, capability, time, revocation.
2
+ // Returns ConsentDecision (allow/deny) without touching the store.
3
+ // Order matters: check revocation first, then expiry, then purpose, then capability.
4
+ export function evaluateGrant(grant, ctx, requiredCapability, now) {
5
+ // CONSENT_REVOKED_DENY_001
6
+ if (!grant) {
7
+ return { allowed: false, reason: "grant_not_found" };
8
+ }
9
+ if (grant.revokedAt !== undefined) {
10
+ return { allowed: false, reason: "grant_revoked" };
11
+ }
12
+ // CONSENT_EXPIRED_DENY_001: grant time window — notBefore and notAfter are distinct codes
13
+ if (now < grant.notBefore) {
14
+ return { allowed: false, reason: "grant_not_yet_active" };
15
+ }
16
+ if (now > grant.notAfter) {
17
+ return { allowed: false, reason: "grant_expired" };
18
+ }
19
+ // CONSENT_EXPIRED_DENY_001: context-level TTL (set by whoever built the ctx)
20
+ if (now > ctx.notAfter) {
21
+ return { allowed: false, reason: "grant_expired" };
22
+ }
23
+ // CONSENT_PURPOSE_BOUND_001
24
+ if (ctx.purpose !== grant.purpose) {
25
+ return { allowed: false, reason: "purpose_mismatch" };
26
+ }
27
+ // CONSENT_CAPABILITY_BOUND_001
28
+ if (!grant.capabilities.includes(requiredCapability)) {
29
+ return { allowed: false, reason: "capability_not_granted" };
30
+ }
31
+ return {
32
+ allowed: true,
33
+ scopedPredicates: grant.scope.predicates,
34
+ maxFieldDepth: grant.maxFieldDepth ?? "full",
35
+ };
36
+ }
37
+ //# sourceMappingURL=consent-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-guard.js","sourceRoot":"","sources":["../../src/consent/consent-guard.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,mEAAmE;AACnE,qFAAqF;AAMrF,MAAM,UAAU,aAAa,CAC3B,KAA+B,EAC/B,GAAwB,EACxB,kBAA8B,EAC9B,GAAY;IAEZ,2BAA2B;IAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;IACvD,CAAC;IAED,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACrD,CAAC;IAED,0FAA0F;IAC1F,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;QAC1B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,GAAG,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACrD,CAAC;IAED,6EAA6E;IAC7E,IAAI,GAAG,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QACvB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACrD,CAAC;IAED,4BAA4B;IAC5B,IAAI,GAAG,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IACxD,CAAC;IAED,+BAA+B;IAC/B,IAAI,CAAE,KAAK,CAAC,YAAsC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAChF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IAC9D,CAAC;IAED,OAAO;QACL,OAAO,EAAS,IAAI;QACpB,gBAAgB,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU;QACxC,aAAa,EAAG,KAAK,CAAC,aAAa,IAAI,MAAM;KAC9C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { GrantId } from "../types/ids.js";
2
+ import type { ConsentGrant } from "../types/consent.js";
3
+ export declare class GrantRegistry {
4
+ private readonly _grants;
5
+ register(grant: ConsentGrant): this;
6
+ lookup(id: GrantId): ConsentGrant | undefined;
7
+ }
@@ -0,0 +1,13 @@
1
+ // Slice-03: GrantRegistry — in-memory lookup of ConsentGrants by GrantId.
2
+ // In production this would be a DB query; for Slice-03 it's a plain Map.
3
+ export class GrantRegistry {
4
+ _grants = new Map();
5
+ register(grant) {
6
+ this._grants.set(grant.id, grant);
7
+ return this;
8
+ }
9
+ lookup(id) {
10
+ return this._grants.get(id);
11
+ }
12
+ }
13
+ //# sourceMappingURL=grant-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grant-registry.js","sourceRoot":"","sources":["../../src/consent/grant-registry.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,yEAAyE;AAKzE,MAAM,OAAO,aAAa;IACP,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE5D,QAAQ,CAAC,KAAmB;QAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,CAAC,EAAW;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ import type { ConsentGrant } from "../types/consent.js";
2
+ import type { ClaimSelector } from "../types/fact-store.js";
3
+ export declare function intersectSelector(requested: ClaimSelector, grant: ConsentGrant): ClaimSelector | null;
@@ -0,0 +1,66 @@
1
+ // Slice-03: Selector intersection — the heart of Consent Pre-Filter.
2
+ // CONSENT_SELECTOR_INTERSECTION_001:
3
+ // restrictedSelector = intersect(requestedSelector, grant.scope)
4
+ // null = empty intersection → zero claims without store read
5
+ //
6
+ // Rule: agent sees ONLY the intersection of what they asked for AND what they're allowed.
7
+ // Empty intersection → null (caller should write deny-audit, return { ok:true, claims:[] }).
8
+ export function intersectSelector(requested, grant) {
9
+ // ── Predicate intersection ────────────────────────────────────────────────
10
+ const grantedPredicates = buildGrantedPredicates(grant);
11
+ if (grantedPredicates.length === 0)
12
+ return null; // grant itself allows nothing
13
+ let allowedPredicates;
14
+ if (requested.predicates !== undefined) {
15
+ // Intersect requested with granted
16
+ const grantedSet = new Set(grantedPredicates);
17
+ allowedPredicates = requested.predicates.filter((p) => grantedSet.has(p));
18
+ }
19
+ else {
20
+ // No restriction requested → use all granted predicates
21
+ allowedPredicates = grantedPredicates;
22
+ }
23
+ if (allowedPredicates.length === 0)
24
+ return null; // nothing in common
25
+ // ── Subject intersection ─────────────────────────────────────────────────
26
+ // grant.scope.subjects: agent may only query these PersonIds
27
+ // requested.subject: specific subject the agent asked about
28
+ let allowedSubject = requested.subject;
29
+ if (grant.scope.subjects !== undefined && grant.scope.subjects.length > 0) {
30
+ if (requested.subject !== undefined) {
31
+ // Agent asked for a specific subject — must be in granted set
32
+ const inGrantedSet = grant.scope.subjects.includes(requested.subject);
33
+ if (!inGrantedSet)
34
+ return null; // subject not granted
35
+ allowedSubject = requested.subject;
36
+ }
37
+ else {
38
+ // Agent didn't specify subject — we cannot widen their query beyond granted subjects
39
+ // For MVP with single subject per query: if only one granted subject, use it
40
+ // If multiple: we'd need a multi-subject selector; for now, null (too broad)
41
+ if (grant.scope.subjects.length === 1) {
42
+ allowedSubject = grant.scope.subjects[0];
43
+ }
44
+ else {
45
+ // Multiple granted subjects, none specified — caller must specify subject
46
+ // Return null to force explicit subject (avoid over-broad reads)
47
+ return null;
48
+ }
49
+ }
50
+ }
51
+ // ── Build restricted selector ─────────────────────────────────────────────
52
+ // Pass through other selector constraints (sinceRecordedSeq, includeRetracted)
53
+ // as-is — they can only NARROW, never widen the result.
54
+ const restricted = {
55
+ predicates: allowedPredicates,
56
+ ...(allowedSubject !== undefined ? { subject: allowedSubject } : {}),
57
+ ...(requested.sinceRecordedSeq !== undefined ? { sinceRecordedSeq: requested.sinceRecordedSeq } : {}),
58
+ ...(requested.includeRetracted !== undefined ? { includeRetracted: requested.includeRetracted } : {}),
59
+ };
60
+ return restricted;
61
+ }
62
+ function buildGrantedPredicates(grant) {
63
+ const excluded = new Set(grant.scope.excludePredicates ?? []);
64
+ return grant.scope.predicates.filter((p) => !excluded.has(p));
65
+ }
66
+ //# sourceMappingURL=intersect-selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intersect-selector.js","sourceRoot":"","sources":["../../src/consent/intersect-selector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { ClaimId, ContractId, EvidenceId, SourceId } from "../types/ids.js";
2
+ import type { ClaimMeta } from "../types/claim.js";
3
+ import type { AccessContext } from "../types/access-context.js";
4
+ import type { EvidenceRef } from "../types/evidence.js";
5
+ import type { ContractProjection } from "./types.js";
6
+ import type { SourceRegistry } from "../source/source-registry.js";
7
+ import type { RawDocumentStore } from "../evidence/raw-document-store.js";
8
+ export type EvidenceStatus = "evidence_present" | "source_missing" | "source_no_evidence" | "evidence_missing" | "not_checked";
9
+ export interface FieldEvidenceDiagnostic {
10
+ readonly fieldName: string;
11
+ readonly status: EvidenceStatus;
12
+ readonly reasonCode: string;
13
+ readonly claimId?: ClaimId;
14
+ readonly sourceId?: SourceId;
15
+ readonly evidenceId?: EvidenceId;
16
+ readonly evidenceRef?: EvidenceRef;
17
+ }
18
+ export interface ConflictEvidenceDiagnostic {
19
+ readonly fieldName: string;
20
+ readonly competingClaimId: ClaimId;
21
+ readonly status: EvidenceStatus;
22
+ readonly reasonCode: string;
23
+ readonly sourceId?: SourceId;
24
+ readonly evidenceId?: EvidenceId;
25
+ }
26
+ export interface ContractProjectionDiagnostics {
27
+ readonly contractId: ContractId;
28
+ readonly fieldDiagnostics: ReadonlyArray<FieldEvidenceDiagnostic>;
29
+ readonly conflictDiagnostics: ReadonlyArray<ConflictEvidenceDiagnostic>;
30
+ readonly policyId: string;
31
+ }
32
+ export declare function diagnoseContractProjections(projections: ReadonlyArray<ContractProjection>, claimMap: ReadonlyMap<ClaimId, ClaimMeta>, sourceReg: SourceRegistry, docStore: RawDocumentStore, ctx: AccessContext): ReadonlyArray<ContractProjectionDiagnostics>;
@@ -0,0 +1,112 @@
1
+ // Slice-11: Evidence-backed Contract Projection Diagnostics.
2
+ // Pure synchronous function — no I/O, no mutations.
3
+ // CONTRACT_DIAGNOSTICS_NO_RAW_BYTES_001: never calls getDocument(); uses getEvidenceRef() only.
4
+ // CONTRACT_DIAGNOSTICS_AGENT_SAFE_METADATA_ONLY_001: output contains no raw bytes.
5
+ // CONTRACT_DIAGNOSTICS_DETERMINISTIC_001: same input → identical output (sort by contractId).
6
+ // Stable iteration order — must match projectContracts field-to-predicate mapping.
7
+ const FIELD_PREDICATE_MAP = [
8
+ ["counterparty", "contract.counterparty"],
9
+ ["amount", "contract.amount"],
10
+ ["cadence", "contract.cadence"],
11
+ ["nextDue", "contract.next_due"],
12
+ ["cancellationTerms", "contract.cancellation_terms"],
13
+ ["contractStatus", "contract.exists"],
14
+ ];
15
+ // CONTRACT_DIAGNOSTICS_EXISTS_001: diagnoseContractProjections is the entry point.
16
+ // CONTRACT_DIAGNOSTICS_DETERMINISTIC_001: output sorted by contractId.
17
+ export function diagnoseContractProjections(projections, claimMap, sourceReg, docStore, ctx) {
18
+ return [...projections]
19
+ .sort((a, b) => a.contractId.localeCompare(b.contractId))
20
+ .map((proj) => diagnoseOne(proj, claimMap, sourceReg, docStore, ctx));
21
+ }
22
+ function diagnoseOne(proj, claimMap, sourceReg, docStore, ctx) {
23
+ // ── Field diagnostics — one entry per ContractFields key ─────────────────
24
+ const fieldDiagnostics = [];
25
+ for (const [fieldKey, fieldName] of FIELD_PREDICATE_MAP) {
26
+ const field = proj.fields[fieldKey];
27
+ if (field.status === "missing") {
28
+ fieldDiagnostics.push({ fieldName, status: "not_checked", reasonCode: "FIELD_MISSING" });
29
+ continue;
30
+ }
31
+ if (field.status === "disputed") {
32
+ fieldDiagnostics.push({ fieldName, status: "not_checked", reasonCode: "FIELD_DISPUTED" });
33
+ continue;
34
+ }
35
+ // resolved — check the winning claim's provenance chain
36
+ if (field.winningClaimId !== undefined) {
37
+ fieldDiagnostics.push(checkClaimEvidence(fieldName, field.winningClaimId, claimMap, sourceReg, docStore, ctx));
38
+ }
39
+ }
40
+ // ── Conflict diagnostics — one entry per (conflict × competingClaimId) ───
41
+ // CONTRACT_CONFLICT_EVIDENCE_VISIBLE_001: each competing claim gets its own entry.
42
+ const conflictDiagnostics = [];
43
+ for (const conflict of [...proj.conflicts].sort((a, b) => a.predicate.localeCompare(b.predicate))) {
44
+ for (const competingClaimId of [...conflict.competingClaimIds].sort()) {
45
+ conflictDiagnostics.push(checkConflictEvidence(conflict.predicate, competingClaimId, claimMap, sourceReg, docStore, ctx));
46
+ }
47
+ }
48
+ return {
49
+ contractId: proj.contractId,
50
+ fieldDiagnostics,
51
+ conflictDiagnostics,
52
+ policyId: proj.policyId,
53
+ };
54
+ }
55
+ // CONTRACT_FIELD_SOURCE_MISSING_001 / CONTRACT_FIELD_SOURCE_NO_EVIDENCE_001 /
56
+ // CONTRACT_FIELD_EVIDENCE_MISSING_001 / CONTRACT_FIELD_EVIDENCE_PRESENT_001
57
+ function checkClaimEvidence(fieldName, claimId, claimMap, sourceReg, docStore, ctx) {
58
+ const claimMeta = claimMap.get(claimId);
59
+ if (claimMeta === undefined) {
60
+ return { fieldName, claimId, status: "source_missing", reasonCode: "CLAIM_NOT_IN_MAP" };
61
+ }
62
+ const sourceId = claimMeta.sourceId;
63
+ const source = sourceReg.getSource(ctx, sourceId);
64
+ if (source === undefined) {
65
+ return { fieldName, claimId, sourceId, status: "source_missing", reasonCode: "SOURCE_UNKNOWN_REJECTED_001" };
66
+ }
67
+ const evidenceId = source.evidenceRef?.id;
68
+ if (evidenceId === undefined) {
69
+ return { fieldName, claimId, sourceId, status: "source_no_evidence", reasonCode: "SOURCE_HAS_NO_EVIDENCE_REF" };
70
+ }
71
+ const evRef = docStore.getEvidenceRef(ctx, evidenceId);
72
+ if (evRef === undefined) {
73
+ return { fieldName, claimId, sourceId, evidenceId, status: "evidence_missing", reasonCode: "EVIDENCE_REF_NOT_IN_STORE" };
74
+ }
75
+ return {
76
+ fieldName,
77
+ claimId,
78
+ sourceId,
79
+ evidenceId,
80
+ status: "evidence_present",
81
+ reasonCode: "EVIDENCE_BACKED_CLAIM_PROVENANCE_CHAIN_001",
82
+ evidenceRef: evRef,
83
+ };
84
+ }
85
+ function checkConflictEvidence(fieldName, competingClaimId, claimMap, sourceReg, docStore, ctx) {
86
+ const claimMeta = claimMap.get(competingClaimId);
87
+ if (claimMeta === undefined) {
88
+ return { fieldName, competingClaimId, status: "source_missing", reasonCode: "CLAIM_NOT_IN_MAP" };
89
+ }
90
+ const sourceId = claimMeta.sourceId;
91
+ const source = sourceReg.getSource(ctx, sourceId);
92
+ if (source === undefined) {
93
+ return { fieldName, competingClaimId, sourceId, status: "source_missing", reasonCode: "SOURCE_UNKNOWN_REJECTED_001" };
94
+ }
95
+ const evidenceId = source.evidenceRef?.id;
96
+ if (evidenceId === undefined) {
97
+ return { fieldName, competingClaimId, sourceId, status: "source_no_evidence", reasonCode: "SOURCE_HAS_NO_EVIDENCE_REF" };
98
+ }
99
+ const evRef = docStore.getEvidenceRef(ctx, evidenceId);
100
+ if (evRef === undefined) {
101
+ return { fieldName, competingClaimId, sourceId, evidenceId, status: "evidence_missing", reasonCode: "EVIDENCE_REF_NOT_IN_STORE" };
102
+ }
103
+ return {
104
+ fieldName,
105
+ competingClaimId,
106
+ sourceId,
107
+ evidenceId,
108
+ status: "evidence_present",
109
+ reasonCode: "EVIDENCE_BACKED_CLAIM_PROVENANCE_CHAIN_001",
110
+ };
111
+ }
112
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/contract/diagnostics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ClaimMeta } from "../types/claim.js";
2
+ import type { PersonId } from "../types/ids.js";
3
+ import type { TrustProfile } from "../resolution/trust-profile.js";
4
+ import type { ContractProjection } from "./types.js";
5
+ export declare function projectContracts(claims: ReadonlyArray<ClaimMeta>, trust: TrustProfile, erasedSubjects?: ReadonlySet<PersonId>): ReadonlyArray<ContractProjection>;
@@ -0,0 +1,159 @@
1
+ // Slice-04: Contract Identity + Projection.
2
+ // Pure function — no I/O, no mutation, no external data invented.
3
+ //
4
+ // CONTRACT_PROJECTION_FROM_CLAIMS_001 — derives only from provided Claims
5
+ // CONTRACT_PROJECTION_NO_MUTATION_001 — never mutates input
6
+ // CONTRACT_PROJECTION_DETERMINISTIC_001 — order-independent output
7
+ // CONTRACT_IDENTITY_LINK_CLAIM_001 — identity must be a live contract.identity.link Claim
8
+ // CONTRACT_PROJECTION_IGNORES_UNLINKED_CLAIMS_001 — no contractId → excluded
9
+ import { ERASURE_TOMBSTONE_PREDICATE } from "../erasure/tombstone.js";
10
+ import { resolveClaims } from "../resolution/resolve-claims.js";
11
+ const POLICY_ID = "trust-then-seq-v1";
12
+ const POLICY_VERSION = "1";
13
+ // All-missing fields constant — used for insufficient_identity projections.
14
+ // CONTRACT_PROJECTION_INSUFFICIENT_IDENTITY_DIAGNOSTIC_001
15
+ const _EMPTY_COMPETING = Object.freeze([]);
16
+ const MISSING_FIELD = Object.freeze({
17
+ status: "missing",
18
+ competingClaimIds: _EMPTY_COMPETING,
19
+ reasonCode: "MISSING",
20
+ });
21
+ const MISSING_FIELDS = Object.freeze({
22
+ counterparty: MISSING_FIELD,
23
+ amount: MISSING_FIELD,
24
+ cadence: MISSING_FIELD,
25
+ nextDue: MISSING_FIELD,
26
+ cancellationTerms: MISSING_FIELD,
27
+ contractStatus: MISSING_FIELD,
28
+ });
29
+ export function projectContracts(claims, trust,
30
+ // ERASURE_QUERY_SUPPRESSION_DEFINED_001: when provided, claims for erased subjects are
31
+ // excluded before projection. Defense-in-depth — callers should also pre-filter.
32
+ erasedSubjects) {
33
+ // ERASURE_QUERY_SUPPRESSION_DEFINED_001: self-detect tombstone claims within input.
34
+ // Defense-in-depth — suppression works even when caller omits erasedSubjects.
35
+ const selfDetectedErased = new Set(claims.filter(c => c.predicate === ERASURE_TOMBSTONE_PREDICATE).map(c => c.subject));
36
+ const allErased = new Set([
37
+ ...selfDetectedErased,
38
+ ...(erasedSubjects ?? []),
39
+ ]);
40
+ // CONTRACT_PROJECTION_NO_MUTATION_001: copy before sorting
41
+ // CONTRACT_PROJECTION_DETERMINISTIC_001: canonical order by recordedSeq
42
+ const liveClaims = allErased.size > 0
43
+ ? claims.filter(c => !allErased.has(c.subject))
44
+ : claims;
45
+ const sorted = [...liveClaims].sort((a, b) => a.recordedSeq - b.recordedSeq);
46
+ const { retractedIds, supersededIds } = buildLiveSets(sorted);
47
+ // Identity links establish which ContractIds exist.
48
+ // A live identity link is: correct predicate, has contractId, not retracted,
49
+ // not superseded, and not itself a retraction marker.
50
+ const liveIdentityLinks = sorted.filter((c) => c.predicate === "contract.identity.link" &&
51
+ c.contractId !== undefined &&
52
+ !retractedIds.has(c.id) &&
53
+ !supersededIds.has(c.id) &&
54
+ c.retracts === undefined);
55
+ const anchoredIds = new Set(liveIdentityLinks.map((c) => c.contractId));
56
+ // Normal projections — contractIds backed by a live identity-link
57
+ const normalProjections = [...anchoredIds].sort().map((contractId) => buildProjection(contractId, sorted, trust));
58
+ // CONTRACT_PROJECTION_INSUFFICIENT_IDENTITY_DIAGNOSTIC_001:
59
+ // Field claims (non-identity-link) that reference a contractId with no valid anchor are
60
+ // never silently dropped — they surface as status: "insufficient_identity".
61
+ // CONTRACT_ID_POINTER_NOT_IDENTITY_REGRESSION_001: contractId is only a pointer here.
62
+ const orphanedIds = new Set();
63
+ for (const c of sorted) {
64
+ if (c.contractId !== undefined &&
65
+ c.predicate !== "contract.identity.link" &&
66
+ !anchoredIds.has(c.contractId)) {
67
+ orphanedIds.add(c.contractId);
68
+ }
69
+ }
70
+ const insufficientProjections = [...orphanedIds].sort().map((contractId) => {
71
+ const orphanClaims = sorted.filter((c) => c.contractId === contractId);
72
+ return {
73
+ contractId,
74
+ status: "insufficient_identity",
75
+ fields: MISSING_FIELDS,
76
+ conflicts: [],
77
+ derivedFrom: orphanClaims.map((c) => c.id),
78
+ policyId: POLICY_ID,
79
+ policyVersion: POLICY_VERSION,
80
+ };
81
+ });
82
+ return [...normalProjections, ...insufficientProjections];
83
+ }
84
+ // ─── private helpers ──────────────────────────────────────────────────────────
85
+ function buildProjection(contractId, allSorted, trust) {
86
+ // All claims tagged to this contract (identity links + content claims).
87
+ // CONTRACT_PROJECTION_DERIVED_FROM_001: derivedFrom includes retracted/excluded claims too.
88
+ const contractClaims = allSorted.filter((c) => c.contractId === contractId);
89
+ const derivedFrom = contractClaims.map((c) => c.id);
90
+ // Project each field by delegating to resolveClaims()
91
+ const r = {
92
+ counterparty: projectField(contractClaims, trust, "contract.counterparty"),
93
+ amount: projectField(contractClaims, trust, "contract.amount"),
94
+ cadence: projectField(contractClaims, trust, "contract.cadence"),
95
+ nextDue: projectField(contractClaims, trust, "contract.next_due"),
96
+ cancellationTerms: projectField(contractClaims, trust, "contract.cancellation_terms"),
97
+ contractStatus: projectField(contractClaims, trust, "contract.exists"),
98
+ };
99
+ const fields = {
100
+ counterparty: r.counterparty.field,
101
+ amount: r.amount.field,
102
+ cadence: r.cadence.field,
103
+ nextDue: r.nextDue.field,
104
+ cancellationTerms: r.cancellationTerms.field,
105
+ contractStatus: r.contractStatus.field,
106
+ };
107
+ // CONTRACT_PROJECTION_CONFLICTS_VISIBLE_001
108
+ const conflicts = Object.values(r).flatMap((x) => (x.conflict !== undefined ? [x.conflict] : []));
109
+ const status = fields.contractStatus.status === "resolved" ? "active" : "uncertain";
110
+ return {
111
+ contractId,
112
+ status,
113
+ fields,
114
+ conflicts,
115
+ derivedFrom,
116
+ policyId: POLICY_ID,
117
+ policyVersion: POLICY_VERSION,
118
+ };
119
+ }
120
+ function projectField(contractClaims, trust, predicate) {
121
+ const resolution = resolveClaims(contractClaims, trust, predicate);
122
+ if (resolution.reasonCode === "NO_LIVE_CLAIMS") {
123
+ return {
124
+ field: { status: "missing", competingClaimIds: [], reasonCode: "MISSING" },
125
+ };
126
+ }
127
+ if (resolution.status === "resolved") {
128
+ const field = {
129
+ status: "resolved",
130
+ competingClaimIds: resolution.competingClaimIds,
131
+ reasonCode: resolution.reasonCode,
132
+ // exactOptionalPropertyTypes: only set when present
133
+ ...(resolution.winningClaimId !== undefined
134
+ ? { winningClaimId: resolution.winningClaimId }
135
+ : {}),
136
+ };
137
+ return { field };
138
+ }
139
+ // disputed — CONTRACT_PROJECTION_DISPUTED_FIELD_001
140
+ const field = {
141
+ status: "disputed",
142
+ competingClaimIds: resolution.competingClaimIds,
143
+ reasonCode: resolution.reasonCode,
144
+ };
145
+ const conflict = {
146
+ predicate,
147
+ competingClaimIds: resolution.competingClaimIds,
148
+ reasonCode: resolution.reasonCode,
149
+ };
150
+ return { field, conflict };
151
+ }
152
+ function buildLiveSets(claims) {
153
+ const retractedIds = new Set(claims.flatMap((c) => (c.retracts !== undefined ? [c.retracts] : [])));
154
+ const supersededIds = new Set(claims
155
+ .filter((c) => c.supersedes !== undefined && !retractedIds.has(c.id))
156
+ .map((c) => c.supersedes));
157
+ return { retractedIds, supersededIds };
158
+ }
159
+ //# sourceMappingURL=project-contracts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-contracts.js","sourceRoot":"","sources":["../../src/contract/project-contracts.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,kEAAkE;AAClE,EAAE;AACF,2EAA2E;AAC3E,6DAA6D;AAC7D,mEAAmE;AACnE,8FAA8F;AAC9F,6EAA6E;AAK7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAShE,MAAM,SAAS,GAAQ,mBAAmB,CAAC;AAC3C,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,4EAA4E;AAC5E,2DAA2D;AAC3D,MAAM,gBAAgB,GAA2B,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACnE,MAAM,aAAa,GAA4B,MAAM,CAAC,MAAM,CAAC;IAC3D,MAAM,EAAa,SAAkB;IACrC,iBAAiB,EAAE,gBAAgB;IACnC,UAAU,EAAS,SAAkB;CACtC,CAAC,CAAC;AACH,MAAM,cAAc,GAAmB,MAAM,CAAC,MAAM,CAAC;IACnD,YAAY,EAAO,aAAa;IAChC,MAAM,EAAa,aAAa;IAChC,OAAO,EAAY,aAAa;IAChC,OAAO,EAAY,aAAa;IAChC,iBAAiB,EAAE,aAAa;IAChC,cAAc,EAAK,aAAa;CACjC,CAAC,CAAC;AAEH,MAAM,UAAU,gBAAgB,CAC9B,MAAgC,EAChC,KAAmB;AACnB,uFAAuF;AACvF,iFAAiF;AACjF,cAAsC;IAEtC,oFAAoF;IACpF,8EAA8E;IAC9E,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAChC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,2BAA2B,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CACpF,CAAC;IACF,MAAM,SAAS,GAA0B,IAAI,GAAG,CAAC;QAC/C,GAAG,kBAAkB;QACrB,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;KAC1B,CAAC,CAAC;IAEH,2DAA2D;IAC3D,wEAAwE;IACxE,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,GAAG,CAAC;QACnC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC,CAAC,MAAM,CAAC;IACX,MAAM,MAAM,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;IAE7E,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAE9D,oDAAoD;IACpD,6EAA6E;IAC7E,sDAAsD;IACtD,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,SAAS,KAAK,wBAAwB;QACxC,CAAC,CAAC,UAAU,KAAK,SAAS;QAC1B,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACvB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACxB,CAAC,CAAC,QAAQ,KAAK,SAAS,CAC3B,CAAC;IAEF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAW,CAAC,CAAC,CAAC;IAEzE,kEAAkE;IAClE,MAAM,iBAAiB,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CACnE,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,CAC3C,CAAC;IAEF,4DAA4D;IAC5D,wFAAwF;IACxF,4EAA4E;IAC5E,sFAAsF;IACtF,MAAM,WAAW,GAAG,IAAI,GAAG,EAAc,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IACE,CAAC,CAAC,UAAU,KAAK,SAAS;YAC1B,CAAC,CAAC,SAAS,KAAK,wBAAwB;YACxC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAC9B,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,MAAM,uBAAuB,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAsB,EAAE;QAC7F,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;QACvE,OAAO;YACL,UAAU;YACV,MAAM,EAAS,uBAAuB;YACtC,MAAM,EAAS,cAAc;YAC7B,SAAS,EAAM,EAAE;YACjB,WAAW,EAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,QAAQ,EAAO,SAAS;YACxB,aAAa,EAAE,cAAc;SAC9B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,iBAAiB,EAAE,GAAG,uBAAuB,CAAC,CAAC;AAC5D,CAAC;AAED,iFAAiF;AAEjF,SAAS,eAAe,CACtB,UAAsB,EACtB,SAAmC,EACnC,KAAmB;IAEnB,wEAAwE;IACxE,4FAA4F;IAC5F,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;IAC5E,MAAM,WAAW,GAA2B,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5E,sDAAsD;IACtD,MAAM,CAAC,GAAG;QACR,YAAY,EAAO,YAAY,CAAC,cAAc,EAAE,KAAK,EAAE,uBAAuB,CAAC;QAC/E,MAAM,EAAa,YAAY,CAAC,cAAc,EAAE,KAAK,EAAE,iBAAiB,CAAC;QACzE,OAAO,EAAY,YAAY,CAAC,cAAc,EAAE,KAAK,EAAE,kBAAkB,CAAC;QAC1E,OAAO,EAAY,YAAY,CAAC,cAAc,EAAE,KAAK,EAAE,mBAAmB,CAAC;QAC3E,iBAAiB,EAAE,YAAY,CAAC,cAAc,EAAE,KAAK,EAAE,6BAA6B,CAAC;QACrF,cAAc,EAAK,YAAY,CAAC,cAAc,EAAE,KAAK,EAAE,iBAAiB,CAAC;KAC1E,CAAC;IAEF,MAAM,MAAM,GAAmB;QAC7B,YAAY,EAAO,CAAC,CAAC,YAAY,CAAC,KAAK;QACvC,MAAM,EAAa,CAAC,CAAC,MAAM,CAAC,KAAK;QACjC,OAAO,EAAY,CAAC,CAAC,OAAO,CAAC,KAAK;QAClC,OAAO,EAAY,CAAC,CAAC,OAAO,CAAC,KAAK;QAClC,iBAAiB,EAAE,CAAC,CAAC,iBAAiB,CAAC,KAAK;QAC5C,cAAc,EAAK,CAAC,CAAC,cAAc,CAAC,KAAK;KAC1C,CAAC;IAEF,4CAA4C;IAC5C,MAAM,SAAS,GACb,MAAM,CAAC,MAAM,CAAC,CAAC,CAChB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEjE,MAAM,MAAM,GACV,MAAM,CAAC,cAAc,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;IAEvE,OAAO;QACL,UAAU;QACV,MAAM;QACN,MAAM;QACN,SAAS;QACT,WAAW;QACX,QAAQ,EAAO,SAAS;QACxB,aAAa,EAAE,cAAc;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,cAAwC,EACxC,KAAmB,EACnB,SAAyB;IAEzB,MAAM,UAAU,GAAG,aAAa,CAAC,cAAc,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAEnE,IAAI,UAAU,CAAC,UAAU,KAAK,gBAAgB,EAAE,CAAC;QAC/C,OAAO;YACL,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE;SAC3E,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACrC,MAAM,KAAK,GAA4B;YACrC,MAAM,EAAa,UAAU;YAC7B,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;YAC/C,UAAU,EAAS,UAAU,CAAC,UAAU;YACxC,oDAAoD;YACpD,GAAG,CAAC,UAAU,CAAC,cAAc,KAAK,SAAS;gBACzC,CAAC,CAAC,EAAE,cAAc,EAAE,UAAU,CAAC,cAAc,EAAE;gBAC/C,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,oDAAoD;IACpD,MAAM,KAAK,GAA4B;QACrC,MAAM,EAAa,UAAU;QAC7B,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,UAAU,EAAS,UAAU,CAAC,UAAU;KACzC,CAAC;IACF,MAAM,QAAQ,GAAqB;QACjC,SAAS;QACT,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,UAAU,EAAS,UAAU,CAAC,UAAkC;KACjE,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,aAAa,CAAC,MAAgC;IAIrD,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CACtE,CAAC;IACF,MAAM,aAAa,GAAG,IAAI,GAAG,CAC3B,MAAM;SACH,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACpE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAW,CAAC,CAC7B,CAAC;IACF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { ClaimId, ContractId } from "../types/ids.js";
2
+ import type { ClaimPredicate } from "../types/claim.js";
3
+ import type { ResolutionReasonCode } from "../resolution/types.js";
4
+ export interface ContractFieldProjection {
5
+ readonly status: "resolved" | "disputed" | "missing";
6
+ readonly winningClaimId?: ClaimId;
7
+ readonly competingClaimIds: ReadonlyArray<ClaimId>;
8
+ readonly reasonCode: ResolutionReasonCode | "MISSING";
9
+ }
10
+ export interface ContractFields {
11
+ readonly counterparty: ContractFieldProjection;
12
+ readonly amount: ContractFieldProjection;
13
+ readonly cadence: ContractFieldProjection;
14
+ readonly nextDue: ContractFieldProjection;
15
+ readonly cancellationTerms: ContractFieldProjection;
16
+ readonly contractStatus: ContractFieldProjection;
17
+ }
18
+ export interface ContractConflict {
19
+ readonly predicate: ClaimPredicate;
20
+ readonly competingClaimIds: ReadonlyArray<ClaimId>;
21
+ readonly reasonCode: ResolutionReasonCode;
22
+ }
23
+ export type ContractProjectionStatus = "active" | "uncertain" | "insufficient_identity";
24
+ export interface ContractProjection {
25
+ readonly contractId: ContractId;
26
+ readonly status: ContractProjectionStatus;
27
+ readonly fields: ContractFields;
28
+ readonly conflicts: ReadonlyArray<ContractConflict>;
29
+ readonly derivedFrom: ReadonlyArray<ClaimId>;
30
+ readonly policyId: string;
31
+ readonly policyVersion: string;
32
+ }
@@ -0,0 +1,5 @@
1
+ // Slice-04: Contract Identity + Projection types.
2
+ // A ContractProjection is derived exclusively from Claims — no external data.
3
+ // CONTRACT_PROJECTION_FROM_CLAIMS_001
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/contract/types.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,8EAA8E;AAC9E,sCAAsC"}
@@ -0,0 +1,11 @@
1
+ import type { CryptoBoundary, EncryptedBlob, KeyProvider } from "./types.js";
2
+ export declare class AesGcmCryptoBoundary implements CryptoBoundary {
3
+ private readonly _keys;
4
+ constructor(_keys: KeyProvider);
5
+ encryptJson(value: unknown): Promise<EncryptedBlob>;
6
+ decryptJson(blob: EncryptedBlob): Promise<unknown>;
7
+ encryptBytes(bytes: Uint8Array): Promise<EncryptedBlob>;
8
+ decryptBytes(blob: EncryptedBlob): Promise<Uint8Array>;
9
+ private _encrypt;
10
+ private _decrypt;
11
+ }
@@ -0,0 +1,78 @@
1
+ // AesGcmCryptoBoundary — AES-256-GCM encryption via WebCrypto.
2
+ //
3
+ // CRYPTO_BOUNDARY_ONLY_001: only this file uses crypto.subtle.
4
+ // No node:crypto import. Uses globalThis.crypto.subtle (Node 18+, all browsers).
5
+ // CRYPTO_WRONG_KEY_FAIL_CLOSED_001: unknown keyId → throws immediately.
6
+ // CRYPTO_TAMPER_DETECTED_001: GCM auth-tag failure → throws.
7
+ // CRYPTO_KEY_PROVIDER_DI_001: KeyProvider injected via constructor.
8
+ const IV_BYTES = 12; // 96-bit nonce — NIST recommended for AES-GCM
9
+ export class AesGcmCryptoBoundary {
10
+ _keys;
11
+ constructor(_keys) {
12
+ this._keys = _keys;
13
+ }
14
+ async encryptJson(value) {
15
+ return this._encrypt(new TextEncoder().encode(JSON.stringify(value)));
16
+ }
17
+ async decryptJson(blob) {
18
+ const bytes = await this._decrypt(blob);
19
+ return JSON.parse(new TextDecoder().decode(bytes));
20
+ }
21
+ async encryptBytes(bytes) {
22
+ return this._encrypt(bytes);
23
+ }
24
+ async decryptBytes(blob) {
25
+ return this._decrypt(blob);
26
+ }
27
+ async _encrypt(plaintext) {
28
+ const { key, keyId } = await this._keys.getCurrentKey();
29
+ // CRYPTO_WEBCRYPTO_TYPES_001: TS 5.7+ made Uint8Array generic; WebCrypto expects
30
+ // ArrayBuffer-backed views. new Uint8Array(N) returns Uint8Array<ArrayBuffer>.
31
+ const iv = new Uint8Array(IV_BYTES);
32
+ globalThis.crypto.getRandomValues(iv);
33
+ // WebCrypto AES-GCM: ciphertext output includes the 16-byte authTag appended.
34
+ const cipherBuf = await globalThis.crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, new Uint8Array(plaintext));
35
+ return {
36
+ algorithm: "AES-256-GCM",
37
+ keyId,
38
+ iv: toBase64Url(iv),
39
+ ciphertext: toBase64Url(new Uint8Array(cipherBuf)),
40
+ };
41
+ }
42
+ async _decrypt(blob) {
43
+ const desc = await this._keys.getKey(blob.keyId);
44
+ if (desc === undefined) {
45
+ // CRYPTO_WRONG_KEY_FAIL_CLOSED_001: no partial plaintext, just a clear error.
46
+ throw new Error(`CRYPTO_WRONG_KEY_FAIL_CLOSED_001: key "${blob.keyId}" is unknown — decryption refused`);
47
+ }
48
+ try {
49
+ const plainBuf = await globalThis.crypto.subtle.decrypt({ name: "AES-GCM", iv: new Uint8Array(fromBase64Url(blob.iv)) }, desc.key, new Uint8Array(fromBase64Url(blob.ciphertext)));
50
+ return new Uint8Array(plainBuf);
51
+ }
52
+ catch {
53
+ // GCM authentication tag verification failed → tamper or wrong key material.
54
+ // CRYPTO_TAMPER_DETECTED_001
55
+ throw new Error("CRYPTO_TAMPER_DETECTED_001: AES-GCM authentication failed — ciphertext is tampered or key material is wrong");
56
+ }
57
+ }
58
+ }
59
+ // ─── base64url helpers ────────────────────────────────────────────────────────
60
+ function toBase64Url(bytes) {
61
+ let binary = "";
62
+ for (let i = 0; i < bytes.length; i++) {
63
+ binary += String.fromCharCode(bytes[i]);
64
+ }
65
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
66
+ }
67
+ function fromBase64Url(s) {
68
+ const padded = s.replace(/-/g, "+").replace(/_/g, "/");
69
+ const remainder = padded.length % 4;
70
+ const padStr = remainder === 0 ? "" : "=".repeat(4 - remainder);
71
+ const binary = atob(padded + padStr);
72
+ const bytes = new Uint8Array(binary.length);
73
+ for (let i = 0; i < binary.length; i++) {
74
+ bytes[i] = binary.charCodeAt(i);
75
+ }
76
+ return bytes;
77
+ }
78
+ //# sourceMappingURL=aes-gcm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aes-gcm.js","sourceRoot":"","sources":["../../src/crypto/aes-gcm.ts"],"names":[],"mappings":"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"}