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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alper
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,377 @@
1
+ # life-as-api
2
+
3
+ A personal context layer: a typed, encrypted, consent-gated claim log that lets authorised
4
+ agents query structured facts about a person's life without exposing raw documents, crypto
5
+ primitives, or the underlying storage engine.
6
+
7
+ > **v0.2.0** · 3908 tests · typecheck clean
8
+
9
+ The production auth boundary is complete for the documented MVP boundary: a scoped 8-method
10
+ facade (`ProductionScopedLifeApi`) enforces subject and proposal scope on every call, backed by
11
+ a SQLite persistence layer with an AES-256-GCM encryption boundary. Security-relevant decisions
12
+ are recorded through an internal audit abstraction with a local hash chain over `audit_events`
13
+ (tamper-evident locally — not court-grade, not external notarization). Operator tooling covers
14
+ backup/restore, key-availability validation, and full decryptability scanning (D2–D4). On top of
15
+ that closure, the platform layer (Platform-01 through 05) adds trusted-agent/data-source
16
+ registries, guardianship, purpose enforcement, a GDPR Art. 15/20 subject data report, and three
17
+ certified first-party agents — all optional, additive, and fail-closed. See
18
+ [docs/specs/post-auth-product-boundary-spec.md](docs/specs/post-auth-product-boundary-spec.md)
19
+ and [CHANGELOG.md](CHANGELOG.md) for exact claims and non-claims release by release.
20
+
21
+ ---
22
+
23
+ ## Concept
24
+
25
+ > "Jarvis, what are my active subscriptions?"
26
+
27
+ The system stores *claims* (immutable, encrypted, provenance-linked facts) and lets agents
28
+ *query* them through a consent gate — seeing only what they've been explicitly granted.
29
+ Nothing is ever mutated in-place. Everything is append-only and audited.
30
+
31
+ ---
32
+
33
+ ## Production factory (MVP-stable)
34
+
35
+ ```ts
36
+ import { createSQLiteLifeApiForProduction } from "life-as-api";
37
+ import type {
38
+ ProductionApiBundle,
39
+ ProductionScopedLifeApi,
40
+ ProductionFactoryConfig,
41
+ MintedContext,
42
+ } from "life-as-api";
43
+
44
+ // 1. Configure and build the production bundle
45
+ const bundle: ProductionApiBundle = await createSQLiteLifeApiForProduction({
46
+ db: yourMigratedSqliteDatabase,
47
+
48
+ // Encryption source — exactly one of encryptionKey or keyProvider must be provided.
49
+ // Option A: raw key bytes (dev/staging) — factory creates StaticKeyProvider internally.
50
+ encryptionKey: { keyId: "key-v1", rawBytes: yourEncryptionKeyBytes },
51
+ // Option B: external KeyProvider (production) — plug in a KMS-backed adapter.
52
+ // keyProvider: yourKmsKeyProvider, // implements KeyProvider; encryptionKey must be absent
53
+
54
+ authAdapter: yourAuthAdapter, // implements AuthAdapter
55
+ rawDocumentStore: yourDurableDocStore, // implements FactoryCompatibleRawDocumentStore
56
+ auditLog: yourDurableAuditLog, // implements FactoryCompatibleAuditLog
57
+ // ... see ProductionFactoryConfig for full field list
58
+ });
59
+
60
+ // 2. Mint a trusted context from bearer credentials
61
+ const minted: MintedContext = await bundle.auth.mint(bearerCredential, targetPersonId, "owner");
62
+
63
+ // 3. Get a subject-scoped production API
64
+ const api: ProductionScopedLifeApi = bundle.createScopedApi(minted);
65
+
66
+ // 4. Use the 8 scope-enforced facade methods
67
+ await api.queryContracts(personId, queryInput);
68
+ await api.requestErasure(personId);
69
+ await api.getErasureStatus(personId);
70
+ await api.acceptProposal(proposalId, acceptOptions);
71
+ await api.rejectProposal(proposalId, { reason: "Not accurate" });
72
+ await api.createProposal(proposalInput);
73
+ await api.getProposal(proposalId); // returns undefined if not found or cross-subject
74
+ await api.listProposals({ status: "pending" }); // scoped to bound person only
75
+ ```
76
+
77
+ All 8 methods enforce subject/proposal scope before delegation. Agents are bound to the
78
+ `personId` from their grant (`authorizedPersonId`). Broad grants (no `personId`) are denied
79
+ at context-minting time, not at query time.
80
+
81
+ **Proposal read semantics:** `getProposal` returns `undefined` for missing, cross-subject,
82
+ unknown-subject (empty `candidateClaims`), and multi-subject proposals — all four cases are
83
+ indistinguishable. `listProposals` returns only proposals whose unique candidate subject
84
+ matches the bound person; cross/unknown/multi-subject proposals are silently omitted.
85
+ `listProposals` does not expose arbitrary `subject` or `underGrant` filters.
86
+
87
+ ```ts
88
+ // 5. Optional: run the D2b local health diagnostic (no user/agent context required)
89
+ const health = await bundle.healthCheck();
90
+ // health.status: "ok" | "degraded" | "failed"
91
+ // health.checks: readonly HealthCheckItem[] — seven named checks
92
+ // health.checkedAt: ISO timestamp
93
+ // { status: "ok" } means all seven local checks passed.
94
+ // It does NOT mean operational production readiness.
95
+ ```
96
+
97
+ **This does not claim full OIDC/OAuth authorization flow, session revocation, rate limiting,
98
+ external tamper-evident audit, GDPR/legal compliance, multi-process consistency, or operational
99
+ production readiness.** RS256/JWKS adapter (`JwksKeyRingAuthAdapter`) is implemented — not exported
100
+ from package root; host-supplied. ES256, full OIDC server, OAuth flow, session revocation remain
101
+ unclaimed. See §3 below.
102
+
103
+ ---
104
+
105
+ ## Platform layer (0.2.0)
106
+
107
+ Five optional, additive slices sit on top of the production auth closure. Every one of them is
108
+ fail-closed and backward-compatible: if you don't configure it, behavior is byte-identical to
109
+ 0.1.0.
110
+
111
+ ### Platform-01 — Trusted Agent Registry + Purpose Binding
112
+
113
+ When a `TrustedAgentRegistry` is configured, no `AgentConsentContext` is minted without
114
+ `isAgentTrusted(agentId, purpose)` returning `true` — the check fires before `issuer.mintAgent`,
115
+ before any context that could read data exists. Registry exceptions, unknown agents, or expired
116
+ certifications deny the mint; the registry never fails open. Leaving `trustedAgentRegistry`
117
+ unset leaves the agent-mint path unchanged.
118
+
119
+ ```ts
120
+ const bundle = await createSQLiteLifeApiForProduction({
121
+ // ...required fields
122
+ trustedAgentRegistry: new InMemoryTrustedAgentRegistry([medicalAgentRegistryEntry(validUntilMs)]),
123
+ });
124
+ ```
125
+
126
+ `GrantDescriptor.purpose` remains declarative — the library does not enforce it on the plain
127
+ access-context path; enforcement there is agent/host responsibility (see Platform-04 for the
128
+ minting-time enforcement path).
129
+
130
+ ### Platform-02 — Trusted Data Source Registry + Proposal Policy
131
+
132
+ `TrustedDataSourceRegistry` and `ProposalPolicy` (`DefaultProposalPolicy`,
133
+ `RegistryBackedProposalPolicy`) decide whether an incoming proposal is auto-accepted,
134
+ auto-rejected, or left for manual review. Unknown source, expired certification, unrecognised
135
+ scope, or any exception during evaluation resolves to `"manual"` — the fail-safe default,
136
+ identical to pre-Platform-02 behavior. An explicit `config.proposalPolicy` always wins over the
137
+ `trustedDataSourceRegistry` convenience wiring when both are supplied.
138
+
139
+ ### Platform-03 — Guardianship / Bevollmächtigung
140
+
141
+ `GuardianRegistry` plus `mintGuardianContext()` let an authorised guardian mint a scoped
142
+ `MintedContext` for a ward. The registry check (`getRelationship` + `isAuthorized`) fires before
143
+ `issuer.mintOwner` — no context exists if the check fails. The registry check is fail-closed on
144
+ an unknown guardian/ward pair, an expired relationship, or a scope that isn't an exact match.
145
+ `requestErasure` and `getErasureStatus` are always denied for guardian contexts, regardless of
146
+ granted scopes — erasure is personal and not delegable. Without a configured `guardianRegistry`,
147
+ `mintGuardianContext` throws `GUARDIAN_REGISTRY_NOT_CONFIGURED_001`; all other behavior is
148
+ unaffected.
149
+
150
+ ```ts
151
+ const minted = await bundle.auth.mintGuardianContext(bearerCredential, wardPersonId, "manage_finances");
152
+ ```
153
+
154
+ ### Platform-04 — Purpose-Enforcement + Subject Data Report (GDPR Art. 15/20)
155
+
156
+ When a caller passes `MintOptions.declaredPurpose` **and** the resolved grant declares its own
157
+ `purpose` **and** the two differ, the mint is denied with the same opaque error used for
158
+ "grant not found" — the two denial reasons are indistinguishable to the caller. If either side
159
+ omits a purpose, there is no enforcement and behavior matches pre-Platform-04. On a successful
160
+ mint with a declared purpose, `MintedContext.declaredPurpose` carries the value.
161
+
162
+ ```ts
163
+ const minted = await bundle.auth.mint(bearerCredential, personId, "agent", {
164
+ declaredPurpose: "diagnosis",
165
+ });
166
+ ```
167
+
168
+ `generateSubjectDataReport(personId)` produces a complete structured account of everything held
169
+ about a person — grants across all statuses, proposals (metadata only, never the encrypted
170
+ payload), and audit events (via grant join plus guardian ward events) — together with a SHA-256
171
+ `dataIntegrityHash` over canonical JSON, making the report tamper-evident. The function does not
172
+ itself enforce caller identity; restricting it to the subject (owner context or an authorised
173
+ guardian) is host responsibility.
174
+
175
+ ### Platform-05 — Certified First-Party Agents
176
+
177
+ `MedicalAgent`, `FinanceAgent`, and `LegalAgent` are read-only, purpose-bound reference agents,
178
+ each with a matching `*AgentRegistryEntry()` factory that builds a `TrustedAgentRegistryEntry`
179
+ certified by `"life-as-api-foundation"` for direct registration with a `TrustedAgentRegistry`.
180
+ Each agent's constructor accepts only a query function — there is no propose/write capability
181
+ anywhere on these classes. `run()` fail-closed throws a `*_SCOPE_DENIED_001` coded error for any
182
+ `declaredPurpose` outside the agent's own allowed set, including an absent purpose. An optional
183
+ `onAudit` hook fires on every `run()` call; persisting that audit trail durably remains a host
184
+ responsibility.
185
+
186
+ ```ts
187
+ const medical = new MedicalAgent({ query: bundle.createScopedApi(minted).queryContracts, clock });
188
+ await medical.run(minted, queryInput); // only proceeds if minted.declaredPurpose is
189
+ // "diagnosis" | "treatment" | "emergency"
190
+ ```
191
+
192
+ `PurposeTag` gained 11 additive values for these agents (`diagnosis`, `treatment`, `emergency`,
193
+ `tax`, `credit_check`, `insurance_claim`, `account_overview`, `notary`, `contract_review`,
194
+ `evidence_preservation`, `court_filing`) — union-widening only, fully backward-compatible.
195
+
196
+ ---
197
+
198
+ ## Test/dev quick start
199
+
200
+ ```ts
201
+ import {
202
+ createInMemoryLifeApiForTest,
203
+ asPersonId, asSourceId, asContractId, asGrantId, asISOTime,
204
+ } from "life-as-api";
205
+ import type { OwnerContext, AgentConsentContext } from "life-as-api";
206
+
207
+ const { api } = await createInMemoryLifeApiForTest();
208
+ const owner: OwnerContext = { kind: "owner", personId: asPersonId("me") };
209
+
210
+ // Store a claim with full provenance
211
+ await api.createClaimWithNewEvidence(owner, {
212
+ document: { bytes: new TextEncoder().encode("...statement..."), mimeType: "application/pdf" },
213
+ source: { id: asSourceId("src-001"), kind: "user_manual", label: "Bank statement" },
214
+ claim: {
215
+ subject: asPersonId("me"),
216
+ predicate: "contract.amount",
217
+ payload: { type: "money", currency: "EUR", minorUnits: 4999 },
218
+ validFrom: asISOTime("2025-01-15T00:00:00.000Z"),
219
+ contractId: asContractId("cntr-001"),
220
+ },
221
+ });
222
+ ```
223
+
224
+ `createInMemoryLifeApiForTest` is for development and testing only. It does not enforce
225
+ production auth boundaries.
226
+
227
+ ---
228
+
229
+ ## MVP-stable public API surface
230
+
231
+ | Import | Kind | Notes |
232
+ |--------|------|-------|
233
+ | `createSQLiteLifeApiForProduction` | factory | Returns `Promise<ProductionApiBundle>` |
234
+ | `ProductionApiBundle` | type | `{ auth: ContextMintingBoundary; createScopedApi; healthCheck }` |
235
+ | `ProductionScopedLifeApi` | type | 8-method scoped facade |
236
+ | `ListProposalsInput` | type | `{ status?: ProposalStatus }` — narrow filter for `listProposals` |
237
+ | `ContextMintingBoundary` | type | Interface for the auth minting boundary |
238
+ | `MintedContext` | type | Trusted context with scope metadata |
239
+ | `ProductionFactoryConfig` | type | Factory configuration interface — `encryptionKey?` (raw bytes → `StaticKeyProvider`) **or** `keyProvider?: KeyProvider` (external KMS-backed adapter); exactly one required; both present → fail-closed; also optional `logger?: Logger`, `metrics?: MetricsRecorder` |
240
+ | `Logger`, `LogEvent`, `LogLevel` | types | D2a best-effort operator diagnostics interface |
241
+ | `noopLogger` | runtime | Safe frozen no-op logger — the library default |
242
+ | `MetricsRecorder` | type | D2c optional push-style metrics adapter interface (`increment?`, `observe?`) |
243
+ | `MetricName` | type | Closed union of the five D2c metric names |
244
+ | `MetricLabels` | type | Closed interface of the six allowed low-cardinality label keys |
245
+ | `noopMetricsRecorder` | runtime | Safe frozen no-op metrics recorder — the library default |
246
+ | `HealthStatus` | type | `"ok" \| "degraded" \| "failed"` — aggregate and per-check status |
247
+ | `HealthCheckItem` | type | `{ name, status, code, errorName? }` — one entry per check, no sensitive fields |
248
+ | `HealthCheckResult` | type | `{ status, checkedAt, checks }` — full D2b result shape |
249
+ | `RejectOptions` | type | `{ reason: string }` for `rejectProposal` |
250
+ | `ProposalInput`, `AcceptOptions` | types | Proposal method parameter types |
251
+ | `PersonId`, `ProposalId`, … | opaque ID types | Tagged string IDs |
252
+ | `AuthAdapter`, `TenantBoundary`, `GrantResolver` | interfaces | Host adapter contracts |
253
+ | `SubjectScopedLifeApi`, `ProposalScopedLifeApi` | lower-level | Host-adapter composition utilities |
254
+ | `assertAuthorizedForSubject`, `inspectProposalScope` | helpers | Host-adapter scope utilities |
255
+ | `createInMemoryLifeApiForTest` | dev/test factory | Not a production pattern |
256
+ | `KeyProvider`, `KeyDescriptor` | types | Interface-only — external KMS adapter contract; no implementation exported |
257
+ | `TrustedAgentRegistry`, `TrustedAgentRegistryEntry` | types (Platform-01) | Interface + entry shape for agent-mint gating |
258
+ | `InMemoryTrustedAgentRegistry` | runtime (Platform-01) | Reference/dev implementation — production hosts supply their own |
259
+ | `TrustedDataSourceRegistry`, `TrustedDataSourceEntry` | types (Platform-02) | Interface + entry shape for source trust/expiry |
260
+ | `InMemoryTrustedDataSourceRegistry` | runtime (Platform-02) | Reference/dev implementation |
261
+ | `ProposalPolicy`, `ProposalPolicyInput`, `ProposalDisposition` | types (Platform-02) | Auto-accept/auto-reject/manual policy contract |
262
+ | `DefaultProposalPolicy`, `RegistryBackedProposalPolicy` | runtime (Platform-02) | Manual-default and registry-backed policy implementations |
263
+ | `GuardianRegistry`, `GuardianRelationship` | types (Platform-03) | Guardian/ward relationship contract |
264
+ | `InMemoryGuardianRegistry` | runtime (Platform-03) | Reference/dev implementation |
265
+ | `GuardianContextMintingBoundary` | type (Platform-03) | `ContextMintingBoundary` extended with `mintGuardianContext()` |
266
+ | `SubjectDataReport`, `GrantSummary`, `ProposalSummary`, `AuditEventSummary`, `SubjectDataReportOptions` | types (Platform-04) | Shape of the GDPR Art. 15/20 subject data report |
267
+ | `generateSubjectDataReport` | runtime (Platform-04) | Builds the subject data report; caller-identity enforcement is host responsibility |
268
+ | `MedicalAgent`, `medicalAgentRegistryEntry`, `MEDICAL_AGENT_ID`, `MEDICAL_AGENT_VERSION`, `ALLOWED_MEDICAL_PURPOSES`, `MedicalPurpose` | Platform-05 | Certified first-party medical agent (read-only, purpose-bound) |
269
+ | `FinanceAgent`, `financeAgentRegistryEntry`, `FINANCE_AGENT_ID`, `FINANCE_AGENT_VERSION`, `ALLOWED_FINANCE_PURPOSES`, `FinancePurpose` | Platform-05 | Certified first-party finance agent (read-only, purpose-bound) |
270
+ | `LegalAgent`, `legalAgentRegistryEntry`, `LEGAL_AGENT_ID`, `LEGAL_AGENT_VERSION`, `ALLOWED_LEGAL_PURPOSES`, `LegalPurpose` | Platform-05 | Certified first-party legal agent (read-only, purpose-bound) |
271
+
272
+ ### Not exported from package root (intentional)
273
+
274
+ | Symbol | Reason |
275
+ |--------|--------|
276
+ | `LifeApiImpl` | Raw factory-internal API — bypasses scope enforcement |
277
+ | `BackendContextMintingBoundary` | Factory-internal production dependency |
278
+ | `AccessContextIssuer` (runtime) | Trust authority — instance-scoped only |
279
+ | `ProductionScopedLifeApiImpl` | Implementation class — use the interface |
280
+ | `JwtAuthAdapter`, `JwtKeyRingAuthAdapter`, `StaticJwtKeyRing` | Not package-root exported |
281
+ | `SQLiteTenantBoundary`, `SQLiteGrantResolver` | Not package-root exported |
282
+ | `SQLiteProposalQueue`, `SQLiteAuditLog`, `SQLiteRawDocumentStore` | Not package-root exported |
283
+ | `JwksKeyRingAuthAdapter` | RS256/JWKS auth adapter — not package-root exported |
284
+ | `TokenRevocationStore`, `RevocationAwareAuthAdapter` | Session revocation wrapper — not package-root exported |
285
+ | `RateLimiter`, `RateLimitedContextMintingBoundary` | Rate-limiting wrapper — not package-root exported |
286
+
287
+ The package exports map (`package.json exports`) is root-only. Unsupported subpath imports
288
+ (e.g. `"life-as-api/src/…"`, `"life-as-api/dist/…"`) are not part of the public API and
289
+ are blocked by Node.js for consumers respecting the exports map.
290
+
291
+ ---
292
+
293
+ ## What this is
294
+
295
+ - A typed, immutable claim log with AES-256-GCM encrypted payloads
296
+ - A consent-gated query surface (agents see only granted predicates)
297
+ - A proposal queue (agents propose, humans/systems accept or reject)
298
+ - A provenance chain: `RawDocument → EvidenceRef → Source → Claim`
299
+ - A production auth boundary: factory returns a scoped production API bundle; trusted context minting is enforced; grant person scope propagates to agent contexts; erasure/query/proposal create/accept/reject/read enforce documented subject/proposal scope
300
+
301
+ ## What this is NOT
302
+
303
+ - **No KMS / external key custody** — JWT secrets in process memory; at-rest keys via `StaticKeyProvider`
304
+ - **No full OIDC/OAuth** — RS256/JWKS auth adapter (`JwksKeyRingAuthAdapter`) implemented (D5, `cbe40ed`); not exported from package root; host-supplied. ES256, full OIDC authorization server, OAuth flow not claimed
305
+ - **No session revocation built in** — `TokenRevocationStore` interface and
306
+ `RevocationAwareAuthAdapter` wrapper are implemented (host-injectable denylist, fail-closed on
307
+ store error); not exported from package root; without wiring one in, compromised credentials
308
+ require out-of-band grant revocation
309
+ - **No rate limiting built in** — `RateLimiter` interface and `RateLimitedContextMintingBoundary`
310
+ wrapper are implemented (host-injectable, principal-scoped, configurable fail-open/fail-closed
311
+ on store error); not exported from package root; no bundled limiter implementation or store, no
312
+ API-level throttle unless a host wires one in
313
+ - **No external tamper-evident audit** — audit events in SQLite only; no hash-chaining or external sink
314
+ - **No GDPR / legal erasure compliance** — tombstone model is not a legally valid erasure mechanism
315
+ - **No multi-process ProposalQueue consistency** — single-process only
316
+ - **No operational production readiness** — D2a adds best-effort operator diagnostics (logger); D2b adds seven local health checks (`healthCheck()` on the bundle — DB, schema, key provider, auth/tenant/grant adapters); `{ status: "ok" }` is not operational production readiness; D2c adds an optional internal `MetricsRecorder` boundary — push-style adapter for counters only; no external sink, no OpenTelemetry, no HTTP/Prometheus endpoint, no SLA/SLO claim; D3a adds internal SQLite backup/validation utilities (`backupSQLiteDatabase`, `validateBackup`) — recoverability tooling only, not an SLA or operational-readiness claim; D4b adds `validateBackupKeyAvailability(sourcePath, keyProvider)` — internal offline key availability check (are all referenced keyIds resolvable?); key availability does not prove correct key material or decryptability; D4c adds `scanBackupDecryptability(sourcePath, cryptoBoundary)` — internal offline AES-GCM decryptability scan across all three encrypted tables; `{ status: "ok" }` proves tag verification passed on all rows, not semantic correctness or DR readiness
317
+ - **No UI, MCP server, OCR, LLM extraction, Open Banking connectors**
318
+ - **No admin methods** — `createSourceAdmin`, `createGrantAdmin`, etc. are deferred
319
+
320
+ ---
321
+
322
+ ## Running tests
323
+
324
+ ```
325
+ npm run build # compile src/ → dist/ (required before dist/-dependent checks)
326
+ npx vitest run # full suite (3908 passing)
327
+ npx tsc --noEmit # typecheck
328
+ ```
329
+
330
+ ---
331
+
332
+ ## Installing / Releasing
333
+
334
+ ```
335
+ npm install life-as-api # once published
336
+ ```
337
+
338
+ Releases are cut manually: `npm publish` runs `prepublishOnly` (`typecheck` → `test` → `build`)
339
+ before anything is packed, so a broken typecheck or a failing test blocks publish. The publish
340
+ step itself is deliberately manual — there is no CI-triggered auto-publish.
341
+
342
+ ---
343
+
344
+ ## Documentation
345
+
346
+ | Doc | Contents |
347
+ |-----|----------|
348
+ | [docs/specs/post-auth-product-boundary-spec.md](docs/specs/post-auth-product-boundary-spec.md) | Post-auth product boundary freeze — capabilities, non-claims, post-MVP tracks |
349
+ | [docs/specs/post-mvp-proposal-read-facade-spec.md](docs/specs/post-mvp-proposal-read-facade-spec.md) | Proposal Read Facade spec — scoped `getProposal`/`listProposals` (implemented `7bc55b4`) |
350
+ | [docs/specs/post-mvp-audit-hardening-spec.md](docs/specs/post-mvp-audit-hardening-spec.md) | Audit Hardening spec — internal audit coverage C1 (implemented `ac44391`); read allow-path audit C3 (implemented `b85df38`); local hash chain C4: `sequence`/`prev_hash`/`event_hash` on `audit_events`, internal `verifyAuditChain` detects row deletion/reorder/naive modification (implemented `ebf52c2`; local-only — not court-grade, not WORM, not external notarization) |
351
+ | [docs/specs/post-auth-mvp-packaging-exports-spec.md](docs/specs/post-auth-mvp-packaging-exports-spec.md) | Packaging/exports review — Phase 1 (type gaps, complete) and Phase 2 (exports map, complete) |
352
+ | [docs/specs/post-auth-mvp-packaging-phase2-spec.md](docs/specs/post-auth-mvp-packaging-phase2-spec.md) | Package Exports Phase 2 spec — build strategy, exports map, deep import policy (implemented `0518c1a`) |
353
+ | [docs/specs/production-auth-closure-recheck-spec.md](docs/specs/production-auth-closure-recheck-spec.md) | C1–C10 Final Audit — Option A accepted |
354
+ | [docs/specs/production-auth-closure-spec.md](docs/specs/production-auth-closure-spec.md) | Auth closure criteria (C1–C10), MUST gaps, DEFER/NEVER inventory |
355
+ | [docs/roadmap/production-auth-track-freeze.md](docs/roadmap/production-auth-track-freeze.md) | Canonical auth track record — all slices, invariants, claims allowed/forbidden |
356
+ | [docs/INVARIANTS.md](docs/INVARIANTS.md) | Machine-checkable property table (all invariant codes) |
357
+ | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | System components, data flow, intentional exclusions |
358
+ | [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md) | Assets, actors, trust boundaries, threats, mitigations |
359
+ | [docs/SDK_USAGE.md](docs/SDK_USAGE.md) | How to use every public API method |
360
+ | [docs/KNOWN_LIMITATIONS.md](docs/KNOWN_LIMITATIONS.md) | MVP gaps and production blockers |
361
+ | [docs/releases/v0.1.0-architecture-ready.md](docs/releases/v0.1.0-architecture-ready.md) | Release notes — v0.1.0-architecture-ready (historical baseline) |
362
+ | [docs/BACKUP_RESTORE.md](docs/BACKUP_RESTORE.md) | Backup and Restore operator procedure — `backupSQLiteDatabase`, `validateBackup`, restore steps, key boundary, non-claims (D3a) |
363
+ | [docs/KEY_MANAGEMENT.md](docs/KEY_MANAGEMENT.md) | Key Management operator procedure — key inventory query, rotation steps, pre-restore key check, KMS adapter contract, non-claims (D4a) |
364
+ | [docs/specs/post-mvp-observability-d2c-metrics-spec.md](docs/specs/post-mvp-observability-d2c-metrics-spec.md) | D2c Metrics Boundary Spec — `MetricsRecorder` interface, five metric names, six label keys, label policy, failure policy, non-claims; runtime accepted at `9820589` |
365
+ | [docs/OPERATIONAL_RUNBOOK.md](docs/OPERATIONAL_RUNBOOK.md) | Operational Runbook — startup/backup/key-availability/restore-drill/promotion checklists, nine incident triage trees, four-layer observability guide, security-sensitive data rules, non-claims (D2/D3/D4 integration) |
366
+ | [docs/specs/post-mvp-kms-adapter-spec.md](docs/specs/post-mvp-kms-adapter-spec.md) | KMS Adapter Spec — `KeyProvider` adapter contract, factory config extension (`keyProvider?`), envelope-encryption pattern, no provider binding, D4e non-exportable deferral; accepted, runtime at `f500719` |
367
+ | [docs/specs/post-mvp-external-idp-oidc-spec.md](docs/specs/post-mvp-external-idp-oidc-spec.md) | External IdP / OIDC / JWKS Spec — `JwksKeyRingAuthAdapter` (RS256 + live JWKS), injectable `HttpClient`, host-injected `ClaimMapper`, OIDC discovery utility, algorithm binding, fetch-amplification bound; ✅ Accepted, runtime at `cbe40ed` |
368
+ | [docs/specs/post-mvp-session-revocation-spec.md](docs/specs/post-mvp-session-revocation-spec.md) | Session Revocation Spec — `TokenRevocationStore` (host-injectable denylist), `RevocationAwareAuthAdapter` wrapper, JTI extraction from unverified payload, fail-closed store error policy, 8 invariants; ✅ Accepted, runtime at `28624ac` |
369
+ | [docs/specs/post-mvp-rate-limiting-spec.md](docs/specs/post-mvp-rate-limiting-spec.md) | Rate Limiting Spec — `RateLimiter` (host-injectable interface), `RateLimitedContextMintingBoundary` wrapper, post-verification key derivation (`principalId + tenantId`), configurable fail-open/closed on store error, 7 invariants; ✅ Accepted, runtime at `88e88c9` |
370
+ | [docs/specs/post-mvp-d4c-decryptability-scan-spec.md](docs/specs/post-mvp-d4c-decryptability-scan-spec.md) | D4c Full Decryptability Scan Spec — `scanBackupDecryptability(sourcePath, cryptoBoundary)`, covers all 3 encrypted tables, aggregate counts only, `"ok"\|"partial"\|"failed"` status, no entity IDs or plaintext in result; ✅ Accepted, runtime at `9995ac5` |
371
+ | [docs/specs/post-mvp-kms-key-recovery-escrow-procedure-spec.md](docs/specs/post-mvp-kms-key-recovery-escrow-procedure-spec.md) | KMS Key Recovery / Escrow Procedure Spec — operator procedure for key inventory, recovery roles, retirement pre-checks (D3a/D4b/D4c chain), restore drill checklist, break-glass controls, evidence artifacts; docs-only, no runtime, no KMS integration, no key escrow implemented by library; 📋 Pending GPT-5.5 acceptance |
372
+
373
+ ---
374
+
375
+ ## Compliance disclaimer
376
+
377
+ This repository describes software architecture decisions. It is not legal advice. Nothing here constitutes a GDPR compliance mechanism, a legally valid erasure mechanism, a security audit, or an operational readiness guarantee. Real production deployments require legal review, external security assessment, and compliance validation appropriate to the jurisdiction and data category.
@@ -0,0 +1,44 @@
1
+ import type { Clock, MintedContext } from "../auth/types.js";
2
+ import type { QueryContractsInput, ContextQueryResult } from "../surface/evidence-backed-context-query.js";
3
+ import type { TrustedAgentRegistryEntry } from "./trusted-agent-registry.js";
4
+ export declare const FINANCE_AGENT_ID = "life-as-api/finance-agent-v1";
5
+ export declare const FINANCE_AGENT_VERSION = "1.0.0";
6
+ export declare const ALLOWED_FINANCE_PURPOSES: readonly ["tax", "credit_check", "insurance_claim", "account_overview"];
7
+ export type FinancePurpose = typeof ALLOWED_FINANCE_PURPOSES[number];
8
+ /**
9
+ * Builds the TrustedAgentRegistryEntry for the certified Finance Agent.
10
+ * FINANCE_AGENT_REGISTRY_ENTRY_001: certifiedBy is always "life-as-api-foundation".
11
+ * Permissions include every allowed purpose (the minting boundary passes
12
+ * decision.purpose as the scope argument to isAgentTrusted) plus declarative
13
+ * read:* scopes for operator documentation.
14
+ */
15
+ export declare function financeAgentRegistryEntry(validUntilMs: number): TrustedAgentRegistryEntry;
16
+ export interface FinanceAgentAuditEvent {
17
+ readonly at: string;
18
+ readonly agentId: string;
19
+ readonly reasonCode: "FINANCE_AGENT_RUN_001";
20
+ readonly decision: "allowed" | "denied";
21
+ readonly declaredPurpose?: string;
22
+ }
23
+ export interface FinanceAgentOptions {
24
+ readonly query: (ctx: MintedContext, input: QueryContractsInput) => Promise<ContextQueryResult>;
25
+ readonly clock: Clock;
26
+ readonly onAudit?: (event: FinanceAgentAuditEvent) => void;
27
+ }
28
+ /**
29
+ * Certified first-party Finance Agent.
30
+ * FINANCE_AGENT_READ_ONLY_001: query-capability only, no propose/write capability.
31
+ */
32
+ export declare class FinanceAgent {
33
+ private readonly opts;
34
+ constructor(opts: FinanceAgentOptions);
35
+ /**
36
+ * FINANCE_AGENT_SCOPE_ENFORCED_001 / FINANCE_AGENT_PURPOSE_BOUND_001: run() only
37
+ * delegates to the configured query function when ctx.declaredPurpose is one of
38
+ * ALLOWED_FINANCE_PURPOSES. Any other value, or an absent declaredPurpose, denies
39
+ * fail-closed before the query function is ever invoked.
40
+ * FINANCE_AGENT_AUDIT_TRAIL_001: the onAudit hook (if configured) always fires,
41
+ * for both the allowed and denied outcome.
42
+ */
43
+ run(ctx: MintedContext, query: QueryContractsInput): Promise<ContextQueryResult>;
44
+ }
@@ -0,0 +1,75 @@
1
+ // Platform-05 — Certified First-Party Agents: Finance Agent.
2
+ //
3
+ // FINANCE_AGENT_PURPOSE_BOUND_001: this agent acts ONLY when the caller's MintedContext
4
+ // carries declaredPurpose "tax" | "credit_check" | "insurance_claim" | "account_overview".
5
+ // Any other declared purpose (or none) is denied before the query function is invoked.
6
+ // FINANCE_AGENT_REGISTRY_ENTRY_001: financeAgentRegistryEntry() returns a
7
+ // TrustedAgentRegistryEntry certifiedBy "life-as-api-foundation" so hosts can register
8
+ // this agent with a TrustedAgentRegistry (Platform-01) without hand-rolling the entry.
9
+ // FINANCE_AGENT_SCOPE_ENFORCED_001: run() throws FINANCE_AGENT_SCOPE_DENIED_001 when
10
+ // declaredPurpose is absent or not in ALLOWED_FINANCE_PURPOSES — fail-closed.
11
+ // FINANCE_AGENT_READ_ONLY_001: the agent has query-capability only. The constructor
12
+ // accepts exclusively a `query` function; there is no propose/write capability anywhere
13
+ // on this class.
14
+ // FINANCE_AGENT_AUDIT_TRAIL_001: every run() call invokes the optional onAudit hook with
15
+ // reasonCode "FINANCE_AGENT_RUN_001" (allowed or denied). Actual audit persistence is a
16
+ // host responsibility — this hook is a notification point only.
17
+ export const FINANCE_AGENT_ID = "life-as-api/finance-agent-v1";
18
+ export const FINANCE_AGENT_VERSION = "1.0.0";
19
+ export const ALLOWED_FINANCE_PURPOSES = ["tax", "credit_check", "insurance_claim", "account_overview"];
20
+ // TRUSTED_AGENT_REGISTRY_PUBKEY_ENFORCEMENT_DEFERRED_001: placeholder public key —
21
+ // cryptographic signature verification at mint time is not yet implemented.
22
+ const FINANCE_AGENT_PUBLIC_KEY_PEM_PLACEHOLDER = "-----BEGIN PUBLIC KEY-----\nPLACEHOLDER-FINANCE-AGENT-KEY-NOT-YET-ENFORCED\n-----END PUBLIC KEY-----";
23
+ /**
24
+ * Builds the TrustedAgentRegistryEntry for the certified Finance Agent.
25
+ * FINANCE_AGENT_REGISTRY_ENTRY_001: certifiedBy is always "life-as-api-foundation".
26
+ * Permissions include every allowed purpose (the minting boundary passes
27
+ * decision.purpose as the scope argument to isAgentTrusted) plus declarative
28
+ * read:* scopes for operator documentation.
29
+ */
30
+ export function financeAgentRegistryEntry(validUntilMs) {
31
+ return {
32
+ agentId: FINANCE_AGENT_ID,
33
+ name: "Certified Finance Agent (first-party)",
34
+ permissions: [...ALLOWED_FINANCE_PURPOSES, "read:finance", "read:tax", "read:insurance"],
35
+ certifiedBy: "life-as-api-foundation",
36
+ validUntil: new Date(validUntilMs).toISOString(),
37
+ publicKeyPem: FINANCE_AGENT_PUBLIC_KEY_PEM_PLACEHOLDER,
38
+ };
39
+ }
40
+ /**
41
+ * Certified first-party Finance Agent.
42
+ * FINANCE_AGENT_READ_ONLY_001: query-capability only, no propose/write capability.
43
+ */
44
+ export class FinanceAgent {
45
+ opts;
46
+ constructor(opts) {
47
+ this.opts = opts;
48
+ }
49
+ /**
50
+ * FINANCE_AGENT_SCOPE_ENFORCED_001 / FINANCE_AGENT_PURPOSE_BOUND_001: run() only
51
+ * delegates to the configured query function when ctx.declaredPurpose is one of
52
+ * ALLOWED_FINANCE_PURPOSES. Any other value, or an absent declaredPurpose, denies
53
+ * fail-closed before the query function is ever invoked.
54
+ * FINANCE_AGENT_AUDIT_TRAIL_001: the onAudit hook (if configured) always fires,
55
+ * for both the allowed and denied outcome.
56
+ */
57
+ async run(ctx, query) {
58
+ const purpose = ctx.declaredPurpose;
59
+ const allowed = purpose !== undefined &&
60
+ ALLOWED_FINANCE_PURPOSES.includes(purpose);
61
+ this.opts.onAudit?.({
62
+ at: this.opts.clock.now(),
63
+ agentId: FINANCE_AGENT_ID,
64
+ reasonCode: "FINANCE_AGENT_RUN_001",
65
+ decision: allowed ? "allowed" : "denied",
66
+ ...(purpose !== undefined ? { declaredPurpose: purpose } : {}),
67
+ });
68
+ if (!allowed) {
69
+ throw Object.assign(new Error("FINANCE_AGENT_SCOPE_DENIED_001: FinanceAgent may only run with declaredPurpose " +
70
+ `"tax" | "credit_check" | "insurance_claim" | "account_overview" (got: ${purpose ?? "undefined"})`), { code: "FINANCE_AGENT_SCOPE_DENIED_001" });
71
+ }
72
+ return this.opts.query(ctx, query);
73
+ }
74
+ }
75
+ //# sourceMappingURL=finance-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finance-agent.js","sourceRoot":"","sources":["../../src/agent/finance-agent.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,wFAAwF;AACxF,6FAA6F;AAC7F,yFAAyF;AACzF,0EAA0E;AAC1E,yFAAyF;AACzF,yFAAyF;AACzF,qFAAqF;AACrF,gFAAgF;AAChF,oFAAoF;AACpF,0FAA0F;AAC1F,mBAAmB;AACnB,yFAAyF;AACzF,0FAA0F;AAC1F,kEAAkE;AAMlE,MAAM,CAAC,MAAM,gBAAgB,GAAG,8BAA8B,CAAC;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG,OAAO,CAAC;AAE7C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,CAAU,CAAC;AAGhH,mFAAmF;AACnF,4EAA4E;AAC5E,MAAM,wCAAwC,GAC5C,sGAAsG,CAAC;AAEzG;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,YAAoB;IAC5D,OAAO;QACL,OAAO,EAAE,gBAAgB;QACzB,IAAI,EAAE,uCAAuC;QAC7C,WAAW,EAAE,CAAC,GAAG,wBAAwB,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,CAAC;QACxF,WAAW,EAAE,wBAAwB;QACrC,UAAU,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;QAChD,YAAY,EAAE,wCAAwC;KACvD,CAAC;AACJ,CAAC;AAgBD;;;GAGG;AACH,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,IAAyB;QAAzB,SAAI,GAAJ,IAAI,CAAqB;IAAG,CAAC;IAE1D;;;;;;;OAOG;IACH,KAAK,CAAC,GAAG,CAAC,GAAkB,EAAE,KAA0B;QACtD,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC;QACpC,MAAM,OAAO,GACX,OAAO,KAAK,SAAS;YACpB,wBAAkD,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAExE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;YACzB,OAAO,EAAE,gBAAgB;YACzB,UAAU,EAAE,uBAAuB;YACnC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;YACxC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/D,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,MAAM,CAAC,MAAM,CACjB,IAAI,KAAK,CACP,iFAAiF;gBACjF,yEAAyE,OAAO,IAAI,WAAW,GAAG,CACnG,EACD,EAAE,IAAI,EAAE,gCAAgC,EAAE,CAC3C,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;CACF"}
@@ -0,0 +1,44 @@
1
+ import type { Clock, MintedContext } from "../auth/types.js";
2
+ import type { QueryContractsInput, ContextQueryResult } from "../surface/evidence-backed-context-query.js";
3
+ import type { TrustedAgentRegistryEntry } from "./trusted-agent-registry.js";
4
+ export declare const LEGAL_AGENT_ID = "life-as-api/legal-agent-v1";
5
+ export declare const LEGAL_AGENT_VERSION = "1.0.0";
6
+ export declare const ALLOWED_LEGAL_PURPOSES: readonly ["notary", "contract_review", "evidence_preservation", "court_filing"];
7
+ export type LegalPurpose = typeof ALLOWED_LEGAL_PURPOSES[number];
8
+ /**
9
+ * Builds the TrustedAgentRegistryEntry for the certified Legal Agent.
10
+ * LEGAL_AGENT_REGISTRY_ENTRY_001: certifiedBy is always "life-as-api-foundation".
11
+ * Permissions include every allowed purpose (the minting boundary passes
12
+ * decision.purpose as the scope argument to isAgentTrusted) plus declarative
13
+ * read:* scopes for operator documentation.
14
+ */
15
+ export declare function legalAgentRegistryEntry(validUntilMs: number): TrustedAgentRegistryEntry;
16
+ export interface LegalAgentAuditEvent {
17
+ readonly at: string;
18
+ readonly agentId: string;
19
+ readonly reasonCode: "LEGAL_AGENT_RUN_001";
20
+ readonly decision: "allowed" | "denied";
21
+ readonly declaredPurpose?: string;
22
+ }
23
+ export interface LegalAgentOptions {
24
+ readonly query: (ctx: MintedContext, input: QueryContractsInput) => Promise<ContextQueryResult>;
25
+ readonly clock: Clock;
26
+ readonly onAudit?: (event: LegalAgentAuditEvent) => void;
27
+ }
28
+ /**
29
+ * Certified first-party Legal Agent.
30
+ * LEGAL_AGENT_READ_ONLY_001: query-capability only, no propose/write capability.
31
+ */
32
+ export declare class LegalAgent {
33
+ private readonly opts;
34
+ constructor(opts: LegalAgentOptions);
35
+ /**
36
+ * LEGAL_AGENT_SCOPE_ENFORCED_001 / LEGAL_AGENT_PURPOSE_BOUND_001: run() only
37
+ * delegates to the configured query function when ctx.declaredPurpose is one of
38
+ * ALLOWED_LEGAL_PURPOSES. Any other value, or an absent declaredPurpose, denies
39
+ * fail-closed before the query function is ever invoked.
40
+ * LEGAL_AGENT_AUDIT_TRAIL_001: the onAudit hook (if configured) always fires,
41
+ * for both the allowed and denied outcome.
42
+ */
43
+ run(ctx: MintedContext, query: QueryContractsInput): Promise<ContextQueryResult>;
44
+ }
@@ -0,0 +1,76 @@
1
+ // Platform-05 — Certified First-Party Agents: Legal Agent.
2
+ //
3
+ // LEGAL_AGENT_PURPOSE_BOUND_001: this agent acts ONLY when the caller's MintedContext
4
+ // carries declaredPurpose "notary" | "contract_review" | "evidence_preservation" |
5
+ // "court_filing". Any other declared purpose (or none) is denied before the query
6
+ // function is invoked.
7
+ // LEGAL_AGENT_REGISTRY_ENTRY_001: legalAgentRegistryEntry() returns a
8
+ // TrustedAgentRegistryEntry certifiedBy "life-as-api-foundation" so hosts can register
9
+ // this agent with a TrustedAgentRegistry (Platform-01) without hand-rolling the entry.
10
+ // LEGAL_AGENT_SCOPE_ENFORCED_001: run() throws LEGAL_AGENT_SCOPE_DENIED_001 when
11
+ // declaredPurpose is absent or not in ALLOWED_LEGAL_PURPOSES — fail-closed.
12
+ // LEGAL_AGENT_READ_ONLY_001: the agent has query-capability only. The constructor
13
+ // accepts exclusively a `query` function; there is no propose/write capability anywhere
14
+ // on this class.
15
+ // LEGAL_AGENT_AUDIT_TRAIL_001: every run() call invokes the optional onAudit hook with
16
+ // reasonCode "LEGAL_AGENT_RUN_001" (allowed or denied). Actual audit persistence is a
17
+ // host responsibility — this hook is a notification point only.
18
+ export const LEGAL_AGENT_ID = "life-as-api/legal-agent-v1";
19
+ export const LEGAL_AGENT_VERSION = "1.0.0";
20
+ export const ALLOWED_LEGAL_PURPOSES = ["notary", "contract_review", "evidence_preservation", "court_filing"];
21
+ // TRUSTED_AGENT_REGISTRY_PUBKEY_ENFORCEMENT_DEFERRED_001: placeholder public key —
22
+ // cryptographic signature verification at mint time is not yet implemented.
23
+ const LEGAL_AGENT_PUBLIC_KEY_PEM_PLACEHOLDER = "-----BEGIN PUBLIC KEY-----\nPLACEHOLDER-LEGAL-AGENT-KEY-NOT-YET-ENFORCED\n-----END PUBLIC KEY-----";
24
+ /**
25
+ * Builds the TrustedAgentRegistryEntry for the certified Legal Agent.
26
+ * LEGAL_AGENT_REGISTRY_ENTRY_001: certifiedBy is always "life-as-api-foundation".
27
+ * Permissions include every allowed purpose (the minting boundary passes
28
+ * decision.purpose as the scope argument to isAgentTrusted) plus declarative
29
+ * read:* scopes for operator documentation.
30
+ */
31
+ export function legalAgentRegistryEntry(validUntilMs) {
32
+ return {
33
+ agentId: LEGAL_AGENT_ID,
34
+ name: "Certified Legal Agent (first-party)",
35
+ permissions: [...ALLOWED_LEGAL_PURPOSES, "read:legal", "read:contracts", "read:identity"],
36
+ certifiedBy: "life-as-api-foundation",
37
+ validUntil: new Date(validUntilMs).toISOString(),
38
+ publicKeyPem: LEGAL_AGENT_PUBLIC_KEY_PEM_PLACEHOLDER,
39
+ };
40
+ }
41
+ /**
42
+ * Certified first-party Legal Agent.
43
+ * LEGAL_AGENT_READ_ONLY_001: query-capability only, no propose/write capability.
44
+ */
45
+ export class LegalAgent {
46
+ opts;
47
+ constructor(opts) {
48
+ this.opts = opts;
49
+ }
50
+ /**
51
+ * LEGAL_AGENT_SCOPE_ENFORCED_001 / LEGAL_AGENT_PURPOSE_BOUND_001: run() only
52
+ * delegates to the configured query function when ctx.declaredPurpose is one of
53
+ * ALLOWED_LEGAL_PURPOSES. Any other value, or an absent declaredPurpose, denies
54
+ * fail-closed before the query function is ever invoked.
55
+ * LEGAL_AGENT_AUDIT_TRAIL_001: the onAudit hook (if configured) always fires,
56
+ * for both the allowed and denied outcome.
57
+ */
58
+ async run(ctx, query) {
59
+ const purpose = ctx.declaredPurpose;
60
+ const allowed = purpose !== undefined &&
61
+ ALLOWED_LEGAL_PURPOSES.includes(purpose);
62
+ this.opts.onAudit?.({
63
+ at: this.opts.clock.now(),
64
+ agentId: LEGAL_AGENT_ID,
65
+ reasonCode: "LEGAL_AGENT_RUN_001",
66
+ decision: allowed ? "allowed" : "denied",
67
+ ...(purpose !== undefined ? { declaredPurpose: purpose } : {}),
68
+ });
69
+ if (!allowed) {
70
+ throw Object.assign(new Error("LEGAL_AGENT_SCOPE_DENIED_001: LegalAgent may only run with declaredPurpose " +
71
+ `"notary" | "contract_review" | "evidence_preservation" | "court_filing" (got: ${purpose ?? "undefined"})`), { code: "LEGAL_AGENT_SCOPE_DENIED_001" });
72
+ }
73
+ return this.opts.query(ctx, query);
74
+ }
75
+ }
76
+ //# sourceMappingURL=legal-agent.js.map