enigma-memory 0.1.16 → 0.1.17

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.
@@ -10,6 +10,7 @@ export const HOSTED_CLOUD_BACKUP_DRILL_SCHEMA = 'enigma.hosted_cloud.backup_dril
10
10
  export const HOSTED_CLOUD_INCIDENT_SLA_SCHEMA = 'enigma.hosted_cloud.incident_sla_refs.v1';
11
11
  export const HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PACKET_SCHEMA = 'enigma.hosted_cloud.customer_lifecycle_packet.v1';
12
12
  export const HOSTED_CLOUD_API_KEY_LIFECYCLE_PACKET_SCHEMA = 'enigma.hosted_cloud.api_key_lifecycle_packet.v1';
13
+ export const HOSTED_CLOUD_READINESS_PACKET_SCHEMA = 'enigma.hosted_cloud.readiness_packet.v1';
13
14
 
14
15
  export const HOSTED_CLOUD_EXTERNAL_BLOCKERS = Object.freeze([
15
16
  'auth_provider',
@@ -106,9 +107,40 @@ const API_KEY_LIFECYCLE_BLOCKER_LABELS = Object.freeze({
106
107
  audit_log: 'Hosted API key lifecycle audit evidence is not provided.',
107
108
  operator_approval: 'Explicit public-safe operator API key lifecycle approval is not provided.',
108
109
  });
110
+ export const HOSTED_CLOUD_READINESS_SURFACES = Object.freeze([
111
+ 'auth',
112
+ 'billing',
113
+ 'legal_dpa',
114
+ 'support',
115
+ 'security_review',
116
+ 'monitoring',
117
+ 'backup',
118
+ 'kms_byok',
119
+ ]);
120
+ const READINESS_BLOCKER_LABELS = Object.freeze({
121
+ auth: 'Auth provider readiness evidence is not provided.',
122
+ billing: 'Billing provider readiness evidence is not provided.',
123
+ legal_dpa: 'Legal and data-processing terms readiness evidence is not provided.',
124
+ support: 'Support ownership readiness evidence is not provided.',
125
+ security_review: 'External security review readiness evidence is not provided.',
126
+ monitoring: 'Monitoring readiness evidence is not provided.',
127
+ backup: 'Backup and disaster recovery readiness evidence is not provided.',
128
+ kms_byok: 'KMS / bring-your-own-key readiness evidence is not provided.',
129
+ operator_go_live: 'Explicit operator go-live approval is not provided.',
130
+ });
131
+ const READINESS_SURFACE_LIFECYCLE_PHASE = Object.freeze({
132
+ auth: 'account',
133
+ billing: 'billing',
134
+ legal_dpa: 'legal',
135
+ support: 'support',
136
+ security_review: 'security_review',
137
+ monitoring: 'monitoring',
138
+ backup: 'backup',
139
+ kms_byok: 'vault',
140
+ });
109
141
  const API_KEY_SECRET_MATERIAL_KEY_RE = /(?:^|_)(?:raw_?api_?key|raw_?key|plaintext_?api_?key|plain_text_?api_?key|plaintext_?key|plain_text_?key|api_?key_?value|key_?value|key_?material|secret_?key|key_?secret|value)(?:$|_)/iu;
110
- const FORBIDDEN_KEY_RE = /(?:^|_)(?:raw_?memory|plaintext|plain_text|prompt|prompts|completion|completions|message_body|transcript|conversation|provider_?response|response_?body|credential|credentials|secret|password|private_?key|bearer|access_token|refresh_token|token_value|api_key_value|api_secret|token_?roi|token_?profit|roi_claim|profit_claim|provider_?deletion|provider_?erasure|model_?forgetting|model_?erasure)(?:$|_)/iu;
111
- const SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16}|\b(?:raw memory|plaintext prompts?|plain text prompts?|private prompts?|provider responses?|full transcript|decrypted memory|credentials?|secrets?|passwords?|private keys?|api key secret|api secrets?|access tokens?|refresh tokens?|token values?|credential material)\b)/iu;
142
+ const FORBIDDEN_KEY_RE = /(?:^|_)(?:raw_?memory|raw_?key|raw_?api_?key|raw_?token|plaintext|plain_text|prompt|prompts|completion|completions|message_body|transcript|conversation|provider_?response|response_?body|credential|credentials|secret|password|private_?key|bearer|access_token|refresh_token|token_value|api_key_value|api_secret|token_?roi|token_?profit|roi_claim|profit_claim|provider_?deletion|provider_?erasure|model_?forgetting|model_?erasure)(?:$|_)/iu;
143
+ const SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16}|eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}|\b(?:raw memory|plaintext prompts?|plain text prompts?|private prompts?|provider responses?|full transcript|decrypted memory|credentials?|secrets?|passwords?|private keys?|api key secret|api secrets?|access tokens?|refresh tokens?|token values?|credential material)\b)/iu;
112
144
  const FORBIDDEN_CLAIM_RE = /(?:token\s+(?:roi|profit|return|investment|price)|(?:roi|profit|return)\s+(?:from|on)\s+token|guaranteed\s+(?:savings|profit|return)|provider(?:-side|\s+side)?\s+(?:deletion|erasure)|model\s+(?:forgetting|forgot|erasure)|makes?\s+models?\s+forget|deleted\s+from\s+every\s+provider)/iu;
