@empire-builder-kit/nx 1.0.0-rc.44 → 1.0.0-rc.46

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 (100) hide show
  1. package/package.json +3 -3
  2. package/src/blueprints/external-sandbox.d.ts +1 -1
  3. package/src/cli/main.d.ts +11 -5
  4. package/src/cli/main.js +88 -29
  5. package/src/container-images.d.ts +1 -1
  6. package/src/container-images.js +1 -1
  7. package/src/developer-agent/generator-planning.js +10 -3
  8. package/src/developer-agent/operation-registry.js +1 -1
  9. package/src/executors/deployment-plan/deployment-plan.js +5 -1
  10. package/src/executors/deployment-plan/schema.json +1 -1
  11. package/src/executors/fleet/fleet.js +4 -0
  12. package/src/executors/fleet/schema.json +1 -1
  13. package/src/executors/github-bootstrap/github-bootstrap.d.ts +3 -0
  14. package/src/executors/github-bootstrap/github-bootstrap.js +28 -0
  15. package/src/executors/github-bootstrap/schema.json +14 -0
  16. package/src/executors/local-deploy/federated-credential-transport.d.ts +4 -3
  17. package/src/executors/local-deploy/federated-credential-transport.js +15 -5
  18. package/src/foundation/cost-estimate.d.ts +8 -3
  19. package/src/foundation/cost-estimate.js +42 -19
  20. package/src/foundation/index.d.ts +1 -0
  21. package/src/foundation/index.js +1 -0
  22. package/src/foundation/local-private-smoke-access.js +6 -0
  23. package/src/foundation/logging.d.ts +3 -1
  24. package/src/foundation/logging.js +8 -1
  25. package/src/foundation/observability.d.ts +42 -0
  26. package/src/foundation/observability.js +181 -0
  27. package/src/foundation/preflight.js +1 -1
  28. package/src/generators/function/function.js +5 -2
  29. package/src/generators/observability-infrastructure.d.ts +2 -0
  30. package/src/generators/observability-infrastructure.js +31 -0
  31. package/src/generators/observability-policy.d.ts +4 -0
  32. package/src/generators/observability-policy.js +23 -0
  33. package/src/generators/preset/dependency-overrides.d.ts +17 -6
  34. package/src/generators/preset/dependency-overrides.js +17 -6
  35. package/src/generators/preset/tool-versions.d.ts +2 -2
  36. package/src/generators/preset/tool-versions.js +2 -2
  37. package/src/generators/preset/workspace-files-adopter-skills.js +28 -17
  38. package/src/generators/preset/workspace-files-agent-development.d.ts +9 -0
  39. package/src/generators/preset/workspace-files-agent-development.js +42 -0
  40. package/src/generators/preset/workspace-files-thin-deploy.js +17 -4
  41. package/src/generators/preset/workspace-files-thin-docs.js +10 -22
  42. package/src/generators/preset/workspace-files.d.ts +1 -0
  43. package/src/generators/preset/workspace-files.js +120 -35
  44. package/src/generators/slice/built-in-plan-alarm-identity.d.ts +173 -0
  45. package/src/generators/slice/built-in-plan-alarm-identity.js +202 -0
  46. package/src/generators/slice/built-in-plan-api-contract-files.js +136 -0
  47. package/src/generators/slice/built-in-plan-data-files.js +10 -3
  48. package/src/generators/slice/built-in-plan-database-lifecycle-files.js +1 -1
  49. package/src/generators/slice/built-in-plan-event-contract-literal.d.ts +6 -0
  50. package/src/generators/slice/built-in-plan-event-contract-literal.js +52 -0
  51. package/src/generators/slice/built-in-plan-infrastructure-files.js +304 -144
  52. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +2 -2
  53. package/src/generators/slice/built-in-plan-metadata-files.js +37 -2
  54. package/src/generators/slice/built-in-plan-operations-files.js +106 -6
  55. package/src/generators/slice/built-in-plan-project-files.js +1 -0
  56. package/src/generators/slice/built-in-plan-release-files.js +2 -44
  57. package/src/generators/slice/built-in-plan-reliability-files.js +222 -236
  58. package/src/generators/slice/built-in-plan-shared.d.ts +29 -3
  59. package/src/generators/slice/built-in-plan-shared.js +29 -2
  60. package/src/generators/slice/built-in-plan-verification-files.js +0 -1
  61. package/src/generators/slice/built-in-plan-web-files.js +22 -6
  62. package/src/generators/slice/built-in-plan.js +2 -2
  63. package/src/generators/slice/slice.js +2 -0
  64. package/src/generators/upgrade/upgrade.d.ts +4 -3
  65. package/src/generators/upgrade/upgrade.js +139 -29
  66. package/src/generators/workload/frozen-container.d.ts +1 -1
  67. package/src/generators/workload/reliability-registration.d.ts +1 -1
  68. package/src/generators/workload/reliability-registration.js +9 -9
  69. package/src/generators/workload/workload.d.ts +1 -1
  70. package/src/generators/workload/workload.js +32 -10
  71. package/src/git-policy/github-bootstrap.d.ts +18 -0
  72. package/src/git-policy/github-bootstrap.js +99 -6
  73. package/src/local-dev/dev-command-core.d.ts +24 -3
  74. package/src/local-dev/dev-command-core.js +124 -12
  75. package/src/local-dev/errors.d.ts +19 -1
  76. package/src/local-dev/errors.js +18 -1
  77. package/src/local-dev/fleet-client.d.ts +64 -6
  78. package/src/local-dev/fleet-client.js +189 -15
  79. package/src/local-dev/fleet-process.d.ts +47 -2
  80. package/src/local-dev/fleet-process.js +248 -31
  81. package/src/local-dev/fleet-runtime.d.ts +37 -0
  82. package/src/local-dev/fleet-runtime.js +127 -69
  83. package/src/local-dev/fleet-session.d.ts +1 -0
  84. package/src/local-dev/fleet-session.js +83 -7
  85. package/src/local-dev/fleet-state.d.ts +5 -0
  86. package/src/local-dev/fleet-state.js +11 -2
  87. package/src/local-dev/fleet-supervisor-daemon.js +1 -5
  88. package/src/local-dev/fleet-supervisor.d.ts +7 -0
  89. package/src/local-dev/fleet-supervisor.js +83 -12
  90. package/src/local-dev/slice-runner.d.ts +19 -1
  91. package/src/local-dev/slice-runner.js +290 -91
  92. package/src/repository-policy/deployment-plan.d.ts +1 -1
  93. package/src/repository-policy/deployment-plan.js +16 -1
  94. package/src/secrets/generated-aws-control-plane.d.ts +11 -1
  95. package/src/secrets/generated-aws-control-plane.js +92 -29
  96. package/src/secrets/operator.d.ts +3 -2
  97. package/src/secrets/operator.js +27 -5
  98. package/src/supply-chain/blueprint-verification-authority.js +24 -3
  99. package/src/supply-chain/generated-files.js +9 -0
  100. package/src/supply-chain/sbom.js +74 -12
