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.
- package/LICENSE +21 -0
- package/README.md +377 -0
- package/dist/agent/finance-agent.d.ts +44 -0
- package/dist/agent/finance-agent.js +75 -0
- package/dist/agent/finance-agent.js.map +1 -0
- package/dist/agent/legal-agent.d.ts +44 -0
- package/dist/agent/legal-agent.js +76 -0
- package/dist/agent/legal-agent.js.map +1 -0
- package/dist/agent/medical-agent.d.ts +44 -0
- package/dist/agent/medical-agent.js +75 -0
- package/dist/agent/medical-agent.js.map +1 -0
- package/dist/agent/trusted-agent-registry.d.ts +53 -0
- package/dist/agent/trusted-agent-registry.js +57 -0
- package/dist/agent/trusted-agent-registry.js.map +1 -0
- package/dist/audit/audit-chain-verifier.d.ts +10 -0
- package/dist/audit/audit-chain-verifier.js +67 -0
- package/dist/audit/audit-chain-verifier.js.map +1 -0
- package/dist/audit/audit-log.d.ts +48 -0
- package/dist/audit/audit-log.js +74 -0
- package/dist/audit/audit-log.js.map +1 -0
- package/dist/audit/sqlite-audit-log.d.ts +29 -0
- package/dist/audit/sqlite-audit-log.js +142 -0
- package/dist/audit/sqlite-audit-log.js.map +1 -0
- package/dist/auth/access-context-issuer.d.ts +18 -0
- package/dist/auth/access-context-issuer.js +88 -0
- package/dist/auth/access-context-issuer.js.map +1 -0
- package/dist/auth/assert-authorized-for-subject.d.ts +2 -0
- package/dist/auth/assert-authorized-for-subject.js +20 -0
- package/dist/auth/assert-authorized-for-subject.js.map +1 -0
- package/dist/auth/backend-context-minting-boundary.d.ts +23 -0
- package/dist/auth/backend-context-minting-boundary.js +281 -0
- package/dist/auth/backend-context-minting-boundary.js.map +1 -0
- package/dist/auth/default-authorization-policy.d.ts +7 -0
- package/dist/auth/default-authorization-policy.js +64 -0
- package/dist/auth/default-authorization-policy.js.map +1 -0
- package/dist/auth/fake-auth-adapter.d.ts +7 -0
- package/dist/auth/fake-auth-adapter.js +27 -0
- package/dist/auth/fake-auth-adapter.js.map +1 -0
- package/dist/auth/http-client.d.ts +12 -0
- package/dist/auth/http-client.js +7 -0
- package/dist/auth/http-client.js.map +1 -0
- package/dist/auth/in-memory-grant-resolver.d.ts +21 -0
- package/dist/auth/in-memory-grant-resolver.js +73 -0
- package/dist/auth/in-memory-grant-resolver.js.map +1 -0
- package/dist/auth/in-memory-tenant-boundary.d.ts +16 -0
- package/dist/auth/in-memory-tenant-boundary.js +37 -0
- package/dist/auth/in-memory-tenant-boundary.js.map +1 -0
- package/dist/auth/jwks-key-ring-auth-adapter.d.ts +38 -0
- package/dist/auth/jwks-key-ring-auth-adapter.js +123 -0
- package/dist/auth/jwks-key-ring-auth-adapter.js.map +1 -0
- package/dist/auth/jwks-key-ring.d.ts +25 -0
- package/dist/auth/jwks-key-ring.js +111 -0
- package/dist/auth/jwks-key-ring.js.map +1 -0
- package/dist/auth/jwt-auth-adapter.d.ts +15 -0
- package/dist/auth/jwt-auth-adapter.js +59 -0
- package/dist/auth/jwt-auth-adapter.js.map +1 -0
- package/dist/auth/jwt-core.d.ts +32 -0
- package/dist/auth/jwt-core.js +226 -0
- package/dist/auth/jwt-core.js.map +1 -0
- package/dist/auth/jwt-key-ring-auth-adapter.d.ts +16 -0
- package/dist/auth/jwt-key-ring-auth-adapter.js +58 -0
- package/dist/auth/jwt-key-ring-auth-adapter.js.map +1 -0
- package/dist/auth/oidc-discovery.d.ts +15 -0
- package/dist/auth/oidc-discovery.js +46 -0
- package/dist/auth/oidc-discovery.js.map +1 -0
- package/dist/auth/production-scoped-life-api.d.ts +58 -0
- package/dist/auth/production-scoped-life-api.js +802 -0
- package/dist/auth/production-scoped-life-api.js.map +1 -0
- package/dist/auth/proposal-scope-inspector.d.ts +3 -0
- package/dist/auth/proposal-scope-inspector.js +42 -0
- package/dist/auth/proposal-scope-inspector.js.map +1 -0
- package/dist/auth/proposal-scoped-life-api.d.ts +21 -0
- package/dist/auth/proposal-scoped-life-api.js +168 -0
- package/dist/auth/proposal-scoped-life-api.js.map +1 -0
- package/dist/auth/rate-limited-context-minting-boundary.d.ts +27 -0
- package/dist/auth/rate-limited-context-minting-boundary.js +77 -0
- package/dist/auth/rate-limited-context-minting-boundary.js.map +1 -0
- package/dist/auth/revocation-aware-auth-adapter.d.ts +21 -0
- package/dist/auth/revocation-aware-auth-adapter.js +88 -0
- package/dist/auth/revocation-aware-auth-adapter.js.map +1 -0
- package/dist/auth/sqlite-grant-resolver.d.ts +8 -0
- package/dist/auth/sqlite-grant-resolver.js +78 -0
- package/dist/auth/sqlite-grant-resolver.js.map +1 -0
- package/dist/auth/sqlite-tenant-boundary.d.ts +7 -0
- package/dist/auth/sqlite-tenant-boundary.js +41 -0
- package/dist/auth/sqlite-tenant-boundary.js.map +1 -0
- package/dist/auth/static-jwt-key-ring.d.ts +13 -0
- package/dist/auth/static-jwt-key-ring.js +73 -0
- package/dist/auth/static-jwt-key-ring.js.map +1 -0
- package/dist/auth/subject-scoped-life-api.d.ts +14 -0
- package/dist/auth/subject-scoped-life-api.js +51 -0
- package/dist/auth/subject-scoped-life-api.js.map +1 -0
- package/dist/auth/test-context-minting-boundary.d.ts +13 -0
- package/dist/auth/test-context-minting-boundary.js +74 -0
- package/dist/auth/test-context-minting-boundary.js.map +1 -0
- package/dist/auth/types.d.ts +77 -0
- package/dist/auth/types.js +16 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/compliance/subject-data-report.d.ts +43 -0
- package/dist/compliance/subject-data-report.js +155 -0
- package/dist/compliance/subject-data-report.js.map +1 -0
- package/dist/consent/consent-guard.d.ts +4 -0
- package/dist/consent/consent-guard.js +37 -0
- package/dist/consent/consent-guard.js.map +1 -0
- package/dist/consent/grant-registry.d.ts +7 -0
- package/dist/consent/grant-registry.js +13 -0
- package/dist/consent/grant-registry.js.map +1 -0
- package/dist/consent/intersect-selector.d.ts +3 -0
- package/dist/consent/intersect-selector.js +66 -0
- package/dist/consent/intersect-selector.js.map +1 -0
- package/dist/contract/diagnostics.d.ts +32 -0
- package/dist/contract/diagnostics.js +112 -0
- package/dist/contract/diagnostics.js.map +1 -0
- package/dist/contract/project-contracts.d.ts +5 -0
- package/dist/contract/project-contracts.js +159 -0
- package/dist/contract/project-contracts.js.map +1 -0
- package/dist/contract/types.d.ts +32 -0
- package/dist/contract/types.js +5 -0
- package/dist/contract/types.js.map +1 -0
- package/dist/crypto/aes-gcm.d.ts +11 -0
- package/dist/crypto/aes-gcm.js +78 -0
- package/dist/crypto/aes-gcm.js.map +1 -0
- package/dist/crypto/claim-serializer.d.ts +26 -0
- package/dist/crypto/claim-serializer.js +59 -0
- package/dist/crypto/claim-serializer.js.map +1 -0
- package/dist/crypto/sha256.d.ts +12 -0
- package/dist/crypto/sha256.js +40 -0
- package/dist/crypto/sha256.js.map +1 -0
- package/dist/crypto/static-key.d.ts +11 -0
- package/dist/crypto/static-key.js +60 -0
- package/dist/crypto/static-key.js.map +1 -0
- package/dist/crypto/types.d.ts +20 -0
- package/dist/crypto/types.js +8 -0
- package/dist/crypto/types.js.map +1 -0
- package/dist/datasource/trusted-data-source-registry.d.ts +51 -0
- package/dist/datasource/trusted-data-source-registry.js +57 -0
- package/dist/datasource/trusted-data-source-registry.js.map +1 -0
- package/dist/erasure/tombstone.d.ts +13 -0
- package/dist/erasure/tombstone.js +20 -0
- package/dist/erasure/tombstone.js.map +1 -0
- package/dist/evidence/evidence-backed-claim-creator.d.ts +48 -0
- package/dist/evidence/evidence-backed-claim-creator.js +107 -0
- package/dist/evidence/evidence-backed-claim-creator.js.map +1 -0
- package/dist/evidence/in-memory-raw-document-store.d.ts +26 -0
- package/dist/evidence/in-memory-raw-document-store.js +84 -0
- package/dist/evidence/in-memory-raw-document-store.js.map +1 -0
- package/dist/evidence/raw-document-store.d.ts +12 -0
- package/dist/evidence/raw-document-store.js +8 -0
- package/dist/evidence/raw-document-store.js.map +1 -0
- package/dist/evidence/source-evidence-validator.d.ts +4 -0
- package/dist/evidence/source-evidence-validator.js +14 -0
- package/dist/evidence/source-evidence-validator.js.map +1 -0
- package/dist/evidence/sqlite-raw-document-store.d.ts +19 -0
- package/dist/evidence/sqlite-raw-document-store.js +122 -0
- package/dist/evidence/sqlite-raw-document-store.js.map +1 -0
- package/dist/guardian/guardian-registry.d.ts +96 -0
- package/dist/guardian/guardian-registry.js +95 -0
- package/dist/guardian/guardian-registry.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/observability/health.d.ts +12 -0
- package/dist/observability/health.js +16 -0
- package/dist/observability/health.js.map +1 -0
- package/dist/observability/logger.d.ts +21 -0
- package/dist/observability/logger.js +40 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +15 -0
- package/dist/observability/metrics.js +52 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/persistence/backup.d.ts +24 -0
- package/dist/persistence/backup.js +251 -0
- package/dist/persistence/backup.js.map +1 -0
- package/dist/persistence/decryptability-scan.d.ts +10 -0
- package/dist/persistence/decryptability-scan.js +144 -0
- package/dist/persistence/decryptability-scan.js.map +1 -0
- package/dist/persistence/in-memory-unit-of-work.d.ts +11 -0
- package/dist/persistence/in-memory-unit-of-work.js +32 -0
- package/dist/persistence/in-memory-unit-of-work.js.map +1 -0
- package/dist/persistence/key-availability.d.ts +9 -0
- package/dist/persistence/key-availability.js +125 -0
- package/dist/persistence/key-availability.js.map +1 -0
- package/dist/persistence/sqlite/migrations.d.ts +9 -0
- package/dist/persistence/sqlite/migrations.js +535 -0
- package/dist/persistence/sqlite/migrations.js.map +1 -0
- package/dist/persistence/sqlite/schema.d.ts +10 -0
- package/dist/persistence/sqlite/schema.js +101 -0
- package/dist/persistence/sqlite/schema.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-fact-store.d.ts +24 -0
- package/dist/persistence/sqlite/sqlite-fact-store.js +207 -0
- package/dist/persistence/sqlite/sqlite-fact-store.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-source-registry.d.ts +17 -0
- package/dist/persistence/sqlite/sqlite-source-registry.js +132 -0
- package/dist/persistence/sqlite/sqlite-source-registry.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.d.ts +8 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.js +41 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.js.map +1 -0
- package/dist/persistence/sqlite/types.d.ts +24 -0
- package/dist/persistence/sqlite/types.js +28 -0
- package/dist/persistence/sqlite/types.js.map +1 -0
- package/dist/persistence/unit-of-work.d.ts +6 -0
- package/dist/persistence/unit-of-work.js +15 -0
- package/dist/persistence/unit-of-work.js.map +1 -0
- package/dist/proposal/accepted-claim-appender.d.ts +7 -0
- package/dist/proposal/accepted-claim-appender.js +16 -0
- package/dist/proposal/accepted-claim-appender.js.map +1 -0
- package/dist/proposal/in-memory-proposal-queue.d.ts +21 -0
- package/dist/proposal/in-memory-proposal-queue.js +218 -0
- package/dist/proposal/in-memory-proposal-queue.js.map +1 -0
- package/dist/proposal/policy-aware-proposal-queue.d.ts +23 -0
- package/dist/proposal/policy-aware-proposal-queue.js +162 -0
- package/dist/proposal/policy-aware-proposal-queue.js.map +1 -0
- package/dist/proposal/proposal-policy.d.ts +37 -0
- package/dist/proposal/proposal-policy.js +72 -0
- package/dist/proposal/proposal-policy.js.map +1 -0
- package/dist/proposal/proposal-queue.d.ts +13 -0
- package/dist/proposal/proposal-queue.js +15 -0
- package/dist/proposal/proposal-queue.js.map +1 -0
- package/dist/proposal/source-aware-claim-appender.d.ts +13 -0
- package/dist/proposal/source-aware-claim-appender.js +47 -0
- package/dist/proposal/source-aware-claim-appender.js.map +1 -0
- package/dist/proposal/sqlite-proposal-queue.d.ts +26 -0
- package/dist/proposal/sqlite-proposal-queue.js +282 -0
- package/dist/proposal/sqlite-proposal-queue.js.map +1 -0
- package/dist/resolution/resolve-claims.d.ts +4 -0
- package/dist/resolution/resolve-claims.js +101 -0
- package/dist/resolution/resolve-claims.js.map +1 -0
- package/dist/resolution/trust-profile.d.ts +12 -0
- package/dist/resolution/trust-profile.js +23 -0
- package/dist/resolution/trust-profile.js.map +1 -0
- package/dist/resolution/types.d.ts +15 -0
- package/dist/resolution/types.js +8 -0
- package/dist/resolution/types.js.map +1 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.d.ts +23 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.js +240 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.js.map +1 -0
- package/dist/sdk/create-life-api.d.ts +55 -0
- package/dist/sdk/create-life-api.js +251 -0
- package/dist/sdk/create-life-api.js.map +1 -0
- package/dist/sdk/create-sqlite-life-api.d.ts +33 -0
- package/dist/sdk/create-sqlite-life-api.js +654 -0
- package/dist/sdk/create-sqlite-life-api.js.map +1 -0
- package/dist/sdk/life-api.d.ts +27 -0
- package/dist/sdk/life-api.js +17 -0
- package/dist/sdk/life-api.js.map +1 -0
- package/dist/sdk/validation.d.ts +8 -0
- package/dist/sdk/validation.js +216 -0
- package/dist/sdk/validation.js.map +1 -0
- package/dist/source/in-memory-source-registry.d.ts +15 -0
- package/dist/source/in-memory-source-registry.js +104 -0
- package/dist/source/in-memory-source-registry.js.map +1 -0
- package/dist/source/source-aware-fact-store.d.ts +19 -0
- package/dist/source/source-aware-fact-store.js +40 -0
- package/dist/source/source-aware-fact-store.js.map +1 -0
- package/dist/source/source-kind-predicate-policy.d.ts +4 -0
- package/dist/source/source-kind-predicate-policy.js +62 -0
- package/dist/source/source-kind-predicate-policy.js.map +1 -0
- package/dist/source/source-registry.d.ts +11 -0
- package/dist/source/source-registry.js +12 -0
- package/dist/source/source-registry.js.map +1 -0
- package/dist/store/in-memory-fact-store.d.ts +25 -0
- package/dist/store/in-memory-fact-store.js +192 -0
- package/dist/store/in-memory-fact-store.js.map +1 -0
- package/dist/surface/context-query.d.ts +21 -0
- package/dist/surface/context-query.js +113 -0
- package/dist/surface/context-query.js.map +1 -0
- package/dist/surface/evidence-backed-context-query.d.ts +62 -0
- package/dist/surface/evidence-backed-context-query.js +240 -0
- package/dist/surface/evidence-backed-context-query.js.map +1 -0
- package/dist/types/access-context.d.ts +25 -0
- package/dist/types/access-context.js +6 -0
- package/dist/types/access-context.js.map +1 -0
- package/dist/types/claim.d.ts +48 -0
- package/dist/types/claim.js +5 -0
- package/dist/types/claim.js.map +1 -0
- package/dist/types/consent.d.ts +41 -0
- package/dist/types/consent.js +3 -0
- package/dist/types/consent.js.map +1 -0
- package/dist/types/crypto-boundary.d.ts +12 -0
- package/dist/types/crypto-boundary.js +15 -0
- package/dist/types/crypto-boundary.js.map +1 -0
- package/dist/types/evidence.d.ts +31 -0
- package/dist/types/evidence.js +8 -0
- package/dist/types/evidence.js.map +1 -0
- package/dist/types/fact-store.d.ts +24 -0
- package/dist/types/fact-store.js +12 -0
- package/dist/types/fact-store.js.map +1 -0
- package/dist/types/ids.d.ts +36 -0
- package/dist/types/ids.js +11 -0
- package/dist/types/ids.js.map +1 -0
- package/dist/types/proposal.d.ts +38 -0
- package/dist/types/proposal.js +7 -0
- package/dist/types/proposal.js.map +1 -0
- package/dist/types/source.d.ts +33 -0
- package/dist/types/source.js +6 -0
- package/dist/types/source.js.map +1 -0
- package/dist/types/trust.d.ts +24 -0
- package/dist/types/trust.js +5 -0
- package/dist/types/trust.js.map +1 -0
- package/dist/utilities/deep-freeze.d.ts +1 -0
- package/dist/utilities/deep-freeze.js +17 -0
- package/dist/utilities/deep-freeze.js.map +1 -0
- 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,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,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":"AAAA,6DAA6D;AAC7D,oDAAoD;AACpD,gGAAgG;AAChG,mFAAmF;AACnF,8FAA8F;AA4C9F,mFAAmF;AACnF,MAAM,mBAAmB,GAAkD;IACzE,CAAC,cAAc,EAAO,uBAAuB,CAAC;IAC9C,CAAC,QAAQ,EAAa,iBAAiB,CAAC;IACxC,CAAC,SAAS,EAAY,kBAAkB,CAAC;IACzC,CAAC,SAAS,EAAY,mBAAmB,CAAC;IAC1C,CAAC,mBAAmB,EAAE,6BAA6B,CAAC;IACpD,CAAC,gBAAgB,EAAK,iBAAiB,CAAC;CACzC,CAAC;AAEF,mFAAmF;AACnF,uEAAuE;AACvE,MAAM,UAAU,2BAA2B,CACzC,WAA8C,EAC9C,QAA4C,EAC5C,SAA2B,EAC3B,QAA6B,EAC7B,GAA0B;IAE1B,OAAO,CAAC,GAAG,WAAW,CAAC;SACpB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;SACxD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,WAAW,CAClB,IAA6B,EAC7B,QAA0C,EAC1C,SAAyB,EACzB,QAA2B,EAC3B,GAAwB;IAExB,4EAA4E;IAC5E,MAAM,gBAAgB,GAA8B,EAAE,CAAC;IAEvD,KAAK,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,mBAAmB,EAAE,CAAC;QACxD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC/B,gBAAgB,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC,CAAC;YACzF,SAAS;QACX,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAChC,gBAAgB,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,CAAC,CAAC;YAC1F,SAAS;QACX,CAAC;QACD,wDAAwD;QACxD,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;YACvC,gBAAgB,CAAC,IAAI,CACnB,kBAAkB,CAAC,SAAS,EAAE,KAAK,CAAC,cAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,CACxF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,mFAAmF;IACnF,MAAM,mBAAmB,GAAiC,EAAE,CAAC;IAE7D,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACvD,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CACvC,EAAE,CAAC;QACF,KAAK,MAAM,gBAAgB,IAAI,CAAC,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACtE,mBAAmB,CAAC,IAAI,CACtB,qBAAqB,CACnB,QAAQ,CAAC,SAAS,EAClB,gBAAgB,EAChB,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,GAAG,CACJ,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,UAAU,EAAW,IAAI,CAAC,UAAU;QACpC,gBAAgB;QAChB,mBAAmB;QACnB,QAAQ,EAAa,IAAI,CAAC,QAAQ;KACnC,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,4EAA4E;AAC5E,SAAS,kBAAkB,CACzB,SAAkB,EAClB,OAAmB,EACnB,QAA2C,EAC3C,SAA0B,EAC1B,QAA4B,EAC5B,GAAyB;IAEzB,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;IAC1F,CAAC;IAED,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC;IACpC,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAClD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,6BAA6B,EAAE,CAAC;IAC/G,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;IAC1C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,oBAAoB,EAAE,UAAU,EAAE,4BAA4B,EAAE,CAAC;IAClH,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACvD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,2BAA2B,EAAE,CAAC;IAC3H,CAAC;IAED,OAAO;QACL,SAAS;QACT,OAAO;QACP,QAAQ;QACR,UAAU;QACV,MAAM,EAAE,kBAAkB;QAC1B,UAAU,EAAE,4CAA4C;QACxD,WAAW,EAAE,KAAK;KACnB,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAC5B,SAAwB,EACxB,gBAAyB,EACzB,QAAiD,EACjD,SAAgC,EAChC,QAAkC,EAClC,GAA+B;IAE/B,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACjD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACnG,CAAC;IAED,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC;IACpC,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAClD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,6BAA6B,EAAE,CAAC;IACxH,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;IAC1C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,oBAAoB,EAAE,UAAU,EAAE,4BAA4B,EAAE,CAAC;IAC3H,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACvD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,2BAA2B,EAAE,CAAC;IACpI,CAAC;IAED,OAAO;QACL,SAAS;QACT,gBAAgB;QAChB,QAAQ;QACR,UAAU;QACV,MAAM,EAAE,kBAAkB;QAC1B,UAAU,EAAE,4CAA4C;KACzD,CAAC;AACJ,CAAC"}
|
|
@@ -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":"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"}
|
|
@@ -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 @@
|
|
|
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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"}
|