113
145
 
114
146
  function isPlainObject(value) {
@@ -959,6 +991,67 @@ function validateCustomerLifecycleReadiness(readiness, expected) {
959
991
  assertSameLifecycleArray(readiness.external_blockers, expected.external_blockers, 'readiness.external_blockers');
960
992
  assertSameLifecycleArray(readiness.missing_evidence_refs, expected.missing_evidence_refs, 'readiness.missing_evidence_refs');
961
993
  }
994
+ function lifecycleNextActions(readiness, operatorGoLiveRef) {
995
+ const actions = [];
996
+ for (const missing of readiness.missing_evidence_refs) {
997
+ actions.push({
998
+ action: `provide_${missing.key}_evidence`,
999
+ surface: missing.key,
1000
+ ref: missing.ref,
1001
+ });
1002
+ }
1003
+ if (operatorGoLiveRef === null) {
1004
+ actions.push({
1005
+ action: 'obtain_operator_go_live_approval',
1006
+ surface: 'operator_go_live',
1007
+ ref: 'blocked:operator_go_live',
1008
+ });
1009
+ }
1010
+ if (actions.length === 0) {
1011
+ actions.push({
1012
+ action: 'lifecycle_complete_review_before_selling',
1013
+ surface: 'operator_go_live',
1014
+ });
1015
+ }
1016
+ return actions;
1017
+ }
1018
+
1019
+ function customerLifecycleDashboard(contracts, requiredEvidenceRefs, readiness, operatorGoLiveRef) {
1020
+ const dashboardContract = isPlainObject(contracts.dashboard) ? contracts.dashboard : null;
1021
+ const providedEvidenceCount = CUSTOMER_LIFECYCLE_REQUIRED_EVIDENCE_PHASES
1022
+ .filter((phase) => requiredEvidenceRefs[phase].status === PROVIDED).length;
1023
+ return {
1024
+ counts: {
1025
+ account_count: dashboardContract ? dashboardContract.account_count : 0,
1026
+ active_api_key_count: dashboardContract ? dashboardContract.active_api_key_count : 0,
1027
+ hosted_vault_count: dashboardContract ? dashboardContract.hosted_vault_count : 0,
1028
+ open_incident_count: dashboardContract ? dashboardContract.open_incident_count : 0,
1029
+ lifecycle_phase_count: HOSTED_CLOUD_CUSTOMER_LIFECYCLE_PHASES.length,
1030
+ provided_evidence_count: providedEvidenceCount,
1031
+ missing_evidence_count: readiness.missing_evidence_refs.length,
1032
+ external_blocker_count: readiness.external_blockers.length,
1033
+ },
1034
+ status_refs: {
1035
+ billing_period_ref: isPlainObject(contracts.billing) ? contracts.billing.billing_record_id : 'blocked:billing',
1036
+ backup_drill_ref: isPlainObject(contracts.backup) ? contracts.backup.backup_drill_id : 'blocked:backup',
1037
+ incident_sla_ref: isPlainObject(contracts.incident_sla) ? contracts.incident_sla.incident_sla_id : 'blocked:incident_sla',
1038
+ operator_go_live_ref: operatorGoLiveRef,
1039
+ },
1040
+ blocker_refs: readiness.external_blockers.map((blocker) => ({
1041
+ surface: blocker.key,
1042
+ ref: blocker.ref,
1043
+ blocker: blocker.blocker,
1044
+ })),
1045
+ next_actions: lifecycleNextActions(readiness, operatorGoLiveRef),
1046
+ safety_summary: {
1047
+ evidence_validation_only: true,
1048
+ key_material_absent: true,
1049
+ token_material_absent: true,
1050
+ auth_material_absent: true,
1051
+ customer_content_absent: true,
1052
+ },
1053
+ };
1054
+ }
962
1055
 
963
1056
  export function buildCustomerLifecyclePacket(input = {}) {
964
1057
  if (!isPlainObject(input)) throw new TypeError('buildCustomerLifecyclePacket requires an options object');
@@ -980,6 +1073,7 @@ export function buildCustomerLifecyclePacket(input = {}) {
980
1073
  missing_evidence_refs: readiness.missing_evidence_refs,
981
1074
  operator_go_live_ref: operatorGoLiveRef,
982
1075
  readiness,
1076
+ dashboard: customerLifecycleDashboard(contracts, requiredEvidenceRefs, readiness, operatorGoLiveRef),
983
1077
  hosted_cloud_sellable: readiness.hosted_cloud_sellable,
984
1078
  guarantees: customerLifecycleSafetyGuarantees(),
985
1079
  public_safety_guarantees: customerLifecycleSafetyGuarantees(),
@@ -1008,6 +1102,7 @@ export function validateCustomerLifecyclePacket(packet) {
1008
1102
  assertSameLifecycleArray(packet.missing_evidence_refs, expectedReadiness.missing_evidence_refs, 'missing_evidence_refs');
1009
1103
  validateCustomerLifecycleReadiness(packet.readiness, expectedReadiness);
1010
1104
  if (packet.hosted_cloud_sellable !== expectedReadiness.hosted_cloud_sellable) throw new TypeError('hosted_cloud_sellable must match readiness.hosted_cloud_sellable');
1105
+ assertSameLifecycleObject(packet.dashboard, customerLifecycleDashboard(packet.contracts, requiredEvidenceRefs, expectedReadiness, operatorGoLiveRef), 'dashboard');
1011
1106
  validateCustomerLifecycleSafetyGuarantees(packet.guarantees ?? packet.public_safety_guarantees);
1012
1107
  return true;
1013
1108
  }
@@ -1400,3 +1495,376 @@ export function validateApiKeyLifecyclePacket(packet) {
1400
1495
  validateApiKeyLifecycleSafetyGuarantees(packet.public_safety_guarantees ?? packet.guarantees);
1401
1496
  return true;
1402
1497
  }
1498
+
1499
+ function readinessEvidenceRefFor(surface, value, lifecyclePhaseEvidence) {
1500
+ const fallback = { ref: `blocked:${surface}`, status: BLOCKED, blocker: READINESS_BLOCKER_LABELS[surface] };
1501
+ if (value === undefined || value === null) {
1502
+ if (lifecyclePhaseEvidence && lifecyclePhaseEvidence.status === PROVIDED) {
1503
+ return { ref: lifecyclePhaseEvidence.ref, status: PROVIDED };
1504
+ }
1505
+ return fallback;
1506
+ }
1507
+ if (typeof value === 'string') {
1508
+ return { ref: requirePublicSafeLifecycleRef(value, `required_evidence_refs.${surface}`), status: PROVIDED };
1509
+ }
1510
+ if (!isPlainObject(value)) throw new TypeError(`required_evidence_refs.${surface} must be a string or object`);
1511
+ const status = stringOrDefault(value.status, PROVIDED);
1512
+ if (!EVIDENCE_STATUSES.has(status)) throw new TypeError(`required_evidence_refs.${surface}.status is invalid`);
1513
+ const ref = status === PROVIDED
1514
+ ? requirePublicSafeLifecycleRef(value.ref, `required_evidence_refs.${surface}.ref`)
1515
+ : requiredString(value.ref, `required_evidence_refs.${surface}.ref`);
1516
+ assertNoForbiddenPayload(ref, `required_evidence_refs.${surface}.ref`);
1517
+ const evidence = { ref, status };
1518
+ const blocker = optionalString(value.blocker, `required_evidence_refs.${surface}.blocker`);
1519
+ if (status === BLOCKED) evidence.blocker = blocker ?? READINESS_BLOCKER_LABELS[surface];
1520
+ return evidence;
1521
+ }
1522
+
1523
+ function readinessEvidenceRefsFrom(input, lifecycleEvidenceRefs) {
1524
+ const explicitRefs = input.required_evidence_refs ?? input.requiredEvidenceRefs
1525
+ ?? input.readiness_evidence_refs ?? input.readinessEvidenceRefs;
1526
+ const refs = isPlainObject(explicitRefs) ? explicitRefs : {};
1527
+ const evidenceRefs = {};
1528
+ for (const surface of HOSTED_CLOUD_READINESS_SURFACES) {
1529
+ const lifecyclePhase = READINESS_SURFACE_LIFECYCLE_PHASE[surface];
1530
+ const lifecycleEvidence = lifecycleEvidenceRefs ? lifecycleEvidenceRefs[lifecyclePhase] : undefined;
1531
+ evidenceRefs[surface] = readinessEvidenceRefFor(surface, refs[surface], lifecycleEvidence);
1532
+ }
1533
+ return evidenceRefs;
1534
+ }
1535
+
1536
+ function propagatedCustomerLifecycleBlockersFrom(lifecycleSellable, lifecycleExternalBlockers) {
1537
+ if (lifecycleSellable === null) {
1538
+ return [{
1539
+ key: 'customer_lifecycle_packet',
1540
+ ref: 'blocked:customer_lifecycle:missing',
1541
+ blocker: 'No customer lifecycle packet is embedded; readiness cannot confirm lifecycle sellability.',
1542
+ }];
1543
+ }
1544
+ if (lifecycleSellable) return [];
1545
+ const blockers = [{
1546
+ key: 'customer_lifecycle_packet',
1547
+ ref: 'blocked:customer_lifecycle:not_sellable',
1548
+ blocker: 'Embedded customer lifecycle packet is not sellable.',
1549
+ }];
1550
+ for (const blocker of lifecycleExternalBlockers) {
1551
+ blockers.push({
1552
+ key: `customer_lifecycle.${blocker.key}`,
1553
+ ref: blocker.ref,
1554
+ blocker: blocker.blocker,
1555
+ });
1556
+ }
1557
+ return blockers;
1558
+ }
1559
+
1560
+ function propagatedApiKeyLifecycleBlockersFrom(operatorApprovalRef, apiKeyExternalBlockers) {
1561
+ if (operatorApprovalRef === undefined) {
1562
+ return [{
1563
+ key: 'api_key_lifecycle_packet',
1564
+ ref: 'blocked:api_key_lifecycle:missing',
1565
+ blocker: 'No API key lifecycle packet is embedded; readiness cannot confirm API key lifecycle operator approval evidence.',
1566
+ }];
1567
+ }
1568
+ return apiKeyExternalBlockers.map((blocker) => ({
1569
+ key: `api_key_lifecycle.${blocker.key}`,
1570
+ ref: blocker.ref,
1571
+ blocker: blocker.blocker,
1572
+ }));
1573
+ }
1574
+
1575
+ function cloudReadinessAssessment(requiredEvidenceRefs, operatorGoLiveRef, lifecycleSellable, apiKeyOperatorApprovalRef, propagatedBlockers) {
1576
+ const missingEvidenceRefs = HOSTED_CLOUD_READINESS_SURFACES
1577
+ .filter((surface) => requiredEvidenceRefs[surface].status !== PROVIDED)
1578
+ .map((surface) => ({
1579
+ key: surface,
1580
+ ref: requiredEvidenceRefs[surface].ref,
1581
+ blocker: requiredEvidenceRefs[surface].blocker ?? READINESS_BLOCKER_LABELS[surface],
1582
+ }));
1583
+ const externalBlockers = [...missingEvidenceRefs, ...propagatedBlockers];
1584
+ if (operatorGoLiveRef === null) {
1585
+ externalBlockers.push({
1586
+ key: 'operator_go_live',
1587
+ ref: 'blocked:operator_go_live',
1588
+ blocker: READINESS_BLOCKER_LABELS.operator_go_live,
1589
+ });
1590
+ }
1591
+ const sellable = missingEvidenceRefs.length === 0
1592
+ && propagatedBlockers.length === 0
1593
+ && operatorGoLiveRef !== null;
1594
+ return {
1595
+ ...HOSTED_CLOUD_CONTRACT_READY,
1596
+ status: sellable ? 'operator_approved_readiness_packet' : 'blocked_readiness_evidence_or_operator_go_live',
1597
+ evidence_validation_only: true,
1598
+ lifecycle_evidence_complete: missingEvidenceRefs.length === 0,
1599
+ lifecycle_packet_sellable: lifecycleSellable === true,
1600
+ lifecycle_packet_embedded: lifecycleSellable !== null,
1601
+ api_key_lifecycle_operator_approved: apiKeyOperatorApprovalRef !== undefined && apiKeyOperatorApprovalRef !== null,
1602
+ api_key_lifecycle_packet_embedded: apiKeyOperatorApprovalRef !== undefined,
1603
+ operator_go_live_approved: operatorGoLiveRef !== null,
1604
+ external_wiring_ready: externalBlockers.length === 0,
1605
+ hosted_cloud_sellable: sellable,
1606
+ selling_gate: sellable
1607
+ ? 'evidence_complete_operator_go_live_approved'
1608
+ : 'blocked_until_readiness_evidence_and_operator_go_live',
1609
+ propagated_lifecycle_blockers: propagatedBlockers,
1610
+ external_blockers: externalBlockers,
1611
+ missing_evidence_refs: missingEvidenceRefs,
1612
+ };
1613
+ }
1614
+
1615
+ function readinessSurfaceRows(requiredEvidenceRefs, operatorGoLiveRef) {
1616
+ const rows = HOSTED_CLOUD_READINESS_SURFACES.map((surface) => {
1617
+ const evidence = requiredEvidenceRefs[surface];
1618
+ const row = {
1619
+ surface,
1620
+ evidence_ref: evidence.ref,
1621
+ evidence_status: evidence.status,
1622
+ ready: evidence.status === PROVIDED,
1623
+ };
1624
+ if (evidence.status === BLOCKED) row.blocker = evidence.blocker ?? READINESS_BLOCKER_LABELS[surface];
1625
+ return row;
1626
+ });
1627
+ const goLiveRow = {
1628
+ surface: 'operator_go_live',
1629
+ evidence_ref: operatorGoLiveRef ?? 'blocked:operator_go_live',
1630
+ evidence_status: operatorGoLiveRef === null ? BLOCKED : PROVIDED,
1631
+ ready: operatorGoLiveRef !== null,
1632
+ };
1633
+ if (operatorGoLiveRef === null) goLiveRow.blocker = READINESS_BLOCKER_LABELS.operator_go_live;
1634
+ rows.push(goLiveRow);
1635
+ return rows;
1636
+ }
1637
+
1638
+ function readinessNextActions(readiness, operatorGoLiveRef) {
1639
+ const actions = [];
1640
+ for (const missing of readiness.missing_evidence_refs) {
1641
+ actions.push({
1642
+ action: `provide_${missing.key}_evidence`,
1643
+ surface: missing.key,
1644
+ ref: missing.ref,
1645
+ });
1646
+ }
1647
+ if (readiness.propagated_lifecycle_blockers && readiness.propagated_lifecycle_blockers.length > 0) {
1648
+ actions.push({
1649
+ action: 'resolve_customer_lifecycle_blockers',
1650
+ surface: 'customer_lifecycle_packet',
1651
+ ref: readiness.propagated_lifecycle_blockers[0].ref,
1652
+ });
1653
+ }
1654
+ if (operatorGoLiveRef === null) {
1655
+ actions.push({
1656
+ action: 'obtain_operator_go_live_approval',
1657
+ surface: 'operator_go_live',
1658
+ ref: 'blocked:operator_go_live',
1659
+ });
1660
+ }
1661
+ if (actions.length === 0) {
1662
+ actions.push({
1663
+ action: 'readiness_complete_review_before_selling',
1664
+ surface: 'operator_go_live',
1665
+ });
1666
+ }
1667
+ return actions;
1668
+ }
1669
+
1670
+ function cloudReadinessDashboard(requiredEvidenceRefs, readiness, operatorGoLiveRef, lifecycleRef) {
1671
+ const providedCount = HOSTED_CLOUD_READINESS_SURFACES
1672
+ .filter((surface) => requiredEvidenceRefs[surface].status === PROVIDED).length;
1673
+ return {
1674
+ counts: {
1675
+ readiness_surface_count: HOSTED_CLOUD_READINESS_SURFACES.length + 1,
1676
+ provided_evidence_count: providedCount,
1677
+ missing_evidence_count: readiness.missing_evidence_refs.length,
1678
+ external_blocker_count: readiness.external_blockers.length,
1679
+ },
1680
+ status_refs: {
1681
+ customer_lifecycle_packet_ref: lifecycleRef,
1682
+ operator_go_live_ref: operatorGoLiveRef,
1683
+ },
1684
+ blocker_refs: readiness.external_blockers.map((blocker) => ({
1685
+ surface: blocker.key,
1686
+ ref: blocker.ref,
1687
+ blocker: blocker.blocker,
1688
+ })),
1689
+ next_actions: readinessNextActions(readiness, operatorGoLiveRef),
1690
+ safety_summary: {
1691
+ evidence_validation_only: true,
1692
+ key_material_absent: true,
1693
+ token_material_absent: true,
1694
+ auth_material_absent: true,
1695
+ customer_content_absent: true,
1696
+ },
1697
+ };
1698
+ }
1699
+
1700
+ function cloudReadinessSafetyGuarantees() {
1701
+ return {
1702
+ opaque_reference_only: true,
1703
+ customer_content_absent: true,
1704
+ sensitive_text_absent: true,
1705
+ auth_material_absent: true,
1706
+ provider_payloads_absent: true,
1707
+ evidence_validation_only: true,
1708
+ financial_outcome_claim_absent: true,
1709
+ remote_erasure_claim_absent: true,
1710
+ };
1711
+ }
1712
+
1713
+ function validateCloudReadinessSafetyGuarantees(guarantees) {
1714
+ if (!isPlainObject(guarantees)) throw new TypeError('public_safety_guarantees must be present');
1715
+ requiredTrue(guarantees.opaque_reference_only, 'public_safety_guarantees.opaque_reference_only');
1716
+ requiredTrue(guarantees.customer_content_absent, 'public_safety_guarantees.customer_content_absent');
1717
+ requiredTrue(guarantees.sensitive_text_absent, 'public_safety_guarantees.sensitive_text_absent');
1718
+ requiredTrue(guarantees.auth_material_absent, 'public_safety_guarantees.auth_material_absent');
1719
+ requiredTrue(guarantees.provider_payloads_absent, 'public_safety_guarantees.provider_payloads_absent');
1720
+ requiredTrue(guarantees.evidence_validation_only, 'public_safety_guarantees.evidence_validation_only');
1721
+ requiredTrue(guarantees.financial_outcome_claim_absent, 'public_safety_guarantees.financial_outcome_claim_absent');
1722
+ requiredTrue(guarantees.remote_erasure_claim_absent, 'public_safety_guarantees.remote_erasure_claim_absent');
1723
+ }
1724
+
1725
+ function validateCloudReadinessReadiness(readiness, expected) {
1726
+ if (!isPlainObject(readiness)) throw new TypeError('readiness must be present');
1727
+ requiredTrue(readiness.contract_ready, 'readiness.contract_ready');
1728
+ if (readiness.integration_kind !== HOSTED_CLOUD_CONTRACT_READY.integration_kind) throw new TypeError('readiness.integration_kind must remain contract_validator_only');
1729
+ requiredTrue(readiness.no_external_provider_calls, 'readiness.no_external_provider_calls');
1730
+ requiredTrue(readiness.evidence_validation_only, 'readiness.evidence_validation_only');
1731
+ if (readiness.status !== expected.status) throw new TypeError('readiness.status must match readiness evidence and operator go-live approval');
1732
+ if (readiness.lifecycle_evidence_complete !== expected.lifecycle_evidence_complete) throw new TypeError('readiness.lifecycle_evidence_complete must match required_evidence_refs');
1733
+ if (readiness.lifecycle_packet_sellable !== expected.lifecycle_packet_sellable) throw new TypeError('readiness.lifecycle_packet_sellable must match embedded lifecycle packet');
1734
+ if (readiness.lifecycle_packet_embedded !== expected.lifecycle_packet_embedded) throw new TypeError('readiness.lifecycle_packet_embedded must match embedded lifecycle packet');
1735
+ if (readiness.api_key_lifecycle_operator_approved !== expected.api_key_lifecycle_operator_approved) throw new TypeError('readiness.api_key_lifecycle_operator_approved must match embedded API key lifecycle operator approval evidence');
1736
+ if (readiness.api_key_lifecycle_packet_embedded !== expected.api_key_lifecycle_packet_embedded) throw new TypeError('readiness.api_key_lifecycle_packet_embedded must match embedded API key lifecycle packet');
1737
+ if (readiness.operator_go_live_approved !== expected.operator_go_live_approved) throw new TypeError('readiness.operator_go_live_approved must match operator_go_live_ref');
1738
+ if (readiness.external_wiring_ready !== expected.external_wiring_ready) throw new TypeError('readiness.external_wiring_ready must match blockers');
1739
+ if (readiness.hosted_cloud_sellable !== expected.hosted_cloud_sellable) throw new TypeError('readiness.hosted_cloud_sellable must match readiness evidence and operator go-live approval');
1740
+ if (readiness.selling_gate !== expected.selling_gate) throw new TypeError('readiness.selling_gate must match readiness evidence and operator go-live approval');
1741
+ assertSameLifecycleArray(readiness.propagated_lifecycle_blockers, expected.propagated_lifecycle_blockers, 'readiness.propagated_lifecycle_blockers');
1742
+ assertSameLifecycleArray(readiness.external_blockers, expected.external_blockers, 'readiness.external_blockers');
1743
+ assertSameLifecycleArray(readiness.missing_evidence_refs, expected.missing_evidence_refs, 'readiness.missing_evidence_refs');
1744
+ }
1745
+
1746
+ function validateReadinessEvidenceRefs(packet) {
1747
+ if (!isPlainObject(packet.required_evidence_refs)) throw new TypeError('required_evidence_refs must be present');
1748
+ for (const key of Object.keys(packet.required_evidence_refs)) {
1749
+ if (!HOSTED_CLOUD_READINESS_SURFACES.includes(key)) throw new TypeError(`required_evidence_refs.${key} is not a readiness surface`);
1750
+ }
1751
+ const requiredEvidenceRefs = {};
1752
+ for (const surface of HOSTED_CLOUD_READINESS_SURFACES) {
1753
+ if (!Object.prototype.hasOwnProperty.call(packet.required_evidence_refs, surface)) throw new TypeError(`required_evidence_refs.${surface} must be present`);
1754
+ requiredEvidenceRefs[surface] = readinessEvidenceRefFor(surface, packet.required_evidence_refs[surface], null);
1755
+ }
1756
+ return requiredEvidenceRefs;
1757
+ }
1758
+
1759
+ export function buildHostedCloudReadinessPacket(input = {}) {
1760
+ if (!isPlainObject(input)) throw new TypeError('buildHostedCloudReadinessPacket requires an options object');
1761
+ assertNoForbiddenPayload(input, 'input');
1762
+ const generatedAt = isoTimestamp(input.generated_at ?? input.generatedAt, 'generated_at');
1763
+ const operatorGoLiveRef = operatorGoLiveRefFromInput(input);
1764
+ let lifecycleSellable = null;
1765
+ let lifecycleEvidenceRefs = null;
1766
+ let lifecycleRef = null;
1767
+ let apiKeyOperatorApprovalRef = undefined;
1768
+ let apiKeyLifecycleRef = null;
1769
+ const providedLifecyclePacket = input.customer_lifecycle_packet ?? input.customerLifecyclePacket;
1770
+ if (providedLifecyclePacket !== undefined && providedLifecyclePacket !== null) {
1771
+ if (!isPlainObject(providedLifecyclePacket)) throw new TypeError('customer_lifecycle_packet must be an object');
1772
+ validateCustomerLifecyclePacket(providedLifecyclePacket);
1773
+ lifecycleSellable = providedLifecyclePacket.hosted_cloud_sellable;
1774
+ lifecycleEvidenceRefs = providedLifecyclePacket.required_evidence_refs;
1775
+ lifecycleRef = {
1776
+ schema: providedLifecyclePacket.schema,
1777
+ packet_id: providedLifecyclePacket.packet_id,
1778
+ contract_hash: providedLifecyclePacket.contract_hash,
1779
+ hosted_cloud_sellable: providedLifecyclePacket.hosted_cloud_sellable,
1780
+ };
1781
+ }
1782
+ const providedApiKeyPacket = input.api_key_lifecycle_packet ?? input.apiKeyLifecyclePacket;
1783
+ if (providedApiKeyPacket !== undefined && providedApiKeyPacket !== null) {
1784
+ if (!isPlainObject(providedApiKeyPacket)) throw new TypeError('api_key_lifecycle_packet must be an object');
1785
+ validateApiKeyLifecyclePacket(providedApiKeyPacket);
1786
+ apiKeyOperatorApprovalRef = providedApiKeyPacket.operator_approval_ref;
1787
+ apiKeyLifecycleRef = {
1788
+ schema: providedApiKeyPacket.schema,
1789
+ packet_id: providedApiKeyPacket.packet_id,
1790
+ contract_hash: providedApiKeyPacket.contract_hash,
1791
+ operator_approval_ref: providedApiKeyPacket.operator_approval_ref,
1792
+ };
1793
+ }
1794
+ const lifecycleExternalBlockers = (providedLifecyclePacket && isPlainObject(providedLifecyclePacket)) ? providedLifecyclePacket.external_blockers : [];
1795
+ const apiKeyExternalBlockers = (providedApiKeyPacket && isPlainObject(providedApiKeyPacket)) ? providedApiKeyPacket.external_blockers : [];
1796
+ const propagatedBlockers = [
1797
+ ...propagatedCustomerLifecycleBlockersFrom(lifecycleSellable, lifecycleExternalBlockers),
1798
+ ...propagatedApiKeyLifecycleBlockersFrom(apiKeyOperatorApprovalRef, apiKeyExternalBlockers),
1799
+ ];
1800
+ const requiredEvidenceRefs = readinessEvidenceRefsFrom(input, lifecycleEvidenceRefs);
1801
+ const readiness = cloudReadinessAssessment(requiredEvidenceRefs, operatorGoLiveRef, lifecycleSellable, apiKeyOperatorApprovalRef, propagatedBlockers);
1802
+ const body = {
1803
+ schema: HOSTED_CLOUD_READINESS_PACKET_SCHEMA,
1804
+ readiness_id: stringOrDefault(input.readiness_id ?? input.readinessId, undefined),
1805
+ generated_at: generatedAt,
1806
+ customer_lifecycle_packet: lifecycleRef,
1807
+ api_key_lifecycle_packet: apiKeyLifecycleRef,
1808
+ required_evidence_refs: requiredEvidenceRefs,
1809
+ readiness_surfaces: readinessSurfaceRows(requiredEvidenceRefs, operatorGoLiveRef),
1810
+ propagated_lifecycle_blockers: readiness.propagated_lifecycle_blockers,
1811
+ operator_go_live_ref: operatorGoLiveRef,
1812
+ external_blockers: readiness.external_blockers,
1813
+ missing_evidence_refs: readiness.missing_evidence_refs,
1814
+ readiness,
1815
+ dashboard: cloudReadinessDashboard(requiredEvidenceRefs, readiness, operatorGoLiveRef, lifecycleRef),
1816
+ hosted_cloud_sellable: readiness.hosted_cloud_sellable,
1817
+ guarantees: cloudReadinessSafetyGuarantees(),
1818
+ public_safety_guarantees: cloudReadinessSafetyGuarantees(),
1819
+ };
1820
+ const packet = withContractIdentity(body, 'hcrp', 'readiness_id');
1821
+ validateHostedCloudReadinessPacket(packet);
1822
+ return packet;
1823
+ }
1824
+
1825
+ export function validateHostedCloudReadinessPacket(packet) {
1826
+ if (!isPlainObject(packet)) throw new TypeError('packet must be an object');
1827
+ assertNoForbiddenPayload(packet, 'packet');
1828
+ if (packet.schema !== HOSTED_CLOUD_READINESS_PACKET_SCHEMA) throw new TypeError(`schema must be ${HOSTED_CLOUD_READINESS_PACKET_SCHEMA}`);
1829
+ requiredString(packet.readiness_id, 'readiness_id');
1830
+ isoTimestamp(packet.generated_at, 'generated_at');
1831
+ requiredString(packet.contract_hash, 'contract_hash');
1832
+ if (!Object.prototype.hasOwnProperty.call(packet, 'customer_lifecycle_packet')) throw new TypeError('customer_lifecycle_packet must be present');
1833
+ if (packet.customer_lifecycle_packet !== null) {
1834
+ if (!isPlainObject(packet.customer_lifecycle_packet)) throw new TypeError('customer_lifecycle_packet must be an object or null');
1835
+ requiredString(packet.customer_lifecycle_packet.schema, 'customer_lifecycle_packet.schema');
1836
+ requiredString(packet.customer_lifecycle_packet.packet_id, 'customer_lifecycle_packet.packet_id');
1837
+ requiredString(packet.customer_lifecycle_packet.contract_hash, 'customer_lifecycle_packet.contract_hash');
1838
+ requiredBoolean(packet.customer_lifecycle_packet.hosted_cloud_sellable, 'customer_lifecycle_packet.hosted_cloud_sellable');
1839
+ }
1840
+ if (!Object.prototype.hasOwnProperty.call(packet, 'api_key_lifecycle_packet')) throw new TypeError('api_key_lifecycle_packet must be present');
1841
+ if (packet.api_key_lifecycle_packet !== null) {
1842
+ if (!isPlainObject(packet.api_key_lifecycle_packet)) throw new TypeError('api_key_lifecycle_packet must be an object or null');
1843
+ requiredString(packet.api_key_lifecycle_packet.schema, 'api_key_lifecycle_packet.schema');
1844
+ requiredString(packet.api_key_lifecycle_packet.packet_id, 'api_key_lifecycle_packet.packet_id');
1845
+ requiredString(packet.api_key_lifecycle_packet.contract_hash, 'api_key_lifecycle_packet.contract_hash');
1846
+ if (!Object.prototype.hasOwnProperty.call(packet.api_key_lifecycle_packet, 'operator_approval_ref')) throw new TypeError('api_key_lifecycle_packet.operator_approval_ref must be present');
1847
+ if (packet.api_key_lifecycle_packet.operator_approval_ref !== null) {
1848
+ requirePublicSafeLifecycleRef(packet.api_key_lifecycle_packet.operator_approval_ref, 'api_key_lifecycle_packet.operator_approval_ref');
1849
+ }
1850
+ }
1851
+ if (!Array.isArray(packet.propagated_lifecycle_blockers)) throw new TypeError('propagated_lifecycle_blockers must be an array');
1852
+ const requiredEvidenceRefs = validateReadinessEvidenceRefs(packet);
1853
+ const operatorGoLiveRef = operatorGoLiveRefFromPacket(packet);
1854
+ const lifecycleSellable = packet.customer_lifecycle_packet === null
1855
+ ? null
1856
+ : packet.customer_lifecycle_packet.hosted_cloud_sellable;
1857
+ const apiKeyOperatorApprovalRef = packet.api_key_lifecycle_packet === null
1858
+ ? undefined
1859
+ : packet.api_key_lifecycle_packet.operator_approval_ref;
1860
+ const expectedReadiness = cloudReadinessAssessment(requiredEvidenceRefs, operatorGoLiveRef, lifecycleSellable, apiKeyOperatorApprovalRef, packet.propagated_lifecycle_blockers);
1861
+ assertSameLifecycleArray(packet.readiness_surfaces, readinessSurfaceRows(requiredEvidenceRefs, operatorGoLiveRef), 'readiness_surfaces');
1862
+ assertSameLifecycleArray(packet.external_blockers, expectedReadiness.external_blockers, 'external_blockers');
1863
+ assertSameLifecycleArray(packet.missing_evidence_refs, expectedReadiness.missing_evidence_refs, 'missing_evidence_refs');
1864
+ validateCloudReadinessReadiness(packet.readiness, expectedReadiness);
1865
+ if (packet.hosted_cloud_sellable !== expectedReadiness.hosted_cloud_sellable) throw new TypeError('hosted_cloud_sellable must match readiness.hosted_cloud_sellable');
1866
+ assertSameLifecycleObject(packet.dashboard, cloudReadinessDashboard(requiredEvidenceRefs, expectedReadiness, operatorGoLiveRef, packet.customer_lifecycle_packet), 'dashboard');
1867
+ validateCloudReadinessSafetyGuarantees(packet.guarantees ?? packet.public_safety_guarantees);
1868
+ validateCloudReadinessSafetyGuarantees(packet.public_safety_guarantees ?? packet.guarantees);
1869
+ return true;
1870
+ }
@@ -17,7 +17,7 @@ import {
17
17
  const DEFAULT_BUNDLE = '.enigma/bundle.json';
18
18
  const JSONRPC_VERSION = '2.0';
19
19
  const MCP_PROTOCOL_VERSION = '2024-11-05';
20
- const SERVER_INFO = Object.freeze({ name: 'enigma-mcp-server', version: '0.1.16' });
20
+ const SERVER_INFO = Object.freeze({ name: 'enigma-mcp-server', version: '0.1.17' });
21
21
  const JSON_RPC_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
22
22
  const JSON_RPC_ERROR = Object.freeze({
23
23
  INVALID_REQUEST: -32600,