@@ -0,0 +1,173 @@
1
+ /**
2
+ * The one identity table for every alarm a Standard Slice registers.
3
+ *
4
+ * The seeded operations/reliability.json (its alarmRegistrations and
5
+ * deployedAlarmResources) and every managed MetricAlarm description
6
+ * (infra/reliability.ts, infra/product.ts, infra/key-value-retention.ts) are
7
+ * rendered from this table. The generated `scripts/verify-reliability.mjs
8
+ * --deployed` compares the inventory's owner, route and runbook with each
9
+ * deployed alarm's description, so a value written in two places can drift
10
+ * into a deployed alarm the verifier rejects (CROSS-SLICE-RETENTION-IDENTITY-003).
11
+ *
12
+ * Where the seeded and managed values disagreed, the seeded value is kept:
13
+ * an upgrade rewrites only the managed emitters, so aligning them with the
14
+ * seeded inventory repairs every existing adopter without a hand edit.
15
+ *
16
+ * For the same reason the runbook of an existing ID, and the owner and route
17
+ * from sliceAlarmOwnership, are frozen for existing adopters:
18
+ * built-in-plan-alarm-identity.spec.ts pins them, and changing one needs a
19
+ * seeded operations/reliability.json migration.
20
+ */
21
+ declare const SLICE_ALARM_IDENTITIES: {
22
+ readonly 'alert-delivery-degraded': {
23
+ readonly businessSymptom: "The primary alert route is failing delivery.";
24
+ readonly runbook: "alert-delivery";
25
+ };
26
+ readonly 'api-fast-burn': {
27
+ readonly businessSymptom: "Critical API operations are failing.";
28
+ readonly runbook: "api-recovery";
29
+ };
30
+ readonly 'api-slow-burn': {
31
+ readonly businessSymptom: "Critical API operations have sustained failures.";
32
+ readonly runbook: "api-recovery";
33
+ };
34
+ readonly 'async-target-dlq-depth': {
35
+ readonly businessSymptom: "An asynchronous target has terminal failures.";
36
+ readonly runbook: "async-recovery";
37
+ };
38
+ readonly 'data-export-cleanup-deadline': {
39
+ readonly businessSymptom: "Confidential-export residue exceeded its deletion deadline.";
40
+ readonly runbook: "database-recovery";
41
+ };
42
+ readonly 'data-export-cleanup-failure': {
43
+ readonly businessSymptom: "The confidential-export cleanup invocation is failing.";
44
+ readonly runbook: "database-recovery";
45
+ };
46
+ readonly 'data-export-cleanup-invocation-missing': {
47
+ readonly businessSymptom: "The scheduled confidential-export cleanup is not running.";
48
+ readonly runbook: "database-recovery";
49
+ };
50
+ readonly 'data-protection-findings': {
51
+ readonly businessSymptom: "A managed log group contains a protected-data finding.";
52
+ readonly runbook: "log-investigation";
53
+ };
54
+ readonly 'database-capacity': {
55
+ readonly businessSymptom: "Slice data access or durable event delivery is being throttled.";
56
+ readonly runbook: "database-recovery";
57
+ };
58
+ readonly 'event-delivery-attempts': {
59
+ readonly businessSymptom: "A domain-event intent is repeatedly failing delivery.";
60
+ readonly runbook: "async-recovery";
61
+ };
62
+ readonly 'event-dlq-depth': {
63
+ readonly businessSymptom: "Domain-event processing has terminal failures.";
64
+ readonly runbook: "async-recovery";
65
+ };
66
+ readonly 'event-intent-rejected': {
67
+ readonly businessSymptom: "A retained domain-event intent cannot be delivered.";
68
+ readonly runbook: "async-recovery";
69
+ };
70
+ readonly 'function-failure': {
71
+ readonly businessSymptom: "The generated confidential-export cleanup Function has a terminal invocation error.";
72
+ readonly runbook: "api-recovery";
73
+ };
74
+ readonly 'inbox-cleanup-backlog': {
75
+ readonly businessSymptom: "Terminal asynchronous inbox records are accumulating.";
76
+ readonly runbook: "async-recovery";
77
+ };
78
+ readonly 'inbox-cleanup-errors': {
79
+ readonly businessSymptom: "The asynchronous inbox cleanup job is failing.";
80
+ readonly runbook: "async-recovery";
81
+ };
82
+ readonly 'key-value-reconciliation-errors': {
83
+ readonly businessSymptom: "Durable domain-event recovery is failing.";
84
+ readonly runbook: "async-recovery";
85
+ };
86
+ readonly 'key-value-stream-delivery-errors': {
87
+ readonly businessSymptom: "The key-value stream delivery Function failed an invocation.";
88
+ readonly runbook: "async-recovery";
89
+ };
90
+ readonly 'key-value-stream-iterator-age': {
91
+ readonly businessSymptom: "Prompt domain-event delivery from the key-value stream is falling behind.";
92
+ readonly runbook: "async-recovery";
93
+ };
94
+ readonly 'outbox-backlog': {
95
+ readonly businessSymptom: "Durable domain-event intents remain undelivered.";
96
+ readonly runbook: "async-recovery";
97
+ };
98
+ readonly 'outbox-relay-errors': {
99
+ readonly businessSymptom: "The isolated performance-sink outbox relay is failing.";
100
+ readonly runbook: "async-recovery";
101
+ };
102
+ readonly 'performance-load-cleanup-backlog': {
103
+ readonly businessSymptom: "Expired protected performance-load control records are accumulating.";
104
+ readonly runbook: "performance-capacity-cost";
105
+ };
106
+ readonly 'performance-load-cleanup-deadline': {
107
+ readonly businessSymptom: "Protected performance-load residue exceeded its cleanup deadline.";
108
+ readonly runbook: "performance-capacity-cost";
109
+ };
110
+ readonly 'provider-dlq-depth': {
111
+ readonly businessSymptom: "Provider deliveries have terminal failures.";
112
+ readonly runbook: "async-recovery";
113
+ };
114
+ readonly 'provider-queue-age': {
115
+ readonly businessSymptom: "Accepted provider work is missing its deadline.";
116
+ readonly runbook: "async-recovery";
117
+ };
118
+ readonly 'retention-job-failure': {
119
+ readonly businessSymptom: "The built-in retention Job terminated unsuccessfully.";
120
+ readonly runbook: "database-recovery";
121
+ };
122
+ readonly 'sql-outbox-attempts': {
123
+ readonly businessSymptom: "A relational event intent is repeatedly failing delivery.";
124
+ readonly runbook: "async-recovery";
125
+ };
126
+ readonly 'sql-outbox-backlog': {
127
+ readonly businessSymptom: "Relational event intents remain undelivered.";
128
+ readonly runbook: "async-recovery";
129
+ };
130
+ readonly 'sql-outbox-relay-errors': {
131
+ readonly businessSymptom: "Relational event delivery is failing.";
132
+ readonly runbook: "async-recovery";
133
+ };
134
+ readonly 'web-latency-fast-burn': {
135
+ readonly businessSymptom: "Server-rendered routes exceed the latency objective.";
136
+ readonly runbook: "web-recovery";
137
+ };
138
+ readonly 'web-latency-slow-burn': {
139
+ readonly businessSymptom: "Server-rendered routes have sustained latency degradation.";
140
+ readonly runbook: "web-recovery";
141
+ };
142
+ };
143
+ export type SliceAlarmId = keyof typeof SLICE_ALARM_IDENTITIES;
144
+ export interface SliceAlarmIdentity {
145
+ businessSymptom: string;
146
+ id: SliceAlarmId;
147
+ owner: string;
148
+ route: string;
149
+ /** The Slice-relative runbook path that the description and inventory name. */
150
+ runbook: string;
151
+ /** The alarm registration's reference to the same runbook. */
152
+ runbookRef: string;
153
+ }
154
+ /** The owner and escalation route every built-in Slice alarm carries. */
155
+ export declare function sliceAlarmOwnership(name: string): {
156
+ owner: string;
157
+ route: string;
158
+ };
159
+ export declare function sliceAlarmIdentity(name: string, id: SliceAlarmId): SliceAlarmIdentity;
160
+ /**
161
+ * The generated description helper's argument for one alarm, as TypeScript
162
+ * source. Both generated helpers (`alarmDescription` in infra/reliability.ts
163
+ * and `operationalAlarmDescription` in infra/product.ts) add the owner,
164
+ * route, schema version and Slice from sliceAlarmOwnership.
165
+ */
166
+ export declare function renderSliceAlarmDescriptionInput(name: string, id: SliceAlarmId, indent: string): string;
167
+ /**
168
+ * The complete alarm description object for one alarm, as TypeScript source
169
+ * for an emitter without a description helper. Keys are in the helpers'
170
+ * order.
171
+ */
172
+ export declare function renderSliceAlarmDescriptionObject(name: string, id: SliceAlarmId): string;
173
+ export {};
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sliceAlarmOwnership = sliceAlarmOwnership;
4
+ exports.sliceAlarmIdentity = sliceAlarmIdentity;
5
+ exports.renderSliceAlarmDescriptionInput = renderSliceAlarmDescriptionInput;
6
+ exports.renderSliceAlarmDescriptionObject = renderSliceAlarmDescriptionObject;
7
+ /**
8
+ * The one identity table for every alarm a Standard Slice registers.
9
+ *
10
+ * The seeded operations/reliability.json (its alarmRegistrations and
11
+ * deployedAlarmResources) and every managed MetricAlarm description
12
+ * (infra/reliability.ts, infra/product.ts, infra/key-value-retention.ts) are
13
+ * rendered from this table. The generated `scripts/verify-reliability.mjs
14
+ * --deployed` compares the inventory's owner, route and runbook with each
15
+ * deployed alarm's description, so a value written in two places can drift
16
+ * into a deployed alarm the verifier rejects (CROSS-SLICE-RETENTION-IDENTITY-003).
17
+ *
18
+ * Where the seeded and managed values disagreed, the seeded value is kept:
19
+ * an upgrade rewrites only the managed emitters, so aligning them with the
20
+ * seeded inventory repairs every existing adopter without a hand edit.
21
+ *
22
+ * For the same reason the runbook of an existing ID, and the owner and route
23
+ * from sliceAlarmOwnership, are frozen for existing adopters:
24
+ * built-in-plan-alarm-identity.spec.ts pins them, and changing one needs a
25
+ * seeded operations/reliability.json migration.
26
+ */
27
+ const SLICE_ALARM_IDENTITIES = {
28
+ 'alert-delivery-degraded': {
29
+ businessSymptom: 'The primary alert route is failing delivery.',
30
+ runbook: 'alert-delivery',
31
+ },
32
+ 'api-fast-burn': {
33
+ businessSymptom: 'Critical API operations are failing.',
34
+ runbook: 'api-recovery',
35
+ },
36
+ 'api-slow-burn': {
37
+ businessSymptom: 'Critical API operations have sustained failures.',
38
+ runbook: 'api-recovery',
39
+ },
40
+ 'async-target-dlq-depth': {
41
+ businessSymptom: 'An asynchronous target has terminal failures.',
42
+ runbook: 'async-recovery',
43
+ },
44
+ 'data-export-cleanup-deadline': {
45
+ businessSymptom: 'Confidential-export residue exceeded its deletion deadline.',
46
+ runbook: 'database-recovery',
47
+ },
48
+ 'data-export-cleanup-failure': {
49
+ businessSymptom: 'The confidential-export cleanup invocation is failing.',
50
+ runbook: 'database-recovery',
51
+ },
52
+ 'data-export-cleanup-invocation-missing': {
53
+ businessSymptom: 'The scheduled confidential-export cleanup is not running.',
54
+ runbook: 'database-recovery',
55
+ },
56
+ 'data-protection-findings': {
57
+ businessSymptom: 'A managed log group contains a protected-data finding.',
58
+ runbook: 'log-investigation',
59
+ },
60
+ 'database-capacity': {
61
+ businessSymptom: 'Slice data access or durable event delivery is being throttled.',
62
+ runbook: 'database-recovery',
63
+ },
64
+ 'event-delivery-attempts': {
65
+ businessSymptom: 'A domain-event intent is repeatedly failing delivery.',
66
+ runbook: 'async-recovery',
67
+ },
68
+ 'event-dlq-depth': {
69
+ businessSymptom: 'Domain-event processing has terminal failures.',
70
+ runbook: 'async-recovery',
71
+ },
72
+ 'event-intent-rejected': {
73
+ businessSymptom: 'A retained domain-event intent cannot be delivered.',
74
+ runbook: 'async-recovery',
75
+ },
76
+ 'function-failure': {
77
+ businessSymptom: 'The generated confidential-export cleanup Function has a terminal invocation error.',
78
+ runbook: 'api-recovery',
79
+ },
80
+ 'inbox-cleanup-backlog': {
81
+ businessSymptom: 'Terminal asynchronous inbox records are accumulating.',
82
+ runbook: 'async-recovery',
83
+ },
84
+ 'inbox-cleanup-errors': {
85
+ businessSymptom: 'The asynchronous inbox cleanup job is failing.',
86
+ runbook: 'async-recovery',
87
+ },
88
+ 'key-value-reconciliation-errors': {
89
+ businessSymptom: 'Durable domain-event recovery is failing.',
90
+ runbook: 'async-recovery',
91
+ },
92
+ 'key-value-stream-delivery-errors': {
93
+ businessSymptom: 'The key-value stream delivery Function failed an invocation.',
94
+ runbook: 'async-recovery',
95
+ },
96
+ 'key-value-stream-iterator-age': {
97
+ businessSymptom: 'Prompt domain-event delivery from the key-value stream is falling behind.',
98
+ runbook: 'async-recovery',
99
+ },
100
+ 'outbox-backlog': {
101
+ businessSymptom: 'Durable domain-event intents remain undelivered.',
102
+ runbook: 'async-recovery',
103
+ },
104
+ 'outbox-relay-errors': {
105
+ businessSymptom: 'The isolated performance-sink outbox relay is failing.',
106
+ runbook: 'async-recovery',
107
+ },
108
+ 'performance-load-cleanup-backlog': {
109
+ businessSymptom: 'Expired protected performance-load control records are accumulating.',
110
+ runbook: 'performance-capacity-cost',
111
+ },
112
+ 'performance-load-cleanup-deadline': {
113
+ businessSymptom: 'Protected performance-load residue exceeded its cleanup deadline.',
114
+ runbook: 'performance-capacity-cost',
115
+ },
116
+ 'provider-dlq-depth': {
117
+ businessSymptom: 'Provider deliveries have terminal failures.',
118
+ runbook: 'async-recovery',
119
+ },
120
+ 'provider-queue-age': {
121
+ businessSymptom: 'Accepted provider work is missing its deadline.',
122
+ runbook: 'async-recovery',
123
+ },
124
+ // The Step Functions retention workflow is a database-lifecycle job: its
125
+ // recovery belongs with the other lifecycle alarms in database-recovery.md,
126
+ // which routes the operator to the Job's own README for the run procedure.
127
+ 'retention-job-failure': {
128
+ businessSymptom: 'The built-in retention Job terminated unsuccessfully.',
129
+ runbook: 'database-recovery',
130
+ },
131
+ 'sql-outbox-attempts': {
132
+ businessSymptom: 'A relational event intent is repeatedly failing delivery.',
133
+ runbook: 'async-recovery',
134
+ },
135
+ 'sql-outbox-backlog': {
136
+ businessSymptom: 'Relational event intents remain undelivered.',
137
+ runbook: 'async-recovery',
138
+ },
139
+ 'sql-outbox-relay-errors': {
140
+ businessSymptom: 'Relational event delivery is failing.',
141
+ runbook: 'async-recovery',
142
+ },
143
+ 'web-latency-fast-burn': {
144
+ businessSymptom: 'Server-rendered routes exceed the latency objective.',
145
+ runbook: 'web-recovery',
146
+ },
147
+ 'web-latency-slow-burn': {
148
+ businessSymptom: 'Server-rendered routes have sustained latency degradation.',
149
+ runbook: 'web-recovery',
150
+ },
151
+ };
152
+ /** The owner and escalation route every built-in Slice alarm carries. */
153
+ function sliceAlarmOwnership(name) {
154
+ return { owner: `${name}-product`, route: `${name}-on-call` };
155
+ }
156
+ function sliceAlarmIdentity(name, id) {
157
+ const { businessSymptom, runbook } = SLICE_ALARM_IDENTITIES[id];
158
+ return {
159
+ businessSymptom,
160
+ id,
161
+ ...sliceAlarmOwnership(name),
162
+ runbook: `docs/runbooks/${runbook}.md`,
163
+ runbookRef: `runbook:${runbook}`,
164
+ };
165
+ }
166
+ /** A TypeScript single-quoted string literal. */
167
+ function typescriptString(value) {
168
+ if (/[\\'\n\r\u2028\u2029]/u.test(value)) {
169
+ throw new Error(`Alarm identity text cannot be rendered: ${value}`);
170
+ }
171
+ return `'${value}'`;
172
+ }
173
+ /**
174
+ * The generated description helper's argument for one alarm, as TypeScript
175
+ * source. Both generated helpers (`alarmDescription` in infra/reliability.ts
176
+ * and `operationalAlarmDescription` in infra/product.ts) add the owner,
177
+ * route, schema version and Slice from sliceAlarmOwnership.
178
+ */
179
+ function renderSliceAlarmDescriptionInput(name, id, indent) {
180
+ const identity = sliceAlarmIdentity(name, id);
181
+ const symptom = `${indent} businessSymptom: ${typescriptString(identity.businessSymptom)},`;
182
+ return [
183
+ '{',
184
+ // Wrap a symptom that would not fit 80 columns, as the template did.
185
+ symptom.length <= 80
186
+ ? symptom
187
+ : `${indent} businessSymptom:\n${indent} ${typescriptString(identity.businessSymptom)},`,
188
+ `${indent} id: ${typescriptString(identity.id)},`,
189
+ `${indent} runbook: ${typescriptString(identity.runbook)},`,
190
+ `${indent}}`,
191
+ ].join('\n');
192
+ }
193
+ /**
194
+ * The complete alarm description object for one alarm, as TypeScript source
195
+ * for an emitter without a description helper. Keys are in the helpers'
196
+ * order.
197
+ */
198
+ function renderSliceAlarmDescriptionObject(name, id) {
199
+ const identity = sliceAlarmIdentity(name, id);
200
+ return `{ businessSymptom: ${typescriptString(identity.businessSymptom)}, id: ${typescriptString(identity.id)}, owner: ${typescriptString(identity.owner)}, route: ${typescriptString(identity.route)}, runbook: ${typescriptString(identity.runbook)}, schemaVersion: 1, slice: ${typescriptString(name)} }`;
201
+ }
202
+ //# sourceMappingURL=built-in-plan-alarm-identity.js.map
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.renderProductApiContractFiles = renderProductApiContractFiles;
4
4
  const api_contract_1 = require("@empire-builder-kit/runtime/api-contract");
5
5
  const index_js_1 = require("../../api-contract/index.js");
6
+ const built_in_plan_event_contract_literal_js_1 = require("./built-in-plan-event-contract-literal.js");
6
7
  const built_in_plan_shared_js_1 = require("./built-in-plan-shared.js");
7
8
  const local_source_identity_js_1 = require("./local-source-identity.js");
8
9
  // Shared by the machine-readable contract and the generated operation source.
@@ -2040,6 +2041,7 @@ database code, or other implementation paths.
2040
2041
  } from 'node:fs';
2041
2042
  import { createRequire } from 'node:module';
2042
2043
  import { isAbsolute, join, relative, resolve, sep } from 'node:path';
2044
+ import ts from 'typescript';
2043
2045
 
2044
2046
  const require = createRequire(import.meta.url);
2045
2047
  const {
@@ -2211,6 +2213,139 @@ function validateContractExports(root, packageJson, publications) {
2211
2213
  }
2212
2214
  }
2213
2215
 
2216
+ ${built_in_plan_event_contract_literal_js_1.EVENT_CONTRACT_LITERAL_SOURCE}
2217
+ function producerEventContract(producer, slice) {
2218
+ const path = join(producer.root, 'contracts', 'events.ts');
2219
+ if (!existsSync(path)) {
2220
+ throw new Error(
2221
+ 'Producer ' + slice + ' publishes no contracts/events.ts EventContractSchema.',
2222
+ );
2223
+ }
2224
+ const file = ts.createSourceFile(
2225
+ path,
2226
+ readFileSync(path, 'utf8'),
2227
+ ts.ScriptTarget.ESNext,
2228
+ true,
2229
+ ts.ScriptKind.TS,
2230
+ );
2231
+ let schema;
2232
+ for (const statement of file.statements) {
2233
+ if (!ts.isVariableStatement(statement)) continue;
2234
+ for (const variable of statement.declarationList.declarations) {
2235
+ if (
2236
+ ts.isIdentifier(variable.name) &&
2237
+ variable.name.text === 'EventContractSchema' &&
2238
+ variable.initializer
2239
+ ) {
2240
+ if (schema !== undefined) {
2241
+ throw new Error(
2242
+ 'Producer ' + slice + ' EventContractSchema export is ambiguous.',
2243
+ );
2244
+ }
2245
+ schema = eventLiteral(variable.initializer);
2246
+ }
2247
+ }
2248
+ }
2249
+ if (
2250
+ schema?.kind !== 'ebk-event-contract-schema' ||
2251
+ schema.schemaVersion !== 1 ||
2252
+ schema.slice !== slice ||
2253
+ !Array.isArray(schema.events)
2254
+ ) {
2255
+ throw new Error(
2256
+ 'Producer ' +
2257
+ slice +
2258
+ ' contracts/events.ts must export one canonical v1 EventContractSchema.',
2259
+ );
2260
+ }
2261
+ return schema;
2262
+ }
2263
+
2264
+ // Bind each declared cross-Slice subscription to the producer's published
2265
+ // EventContractSchema, so a removed, renamed or re-versioned event fails here
2266
+ // instead of silently stopping delivery.
2267
+ async function checkEventSubscriptions(dependencies, projects) {
2268
+ const subscriptionPath = join(
2269
+ projectRoot,
2270
+ 'contracts',
2271
+ 'event-subscriptions.json',
2272
+ );
2273
+ if (!existsSync(subscriptionPath)) {
2274
+ throw new Error(
2275
+ 'contracts/event-subscriptions.json is missing. Restore the seeded ' +
2276
+ 'declaration with schemaVersion 1 and an empty subscriptions list.',
2277
+ );
2278
+ }
2279
+ // The managed infrastructure validator is the one authority for the
2280
+ // declaration shape; this check runs it exactly as deployment does.
2281
+ const validator = await import(
2282
+ 'data:text/javascript;base64,' +
2283
+ Buffer.from(
2284
+ ts.transpileModule(
2285
+ readFileSync(
2286
+ join(projectRoot, 'infra', 'event-subscriptions.ts'),
2287
+ 'utf8',
2288
+ ),
2289
+ {
2290
+ compilerOptions: {
2291
+ module: ts.ModuleKind.ESNext,
2292
+ target: ts.ScriptTarget.ES2022,
2293
+ },
2294
+ },
2295
+ ).outputText,
2296
+ ).toString('base64')
2297
+ );
2298
+ const subscriptions = validator.crossSliceEventSubscriptions(
2299
+ readJson(subscriptionPath),
2300
+ dependencies,
2301
+ );
2302
+ for (const subscription of subscriptions) {
2303
+ const producer = projects.get(subscription.source);
2304
+ if (
2305
+ !producer ||
2306
+ !dependencies.consumes.includes(producer.packageJson.name + '/contracts')
2307
+ ) {
2308
+ throw new Error(
2309
+ 'Subscribed source ' +
2310
+ subscription.source +
2311
+ ' is not a consumed Product Slice contracts package.',
2312
+ );
2313
+ }
2314
+ const schema = producerEventContract(producer, subscription.source);
2315
+ for (const detailType of subscription.detailTypes) {
2316
+ const published = schema.events.filter(
2317
+ (event) => event?.detailType === detailType,
2318
+ );
2319
+ if (
2320
+ published.length !== 1 ||
2321
+ published[0].source !== subscription.source
2322
+ ) {
2323
+ throw new Error(
2324
+ 'Producer ' +
2325
+ subscription.source +
2326
+ ' does not publish ' +
2327
+ detailType +
2328
+ ' in its EventContractSchema. Restore the producer event or ' +
2329
+ 'remove the subscription from contracts/event-subscriptions.json.',
2330
+ );
2331
+ }
2332
+ if (!subscription.schemaVersions.includes(published[0].schemaVersion)) {
2333
+ throw new Error(
2334
+ 'Producer ' +
2335
+ subscription.source +
2336
+ ' publishes ' +
2337
+ detailType +
2338
+ ' schemaVersion ' +
2339
+ published[0].schemaVersion +
2340
+ ', which ${name} does not subscribe to. Accept that version ' +
2341
+ 'in api/event-consumer.ts, then declare it in ' +
2342
+ 'contracts/event-subscriptions.json.',
2343
+ );
2344
+ }
2345
+ }
2346
+ }
2347
+ }
2348
+
2214
2349
  const declaration = readJson(declarationPath);
2215
2350
  if (
2216
2351
  !declaration ||
@@ -2345,6 +2480,7 @@ for (const publication of resolution.contracts) {
2345
2480
  const current = [...(ownership.contracts?.consumes ?? [])].sort();
2346
2481
  const expected = [...normalized.contracts.consumes];
2347
2482
  if (action === 'check') {
2483
+ await checkEventSubscriptions(declaration, projects);
2348
2484
  if (JSON.stringify(current) !== JSON.stringify(expected)) {
2349
2485
  throw new Error(
2350
2486
  'Contract declarations are out of sync. Run ' +
@@ -350,9 +350,16 @@ value to GitHub secrets, workflow input, argv, or agent-visible material.
350
350
 
351
351
  The protected deploy role needs metadata authority for the Slice prefix:
352
352
  \`ListSecrets\`, \`DescribeSecret\`, \`CreateSecret\`, and \`TagResource\`.
353
- It must be denied \`BatchGetSecretValue\`, \`GetSecretValue\`,
354
- \`PutSecretValue\`, \`UpdateSecret\`, \`UpdateSecretVersionStage\`,
355
- and application deployment outside its separately reviewed deploy policy.
353
+ It is denied \`BatchGetSecretValue\`, \`UpdateSecretVersionStage\`, and
354
+ application deployment outside its separately reviewed deploy policy, and it is
355
+ denied \`GetSecretValue\` and \`PutSecretValue\` for every operator and
356
+ generated secret; the exact tagged Foundation database credential is the only
357
+ value-action exception. \`UpdateSecret\` is permitted only inside the stage's
358
+ \`ebk/<stage>/*\` namespace and the Foundation provider secret, so native
359
+ recovery can reconcile EBK-owned containers. \`CreateSecret\` and
360
+ \`UpdateSecret\` can both carry a value and IAM cannot prove a call is
361
+ metadata-only, so reviewed generated source, temporary deployment credentials,
362
+ and CloudTrail are the controls.
356
363
  \`DeleteSecret\` is used only by the governed generated-secret retirement path
357
364
  after native Slice removal succeeds; the executor binds that call to the exact
358
365
  generated HMAC name and ownership tags described above.
@@ -300,7 +300,7 @@ RUN --network=none pnpm --config.inject-workspace-packages=true --config.store-d
300
300
 
301
301
  FROM ${frozen_container_js_1.WORKLOAD_CONTAINER_NODE_IMAGE}
302
302
  WORKDIR /app
303
- ADD --chown=node:node --chmod=0444 --checksum=sha256:fe45bbebf92ad3e27a583bbb2ddd1553c521ed4d49af5514dc0a40372ea5395c https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem ./rds-global-bundle.pem
303
+ ADD --chown=node:node --chmod=0444 --checksum=sha256:90a6f1a7978a1b1b096dca6c57511ca48d3b8cf052f8e704baf358f34ea2f21b https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem ./rds-global-bundle.pem
304
304
  COPY --from=build --chown=node:node /opt/migration ./
305
305
  COPY --chown=node:node packages/${name}/jobs/database-lifecycle-logging.mjs ./jobs/database-lifecycle-logging.mjs
306
306
  COPY --chown=node:node packages/${name}/jobs/bootstrap-database.mjs ./jobs/bootstrap-database.mjs
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Literal-only evaluator for a Slice's canonical EventContractSchema export.
3
+ * Release compatibility and the cross-Slice subscription check render the
4
+ * same source so both read a producer contract identically.
5
+ */
6
+ export declare const EVENT_CONTRACT_LITERAL_SOURCE = "const eventLiteral = (node) => {\n while (\n ts.isAsExpression(node) ||\n ts.isSatisfiesExpression(node) ||\n ts.isParenthesizedExpression(node)\n ) {\n node = node.expression;\n }\n if (ts.isObjectLiteralExpression(node)) {\n return Object.fromEntries(\n node.properties.map((property) => {\n if (\n !ts.isPropertyAssignment(property) ||\n !(\n ts.isIdentifier(property.name) ||\n ts.isStringLiteral(property.name)\n )\n ) {\n throw new Error(\n 'EventContractSchema accepts only explicit literal properties.',\n );\n }\n return [property.name.text, eventLiteral(property.initializer)];\n }),\n );\n }\n if (ts.isArrayLiteralExpression(node)) {\n return node.elements.map(eventLiteral);\n }\n if (ts.isStringLiteral(node) || ts.isNumericLiteral(node)) {\n return ts.isNumericLiteral(node) ? Number(node.text) : node.text;\n }\n if (\n node.kind === ts.SyntaxKind.TrueKeyword ||\n node.kind === ts.SyntaxKind.FalseKeyword\n ) {\n return node.kind === ts.SyntaxKind.TrueKeyword;\n }\n throw new Error(\n 'EventContractSchema must remain a canonical literal-only export.',\n );\n};\n";
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EVENT_CONTRACT_LITERAL_SOURCE = void 0;
4
+ /**
5
+ * Literal-only evaluator for a Slice's canonical EventContractSchema export.
6
+ * Release compatibility and the cross-Slice subscription check render the
7
+ * same source so both read a producer contract identically.
8
+ */
9
+ exports.EVENT_CONTRACT_LITERAL_SOURCE = `const eventLiteral = (node) => {
10
+ while (
11
+ ts.isAsExpression(node) ||
12
+ ts.isSatisfiesExpression(node) ||
13
+ ts.isParenthesizedExpression(node)
14
+ ) {
15
+ node = node.expression;
16
+ }
17
+ if (ts.isObjectLiteralExpression(node)) {
18
+ return Object.fromEntries(
19
+ node.properties.map((property) => {
20
+ if (
21
+ !ts.isPropertyAssignment(property) ||
22
+ !(
23
+ ts.isIdentifier(property.name) ||
24
+ ts.isStringLiteral(property.name)
25
+ )
26
+ ) {
27
+ throw new Error(
28
+ 'EventContractSchema accepts only explicit literal properties.',
29
+ );
30
+ }
31
+ return [property.name.text, eventLiteral(property.initializer)];
32
+ }),
33
+ );
34
+ }
35
+ if (ts.isArrayLiteralExpression(node)) {
36
+ return node.elements.map(eventLiteral);
37
+ }
38
+ if (ts.isStringLiteral(node) || ts.isNumericLiteral(node)) {
39
+ return ts.isNumericLiteral(node) ? Number(node.text) : node.text;
40
+ }
41
+ if (
42
+ node.kind === ts.SyntaxKind.TrueKeyword ||
43
+ node.kind === ts.SyntaxKind.FalseKeyword
44
+ ) {
45
+ return node.kind === ts.SyntaxKind.TrueKeyword;
46
+ }
47
+ throw new Error(
48
+ 'EventContractSchema must remain a canonical literal-only export.',
49
+ );
50
+ };
51
+ `;
52
+ //# sourceMappingURL=built-in-plan-event-contract-literal.js.map