@empire-builder-kit/nx 1.0.0-rc.4 → 1.0.0-rc.41
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/README.md +44 -10
- package/executors.json +21 -1
- package/generators.json +10 -0
- package/package.json +31 -7
- package/src/aws/child-environment.d.ts +10 -0
- package/src/aws/child-environment.js +77 -0
- package/src/aws/identity.d.ts +13 -0
- package/src/aws/identity.js +41 -0
- package/src/aws-authority/index.d.ts +2 -0
- package/src/aws-authority/index.js +6 -0
- package/src/aws-authority/lambda-policy-ordering.d.ts +38 -0
- package/src/aws-authority/lambda-policy-ordering.js +56 -0
- package/src/aws-authority/stage-authority.d.ts +248 -0
- package/src/aws-authority/stage-authority.js +3558 -0
- package/src/blueprints/external-sandbox.d.ts +1 -1
- package/src/blueprints/external-sandbox.js +21 -9
- package/src/blueprints/manifest.d.ts +1 -1
- package/src/blueprints/resolver.js +28 -15
- package/src/cli/bootstrap.d.ts +1 -1
- package/src/cli/deploy-runtime.d.ts +30 -0
- package/src/cli/deploy-runtime.js +174 -0
- package/src/cli/dev-command.d.ts +18 -4
- package/src/cli/dev-command.js +71 -0
- package/src/cli/main.d.ts +9 -1
- package/src/cli/main.js +157 -24
- package/src/cli/output.d.ts +1 -1
- package/src/cli/output.js +1 -1
- package/src/cli/personal-secret-runtime.d.ts +12 -0
- package/src/cli/personal-secret-runtime.js +18 -3
- package/src/cli/secret-terminal.js +1 -1
- package/src/container-images.d.ts +1 -1
- package/src/container-images.js +1 -1
- package/src/developer-agent/context.js +41 -9
- package/src/developer-agent/generator-planning.js +20 -6
- package/src/developer-agent/git-inspection.d.ts +6 -2
- package/src/developer-agent/git-inspection.js +78 -6
- package/src/developer-agent/model.d.ts +5 -3
- package/src/developer-agent/model.js +4 -4
- package/src/developer-agent/operation-registry.d.ts +15 -0
- package/src/developer-agent/operation-registry.js +342 -49
- package/src/developer-agent/planning.d.ts +8 -1
- package/src/developer-agent/planning.js +39 -16
- package/src/developer-agent/preview-changes.d.ts +2 -0
- package/src/developer-agent/preview-changes.js +14 -2
- package/src/developer-agent/preview-source.js +3 -0
- package/src/developer-agent/validation.js +25 -9
- package/src/developer-agent/workspace-inspection.js +60 -5
- package/src/executors/blueprint-trust/blueprint-trust.js +6 -0
- package/src/executors/deployment-plan/deployment-plan.d.ts +2 -0
- package/src/executors/deployment-plan/deployment-plan.js +57 -2
- package/src/executors/dev-doctor/dev-doctor.js +13 -6
- package/src/executors/dev-task-cleanup/dev-task-cleanup.d.ts +23 -0
- package/src/executors/dev-task-cleanup/dev-task-cleanup.js +145 -0
- package/src/executors/dev-task-cleanup/schema.json +9 -0
- package/src/executors/dev-task-cleanup/task-stack-absence.d.ts +27 -0
- package/src/executors/dev-task-cleanup/task-stack-absence.js +281 -0
- package/src/executors/dev-task-cleanup/task-stack-checkpoint.d.ts +12 -0
- package/src/executors/dev-task-cleanup/task-stack-checkpoint.js +92 -0
- package/src/executors/fleet/fleet.js +1 -1
- package/src/executors/foundation-preflight/foundation-preflight.d.ts +1 -0
- package/src/executors/foundation-preflight/foundation-preflight.js +6 -2
- package/src/executors/foundation-preflight/schema.json +5 -0
- package/src/executors/foundation-profile-preflight/foundation-profile-preflight.d.ts +13 -2
- package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js +95 -31
- package/src/executors/foundation-profile-preflight/production-database-safeguard.d.ts +65 -0
- package/src/executors/foundation-profile-preflight/production-database-safeguard.js +223 -0
- package/src/executors/foundation-profile-preflight/schema.json +15 -4
- package/src/executors/foundation-remove-preflight/foundation-remove-preflight.d.ts +11 -1
- package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js +70 -20
- package/src/executors/foundation-remove-preflight/schema.json +6 -1
- package/src/executors/github-bootstrap/github-bootstrap.d.ts +1 -0
- package/src/executors/github-bootstrap/github-bootstrap.js +3 -0
- package/src/executors/github-bootstrap/schema.json +7 -1
- package/src/executors/infrastructure-plan/infrastructure-plan.d.ts +29 -136
- package/src/executors/infrastructure-plan/infrastructure-plan.js +230 -3282
- package/src/executors/infrastructure-plan/schema.json +12 -52
- package/src/executors/local-deploy/federated-credential-transport.d.ts +48 -0
- package/src/executors/local-deploy/federated-credential-transport.js +252 -0
- package/src/executors/local-deploy/local-approval.d.ts +18 -0
- package/src/executors/local-deploy/local-approval.js +39 -0
- package/src/executors/local-deploy/local-deploy.d.ts +112 -0
- package/src/executors/local-deploy/local-deploy.js +1404 -0
- package/src/executors/local-deploy/schema.json +70 -0
- package/src/executors/refresh/refresh.js +2 -2
- package/src/executors/remove/remove.js +2 -2
- package/src/executors/router-waf-rehearsal/router-waf-rehearsal.d.ts +42 -0
- package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +1229 -0
- package/src/executors/router-waf-rehearsal/schema.json +29 -0
- package/src/executors/secret-initialize/schema.json +42 -0
- package/src/executors/secret-initialize/secret-initialize.d.ts +34 -0
- package/src/executors/secret-initialize/secret-initialize.js +297 -0
- package/src/executors/secret-metadata/schema.json +5 -0
- package/src/executors/secret-metadata/secret-metadata.d.ts +16 -2
- package/src/executors/secret-metadata/secret-metadata.js +129 -30
- package/src/executors/sst-lifecycle/generated-secret-retirement.d.ts +53 -0
- package/src/executors/sst-lifecycle/generated-secret-retirement.js +192 -0
- package/src/executors/sst-lifecycle/governed-native-operation.d.ts +48 -0
- package/src/executors/sst-lifecycle/governed-native-operation.js +163 -0
- package/src/executors/sst-lifecycle/logging-preflight.d.ts +5 -0
- package/src/executors/sst-lifecycle/logging-preflight.js +23 -13
- package/src/executors/sst-lifecycle/run-sst-command.d.ts +46 -6
- package/src/executors/sst-lifecycle/run-sst-command.js +750 -71
- package/src/executors/sst-lifecycle/schema.json +8 -1
- package/src/executors/sst-lifecycle/secret-preflight.d.ts +2 -0
- package/src/executors/sst-lifecycle/secret-preflight.js +13 -7
- package/src/executors/sst-lifecycle/sst-environment-source.d.ts +33 -0
- package/src/executors/sst-lifecycle/sst-environment-source.js +267 -0
- package/src/executors/sst-lifecycle/task-unlock.d.ts +15 -0
- package/src/executors/sst-lifecycle/task-unlock.js +126 -0
- package/src/executors/unlock/unlock.js +2 -2
- package/src/foundation/capability-plan.d.ts +43 -0
- package/src/foundation/capability-plan.js +168 -0
- package/src/foundation/cost-estimate.d.ts +170 -0
- package/src/foundation/cost-estimate.js +683 -0
- package/src/foundation/discovery.d.ts +14 -11
- package/src/foundation/discovery.js +32 -6
- package/src/foundation/index.d.ts +4 -0
- package/src/foundation/index.js +11 -0
- package/src/foundation/local-database-contract.d.ts +20 -0
- package/src/foundation/local-database-contract.js +262 -13
- package/src/foundation/local-private-smoke-access.d.ts +20 -0
- package/src/foundation/local-private-smoke-access.js +197 -0
- package/src/foundation/logging-preflight.js +1 -1
- package/src/foundation/logging.d.ts +3 -1
- package/src/foundation/logging.js +1 -1
- package/src/foundation/partial-state.d.ts +10 -0
- package/src/foundation/partial-state.js +21 -0
- package/src/foundation/preflight.js +37 -18
- package/src/foundation/private-smoke-access.d.ts +25 -0
- package/src/foundation/private-smoke-access.js +135 -0
- package/src/foundation/private-smoke-admission.d.ts +45 -0
- package/src/foundation/private-smoke-admission.js +180 -0
- package/src/foundation/private-smoke-control-plane.d.ts +18 -0
- package/src/foundation/private-smoke-control-plane.js +184 -0
- package/src/foundation/provision-database-bindings.d.ts +5 -0
- package/src/foundation/provision-database-bindings.js +41 -8
- package/src/foundation/provision-logical-database.js +15 -8
- package/src/foundation/requirements.d.ts +3 -3
- package/src/foundation/requirements.js +24 -12
- package/src/foundation/router-waf-rate-rehearsal.d.ts +97 -0
- package/src/foundation/router-waf-rate-rehearsal.js +210 -0
- package/src/foundation/router-waf.d.ts +149 -0
- package/src/foundation/router-waf.js +809 -0
- package/src/foundation/stages.d.ts +1 -0
- package/src/foundation/stages.js +11 -0
- package/src/generators/blueprint/blueprint.d.ts +5 -0
- package/src/generators/blueprint/blueprint.js +102 -0
- package/src/generators/blueprint/files.d.ts +6 -0
- package/src/generators/blueprint/files.js +217 -0
- package/src/generators/blueprint/schema.d.ts +4 -0
- package/src/generators/blueprint/schema.json +18 -0
- package/src/generators/formatting.d.ts +8 -0
- package/src/generators/formatting.js +141 -0
- package/src/generators/function/function.js +38 -17
- package/src/generators/logging-registry.d.ts +2 -0
- package/src/generators/logging-registry.js +22 -0
- package/src/generators/post-generation-install.js +2 -2
- package/src/generators/preset/dependency-overrides.d.ts +8 -0
- package/src/generators/preset/dependency-overrides.js +55 -0
- package/src/generators/preset/generator.js +43 -3
- package/src/generators/preset/schema.d.ts +10 -0
- package/src/generators/preset/schema.json +47 -0
- package/src/generators/preset/workspace-files-adopter-skills.d.ts +7 -0
- package/src/generators/preset/workspace-files-adopter-skills.js +324 -0
- package/src/generators/preset/workspace-files-ci-acceptance.d.ts +1 -0
- package/src/generators/preset/workspace-files-ci-acceptance.js +791 -0
- package/src/generators/preset/workspace-files-ci-install.d.ts +2 -0
- package/src/generators/preset/workspace-files-ci-install.js +196 -0
- package/src/generators/preset/workspace-files-developer-agent.d.ts +2 -0
- package/src/generators/preset/workspace-files-developer-agent.js +162 -44
- package/src/generators/preset/workspace-files-ecr-inspector.d.ts +18 -0
- package/src/generators/preset/workspace-files-ecr-inspector.js +298 -0
- package/src/generators/preset/workspace-files-foundation-workload-roles.js +5 -2
- package/src/generators/preset/workspace-files-performance-cost.d.ts +2 -2
- package/src/generators/preset/workspace-files-performance-cost.js +8 -8
- package/src/generators/preset/workspace-files-performance-load.d.ts +1 -1
- package/src/generators/preset/workspace-files-performance-load.js +39 -25
- package/src/generators/preset/workspace-files-shared-operation-claims.d.ts +10 -0
- package/src/generators/preset/workspace-files-shared-operation-claims.js +59 -0
- package/src/generators/preset/workspace-files-stage-authority.d.ts +6 -0
- package/src/generators/preset/workspace-files-stage-authority.js +529 -0
- package/src/generators/preset/workspace-files-thin-deploy.d.ts +65 -0
- package/src/generators/preset/workspace-files-thin-deploy.js +2507 -0
- package/src/generators/preset/workspace-files-thin-docs.d.ts +7 -0
- package/src/generators/preset/workspace-files-thin-docs.js +370 -0
- package/src/generators/preset/workspace-files-thin-release.d.ts +14 -0
- package/src/generators/preset/workspace-files-thin-release.js +26 -0
- package/src/generators/preset/workspace-files-workload-role-baseline.js +254 -42
- package/src/generators/preset/workspace-files.d.ts +18 -2
- package/src/generators/preset/workspace-files.js +1525 -609
- package/src/generators/repository-policy/repository-policy.js +235 -5
- package/src/generators/repository-policy/schema.d.ts +10 -0
- package/src/generators/repository-policy/schema.json +80 -4
- package/src/generators/repository-policy/tree-policy.d.ts +3 -0
- package/src/generators/repository-policy/tree-policy.js +25 -0
- package/src/generators/slice/built-in-plan-api-contract-files.js +49 -11
- package/src/generators/slice/built-in-plan-api-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-api-files.js +130 -414
- package/src/generators/slice/built-in-plan-async-work-files.js +166 -1969
- package/src/generators/slice/built-in-plan-authorization-files.js +102 -334
- package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +975 -233
- package/src/generators/slice/built-in-plan-authorization-storage.d.ts +3 -0
- package/src/generators/slice/built-in-plan-authorization-storage.js +119 -0
- package/src/generators/slice/built-in-plan-background-work-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-background-work-files.js +99 -0
- package/src/generators/slice/built-in-plan-data-deletion-files.js +2 -830
- package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js +5 -31
- package/src/generators/slice/built-in-plan-data-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-data-files.js +176 -1200
- package/src/generators/slice/built-in-plan-data-lifecycle-files.js +53 -28
- package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js +37 -2
- package/src/generators/slice/built-in-plan-data-retention-job-files.js +7 -2443
- package/src/generators/slice/built-in-plan-data-retention-launcher-files.js +50 -8
- package/src/generators/slice/built-in-plan-data-rights-files.js +6 -4482
- package/src/generators/slice/built-in-plan-database-lifecycle-files.js +44 -25
- package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js +25 -2
- package/src/generators/slice/built-in-plan-foundation-files.d.ts +2 -1
- package/src/generators/slice/built-in-plan-foundation-files.js +39 -18
- package/src/generators/slice/built-in-plan-frontend-files.js +14 -3
- package/src/generators/slice/built-in-plan-infrastructure-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-infrastructure-files.js +933 -730
- package/src/generators/slice/built-in-plan-infrastructure-safety-files.js +75 -14
- package/src/generators/slice/built-in-plan-key-value-cleanup.d.ts +4 -0
- package/src/generators/slice/built-in-plan-key-value-cleanup.js +100 -0
- package/src/generators/slice/built-in-plan-key-value-consumer.d.ts +4 -0
- package/src/generators/slice/built-in-plan-key-value-consumer.js +151 -0
- package/src/generators/slice/built-in-plan-key-value-deletion.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-deletion.js +377 -0
- package/src/generators/slice/built-in-plan-key-value-delivery.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-delivery.js +137 -0
- package/src/generators/slice/built-in-plan-key-value-export.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-export.js +595 -0
- package/src/generators/slice/built-in-plan-key-value-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-files.js +31 -0
- package/src/generators/slice/built-in-plan-key-value-holds.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-holds.js +189 -0
- package/src/generators/slice/built-in-plan-key-value-infrastructure.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-infrastructure.js +102 -0
- package/src/generators/slice/built-in-plan-key-value-performance.d.ts +5 -0
- package/src/generators/slice/built-in-plan-key-value-performance.js +530 -0
- package/src/generators/slice/built-in-plan-key-value-provider.d.ts +4 -0
- package/src/generators/slice/built-in-plan-key-value-provider.js +366 -0
- package/src/generators/slice/built-in-plan-key-value-records.d.ts +3 -0
- package/src/generators/slice/built-in-plan-key-value-records.js +232 -0
- package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +103 -0
- package/src/generators/slice/built-in-plan-key-value-retention-job-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention-job-files.js +160 -0
- package/src/generators/slice/built-in-plan-key-value-retention-maintenance.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention-maintenance.js +329 -0
- package/src/generators/slice/built-in-plan-key-value-retention-worker.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention-worker.js +477 -0
- package/src/generators/slice/built-in-plan-key-value-retention.d.ts +2 -0
- package/src/generators/slice/built-in-plan-key-value-retention.js +184 -0
- package/src/generators/slice/built-in-plan-metadata-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-metadata-files.js +159 -29
- package/src/generators/slice/built-in-plan-native-runtime-authority-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-native-runtime-authority-files.js +324 -0
- package/src/generators/slice/built-in-plan-operations-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-operations-files.js +585 -97
- package/src/generators/slice/built-in-plan-performance-files.d.ts +2 -1
- package/src/generators/slice/built-in-plan-performance-files.js +220 -1074
- package/src/generators/slice/built-in-plan-project-files.js +141 -135
- package/src/generators/slice/built-in-plan-release-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-release-files.js +310 -70
- package/src/generators/slice/built-in-plan-reliability-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-reliability-files.js +283 -44
- package/src/generators/slice/built-in-plan-secret-runtime-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-secret-runtime-files.js +87 -76
- package/src/generators/slice/built-in-plan-shared.d.ts +4 -2
- package/src/generators/slice/built-in-plan-shared.js +41 -19
- package/src/generators/slice/built-in-plan-sql-events.d.ts +2 -0
- package/src/generators/slice/built-in-plan-sql-events.js +276 -0
- package/src/generators/slice/built-in-plan-testing-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-testing-files.js +304 -172
- package/src/generators/slice/built-in-plan-testing-persistence-event-files.d.ts +7 -0
- package/src/generators/slice/built-in-plan-testing-persistence-event-files.js +487 -0
- package/src/generators/slice/built-in-plan-testing-persistence-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-testing-persistence-files.js +180 -0
- package/src/generators/slice/built-in-plan-thin-release-files.d.ts +11 -0
- package/src/generators/slice/built-in-plan-thin-release-files.js +162 -0
- package/src/generators/slice/built-in-plan-verification-files.js +76 -2
- package/src/generators/slice/built-in-plan-web-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-web-files.js +223 -16
- package/src/generators/slice/built-in-plan-workload-role-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-workload-role-files.js +143 -279
- package/src/generators/slice/built-in-plan.d.ts +11 -1
- package/src/generators/slice/built-in-plan.js +83 -30
- package/src/generators/slice/data-policy-review-seed.d.ts +2 -0
- package/src/generators/slice/data-policy-review-seed.js +22 -0
- package/src/generators/slice/deployed-smoke-readiness.d.ts +2 -0
- package/src/generators/slice/deployed-smoke-readiness.js +214 -0
- package/src/generators/slice/local-source-identity.d.ts +2 -0
- package/src/generators/slice/local-source-identity.js +31 -0
- package/src/generators/slice/persistence-contract.d.ts +14 -0
- package/src/generators/slice/persistence-contract.js +32 -0
- package/src/generators/slice/slice.js +61 -50
- package/src/generators/sql/schema.d.ts +7 -0
- package/src/generators/sql/schema.json +38 -0
- package/src/generators/sql/sql.d.ts +6 -0
- package/src/generators/sql/sql.js +53 -0
- package/src/generators/upgrade/sql-seeded-reconciliation.d.ts +2 -0
- package/src/generators/upgrade/sql-seeded-reconciliation.js +170 -0
- package/src/generators/upgrade/upgrade.d.ts +15 -1
- package/src/generators/upgrade/upgrade.js +435 -44
- package/src/generators/workload/frozen-container.d.ts +1 -1
- package/src/generators/workload/performance-registration.d.ts +1 -0
- package/src/generators/workload/performance-registration.js +9 -11
- package/src/generators/workload/service-performance-files.d.ts +1 -0
- package/src/generators/workload/service-performance-files.js +27 -7
- package/src/generators/workload/workload.d.ts +1 -1
- package/src/generators/workload/workload.js +105 -29
- package/src/git-policy/action-pins.d.ts +5 -0
- package/src/git-policy/action-pins.js +5 -0
- package/src/git-policy/github-bootstrap.d.ts +48 -8
- package/src/git-policy/github-bootstrap.js +344 -176
- package/src/git-policy/routing.d.ts +7 -1
- package/src/git-policy/routing.js +62 -1
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/infrastructure-change/local-capability.d.ts +73 -0
- package/src/infrastructure-change/local-capability.js +114 -0
- package/src/infrastructure-change/model.d.ts +25 -4
- package/src/infrastructure-change/model.js +1 -0
- package/src/infrastructure-change/normalize.d.ts +4 -0
- package/src/infrastructure-change/normalize.js +47 -7
- package/src/infrastructure-change/plan.d.ts +30 -3
- package/src/infrastructure-change/plan.js +323 -13
- package/src/infrastructure-change/risk.d.ts +3 -1
- package/src/infrastructure-change/risk.js +96 -16
- package/src/local-dev/browser-verification.d.ts +37 -0
- package/src/local-dev/browser-verification.js +281 -0
- package/src/local-dev/contracts.d.ts +10 -1
- package/src/local-dev/contracts.js +114 -13
- package/src/local-dev/dev-command-core.js +24 -5
- package/src/local-dev/docker-credential-health.d.ts +14 -0
- package/src/local-dev/docker-credential-health.js +94 -0
- package/src/local-dev/environment-inspector.d.ts +7 -0
- package/src/local-dev/environment-inspector.js +42 -15
- package/src/local-dev/environment-state.js +2 -2
- package/src/local-dev/errors.d.ts +1 -1
- package/src/local-dev/errors.js +2 -0
- package/src/local-dev/fleet-client.js +2 -2
- package/src/local-dev/fleet-configuration.js +57 -25
- package/src/local-dev/fleet-inventory.js +58 -22
- package/src/local-dev/fleet-ipc.d.ts +7 -0
- package/src/local-dev/fleet-ipc.js +14 -2
- package/src/local-dev/fleet-launcher.d.ts +6 -0
- package/src/local-dev/fleet-launcher.js +16 -4
- package/src/local-dev/fleet-logs.js +50 -22
- package/src/local-dev/fleet-process.d.ts +20 -1
- package/src/local-dev/fleet-process.js +197 -41
- package/src/local-dev/fleet-runner-evidence.d.ts +5 -0
- package/src/local-dev/fleet-runner-evidence.js +56 -0
- package/src/local-dev/fleet-runtime.js +268 -229
- package/src/local-dev/fleet-session.d.ts +2 -0
- package/src/local-dev/fleet-session.js +28 -11
- package/src/local-dev/fleet-slice-runner-daemon.js +4 -0
- package/src/local-dev/fleet-state.d.ts +5 -2
- package/src/local-dev/fleet-state.js +25 -4
- package/src/local-dev/fleet-supervisor.d.ts +3 -0
- package/src/local-dev/fleet-supervisor.js +66 -11
- package/src/local-dev/fleet-web-start.d.ts +12 -0
- package/src/local-dev/fleet-web-start.js +48 -0
- package/src/local-dev/identity.js +3 -14
- package/src/local-dev/index.d.ts +1 -0
- package/src/local-dev/index.js +1 -0
- package/src/local-dev/native-completion.d.ts +9 -0
- package/src/local-dev/native-completion.js +130 -0
- package/src/local-dev/nx-workspace.d.ts +4 -2
- package/src/local-dev/nx-workspace.js +11 -6
- package/src/local-dev/personal-stage.d.ts +4 -5
- package/src/local-dev/personal-stage.js +6 -54
- package/src/local-dev/port-claims.d.ts +13 -0
- package/src/local-dev/port-claims.js +46 -0
- package/src/local-dev/ports.d.ts +14 -2
- package/src/local-dev/ports.js +78 -3
- package/src/local-dev/private-state.d.ts +11 -0
- package/src/local-dev/private-state.js +146 -40
- package/src/local-dev/process-group.d.ts +4 -0
- package/src/local-dev/process-group.js +29 -0
- package/src/local-dev/process-identity.d.ts +8 -0
- package/src/local-dev/process-identity.js +31 -1
- package/src/local-dev/proxy.js +11 -12
- package/src/local-dev/runtime-paths.js +1 -1
- package/src/local-dev/slice-claim.js +1 -1
- package/src/local-dev/slice-runner.d.ts +15 -6
- package/src/local-dev/slice-runner.js +189 -54
- package/src/local-dev/task-attachment.d.ts +17 -0
- package/src/local-dev/task-attachment.js +73 -0
- package/src/local-dev/task-authority.d.ts +10 -0
- package/src/local-dev/task-authority.js +27 -0
- package/src/local-dev/task-identity.d.ts +33 -0
- package/src/local-dev/task-identity.js +418 -0
- package/src/local-dev/task-native-writer.d.ts +18 -0
- package/src/local-dev/task-native-writer.js +329 -0
- package/src/local-dev/tls.js +8 -2
- package/src/local-dev/web-launch.d.ts +9 -0
- package/src/local-dev/web-launch.js +130 -0
- package/src/ownership/composition.d.ts +2 -1
- package/src/ownership/composition.js +1 -0
- package/src/performance/cost-collection.d.ts +1 -1
- package/src/performance/cost-collection.js +4 -2
- package/src/performance/cost-controls.d.ts +8 -4
- package/src/performance/cost-controls.js +39 -28
- package/src/performance/evidence.d.ts +1 -1
- package/src/performance/evidence.js +5 -3
- package/src/performance/load-safety.js +5 -3
- package/src/performance/model.d.ts +4 -4
- package/src/performance/model.js +4 -5
- package/src/performance/scenario.d.ts +22 -0
- package/src/performance/scenario.js +100 -92
- package/src/release/index.d.ts +0 -2
- package/src/release/index.js +0 -2
- package/src/release/source-authority.d.ts +5 -5
- package/src/release/source-authority.js +141 -124
- package/src/repository-policy/aurora-preflight.d.ts +1 -1
- package/src/repository-policy/aurora-preflight.js +4 -1
- package/src/repository-policy/capacity-migration.d.ts +3 -0
- package/src/repository-policy/capacity-migration.js +21 -0
- package/src/repository-policy/deployment-plan.d.ts +4 -1
- package/src/repository-policy/deployment-plan.js +9 -0
- package/src/repository-policy/foundation-profile.js +10 -1
- package/src/repository-policy/policy.d.ts +57 -3
- package/src/repository-policy/policy.js +497 -11
- package/src/schemas/blueprint-v1.json +5 -4
- package/src/schemas/foundation-requirement-v1.json +5 -4
- package/src/schemas/performance-policy-v1.json +3 -3
- package/src/schemas/repository-policy-v1.json +130 -6
- package/src/schemas/testing-evidence-result-v1.json +1 -1
- package/src/secrets/adapters.d.ts +7 -2
- package/src/secrets/adapters.js +34 -3
- package/src/secrets/aws-control-plane.d.ts +10 -1
- package/src/secrets/aws-control-plane.js +67 -0
- package/src/secrets/generated-aws-control-plane.d.ts +23 -0
- package/src/secrets/generated-aws-control-plane.js +259 -0
- package/src/secrets/metadata.js +38 -10
- package/src/secrets/model.d.ts +8 -1
- package/src/secrets/model.js +24 -3
- package/src/secrets/operator.d.ts +91 -3
- package/src/secrets/operator.js +463 -13
- package/src/secrets/personal-command.d.ts +18 -2
- package/src/secrets/personal-command.js +66 -12
- package/src/secrets/registry.d.ts +2 -1
- package/src/secrets/registry.js +18 -1
- package/src/secrets/verification.js +15 -2
- package/src/secrets/workload-access.js +10 -2
- package/src/sst-environment-source-format.d.ts +6 -0
- package/src/sst-environment-source-format.js +199 -0
- package/src/supply-chain/action-pins.js +61 -7
- package/src/supply-chain/blueprint-trust-git.js +85 -24
- package/src/supply-chain/blueprint-verification-authority.js +55 -3
- package/src/supply-chain/build-output-bounds.d.ts +2 -0
- package/src/supply-chain/build-output-bounds.js +12 -0
- package/src/supply-chain/build-output.d.ts +7 -1
- package/src/supply-chain/build-output.js +177 -24
- package/src/supply-chain/ecr-scanning.d.ts +5 -3
- package/src/supply-chain/ecr-scanning.js +11 -7
- package/src/supply-chain/ecs-deployed-image.d.ts +5 -3
- package/src/supply-chain/ecs-deployed-image.js +6 -4
- package/src/supply-chain/generated-blueprint-trust-command.js +18 -1
- package/src/supply-chain/generated-command.js +1 -0
- package/src/supply-chain/generated-container-release-command.js +1285 -124
- package/src/supply-chain/generated-ecr-collector-command.d.ts +0 -1
- package/src/supply-chain/generated-ecr-collector-command.js +200 -93
- package/src/supply-chain/generated-files.js +25 -14
- package/src/supply-chain/generated-scanner-command.js +2 -1
- package/src/supply-chain/index.d.ts +1 -1
- package/src/supply-chain/index.js +2 -1
- package/src/supply-chain/sbom.d.ts +1 -1
- package/src/supply-chain/sbom.js +30 -5
- package/src/supply-chain/scanner.js +3 -0
- package/src/testing-evidence/fixture-scope.d.ts +2 -1
- package/src/testing-evidence/fixture-scope.js +4 -2
- package/src/testing-evidence/result.d.ts +2 -1
- package/src/testing-evidence/result.js +18 -4
- package/src/workload-roles/account-baseline.d.ts +11 -0
- package/src/workload-roles/account-baseline.js +253 -16
- package/src/workload-roles/authority.d.ts +3 -1
- package/src/workload-roles/authority.js +48 -2
- package/src/workload-roles/aws-s3-state.js +27 -0
- package/src/workload-roles/boundary.d.ts +2 -1
- package/src/workload-roles/boundary.js +9 -2
- package/src/workload-roles/handler.js +52 -24
- package/src/workload-roles/index.d.ts +10 -17
- package/src/workload-roles/index.js +5 -18
- package/src/workload-roles/injection.js +1 -1
- package/src/workload-roles/provisioner.js +12 -4
- package/src/workload-roles/registration.d.ts +1 -0
- package/src/workload-roles/registration.js +5 -0
- package/src/workload-roles/stage-boundary.js +1 -1
- package/src/workload-roles/standard-slice.js +3 -3
- package/src/workspace-deployment/affected-lifecycle.d.ts +53 -0
- package/src/workspace-deployment/affected-lifecycle.js +84 -0
- package/src/workspace-deployment/identity.d.ts +3 -0
- package/src/workspace-deployment/identity.js +22 -0
- package/src/workspace-deployment/index.d.ts +4 -0
- package/src/workspace-deployment/index.js +8 -0
- package/src/workspace-deployment/migration-evidence.d.ts +29 -0
- package/src/workspace-deployment/migration-evidence.js +83 -0
- package/src/workspace-deployment/migration.d.ts +27 -0
- package/src/workspace-deployment/migration.js +109 -0
- package/src/workspace-deployment/ownership.d.ts +81 -0
- package/src/workspace-deployment/ownership.js +381 -0
- package/src/api-contract/baseline-update.js.map +0 -1
- package/src/api-contract/compatibility.js.map +0 -1
- package/src/api-contract/contract-graph.js.map +0 -1
- package/src/api-contract/evidence.js.map +0 -1
- package/src/api-contract/index.js.map +0 -1
- package/src/api-contract/model.fixtures.d.ts +0 -2
- package/src/api-contract/model.fixtures.js +0 -81
- package/src/api-contract/model.fixtures.js.map +0 -1
- package/src/api-contract/model.js.map +0 -1
- package/src/api-contract/rollout.js.map +0 -1
- package/src/authorization/compatibility.js.map +0 -1
- package/src/authorization/index.js.map +0 -1
- package/src/blueprints/execution.js.map +0 -1
- package/src/blueprints/external-sandbox.js.map +0 -1
- package/src/blueprints/index.js.map +0 -1
- package/src/blueprints/inputs.js.map +0 -1
- package/src/blueprints/manifest.js.map +0 -1
- package/src/blueprints/resolver.js.map +0 -1
- package/src/blueprints/transitions.js.map +0 -1
- package/src/cli/agent-command.js.map +0 -1
- package/src/cli/agent-runtime.js.map +0 -1
- package/src/cli/blueprint-authority.js.map +0 -1
- package/src/cli/blueprint-command.js.map +0 -1
- package/src/cli/bootstrap.js.map +0 -1
- package/src/cli/dev-command.js.map +0 -1
- package/src/cli/main.js.map +0 -1
- package/src/cli/output.js.map +0 -1
- package/src/cli/personal-secret-runtime.js.map +0 -1
- package/src/cli/secret-terminal.js.map +0 -1
- package/src/container-images.js.map +0 -1
- package/src/data-lifecycle/index.js.map +0 -1
- package/src/data-lifecycle/model.fixtures.d.ts +0 -2
- package/src/data-lifecycle/model.fixtures.js +0 -244
- package/src/data-lifecycle/model.fixtures.js.map +0 -1
- package/src/data-lifecycle/model.js.map +0 -1
- package/src/data-lifecycle/sensitive-artifacts.js.map +0 -1
- package/src/data-lifecycle/validation.js.map +0 -1
- package/src/database-retirement/contract.js.map +0 -1
- package/src/database-retirement/index.js.map +0 -1
- package/src/deterministic-order.js.map +0 -1
- package/src/developer-agent/context.js.map +0 -1
- package/src/developer-agent/generator-planning.js.map +0 -1
- package/src/developer-agent/generator-preview.js.map +0 -1
- package/src/developer-agent/git-inspection.js.map +0 -1
- package/src/developer-agent/handoff.js.map +0 -1
- package/src/developer-agent/index.js.map +0 -1
- package/src/developer-agent/model.js.map +0 -1
- package/src/developer-agent/operation-registry.js.map +0 -1
- package/src/developer-agent/ordering.js.map +0 -1
- package/src/developer-agent/planning.js.map +0 -1
- package/src/developer-agent/preview-changes.js.map +0 -1
- package/src/developer-agent/preview-source.js.map +0 -1
- package/src/developer-agent/validation.js.map +0 -1
- package/src/developer-agent/workspace-inspection.js.map +0 -1
- package/src/developer-agent/workspace-path.js.map +0 -1
- package/src/executors/blueprint-trust/blueprint-trust.js.map +0 -1
- package/src/executors/blueprint-verification/blueprint-verification.js.map +0 -1
- package/src/executors/deploy/deploy.js.map +0 -1
- package/src/executors/deployment-plan/deployment-plan.js.map +0 -1
- package/src/executors/dev/dev.js.map +0 -1
- package/src/executors/dev-doctor/dev-doctor.js.map +0 -1
- package/src/executors/dev-setup/dev-setup.js.map +0 -1
- package/src/executors/developer-context/developer-context.js.map +0 -1
- package/src/executors/fleet/fleet.js.map +0 -1
- package/src/executors/foundation-preflight/foundation-preflight.js.map +0 -1
- package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +0 -1
- package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js.map +0 -1
- package/src/executors/github-bootstrap/github-bootstrap.js.map +0 -1
- package/src/executors/infrastructure-plan/infrastructure-plan.js.map +0 -1
- package/src/executors/refresh/refresh.js.map +0 -1
- package/src/executors/remove/remove.js.map +0 -1
- package/src/executors/secret-guardrails/secret-guardrails.js.map +0 -1
- package/src/executors/secret-metadata/secret-metadata.js.map +0 -1
- package/src/executors/sst-lifecycle/logging-preflight.js.map +0 -1
- package/src/executors/sst-lifecycle/run-sst-command.js.map +0 -1
- package/src/executors/sst-lifecycle/secret-preflight.js.map +0 -1
- package/src/executors/unlock/unlock.js.map +0 -1
- package/src/executors/work-markers/work-markers.js.map +0 -1
- package/src/foundation/discovery.js.map +0 -1
- package/src/foundation/index.js.map +0 -1
- package/src/foundation/local-database-contract.js.map +0 -1
- package/src/foundation/logging-preflight.js.map +0 -1
- package/src/foundation/logging.js.map +0 -1
- package/src/foundation/preflight.js.map +0 -1
- package/src/foundation/provision-database-bindings.js.map +0 -1
- package/src/foundation/provision-logical-database.js.map +0 -1
- package/src/foundation/requirements.js.map +0 -1
- package/src/foundation/router-origin-proof.js.map +0 -1
- package/src/foundation/stages.js.map +0 -1
- package/src/frontend-security/index.js.map +0 -1
- package/src/frontend-security/security-headers.js.map +0 -1
- package/src/generators/feature-registry.js.map +0 -1
- package/src/generators/function/function.js.map +0 -1
- package/src/generators/job/job.js.map +0 -1
- package/src/generators/logging-registry.js.map +0 -1
- package/src/generators/post-generation-install.js.map +0 -1
- package/src/generators/preset/generator.js.map +0 -1
- package/src/generators/preset/tool-versions.js.map +0 -1
- package/src/generators/preset/workspace-files-developer-agent.js.map +0 -1
- package/src/generators/preset/workspace-files-foundation-workload-roles.js.map +0 -1
- package/src/generators/preset/workspace-files-performance-cost.js.map +0 -1
- package/src/generators/preset/workspace-files-performance-load.js.map +0 -1
- package/src/generators/preset/workspace-files-workload-role-baseline.js.map +0 -1
- package/src/generators/preset/workspace-files.js.map +0 -1
- package/src/generators/repository-policy/repository-policy.js.map +0 -1
- package/src/generators/service/service.js.map +0 -1
- package/src/generators/slice/built-in-plan-api-contract-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-api-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-async-work-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-authorization-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-deletion-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-lifecycle-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-retention-job-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-retention-launcher-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-data-rights-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-database-lifecycle-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-foundation-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-frontend-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-infrastructure-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-infrastructure-safety-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-metadata-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-operations-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-performance-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-project-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-release-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-reliability-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-shared.js.map +0 -1
- package/src/generators/slice/built-in-plan-testing-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-verification-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-web-files.js.map +0 -1
- package/src/generators/slice/built-in-plan-workload-role-files.js.map +0 -1
- package/src/generators/slice/built-in-plan.js.map +0 -1
- package/src/generators/slice/slice.js.map +0 -1
- package/src/generators/upgrade/upgrade.js.map +0 -1
- package/src/generators/workload/frozen-container.js.map +0 -1
- package/src/generators/workload/performance-registration.js.map +0 -1
- package/src/generators/workload/reliability-registration.js.map +0 -1
- package/src/generators/workload/service-performance-files.js.map +0 -1
- package/src/generators/workload/workload.js.map +0 -1
- package/src/git-policy/action-pins.js.map +0 -1
- package/src/git-policy/github-bootstrap.js.map +0 -1
- package/src/git-policy/index.js.map +0 -1
- package/src/git-policy/routing.js.map +0 -1
- package/src/index.js.map +0 -1
- package/src/infrastructure-change/convergence.js.map +0 -1
- package/src/infrastructure-change/drift.js.map +0 -1
- package/src/infrastructure-change/index.js.map +0 -1
- package/src/infrastructure-change/model.js.map +0 -1
- package/src/infrastructure-change/normalize.js.map +0 -1
- package/src/infrastructure-change/plan.js.map +0 -1
- package/src/infrastructure-change/risk.js.map +0 -1
- package/src/infrastructure-change/summary.js.map +0 -1
- package/src/local-dev/context-discovery.js.map +0 -1
- package/src/local-dev/contract-validation.js.map +0 -1
- package/src/local-dev/contracts.js.map +0 -1
- package/src/local-dev/control-contract.js.map +0 -1
- package/src/local-dev/dev-command-core.js.map +0 -1
- package/src/local-dev/effects.js.map +0 -1
- package/src/local-dev/environment-inspector.js.map +0 -1
- package/src/local-dev/environment-state.js.map +0 -1
- package/src/local-dev/errors.js.map +0 -1
- package/src/local-dev/fleet-client.js.map +0 -1
- package/src/local-dev/fleet-configuration.js.map +0 -1
- package/src/local-dev/fleet-inventory.js.map +0 -1
- package/src/local-dev/fleet-ipc.js.map +0 -1
- package/src/local-dev/fleet-launcher.js.map +0 -1
- package/src/local-dev/fleet-lock.js.map +0 -1
- package/src/local-dev/fleet-logs.js.map +0 -1
- package/src/local-dev/fleet-process.js.map +0 -1
- package/src/local-dev/fleet-runtime.js.map +0 -1
- package/src/local-dev/fleet-session.js.map +0 -1
- package/src/local-dev/fleet-slice-runner-daemon.js.map +0 -1
- package/src/local-dev/fleet-startup.js.map +0 -1
- package/src/local-dev/fleet-state.js.map +0 -1
- package/src/local-dev/fleet-supervisor-daemon.js.map +0 -1
- package/src/local-dev/fleet-supervisor.js.map +0 -1
- package/src/local-dev/gateway-daemon.js.map +0 -1
- package/src/local-dev/gateway.js.map +0 -1
- package/src/local-dev/identity.js.map +0 -1
- package/src/local-dev/index.js.map +0 -1
- package/src/local-dev/local-context.js.map +0 -1
- package/src/local-dev/nx-workspace.js.map +0 -1
- package/src/local-dev/personal-secret-ledger.js.map +0 -1
- package/src/local-dev/personal-stage.js.map +0 -1
- package/src/local-dev/portless.js.map +0 -1
- package/src/local-dev/ports.js.map +0 -1
- package/src/local-dev/private-state.js.map +0 -1
- package/src/local-dev/process-identity.js.map +0 -1
- package/src/local-dev/proxy.js.map +0 -1
- package/src/local-dev/runtime-paths.js.map +0 -1
- package/src/local-dev/secret-slice-claim.js.map +0 -1
- package/src/local-dev/slice-claim.js.map +0 -1
- package/src/local-dev/slice-runner.js.map +0 -1
- package/src/local-dev/tls.js.map +0 -1
- package/src/ownership/composition.js.map +0 -1
- package/src/ownership/foundation-record.js.map +0 -1
- package/src/ownership/hash.js.map +0 -1
- package/src/ownership/index.js.map +0 -1
- package/src/ownership/json-ownership.js.map +0 -1
- package/src/ownership/record.js.map +0 -1
- package/src/ownership/workspace-record.js.map +0 -1
- package/src/performance/cost-collection.js.map +0 -1
- package/src/performance/cost-controls.js.map +0 -1
- package/src/performance/evidence.js.map +0 -1
- package/src/performance/index.js.map +0 -1
- package/src/performance/load-safety.js.map +0 -1
- package/src/performance/model.js.map +0 -1
- package/src/performance/pr-artifact-budget.js.map +0 -1
- package/src/performance/runner.js.map +0 -1
- package/src/performance/scenario-endpoint.js.map +0 -1
- package/src/performance/scenario.js.map +0 -1
- package/src/performance/test-fixtures.d.ts +0 -7
- package/src/performance/test-fixtures.js +0 -169
- package/src/performance/test-fixtures.js.map +0 -1
- package/src/performance/unit-cost.js.map +0 -1
- package/src/release/index.js.map +0 -1
- package/src/release/lifecycle.js.map +0 -1
- package/src/release/manifest.js.map +0 -1
- package/src/release/rollout.js.map +0 -1
- package/src/release/source-authority.js.map +0 -1
- package/src/repository-policy/aurora-preflight.js.map +0 -1
- package/src/repository-policy/deployment-plan.js.map +0 -1
- package/src/repository-policy/foundation-profile.js.map +0 -1
- package/src/repository-policy/index.js.map +0 -1
- package/src/repository-policy/policy.js.map +0 -1
- package/src/secrets/adapters.js.map +0 -1
- package/src/secrets/aws-control-plane.js.map +0 -1
- package/src/secrets/declaration-verification.js.map +0 -1
- package/src/secrets/guardrails.js.map +0 -1
- package/src/secrets/index.js.map +0 -1
- package/src/secrets/metadata.js.map +0 -1
- package/src/secrets/model.js.map +0 -1
- package/src/secrets/operator.js.map +0 -1
- package/src/secrets/permissions.js.map +0 -1
- package/src/secrets/personal-command.js.map +0 -1
- package/src/secrets/personal-ledger.js.map +0 -1
- package/src/secrets/registry.js.map +0 -1
- package/src/secrets/verification.js.map +0 -1
- package/src/secrets/workload-access.js.map +0 -1
- package/src/supply-chain/action-pins.js.map +0 -1
- package/src/supply-chain/blueprint-trust-git.js.map +0 -1
- package/src/supply-chain/blueprint-trust-process.js.map +0 -1
- package/src/supply-chain/blueprint-trust.js.map +0 -1
- package/src/supply-chain/blueprint-verification-authority.js.map +0 -1
- package/src/supply-chain/blueprint-verification-execution.js.map +0 -1
- package/src/supply-chain/build-output.js.map +0 -1
- package/src/supply-chain/common.js.map +0 -1
- package/src/supply-chain/container-artifact-contract.js.map +0 -1
- package/src/supply-chain/container-release.js.map +0 -1
- package/src/supply-chain/ecr-applicability.js.map +0 -1
- package/src/supply-chain/ecr-scanning.js.map +0 -1
- package/src/supply-chain/ecs-deployed-image.js.map +0 -1
- package/src/supply-chain/errors.js.map +0 -1
- package/src/supply-chain/generated-blueprint-trust-command.js.map +0 -1
- package/src/supply-chain/generated-command.js.map +0 -1
- package/src/supply-chain/generated-container-release-command.js.map +0 -1
- package/src/supply-chain/generated-ecr-collector-command.js.map +0 -1
- package/src/supply-chain/generated-files.js.map +0 -1
- package/src/supply-chain/generated-scanner-command.js.map +0 -1
- package/src/supply-chain/index.js.map +0 -1
- package/src/supply-chain/inventory.js.map +0 -1
- package/src/supply-chain/license-expression.js.map +0 -1
- package/src/supply-chain/pnpm-toolchain-authority.js.map +0 -1
- package/src/supply-chain/policy.js.map +0 -1
- package/src/supply-chain/publication.js.map +0 -1
- package/src/supply-chain/sbom.js.map +0 -1
- package/src/supply-chain/scanner.js.map +0 -1
- package/src/supply-chain/vendored-source.js.map +0 -1
- package/src/testing-evidence/fixture-scope.js.map +0 -1
- package/src/testing-evidence/index.js.map +0 -1
- package/src/testing-evidence/quarantine.js.map +0 -1
- package/src/testing-evidence/result.js.map +0 -1
- package/src/testing-evidence/runner-adapter.js.map +0 -1
- package/src/testing-evidence/sensitive-artifacts.js.map +0 -1
- package/src/validation.js.map +0 -1
- package/src/work-markers/index.js.map +0 -1
- package/src/work-markers/work-markers.js.map +0 -1
- package/src/workload-roles/account-baseline.js.map +0 -1
- package/src/workload-roles/authority.js.map +0 -1
- package/src/workload-roles/aws-adapter.js.map +0 -1
- package/src/workload-roles/aws-internal-handler.js.map +0 -1
- package/src/workload-roles/aws-s3-state.js.map +0 -1
- package/src/workload-roles/aws-sdk-control-plane.js.map +0 -1
- package/src/workload-roles/boundary.js.map +0 -1
- package/src/workload-roles/convergence.js.map +0 -1
- package/src/workload-roles/effective-policy.js.map +0 -1
- package/src/workload-roles/handler.js.map +0 -1
- package/src/workload-roles/history.js.map +0 -1
- package/src/workload-roles/index.js.map +0 -1
- package/src/workload-roles/injection.js.map +0 -1
- package/src/workload-roles/manifest.js.map +0 -1
- package/src/workload-roles/provisioner.js.map +0 -1
- package/src/workload-roles/registration.js.map +0 -1
- package/src/workload-roles/stage-boundary.js.map +0 -1
- package/src/workload-roles/standard-slice.js.map +0 -1
|
@@ -4,6 +4,7 @@ exports.PRODUCT_PERFORMANCE_SEEDED_PATHS = void 0;
|
|
|
4
4
|
exports.renderProductPerformanceFiles = renderProductPerformanceFiles;
|
|
5
5
|
const built_in_plan_shared_js_1 = require("./built-in-plan-shared.js");
|
|
6
6
|
const index_js_1 = require("../../performance/index.js");
|
|
7
|
+
const built_in_plan_key_value_performance_js_1 = require("./built-in-plan-key-value-performance.js");
|
|
7
8
|
exports.PRODUCT_PERFORMANCE_SEEDED_PATHS = [
|
|
8
9
|
'docs/runbooks/performance-capacity-cost.md',
|
|
9
10
|
'performance/aggregate-count-provider.ts',
|
|
@@ -13,11 +14,31 @@ exports.PRODUCT_PERFORMANCE_SEEDED_PATHS = [
|
|
|
13
14
|
'performance/policy.json',
|
|
14
15
|
];
|
|
15
16
|
/** @internal */
|
|
16
|
-
function renderProductPerformanceFiles(name) {
|
|
17
|
+
function renderProductPerformanceFiles(name, deploymentProfile = 'starter') {
|
|
18
|
+
const databaseAdapter = 'ebk-dynamodb-v1';
|
|
19
|
+
const asyncAdapter = 'ebk-dynamodb-async-v1';
|
|
20
|
+
const databaseSignal = 'dynamodb:protected-request-budget-utilization-percent';
|
|
21
|
+
const asyncSignal = 'dynamodb:protected-run-unprocessed-effects-percent';
|
|
17
22
|
const pascalName = name
|
|
18
23
|
.split('-')
|
|
19
24
|
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
20
25
|
.join('');
|
|
26
|
+
const costDefaults = deploymentProfile === 'starter'
|
|
27
|
+
? {
|
|
28
|
+
accountMonthlyMaximumUsd: 250,
|
|
29
|
+
anomalyThresholdUsd: 10,
|
|
30
|
+
pilotMonthlyMaximumUsd: 50,
|
|
31
|
+
}
|
|
32
|
+
: {
|
|
33
|
+
accountMonthlyMaximumUsd: 1_000,
|
|
34
|
+
anomalyThresholdUsd: 50,
|
|
35
|
+
pilotMonthlyMaximumUsd: 250,
|
|
36
|
+
};
|
|
37
|
+
const rehearsalStage = deploymentProfile === 'starter' ? 'development' : 'staging';
|
|
38
|
+
const rehearsalStageTitle = rehearsalStage === 'development' ? 'Development' : 'Staging';
|
|
39
|
+
const protectedPerformanceStages = deploymentProfile === 'starter'
|
|
40
|
+
? ['development', 'production']
|
|
41
|
+
: ['staging', 'production'];
|
|
21
42
|
return {
|
|
22
43
|
'infra/performance-cost-controls.ts': `import {
|
|
23
44
|
createFoundationAccountCostControlPlan,
|
|
@@ -53,6 +74,7 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
53
74
|
const foundationAccountCostControl = createFoundationAccountCostControlPlan({
|
|
54
75
|
evaluatedAt,
|
|
55
76
|
policy: accountCostPolicy,
|
|
77
|
+
rehearsalStage: '${rehearsalStage}',
|
|
56
78
|
region: process.env.AWS_REGION,
|
|
57
79
|
stage: $app.stage,
|
|
58
80
|
workspace: input.workspace,
|
|
@@ -61,6 +83,7 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
61
83
|
accountBudgetAuthority: foundationAccountCostControl.authority,
|
|
62
84
|
evaluatedAt,
|
|
63
85
|
policy: performancePolicy,
|
|
86
|
+
rehearsalStage: '${rehearsalStage}',
|
|
64
87
|
region: process.env.AWS_REGION,
|
|
65
88
|
stage: $app.stage,
|
|
66
89
|
workspace: input.workspace,
|
|
@@ -119,39 +142,10 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
119
142
|
timeUnit: plan.pilotBudget.timeUnit,
|
|
120
143
|
})
|
|
121
144
|
: undefined;
|
|
122
|
-
const anomalyMonitor = plan.anomaly
|
|
123
|
-
? new aws.costexplorer.AnomalyMonitor(
|
|
124
|
-
'${pascalName}CostAnomalyMonitor',
|
|
125
|
-
{
|
|
126
|
-
monitorSpecification: plan.anomaly.monitor.monitorSpecification,
|
|
127
|
-
monitorType: plan.anomaly.monitor.monitorType,
|
|
128
|
-
name: plan.anomaly.monitor.name,
|
|
129
|
-
tags,
|
|
130
|
-
},
|
|
131
|
-
)
|
|
132
|
-
: undefined;
|
|
133
|
-
const anomalySubscription =
|
|
134
|
-
plan.anomaly && anomalyMonitor
|
|
135
|
-
? new aws.costexplorer.AnomalySubscription(
|
|
136
|
-
'${pascalName}CostAnomalySubscription',
|
|
137
|
-
{
|
|
138
|
-
frequency: plan.anomaly.subscription.frequency,
|
|
139
|
-
monitorArnLists: [anomalyMonitor.arn],
|
|
140
|
-
name: plan.anomaly.subscription.name,
|
|
141
|
-
subscribers: [
|
|
142
|
-
{ address: input.alertTopicArn, type: 'SNS' },
|
|
143
|
-
],
|
|
144
|
-
tags,
|
|
145
|
-
thresholdExpression:
|
|
146
|
-
plan.anomaly.subscription.thresholdExpression,
|
|
147
|
-
},
|
|
148
|
-
{ dependsOn: [anomalyMonitor] },
|
|
149
|
-
)
|
|
150
|
-
: undefined;
|
|
151
145
|
return {
|
|
152
146
|
accountBudgetAuthority: deployedAccountBudgetAuthority,
|
|
153
|
-
anomalyMonitor,
|
|
154
|
-
anomalySubscription,
|
|
147
|
+
anomalyMonitor: undefined,
|
|
148
|
+
anomalySubscription: undefined,
|
|
155
149
|
materialDigest: plan.materialDigest,
|
|
156
150
|
pilotBudget,
|
|
157
151
|
policyDigest: plan.policyDigest,
|
|
@@ -215,7 +209,7 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
215
209
|
population: 'all',
|
|
216
210
|
scenarioRef: 'scenario:normal-month',
|
|
217
211
|
status: 'example',
|
|
218
|
-
threshold:
|
|
212
|
+
threshold: costDefaults.accountMonthlyMaximumUsd,
|
|
219
213
|
unit: 'usd',
|
|
220
214
|
},
|
|
221
215
|
],
|
|
@@ -241,19 +235,19 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
241
235
|
kind: 'async-worker',
|
|
242
236
|
protectionRef: 'control:async-worker-concurrency',
|
|
243
237
|
quotaMaximum: null,
|
|
244
|
-
saturationSignalRef:
|
|
238
|
+
saturationSignalRef: asyncSignal,
|
|
245
239
|
status: 'requires-adopter-value',
|
|
246
240
|
},
|
|
247
241
|
{
|
|
248
|
-
capacityUnit: '
|
|
242
|
+
capacityUnit: 'concurrent-requests',
|
|
249
243
|
configuredMaximum: null,
|
|
250
244
|
downstreamMaximum: null,
|
|
251
|
-
failureMode: '
|
|
245
|
+
failureMode: 'request-latency-or-throttling',
|
|
252
246
|
id: 'database',
|
|
253
247
|
kind: 'database',
|
|
254
|
-
protectionRef: 'control:database-
|
|
248
|
+
protectionRef: 'control:database-request-concurrency',
|
|
255
249
|
quotaMaximum: null,
|
|
256
|
-
saturationSignalRef:
|
|
250
|
+
saturationSignalRef: databaseSignal,
|
|
257
251
|
status: 'requires-adopter-value',
|
|
258
252
|
},
|
|
259
253
|
{
|
|
@@ -270,13 +264,13 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
270
264
|
},
|
|
271
265
|
],
|
|
272
266
|
cost: {
|
|
273
|
-
accountMonthlyMaximumUsd:
|
|
267
|
+
accountMonthlyMaximumUsd: costDefaults.accountMonthlyMaximumUsd,
|
|
274
268
|
actualNotificationThresholdPercent: 80,
|
|
275
269
|
anomalyRouteRef: 'alarm:cost-anomaly',
|
|
276
|
-
anomalyThresholdUsd:
|
|
270
|
+
anomalyThresholdUsd: costDefaults.anomalyThresholdUsd,
|
|
277
271
|
forecastNotificationThresholdPercent: 100,
|
|
278
272
|
notificationRoute: 'foundation-alert-topic',
|
|
279
|
-
pilotMonthlyMaximumUsd:
|
|
273
|
+
pilotMonthlyMaximumUsd: costDefaults.pilotMonthlyMaximumUsd,
|
|
280
274
|
sharedCostAllocationRef: 'performance/cost-allocation.json',
|
|
281
275
|
status: 'example',
|
|
282
276
|
testRunMaximumUsd: 25,
|
|
@@ -288,7 +282,7 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
288
282
|
},
|
|
289
283
|
kind: 'ebk-performance-policy',
|
|
290
284
|
load: {
|
|
291
|
-
allowedProtectedStages: [
|
|
285
|
+
allowedProtectedStages: [rehearsalStage],
|
|
292
286
|
maximumConcurrency: 100,
|
|
293
287
|
maximumDurationSeconds: 1_800,
|
|
294
288
|
maximumEstimatedCostUsd: 25,
|
|
@@ -308,8 +302,6 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
308
302
|
'ebk:framework-version',
|
|
309
303
|
'ebk:managed-by',
|
|
310
304
|
'ebk:owner',
|
|
311
|
-
'ebk:production-profile',
|
|
312
|
-
'ebk:repository',
|
|
313
305
|
'ebk:slice',
|
|
314
306
|
'ebk:stage',
|
|
315
307
|
'ebk:workspace',
|
|
@@ -332,22 +324,22 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
332
324
|
},
|
|
333
325
|
{
|
|
334
326
|
adapterStatus: 'managed',
|
|
335
|
-
adapterId:
|
|
327
|
+
adapterId: asyncAdapter,
|
|
336
328
|
demandShape: 'bounded-flash-burst-and-recovery',
|
|
337
329
|
disabledUntilAdopted: true,
|
|
338
330
|
estimatedCostUsdPerRequest: 0.00002,
|
|
339
|
-
id: 'async-burst',
|
|
340
|
-
saturationSignalRef:
|
|
331
|
+
id: 'async-key-value-burst',
|
|
332
|
+
saturationSignalRef: asyncSignal,
|
|
341
333
|
workload: 'async-worker',
|
|
342
334
|
},
|
|
343
335
|
{
|
|
344
336
|
adapterStatus: 'managed',
|
|
345
|
-
adapterId:
|
|
346
|
-
demandShape: '
|
|
337
|
+
adapterId: databaseAdapter,
|
|
338
|
+
demandShape: 'bounded-write-and-consistent-read',
|
|
347
339
|
disabledUntilAdopted: true,
|
|
348
340
|
estimatedCostUsdPerRequest: 0.0001,
|
|
349
|
-
id: 'database-
|
|
350
|
-
saturationSignalRef:
|
|
341
|
+
id: 'database-read-write',
|
|
342
|
+
saturationSignalRef: databaseSignal,
|
|
351
343
|
workload: 'database',
|
|
352
344
|
},
|
|
353
345
|
{
|
|
@@ -428,14 +420,14 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
428
420
|
accountBudgetBinding: 'foundation-discovery-schema-v6-policy-digest-and-amount',
|
|
429
421
|
accountBudgetInfrastructure: 'packages/foundation/infra/foundation.ts',
|
|
430
422
|
accountBudgetOwner: 'foundation',
|
|
431
|
-
accountBudgetStages: [
|
|
432
|
-
anomalyMonitorScope: '
|
|
433
|
-
|
|
423
|
+
accountBudgetStages: [rehearsalStage, 'production'],
|
|
424
|
+
anomalyMonitorScope: 'foundation-production-account-aws-services',
|
|
425
|
+
anomalySubscriptionOwner: 'foundation',
|
|
434
426
|
automaticSpendActions: 'forbidden',
|
|
435
427
|
infrastructure: 'infra/performance-cost-controls.ts',
|
|
436
428
|
owner: 'performance/policy.json#owner',
|
|
437
429
|
pilotBudgetOwner: 'product-slice',
|
|
438
|
-
pilotBudgetStage:
|
|
430
|
+
pilotBudgetStage: rehearsalStage,
|
|
439
431
|
policy: 'performance/policy.json#cost',
|
|
440
432
|
route: 'foundation-alert-topic',
|
|
441
433
|
status: 'blocked-until-cost-policy-adopted',
|
|
@@ -450,13 +442,13 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
450
442
|
evidence: {
|
|
451
443
|
exactReleaseRequiredForProtectedResults: true,
|
|
452
444
|
provenanceLabels: ['estimate', 'test', 'actual'],
|
|
453
|
-
|
|
445
|
+
rehearsalIsNotProduction: true,
|
|
454
446
|
},
|
|
455
447
|
liveEvidence: {
|
|
456
448
|
accountBudgetAndAnomalyRoute: 'required-pre-v1',
|
|
457
449
|
actualBillingAndTwoUnitCosts: 'required-pre-v1',
|
|
458
450
|
coldAndWarmLambdaNextPaths: 'required-pre-v1',
|
|
459
|
-
databaseColdResumeAndIdleCost: '
|
|
451
|
+
databaseColdResumeAndIdleCost: 'not-applicable-without-sql',
|
|
460
452
|
profileTransitionRehearsal: 'required-pre-v1',
|
|
461
453
|
protectedApiAsyncDatabaseLoad: 'required-pre-v1',
|
|
462
454
|
serviceRuntimeLoad: 'required-pre-v1-adopter-integration',
|
|
@@ -465,8 +457,8 @@ export function create${pascalName}PerformanceCostControls(input: {
|
|
|
465
457
|
load: {
|
|
466
458
|
allowlistedScenarioAdapters: [
|
|
467
459
|
'ebk-api-lambda-v1',
|
|
468
|
-
|
|
469
|
-
|
|
460
|
+
asyncAdapter,
|
|
461
|
+
databaseAdapter,
|
|
470
462
|
],
|
|
471
463
|
localProtectedMutationForbidden: true,
|
|
472
464
|
productionExceptionalOnly: true,
|
|
@@ -759,7 +751,7 @@ process.stdout.write(JSON.stringify(result) + '\\n');
|
|
|
759
751
|
accountFingerprint: string;
|
|
760
752
|
region: string;
|
|
761
753
|
slice: string;
|
|
762
|
-
stage: 'production' | 'staging';
|
|
754
|
+
stage: 'development' | 'production' | 'staging';
|
|
763
755
|
workspace: string;
|
|
764
756
|
}>;
|
|
765
757
|
period: Readonly<{ end: string; start: string }>;
|
|
@@ -990,7 +982,7 @@ if (
|
|
|
990
982
|
!/^(?:af|ap|ca|cn|eu|il|me|mx|sa|us)(?:-gov|-iso|-isob)?-[a-z]+-\\d$/.test(
|
|
991
983
|
environment.region,
|
|
992
984
|
) ||
|
|
993
|
-
(stage
|
|
985
|
+
!${JSON.stringify(protectedPerformanceStages)}.includes(stage)
|
|
994
986
|
) {
|
|
995
987
|
throw new Error(
|
|
996
988
|
'Aggregate environment and closed billing period are invalid.',
|
|
@@ -1492,6 +1484,33 @@ import {
|
|
|
1492
1484
|
runBoundedProtectedLoad,
|
|
1493
1485
|
validatePerformancePolicy,
|
|
1494
1486
|
} from '@empire-builder-kit/nx/performance';
|
|
1487
|
+
import { assertWorkspaceStageOwnershipForWorkspace } from '@empire-builder-kit/nx/workspace-deployment';
|
|
1488
|
+
import { resolve } from 'node:path';
|
|
1489
|
+
|
|
1490
|
+
const stage = process.env.EBK_STAGE?.trim();
|
|
1491
|
+
if (!['development', 'staging', 'production'].includes(stage)) {
|
|
1492
|
+
throw new Error('Protected load runner requires one canonical EBK stage.');
|
|
1493
|
+
}
|
|
1494
|
+
const ownership = await assertWorkspaceStageOwnershipForWorkspace(
|
|
1495
|
+
resolve(import.meta.dirname, '../../..'),
|
|
1496
|
+
stage,
|
|
1497
|
+
{
|
|
1498
|
+
...(process.env.AWS_PROFILE ? { profile: process.env.AWS_PROFILE } : {}),
|
|
1499
|
+
...(process.env.AWS_CONFIG_FILE ? { configFilepath: process.env.AWS_CONFIG_FILE } : {}),
|
|
1500
|
+
...(process.env.AWS_SHARED_CREDENTIALS_FILE
|
|
1501
|
+
? { credentialsFilepath: process.env.AWS_SHARED_CREDENTIALS_FILE }
|
|
1502
|
+
: {}),
|
|
1503
|
+
},
|
|
1504
|
+
);
|
|
1505
|
+
if (process.env.AWS_REGION?.trim() !== ownership.region) {
|
|
1506
|
+
throw new Error('Protected load runner Region differs from its exact workspace owner tuple.');
|
|
1507
|
+
}
|
|
1508
|
+
for (const name of [
|
|
1509
|
+
'AWS_ACCESS_KEY_ID',
|
|
1510
|
+
'AWS_SECRET_ACCESS_KEY',
|
|
1511
|
+
'AWS_SESSION_TOKEN',
|
|
1512
|
+
'AWS_SECURITY_TOKEN',
|
|
1513
|
+
]) delete process.env[name];
|
|
1495
1514
|
|
|
1496
1515
|
const planPath = process.env.EBK_PROTECTED_LOAD_PLAN_PATH?.trim();
|
|
1497
1516
|
const authorizationPath =
|
|
@@ -1691,6 +1710,33 @@ import {
|
|
|
1691
1710
|
createProtectedLoadPlan,
|
|
1692
1711
|
validatePerformancePolicy,
|
|
1693
1712
|
} from '@empire-builder-kit/nx/performance';
|
|
1713
|
+
import { assertWorkspaceStageOwnershipForWorkspace } from '@empire-builder-kit/nx/workspace-deployment';
|
|
1714
|
+
import { resolve } from 'node:path';
|
|
1715
|
+
|
|
1716
|
+
const stage = process.env.EBK_STAGE?.trim();
|
|
1717
|
+
if (!['development', 'staging', 'production'].includes(stage)) {
|
|
1718
|
+
throw new Error('Protected load cleanup requires one canonical EBK stage.');
|
|
1719
|
+
}
|
|
1720
|
+
const ownership = await assertWorkspaceStageOwnershipForWorkspace(
|
|
1721
|
+
resolve(import.meta.dirname, '../../..'),
|
|
1722
|
+
stage,
|
|
1723
|
+
{
|
|
1724
|
+
...(process.env.AWS_PROFILE ? { profile: process.env.AWS_PROFILE } : {}),
|
|
1725
|
+
...(process.env.AWS_CONFIG_FILE ? { configFilepath: process.env.AWS_CONFIG_FILE } : {}),
|
|
1726
|
+
...(process.env.AWS_SHARED_CREDENTIALS_FILE
|
|
1727
|
+
? { credentialsFilepath: process.env.AWS_SHARED_CREDENTIALS_FILE }
|
|
1728
|
+
: {}),
|
|
1729
|
+
},
|
|
1730
|
+
);
|
|
1731
|
+
if (process.env.AWS_REGION?.trim() !== ownership.region) {
|
|
1732
|
+
throw new Error('Protected load cleanup Region differs from its exact workspace owner tuple.');
|
|
1733
|
+
}
|
|
1734
|
+
for (const name of [
|
|
1735
|
+
'AWS_ACCESS_KEY_ID',
|
|
1736
|
+
'AWS_SECRET_ACCESS_KEY',
|
|
1737
|
+
'AWS_SESSION_TOKEN',
|
|
1738
|
+
'AWS_SECURITY_TOKEN',
|
|
1739
|
+
]) delete process.env[name];
|
|
1694
1740
|
|
|
1695
1741
|
const planPath = process.env.EBK_PROTECTED_LOAD_PLAN_PATH?.trim();
|
|
1696
1742
|
const hmacKeyPath =
|
|
@@ -1857,18 +1903,15 @@ import {
|
|
|
1857
1903
|
handleProtectedLoadCleanupEndpoint,
|
|
1858
1904
|
handleProtectedLoadScenarioEndpoint,
|
|
1859
1905
|
type ProtectedLoadEndpointBindingV1,
|
|
1860
|
-
type ProtectedLoadEndpointAdapterId,
|
|
1861
1906
|
type ProtectedLoadRequestAuthorizationV1,
|
|
1907
|
+
${' DYNAMODB_PROTECTED_REQUEST_BUDGET_MS,\n'}\
|
|
1862
1908
|
} from '@empire-builder-kit/runtime/performance';
|
|
1863
|
-
import {
|
|
1864
|
-
import {
|
|
1909
|
+
${`import { dataStore } from '../../../../../data/key-value';
|
|
1910
|
+
import { createPerformancePersistence } from '../../../../../performance/persistence';`}
|
|
1865
1911
|
import { Secrets } from '../../../../../secrets/declarations';
|
|
1866
1912
|
import { createStandardSliceSecretRuntime } from '../../../../../secrets/runtime';
|
|
1867
1913
|
|
|
1868
|
-
type ManagedAdapterId =
|
|
1869
|
-
ProtectedLoadEndpointAdapterId,
|
|
1870
|
-
'ebk-service-v1'
|
|
1871
|
-
>;
|
|
1914
|
+
type ManagedAdapterId = 'ebk-api-lambda-v1' | '${asyncAdapter}' | '${databaseAdapter}';
|
|
1872
1915
|
|
|
1873
1916
|
function required(name: string): string {
|
|
1874
1917
|
const value = process.env[name]?.trim();
|
|
@@ -1879,11 +1922,21 @@ function required(name: string): string {
|
|
|
1879
1922
|
type EndpointSecretRuntime = ReturnType<
|
|
1880
1923
|
typeof createStandardSliceSecretRuntime
|
|
1881
1924
|
>;
|
|
1925
|
+
const protectedPerformanceStages = ${JSON.stringify(protectedPerformanceStages)} as const;
|
|
1926
|
+
type ProtectedPerformanceStage = (typeof protectedPerformanceStages)[number];
|
|
1927
|
+
|
|
1928
|
+
function isProtectedPerformanceStage(
|
|
1929
|
+
value: string | undefined,
|
|
1930
|
+
): value is ProtectedPerformanceStage {
|
|
1931
|
+
return value !== undefined &&
|
|
1932
|
+
(protectedPerformanceStages as readonly string[]).includes(value);
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1882
1935
|
let endpointSecretRuntime: EndpointSecretRuntime | undefined;
|
|
1883
|
-
let endpointSecretRuntimeStage:
|
|
1936
|
+
let endpointSecretRuntimeStage: ProtectedPerformanceStage | undefined;
|
|
1884
1937
|
|
|
1885
1938
|
function performanceSecretRuntime(
|
|
1886
|
-
stage:
|
|
1939
|
+
stage: ProtectedPerformanceStage,
|
|
1887
1940
|
): EndpointSecretRuntime {
|
|
1888
1941
|
if (
|
|
1889
1942
|
endpointSecretRuntimeStage !== undefined &&
|
|
@@ -1906,12 +1959,12 @@ async function withEndpointBinding<Result>(
|
|
|
1906
1959
|
const stage = process.env.EBK_STAGE;
|
|
1907
1960
|
if (
|
|
1908
1961
|
process.env.EBK_PERFORMANCE_LOAD_ENABLED !== 'true' ||
|
|
1909
|
-
(stage
|
|
1962
|
+
!isProtectedPerformanceStage(stage)
|
|
1910
1963
|
) {
|
|
1911
1964
|
throw new Error('protected-performance-endpoint-disabled');
|
|
1912
1965
|
}
|
|
1913
1966
|
return performanceSecretRuntime(stage).runWithSecret({
|
|
1914
|
-
declaration: Secrets
|
|
1967
|
+
declaration: Secrets.GeneratedPerformanceLoadHmacKeys,
|
|
1915
1968
|
isAuthenticationFailure: () => false,
|
|
1916
1969
|
operation: (hmacKeys) =>
|
|
1917
1970
|
operation({
|
|
@@ -1996,396 +2049,7 @@ function memorySaturation(): number {
|
|
|
1996
2049
|
return Math.min(100, (memory.heapUsed / memory.heapTotal) * 100);
|
|
1997
2050
|
}
|
|
1998
2051
|
|
|
1999
|
-
|
|
2000
|
-
return [
|
|
2001
|
-
effectId.slice(0, 8),
|
|
2002
|
-
effectId.slice(8, 12),
|
|
2003
|
-
'4' + effectId.slice(13, 16),
|
|
2004
|
-
'8' + effectId.slice(17, 20),
|
|
2005
|
-
effectId.slice(20, 32),
|
|
2006
|
-
].join('-');
|
|
2007
|
-
}
|
|
2008
|
-
|
|
2009
|
-
interface ProtectedPerformanceRunRow {
|
|
2010
|
-
adapterId: string;
|
|
2011
|
-
cleanupStartedAt: Date | null;
|
|
2012
|
-
createdAt: Date;
|
|
2013
|
-
expiresAt: Date;
|
|
2014
|
-
maximumRequests: number;
|
|
2015
|
-
releaseMaterialDigest: string;
|
|
2016
|
-
runId: string;
|
|
2017
|
-
scenarioId: string;
|
|
2018
|
-
sourceCommit: string;
|
|
2019
|
-
stage: string;
|
|
2020
|
-
}
|
|
2021
|
-
|
|
2022
|
-
function matchesProtectedPerformanceRun(
|
|
2023
|
-
actual: ProtectedPerformanceRunRow | undefined,
|
|
2024
|
-
authorization: ProtectedLoadRequestAuthorizationV1,
|
|
2025
|
-
): actual is ProtectedPerformanceRunRow {
|
|
2026
|
-
return (
|
|
2027
|
-
actual !== undefined &&
|
|
2028
|
-
actual.adapterId === authorization.adapterId &&
|
|
2029
|
-
actual.createdAt.toISOString() === authorization.createdAt &&
|
|
2030
|
-
actual.expiresAt.toISOString() === authorization.expiresAt &&
|
|
2031
|
-
actual.maximumRequests === authorization.maximumRequests &&
|
|
2032
|
-
actual.releaseMaterialDigest ===
|
|
2033
|
-
authorization.release.releaseMaterialDigest &&
|
|
2034
|
-
actual.runId === authorization.runId &&
|
|
2035
|
-
actual.scenarioId === authorization.scenarioId &&
|
|
2036
|
-
actual.sourceCommit === authorization.release.sourceCommit &&
|
|
2037
|
-
actual.stage === authorization.stage
|
|
2038
|
-
);
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
|
-
export async function reserveRequest(
|
|
2042
|
-
authorization: ProtectedLoadRequestAuthorizationV1,
|
|
2043
|
-
) {
|
|
2044
|
-
return withPrimaryDatabase(
|
|
2045
|
-
{ correlationId: randomUUID() },
|
|
2046
|
-
'web-server',
|
|
2047
|
-
async (client) => {
|
|
2048
|
-
await client.query('BEGIN');
|
|
2049
|
-
try {
|
|
2050
|
-
await client.query(
|
|
2051
|
-
\`INSERT INTO performance_load_runs
|
|
2052
|
-
(plan_digest, run_id, adapter_id, scenario_id, stage,
|
|
2053
|
-
source_commit, release_material_digest, maximum_requests,
|
|
2054
|
-
created_at, expires_at)
|
|
2055
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::timestamptz,
|
|
2056
|
-
$10::timestamptz)
|
|
2057
|
-
ON CONFLICT (plan_digest) DO NOTHING\`,
|
|
2058
|
-
[
|
|
2059
|
-
authorization.planMaterialDigest,
|
|
2060
|
-
authorization.runId,
|
|
2061
|
-
authorization.adapterId,
|
|
2062
|
-
authorization.scenarioId,
|
|
2063
|
-
authorization.stage,
|
|
2064
|
-
authorization.release.sourceCommit,
|
|
2065
|
-
authorization.release.releaseMaterialDigest,
|
|
2066
|
-
authorization.maximumRequests,
|
|
2067
|
-
authorization.createdAt,
|
|
2068
|
-
authorization.expiresAt,
|
|
2069
|
-
],
|
|
2070
|
-
);
|
|
2071
|
-
const run = await client.query<ProtectedPerformanceRunRow>(
|
|
2072
|
-
\`SELECT
|
|
2073
|
-
adapter_id AS "adapterId",
|
|
2074
|
-
cleanup_started_at AS "cleanupStartedAt",
|
|
2075
|
-
created_at AS "createdAt",
|
|
2076
|
-
expires_at AS "expiresAt",
|
|
2077
|
-
maximum_requests AS "maximumRequests",
|
|
2078
|
-
release_material_digest AS "releaseMaterialDigest",
|
|
2079
|
-
run_id AS "runId",
|
|
2080
|
-
scenario_id AS "scenarioId",
|
|
2081
|
-
source_commit AS "sourceCommit",
|
|
2082
|
-
stage
|
|
2083
|
-
FROM performance_load_runs
|
|
2084
|
-
WHERE plan_digest = $1
|
|
2085
|
-
FOR UPDATE\`,
|
|
2086
|
-
[authorization.planMaterialDigest],
|
|
2087
|
-
);
|
|
2088
|
-
const actual = run.rows[0];
|
|
2089
|
-
if (
|
|
2090
|
-
!matchesProtectedPerformanceRun(actual, authorization) ||
|
|
2091
|
-
actual.cleanupStartedAt !== null
|
|
2092
|
-
) {
|
|
2093
|
-
throw new Error('protected-performance-run-collision');
|
|
2094
|
-
}
|
|
2095
|
-
const claimed = await client.query(
|
|
2096
|
-
\`INSERT INTO performance_load_requests
|
|
2097
|
-
(plan_digest, request_ordinal, effect_id)
|
|
2098
|
-
VALUES ($1, $2, $3)
|
|
2099
|
-
ON CONFLICT (plan_digest, request_ordinal) DO NOTHING\`,
|
|
2100
|
-
[
|
|
2101
|
-
authorization.planMaterialDigest,
|
|
2102
|
-
authorization.requestOrdinal,
|
|
2103
|
-
authorization.effectId,
|
|
2104
|
-
],
|
|
2105
|
-
);
|
|
2106
|
-
if (claimed.rowCount !== 1) {
|
|
2107
|
-
throw new Error('protected-performance-request-replayed');
|
|
2108
|
-
}
|
|
2109
|
-
await client.query('COMMIT');
|
|
2110
|
-
return 'claimed' as const;
|
|
2111
|
-
} catch (error) {
|
|
2112
|
-
await client.query('ROLLBACK').catch(() => undefined);
|
|
2113
|
-
throw error;
|
|
2114
|
-
}
|
|
2115
|
-
},
|
|
2116
|
-
);
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
export async function databaseExecution(
|
|
2120
|
-
adapterId: 'ebk-async-worker-v1' | 'ebk-database-v1',
|
|
2121
|
-
effectId: string,
|
|
2122
|
-
authorization: ProtectedLoadRequestAuthorizationV1,
|
|
2123
|
-
) {
|
|
2124
|
-
return withPrimaryDatabase(
|
|
2125
|
-
{ correlationId: randomUUID() },
|
|
2126
|
-
'web-server',
|
|
2127
|
-
async (client) => {
|
|
2128
|
-
await client.query('BEGIN');
|
|
2129
|
-
try {
|
|
2130
|
-
const run = await client.query<ProtectedPerformanceRunRow>(
|
|
2131
|
-
\`SELECT
|
|
2132
|
-
adapter_id AS "adapterId",
|
|
2133
|
-
cleanup_started_at AS "cleanupStartedAt",
|
|
2134
|
-
created_at AS "createdAt",
|
|
2135
|
-
expires_at AS "expiresAt",
|
|
2136
|
-
maximum_requests AS "maximumRequests",
|
|
2137
|
-
release_material_digest AS "releaseMaterialDigest",
|
|
2138
|
-
run_id AS "runId",
|
|
2139
|
-
scenario_id AS "scenarioId",
|
|
2140
|
-
source_commit AS "sourceCommit",
|
|
2141
|
-
stage
|
|
2142
|
-
FROM performance_load_runs
|
|
2143
|
-
WHERE plan_digest = $1
|
|
2144
|
-
FOR UPDATE\`,
|
|
2145
|
-
[authorization.planMaterialDigest],
|
|
2146
|
-
);
|
|
2147
|
-
const activeRun = run.rows[0];
|
|
2148
|
-
if (
|
|
2149
|
-
!matchesProtectedPerformanceRun(activeRun, authorization) ||
|
|
2150
|
-
activeRun.cleanupStartedAt !== null
|
|
2151
|
-
) {
|
|
2152
|
-
throw new Error('protected-performance-run-cleaning');
|
|
2153
|
-
}
|
|
2154
|
-
if (adapterId === 'ebk-async-worker-v1') {
|
|
2155
|
-
const inserted = await client.query(
|
|
2156
|
-
\`INSERT INTO performance_load_async_effects
|
|
2157
|
-
(effect_id, plan_digest, run_id, expires_at)
|
|
2158
|
-
VALUES ($1, $2, $3, now() + INTERVAL '24 hours')
|
|
2159
|
-
ON CONFLICT (effect_id) DO NOTHING\`,
|
|
2160
|
-
[
|
|
2161
|
-
effectId,
|
|
2162
|
-
authorization.planMaterialDigest,
|
|
2163
|
-
authorization.runId,
|
|
2164
|
-
],
|
|
2165
|
-
);
|
|
2166
|
-
const identity = await client.query<{
|
|
2167
|
-
planDigest: string;
|
|
2168
|
-
runId: string;
|
|
2169
|
-
}>(
|
|
2170
|
-
\`SELECT
|
|
2171
|
-
plan_digest AS "planDigest",
|
|
2172
|
-
run_id AS "runId"
|
|
2173
|
-
FROM performance_load_async_effects
|
|
2174
|
-
WHERE effect_id = $1\`,
|
|
2175
|
-
[effectId],
|
|
2176
|
-
);
|
|
2177
|
-
if (
|
|
2178
|
-
identity.rows[0]?.planDigest !==
|
|
2179
|
-
authorization.planMaterialDigest ||
|
|
2180
|
-
identity.rows[0]?.runId !== authorization.runId
|
|
2181
|
-
) {
|
|
2182
|
-
throw new Error('protected-performance-effect-collision');
|
|
2183
|
-
}
|
|
2184
|
-
const pending = await client.query<{ count: string }>(
|
|
2185
|
-
\`SELECT count(*)::text AS count
|
|
2186
|
-
FROM performance_load_async_effects
|
|
2187
|
-
WHERE processed_at IS NULL AND expires_at > now()\`,
|
|
2188
|
-
);
|
|
2189
|
-
const maximum = authorization.configuredMaximum;
|
|
2190
|
-
if (!Number.isFinite(maximum) || maximum <= 0) {
|
|
2191
|
-
throw new Error('protected-performance-async-maximum-invalid');
|
|
2192
|
-
}
|
|
2193
|
-
const result = {
|
|
2194
|
-
effectState:
|
|
2195
|
-
inserted.rowCount === 1
|
|
2196
|
-
? ('created' as const)
|
|
2197
|
-
: ('already-existed' as const),
|
|
2198
|
-
saturationPercent: Math.min(
|
|
2199
|
-
100,
|
|
2200
|
-
(Number(pending.rows[0]?.count ?? 0) / maximum) * 100,
|
|
2201
|
-
),
|
|
2202
|
-
};
|
|
2203
|
-
await client.query('COMMIT');
|
|
2204
|
-
return result;
|
|
2205
|
-
}
|
|
2206
|
-
const id = effectUuid(effectId);
|
|
2207
|
-
const inserted = await client.query(
|
|
2208
|
-
\`INSERT INTO records
|
|
2209
|
-
(id, name, owner_id, run_scope, test_expires_at)
|
|
2210
|
-
VALUES (
|
|
2211
|
-
$1::uuid,
|
|
2212
|
-
'ebk-protected-performance-load',
|
|
2213
|
-
'ebk-performance',
|
|
2214
|
-
$2,
|
|
2215
|
-
now() + INTERVAL '24 hours'
|
|
2216
|
-
)
|
|
2217
|
-
ON CONFLICT (id) DO NOTHING\`,
|
|
2218
|
-
[id, authorization.planMaterialDigest],
|
|
2219
|
-
);
|
|
2220
|
-
const identity = await client.query<{
|
|
2221
|
-
name: string;
|
|
2222
|
-
ownerId: string;
|
|
2223
|
-
runScope: string;
|
|
2224
|
-
}>(
|
|
2225
|
-
\`SELECT
|
|
2226
|
-
name,
|
|
2227
|
-
owner_id AS "ownerId",
|
|
2228
|
-
run_scope AS "runScope"
|
|
2229
|
-
FROM records
|
|
2230
|
-
WHERE id = $1::uuid\`,
|
|
2231
|
-
[id],
|
|
2232
|
-
);
|
|
2233
|
-
if (
|
|
2234
|
-
identity.rows[0]?.name !== 'ebk-protected-performance-load' ||
|
|
2235
|
-
identity.rows[0]?.ownerId !== 'ebk-performance' ||
|
|
2236
|
-
identity.rows[0]?.runScope !== authorization.planMaterialDigest
|
|
2237
|
-
) {
|
|
2238
|
-
throw new Error('protected-performance-effect-collision');
|
|
2239
|
-
}
|
|
2240
|
-
const activity = await client.query<{
|
|
2241
|
-
active: string;
|
|
2242
|
-
maximum: string;
|
|
2243
|
-
}>(
|
|
2244
|
-
\`SELECT
|
|
2245
|
-
count(*)::text AS active,
|
|
2246
|
-
current_setting('max_connections') AS maximum
|
|
2247
|
-
FROM pg_stat_activity
|
|
2248
|
-
WHERE datname = current_database()\`,
|
|
2249
|
-
);
|
|
2250
|
-
const active = Number(activity.rows[0]?.active ?? 0);
|
|
2251
|
-
const maximum = Number(activity.rows[0]?.maximum ?? 0);
|
|
2252
|
-
if (!Number.isFinite(maximum) || maximum <= 0) {
|
|
2253
|
-
throw new Error('protected-performance-database-maximum-invalid');
|
|
2254
|
-
}
|
|
2255
|
-
const result = {
|
|
2256
|
-
effectState:
|
|
2257
|
-
inserted.rowCount === 1
|
|
2258
|
-
? ('created' as const)
|
|
2259
|
-
: ('already-existed' as const),
|
|
2260
|
-
saturationPercent: Math.min(100, (active / maximum) * 100),
|
|
2261
|
-
};
|
|
2262
|
-
await client.query('COMMIT');
|
|
2263
|
-
return result;
|
|
2264
|
-
} catch (error) {
|
|
2265
|
-
await client.query('ROLLBACK').catch(() => undefined);
|
|
2266
|
-
throw error;
|
|
2267
|
-
}
|
|
2268
|
-
},
|
|
2269
|
-
);
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
|
-
export async function cleanupRun(
|
|
2273
|
-
adapterId: 'ebk-async-worker-v1' | 'ebk-database-v1',
|
|
2274
|
-
authorization: ProtectedLoadRequestAuthorizationV1,
|
|
2275
|
-
) {
|
|
2276
|
-
return withPrimaryDatabase(
|
|
2277
|
-
{ correlationId: randomUUID() },
|
|
2278
|
-
'web-server',
|
|
2279
|
-
async (client) => {
|
|
2280
|
-
await client.query('BEGIN');
|
|
2281
|
-
try {
|
|
2282
|
-
await client.query(
|
|
2283
|
-
\`INSERT INTO performance_load_runs
|
|
2284
|
-
(plan_digest, run_id, adapter_id, scenario_id, stage,
|
|
2285
|
-
source_commit, release_material_digest, maximum_requests,
|
|
2286
|
-
created_at, expires_at, cleanup_started_at)
|
|
2287
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::timestamptz,
|
|
2288
|
-
$10::timestamptz, now())
|
|
2289
|
-
ON CONFLICT (plan_digest) DO NOTHING\`,
|
|
2290
|
-
[
|
|
2291
|
-
authorization.planMaterialDigest,
|
|
2292
|
-
authorization.runId,
|
|
2293
|
-
authorization.adapterId,
|
|
2294
|
-
authorization.scenarioId,
|
|
2295
|
-
authorization.stage,
|
|
2296
|
-
authorization.release.sourceCommit,
|
|
2297
|
-
authorization.release.releaseMaterialDigest,
|
|
2298
|
-
authorization.maximumRequests,
|
|
2299
|
-
authorization.createdAt,
|
|
2300
|
-
authorization.expiresAt,
|
|
2301
|
-
],
|
|
2302
|
-
);
|
|
2303
|
-
const run = await client.query<ProtectedPerformanceRunRow>(
|
|
2304
|
-
\`SELECT
|
|
2305
|
-
adapter_id AS "adapterId",
|
|
2306
|
-
cleanup_started_at AS "cleanupStartedAt",
|
|
2307
|
-
created_at AS "createdAt",
|
|
2308
|
-
expires_at AS "expiresAt",
|
|
2309
|
-
maximum_requests AS "maximumRequests",
|
|
2310
|
-
release_material_digest AS "releaseMaterialDigest",
|
|
2311
|
-
run_id AS "runId",
|
|
2312
|
-
scenario_id AS "scenarioId",
|
|
2313
|
-
source_commit AS "sourceCommit",
|
|
2314
|
-
stage
|
|
2315
|
-
FROM performance_load_runs
|
|
2316
|
-
WHERE plan_digest = $1
|
|
2317
|
-
FOR UPDATE\`,
|
|
2318
|
-
[authorization.planMaterialDigest],
|
|
2319
|
-
);
|
|
2320
|
-
if (!matchesProtectedPerformanceRun(run.rows[0], authorization)) {
|
|
2321
|
-
throw new Error('protected-performance-run-collision');
|
|
2322
|
-
}
|
|
2323
|
-
await client.query(
|
|
2324
|
-
\`UPDATE performance_load_runs
|
|
2325
|
-
SET cleanup_started_at = COALESCE(cleanup_started_at, now())
|
|
2326
|
-
WHERE plan_digest = $1\`,
|
|
2327
|
-
[authorization.planMaterialDigest],
|
|
2328
|
-
);
|
|
2329
|
-
await client.query('COMMIT');
|
|
2330
|
-
} catch (error) {
|
|
2331
|
-
await client.query('ROLLBACK').catch(() => undefined);
|
|
2332
|
-
throw error;
|
|
2333
|
-
}
|
|
2334
|
-
|
|
2335
|
-
await client.query('BEGIN');
|
|
2336
|
-
try {
|
|
2337
|
-
const removed =
|
|
2338
|
-
adapterId === 'ebk-async-worker-v1'
|
|
2339
|
-
? await client.query(
|
|
2340
|
-
\`DELETE FROM performance_load_async_effects
|
|
2341
|
-
WHERE plan_digest = $1
|
|
2342
|
-
AND run_id = $2\`,
|
|
2343
|
-
[authorization.planMaterialDigest, authorization.runId],
|
|
2344
|
-
)
|
|
2345
|
-
: await client.query(
|
|
2346
|
-
\`DELETE FROM records
|
|
2347
|
-
WHERE owner_id = 'ebk-performance'
|
|
2348
|
-
AND name = 'ebk-protected-performance-load'
|
|
2349
|
-
AND run_scope = $1\`,
|
|
2350
|
-
[authorization.planMaterialDigest],
|
|
2351
|
-
);
|
|
2352
|
-
const remaining =
|
|
2353
|
-
adapterId === 'ebk-async-worker-v1'
|
|
2354
|
-
? await client.query<{ count: string }>(
|
|
2355
|
-
\`SELECT count(*)::text AS count
|
|
2356
|
-
FROM performance_load_async_effects
|
|
2357
|
-
WHERE plan_digest = $1
|
|
2358
|
-
AND run_id = $2\`,
|
|
2359
|
-
[authorization.planMaterialDigest, authorization.runId],
|
|
2360
|
-
)
|
|
2361
|
-
: await client.query<{ count: string }>(
|
|
2362
|
-
\`SELECT count(*)::text AS count
|
|
2363
|
-
FROM records
|
|
2364
|
-
WHERE owner_id = 'ebk-performance'
|
|
2365
|
-
AND name = 'ebk-protected-performance-load'
|
|
2366
|
-
AND run_scope = $1\`,
|
|
2367
|
-
[authorization.planMaterialDigest],
|
|
2368
|
-
);
|
|
2369
|
-
const remainingEffectCount = Number(remaining.rows[0]?.count ?? 0);
|
|
2370
|
-
if (
|
|
2371
|
-
!Number.isSafeInteger(remainingEffectCount) ||
|
|
2372
|
-
remainingEffectCount !== 0
|
|
2373
|
-
) {
|
|
2374
|
-
throw new Error('protected-performance-cleanup-incomplete');
|
|
2375
|
-
}
|
|
2376
|
-
await client.query('COMMIT');
|
|
2377
|
-
return {
|
|
2378
|
-
remainingEffectCount,
|
|
2379
|
-
removedEffectCount: removed.rowCount ?? 0,
|
|
2380
|
-
};
|
|
2381
|
-
} catch (error) {
|
|
2382
|
-
await client.query('ROLLBACK').catch(() => undefined);
|
|
2383
|
-
throw error;
|
|
2384
|
-
}
|
|
2385
|
-
},
|
|
2386
|
-
);
|
|
2387
|
-
}
|
|
2388
|
-
|
|
2052
|
+
${(0, built_in_plan_key_value_performance_js_1.renderKeyValuePerformanceEndpointFunctions)()}
|
|
2389
2053
|
function refused() {
|
|
2390
2054
|
return Response.json(
|
|
2391
2055
|
{
|
|
@@ -2410,8 +2074,8 @@ export async function runPerformanceScenarioEndpoint(
|
|
|
2410
2074
|
binding,
|
|
2411
2075
|
execute: async ({ authorization, effectId }) => {
|
|
2412
2076
|
if (
|
|
2413
|
-
adapterId === '
|
|
2414
|
-
adapterId === '
|
|
2077
|
+
adapterId === '${asyncAdapter}' ||
|
|
2078
|
+
adapterId === '${databaseAdapter}'
|
|
2415
2079
|
) {
|
|
2416
2080
|
if (!effectId) throw new Error('protected-effect-required');
|
|
2417
2081
|
return databaseExecution(adapterId, effectId, authorization);
|
|
@@ -2429,7 +2093,7 @@ export async function runPerformanceScenarioEndpoint(
|
|
|
2429
2093
|
}
|
|
2430
2094
|
|
|
2431
2095
|
export async function runPerformanceCleanupEndpoint(
|
|
2432
|
-
adapterId: '
|
|
2096
|
+
adapterId: '${asyncAdapter}' | '${databaseAdapter}',
|
|
2433
2097
|
request: Request,
|
|
2434
2098
|
) {
|
|
2435
2099
|
try {
|
|
@@ -2482,11 +2146,11 @@ vi.mock('@empire-builder-kit/runtime/performance', () => ({
|
|
|
2482
2146
|
status: 200,
|
|
2483
2147
|
})),
|
|
2484
2148
|
}));
|
|
2485
|
-
vi.mock('../../../../../
|
|
2486
|
-
|
|
2487
|
-
}))
|
|
2149
|
+
${`vi.mock('../../../../../performance/persistence', () => ({
|
|
2150
|
+
createPerformancePersistence: vi.fn(),
|
|
2151
|
+
}));`}
|
|
2488
2152
|
vi.mock('../../../../../secrets/declarations', () => ({
|
|
2489
|
-
Secrets: {
|
|
2153
|
+
Secrets: { GeneratedPerformanceLoadHmacKeys: {} },
|
|
2490
2154
|
}));
|
|
2491
2155
|
vi.mock('../../../../../secrets/runtime', () => ({
|
|
2492
2156
|
createStandardSliceSecretRuntime: mocks.createSecretRuntime,
|
|
@@ -2507,7 +2171,7 @@ describe('${name} protected performance secret cache lifetime', () => {
|
|
|
2507
2171
|
process.env.EBK_PERFORMANCE_RELEASE_MATERIAL_DIGEST = 'd'.repeat(64);
|
|
2508
2172
|
process.env.EBK_PERFORMANCE_SLICE = '${name}';
|
|
2509
2173
|
process.env.EBK_SOURCE_COMMIT = 'c'.repeat(40);
|
|
2510
|
-
process.env.EBK_STAGE = '
|
|
2174
|
+
process.env.EBK_STAGE = '${rehearsalStage}';
|
|
2511
2175
|
});
|
|
2512
2176
|
|
|
2513
2177
|
it('reuses one resolver across requests so declaration TTL is effective', async () => {
|
|
@@ -2530,590 +2194,7 @@ describe('${name} protected performance secret cache lifetime', () => {
|
|
|
2530
2194
|
});
|
|
2531
2195
|
});
|
|
2532
2196
|
`,
|
|
2533
|
-
|
|
2534
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2535
|
-
import type { ProtectedLoadRequestAuthorizationV1 } from '@empire-builder-kit/runtime/performance';
|
|
2536
|
-
import { createInboxCleanupHandler } from '../async/inbox-cleanup.js';
|
|
2537
|
-
import {
|
|
2538
|
-
cleanupRun,
|
|
2539
|
-
databaseExecution,
|
|
2540
|
-
reserveRequest,
|
|
2541
|
-
} from '../web/src/app/%5F%5Febk/performance/handler.js';
|
|
2542
|
-
|
|
2543
|
-
vi.mock('server-only', () => ({}));
|
|
2544
|
-
vi.mock('../database/runtime-client.js', () => ({
|
|
2545
|
-
withPrimaryDatabase: async (
|
|
2546
|
-
_context: unknown,
|
|
2547
|
-
_workload: unknown,
|
|
2548
|
-
operation: (client: Client) => Promise<unknown>,
|
|
2549
|
-
) => {
|
|
2550
|
-
const { Client: RuntimeClient } = await import('pg');
|
|
2551
|
-
const client = new RuntimeClient({
|
|
2552
|
-
connectionString: process.env.DATABASE_URL,
|
|
2553
|
-
});
|
|
2554
|
-
await client.connect();
|
|
2555
|
-
try {
|
|
2556
|
-
return await operation(client);
|
|
2557
|
-
} finally {
|
|
2558
|
-
await client.end();
|
|
2559
|
-
}
|
|
2560
|
-
},
|
|
2561
|
-
}));
|
|
2562
|
-
|
|
2563
|
-
const databaseUrl = process.env.DATABASE_URL;
|
|
2564
|
-
if (!databaseUrl) {
|
|
2565
|
-
throw new Error(
|
|
2566
|
-
'DATABASE_URL is required for ${name} performance cleanup integration proof.',
|
|
2567
|
-
);
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
|
-
const touchedPlanDigests = new Set<string>();
|
|
2571
|
-
|
|
2572
|
-
function authorization(input: {
|
|
2573
|
-
effectId: string | null;
|
|
2574
|
-
operation: 'cleanup' | 'execute';
|
|
2575
|
-
planMaterialDigest: string;
|
|
2576
|
-
requestOrdinal?: number;
|
|
2577
|
-
}): ProtectedLoadRequestAuthorizationV1 {
|
|
2578
|
-
return {
|
|
2579
|
-
adapterId: 'ebk-async-worker-v1',
|
|
2580
|
-
configuredMaximum: 100,
|
|
2581
|
-
createdAt: '2026-07-29T12:00:00.000Z',
|
|
2582
|
-
durationSeconds: 60,
|
|
2583
|
-
effectId: input.effectId,
|
|
2584
|
-
expiresAt: '2026-07-29T13:00:00.000Z',
|
|
2585
|
-
hmacKeyId: 'integration-v1',
|
|
2586
|
-
maximumRequests: 10,
|
|
2587
|
-
operation: input.operation,
|
|
2588
|
-
planMaterialDigest: input.planMaterialDigest,
|
|
2589
|
-
release: {
|
|
2590
|
-
candidateDigest: 'c'.repeat(64),
|
|
2591
|
-
releaseId: 'integration-release',
|
|
2592
|
-
releaseMaterialDigest: 'd'.repeat(64),
|
|
2593
|
-
sourceCommit: 'b'.repeat(40),
|
|
2594
|
-
},
|
|
2595
|
-
requestOrdinal: input.requestOrdinal ?? 1,
|
|
2596
|
-
runId: 'integration-run-' + input.planMaterialDigest.slice(0, 8),
|
|
2597
|
-
saturationSignalRef:
|
|
2598
|
-
'database:protected-async-backlog-utilization-percent',
|
|
2599
|
-
scenarioId: 'async-burst',
|
|
2600
|
-
stage: 'staging',
|
|
2601
|
-
target: {
|
|
2602
|
-
accountFingerprint: 'sha256:' + 'e'.repeat(64),
|
|
2603
|
-
endpoint:
|
|
2604
|
-
'https://performance.example.test/${name}/__ebk/performance/async-worker',
|
|
2605
|
-
region: 'us-east-1',
|
|
2606
|
-
slice: '${name}',
|
|
2607
|
-
},
|
|
2608
|
-
workload: 'async-worker',
|
|
2609
|
-
};
|
|
2610
|
-
}
|
|
2611
|
-
|
|
2612
|
-
async function withClient<Result>(
|
|
2613
|
-
operation: (client: Client) => Promise<Result>,
|
|
2614
|
-
): Promise<Result> {
|
|
2615
|
-
const client = new Client({ connectionString: databaseUrl });
|
|
2616
|
-
await client.connect();
|
|
2617
|
-
try {
|
|
2618
|
-
return await operation(client);
|
|
2619
|
-
} finally {
|
|
2620
|
-
await client.end();
|
|
2621
|
-
}
|
|
2622
|
-
}
|
|
2623
|
-
|
|
2624
|
-
// A loaded-host budget: hosted runners share four cores between Vitest,
|
|
2625
|
-
// the proof registry, and the dockerized database.
|
|
2626
|
-
async function waitForActiveStatement(
|
|
2627
|
-
client: Client,
|
|
2628
|
-
fragment: string,
|
|
2629
|
-
): Promise<void> {
|
|
2630
|
-
const deadline = Date.now() + 15_000;
|
|
2631
|
-
while (Date.now() < deadline) {
|
|
2632
|
-
const active = await client.query<{ count: string }>(
|
|
2633
|
-
\`SELECT count(*)::text AS count
|
|
2634
|
-
FROM pg_stat_activity
|
|
2635
|
-
WHERE datname = current_database()
|
|
2636
|
-
AND pid <> pg_backend_pid()
|
|
2637
|
-
AND state = 'active'
|
|
2638
|
-
AND query LIKE $1\`,
|
|
2639
|
-
['%' + fragment + '%'],
|
|
2640
|
-
);
|
|
2641
|
-
if (Number(active.rows[0]?.count ?? 0) > 0) return;
|
|
2642
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
2643
|
-
}
|
|
2644
|
-
throw new Error('Timed out waiting for the adversarial database statement.');
|
|
2645
|
-
}
|
|
2646
|
-
|
|
2647
|
-
afterEach(async () => {
|
|
2648
|
-
await withClient(async (client) => {
|
|
2649
|
-
await client
|
|
2650
|
-
.query(
|
|
2651
|
-
'DROP TRIGGER IF EXISTS ebk_performance_delay_effect ON performance_load_async_effects',
|
|
2652
|
-
)
|
|
2653
|
-
.catch(() => undefined);
|
|
2654
|
-
await client
|
|
2655
|
-
.query('DROP FUNCTION IF EXISTS ebk_performance_delay_effect()')
|
|
2656
|
-
.catch(() => undefined);
|
|
2657
|
-
for (const planDigest of touchedPlanDigests) {
|
|
2658
|
-
await client.query('DELETE FROM records WHERE run_scope = $1', [
|
|
2659
|
-
planDigest,
|
|
2660
|
-
]);
|
|
2661
|
-
await client.query(
|
|
2662
|
-
'DELETE FROM performance_load_async_effects WHERE plan_digest = $1',
|
|
2663
|
-
[planDigest],
|
|
2664
|
-
);
|
|
2665
|
-
await client.query(
|
|
2666
|
-
'DELETE FROM performance_load_requests WHERE plan_digest = $1',
|
|
2667
|
-
[planDigest],
|
|
2668
|
-
);
|
|
2669
|
-
await client.query(
|
|
2670
|
-
'DELETE FROM performance_load_runs WHERE plan_digest = $1',
|
|
2671
|
-
[planDigest],
|
|
2672
|
-
);
|
|
2673
|
-
}
|
|
2674
|
-
await client.query(
|
|
2675
|
-
"DELETE FROM cleanup_deadline_reports WHERE feature = 'performance-load'",
|
|
2676
|
-
);
|
|
2677
|
-
});
|
|
2678
|
-
touchedPlanDigests.clear();
|
|
2679
|
-
});
|
|
2680
|
-
|
|
2681
|
-
describe('${name} protected performance cleanup integration', () => {
|
|
2682
|
-
it('serializes cleanup behind an in-flight effect and rejects every late effect', async () => {
|
|
2683
|
-
const planMaterialDigest = '1'.repeat(64);
|
|
2684
|
-
const effectId = '2'.repeat(64);
|
|
2685
|
-
touchedPlanDigests.add(planMaterialDigest);
|
|
2686
|
-
const executeAuthorization = authorization({
|
|
2687
|
-
effectId,
|
|
2688
|
-
operation: 'execute',
|
|
2689
|
-
planMaterialDigest,
|
|
2690
|
-
});
|
|
2691
|
-
const cleanupAuthorization = authorization({
|
|
2692
|
-
effectId: null,
|
|
2693
|
-
operation: 'cleanup',
|
|
2694
|
-
planMaterialDigest,
|
|
2695
|
-
});
|
|
2696
|
-
|
|
2697
|
-
await reserveRequest(executeAuthorization);
|
|
2698
|
-
await withClient(async (client) => {
|
|
2699
|
-
await client.query(
|
|
2700
|
-
\`CREATE OR REPLACE FUNCTION ebk_performance_delay_effect()
|
|
2701
|
-
RETURNS trigger
|
|
2702
|
-
LANGUAGE plpgsql
|
|
2703
|
-
AS $$
|
|
2704
|
-
BEGIN
|
|
2705
|
-
PERFORM pg_sleep(1);
|
|
2706
|
-
RETURN NEW;
|
|
2707
|
-
END
|
|
2708
|
-
$$\`,
|
|
2709
|
-
);
|
|
2710
|
-
await client.query(
|
|
2711
|
-
\`CREATE TRIGGER ebk_performance_delay_effect
|
|
2712
|
-
BEFORE INSERT ON performance_load_async_effects
|
|
2713
|
-
FOR EACH ROW EXECUTE FUNCTION ebk_performance_delay_effect()\`,
|
|
2714
|
-
);
|
|
2715
|
-
});
|
|
2716
|
-
|
|
2717
|
-
const observer = new Client({ connectionString: databaseUrl });
|
|
2718
|
-
await observer.connect();
|
|
2719
|
-
try {
|
|
2720
|
-
const effect = databaseExecution(
|
|
2721
|
-
'ebk-async-worker-v1',
|
|
2722
|
-
effectId,
|
|
2723
|
-
executeAuthorization,
|
|
2724
|
-
);
|
|
2725
|
-
await waitForActiveStatement(
|
|
2726
|
-
observer,
|
|
2727
|
-
'INSERT INTO performance_load_async_effects',
|
|
2728
|
-
);
|
|
2729
|
-
const cleanup = cleanupRun(
|
|
2730
|
-
'ebk-async-worker-v1',
|
|
2731
|
-
cleanupAuthorization,
|
|
2732
|
-
);
|
|
2733
|
-
await expect(effect).resolves.toMatchObject({ effectState: 'created' });
|
|
2734
|
-
await expect(cleanup).resolves.toEqual({
|
|
2735
|
-
remainingEffectCount: 0,
|
|
2736
|
-
removedEffectCount: 1,
|
|
2737
|
-
});
|
|
2738
|
-
} finally {
|
|
2739
|
-
await observer.end();
|
|
2740
|
-
}
|
|
2741
|
-
|
|
2742
|
-
await expect(
|
|
2743
|
-
databaseExecution(
|
|
2744
|
-
'ebk-async-worker-v1',
|
|
2745
|
-
'3'.repeat(64),
|
|
2746
|
-
{
|
|
2747
|
-
...executeAuthorization,
|
|
2748
|
-
effectId: '3'.repeat(64),
|
|
2749
|
-
requestOrdinal: 2,
|
|
2750
|
-
},
|
|
2751
|
-
),
|
|
2752
|
-
).rejects.toThrow('protected-performance-run-cleaning');
|
|
2753
|
-
await expect(
|
|
2754
|
-
reserveRequest({
|
|
2755
|
-
...executeAuthorization,
|
|
2756
|
-
effectId: '3'.repeat(64),
|
|
2757
|
-
requestOrdinal: 2,
|
|
2758
|
-
}),
|
|
2759
|
-
).rejects.toThrow('protected-performance-run-collision');
|
|
2760
|
-
|
|
2761
|
-
await withClient(async (client) => {
|
|
2762
|
-
const state = await client.query<{
|
|
2763
|
-
cleanupStarted: boolean;
|
|
2764
|
-
effects: string;
|
|
2765
|
-
}>(
|
|
2766
|
-
\`SELECT
|
|
2767
|
-
run.cleanup_started_at IS NOT NULL AS "cleanupStarted",
|
|
2768
|
-
(
|
|
2769
|
-
SELECT count(*)::text
|
|
2770
|
-
FROM performance_load_async_effects AS effect
|
|
2771
|
-
WHERE effect.plan_digest = run.plan_digest
|
|
2772
|
-
) AS effects
|
|
2773
|
-
FROM performance_load_runs AS run
|
|
2774
|
-
WHERE run.plan_digest = $1\`,
|
|
2775
|
-
[planMaterialDigest],
|
|
2776
|
-
);
|
|
2777
|
-
expect(state.rows).toEqual([
|
|
2778
|
-
{ cleanupStarted: true, effects: '0' },
|
|
2779
|
-
]);
|
|
2780
|
-
});
|
|
2781
|
-
});
|
|
2782
|
-
|
|
2783
|
-
it('tombstones and proves an effect-free run absent without a local ledger', async () => {
|
|
2784
|
-
const planMaterialDigest = '4'.repeat(64);
|
|
2785
|
-
touchedPlanDigests.add(planMaterialDigest);
|
|
2786
|
-
const cleanupAuthorization = authorization({
|
|
2787
|
-
effectId: null,
|
|
2788
|
-
operation: 'cleanup',
|
|
2789
|
-
planMaterialDigest,
|
|
2790
|
-
});
|
|
2791
|
-
|
|
2792
|
-
await expect(
|
|
2793
|
-
cleanupRun('ebk-async-worker-v1', cleanupAuthorization),
|
|
2794
|
-
).resolves.toEqual({
|
|
2795
|
-
remainingEffectCount: 0,
|
|
2796
|
-
removedEffectCount: 0,
|
|
2797
|
-
});
|
|
2798
|
-
await expect(
|
|
2799
|
-
cleanupRun('ebk-async-worker-v1', cleanupAuthorization),
|
|
2800
|
-
).resolves.toEqual({
|
|
2801
|
-
remainingEffectCount: 0,
|
|
2802
|
-
removedEffectCount: 0,
|
|
2803
|
-
});
|
|
2804
|
-
await expect(
|
|
2805
|
-
reserveRequest({
|
|
2806
|
-
...cleanupAuthorization,
|
|
2807
|
-
effectId: '5'.repeat(64),
|
|
2808
|
-
operation: 'execute',
|
|
2809
|
-
}),
|
|
2810
|
-
).rejects.toThrow('protected-performance-run-collision');
|
|
2811
|
-
});
|
|
2812
|
-
|
|
2813
|
-
it('expires only framework-owned due rows and retains fresh audit state', async () => {
|
|
2814
|
-
const oldPlan = '6'.repeat(64);
|
|
2815
|
-
const freshPlan = '7'.repeat(64);
|
|
2816
|
-
const expiredEffectPlan = '8'.repeat(64);
|
|
2817
|
-
const freshEffectPlan = '9'.repeat(64);
|
|
2818
|
-
for (const digest of [
|
|
2819
|
-
oldPlan,
|
|
2820
|
-
freshPlan,
|
|
2821
|
-
expiredEffectPlan,
|
|
2822
|
-
freshEffectPlan,
|
|
2823
|
-
]) {
|
|
2824
|
-
touchedPlanDigests.add(digest);
|
|
2825
|
-
}
|
|
2826
|
-
const expiredRecordId = '10000000-0000-4000-8000-000000000001';
|
|
2827
|
-
const freshRecordId = '10000000-0000-4000-8000-000000000002';
|
|
2828
|
-
const adopterRecordId = '10000000-0000-4000-8000-000000000003';
|
|
2829
|
-
|
|
2830
|
-
await withClient(async (client) => {
|
|
2831
|
-
await client.query(
|
|
2832
|
-
\`INSERT INTO performance_load_runs
|
|
2833
|
-
(plan_digest, run_id, adapter_id, scenario_id, stage,
|
|
2834
|
-
source_commit, release_material_digest, maximum_requests,
|
|
2835
|
-
created_at, expires_at)
|
|
2836
|
-
VALUES
|
|
2837
|
-
($1, 'old-run', 'ebk-async-worker-v1', 'async-burst', 'staging',
|
|
2838
|
-
$3, $4, 10, now() - INTERVAL '32 days',
|
|
2839
|
-
now() - INTERVAL '31 days'),
|
|
2840
|
-
($2, 'fresh-run', 'ebk-async-worker-v1', 'async-burst', 'staging',
|
|
2841
|
-
$3, $4, 10, now() - INTERVAL '30 days',
|
|
2842
|
-
now() - INTERVAL '29 days')\`,
|
|
2843
|
-
[oldPlan, freshPlan, 'b'.repeat(40), 'd'.repeat(64)],
|
|
2844
|
-
);
|
|
2845
|
-
await client.query(
|
|
2846
|
-
\`INSERT INTO performance_load_requests
|
|
2847
|
-
(plan_digest, request_ordinal, effect_id)
|
|
2848
|
-
VALUES ($1, 1, NULL), ($2, 1, NULL)\`,
|
|
2849
|
-
[oldPlan, freshPlan],
|
|
2850
|
-
);
|
|
2851
|
-
await client.query(
|
|
2852
|
-
\`INSERT INTO performance_load_async_effects
|
|
2853
|
-
(effect_id, plan_digest, run_id, expires_at)
|
|
2854
|
-
VALUES
|
|
2855
|
-
($1, $2, 'expired', now() - INTERVAL '1 minute'),
|
|
2856
|
-
($3, $4, 'fresh', now() + INTERVAL '1 day')\`,
|
|
2857
|
-
['a'.repeat(64), expiredEffectPlan, 'f'.repeat(64), freshEffectPlan],
|
|
2858
|
-
);
|
|
2859
|
-
await client.query(
|
|
2860
|
-
\`INSERT INTO records
|
|
2861
|
-
(id, name, owner_id, run_scope, test_expires_at)
|
|
2862
|
-
VALUES
|
|
2863
|
-
($1::uuid, 'ebk-protected-performance-load', 'ebk-performance',
|
|
2864
|
-
$4, now() - INTERVAL '1 minute'),
|
|
2865
|
-
($2::uuid, 'ebk-protected-performance-load', 'ebk-performance',
|
|
2866
|
-
$5, now() + INTERVAL '1 day'),
|
|
2867
|
-
($3::uuid, 'adopter-performance-data', 'adopter-owner',
|
|
2868
|
-
$4, now() - INTERVAL '1 minute')\`,
|
|
2869
|
-
[
|
|
2870
|
-
expiredRecordId,
|
|
2871
|
-
freshRecordId,
|
|
2872
|
-
adopterRecordId,
|
|
2873
|
-
expiredEffectPlan,
|
|
2874
|
-
freshEffectPlan,
|
|
2875
|
-
],
|
|
2876
|
-
);
|
|
2877
|
-
});
|
|
2878
|
-
|
|
2879
|
-
const emitted: Array<{ metricName?: string; value?: number }> = [];
|
|
2880
|
-
const handler = createInboxCleanupHandler({
|
|
2881
|
-
logger: {
|
|
2882
|
-
error: vi.fn(),
|
|
2883
|
-
info: vi.fn(),
|
|
2884
|
-
} as never,
|
|
2885
|
-
metrics: {
|
|
2886
|
-
emit: (metric: { metricName?: string; value?: number }) => {
|
|
2887
|
-
emitted.push(metric);
|
|
2888
|
-
return {} as never;
|
|
2889
|
-
},
|
|
2890
|
-
} as never,
|
|
2891
|
-
now: Date.now,
|
|
2892
|
-
withDatabase: (async (
|
|
2893
|
-
_context: unknown,
|
|
2894
|
-
_workload: unknown,
|
|
2895
|
-
operation: (client: Client) => Promise<unknown>,
|
|
2896
|
-
) => withClient(operation)) as never,
|
|
2897
|
-
});
|
|
2898
|
-
await expect(handler({ id: 'performance-expiry-proof' })).resolves.toMatchObject({
|
|
2899
|
-
performanceAuditRetentionDays: 30,
|
|
2900
|
-
performanceCleanupDeadlineHours: 24,
|
|
2901
|
-
reportedPerformanceDeadlineBreaches: 0,
|
|
2902
|
-
remainingPerformanceExpired: 0,
|
|
2903
|
-
removedPerformance: 4,
|
|
2904
|
-
});
|
|
2905
|
-
expect(emitted).toContainEqual(
|
|
2906
|
-
expect.objectContaining({
|
|
2907
|
-
metricName: 'PerformanceLoadCleanupBacklog',
|
|
2908
|
-
value: 0,
|
|
2909
|
-
}),
|
|
2910
|
-
);
|
|
2911
|
-
expect(emitted).toContainEqual(
|
|
2912
|
-
expect.objectContaining({
|
|
2913
|
-
metricName: 'PerformanceLoadCleanupDeadlineBreaches',
|
|
2914
|
-
value: 0,
|
|
2915
|
-
}),
|
|
2916
|
-
);
|
|
2917
|
-
|
|
2918
|
-
await withClient(async (client) => {
|
|
2919
|
-
const effects = await client.query<{ planDigest: string }>(
|
|
2920
|
-
\`SELECT plan_digest AS "planDigest"
|
|
2921
|
-
FROM performance_load_async_effects
|
|
2922
|
-
WHERE plan_digest = ANY($1::text[])
|
|
2923
|
-
ORDER BY plan_digest\`,
|
|
2924
|
-
[[expiredEffectPlan, freshEffectPlan]],
|
|
2925
|
-
);
|
|
2926
|
-
expect(effects.rows).toEqual([{ planDigest: freshEffectPlan }]);
|
|
2927
|
-
const records = await client.query<{ id: string }>(
|
|
2928
|
-
\`SELECT id::text AS id
|
|
2929
|
-
FROM records
|
|
2930
|
-
WHERE id = ANY($1::uuid[])
|
|
2931
|
-
ORDER BY id\`,
|
|
2932
|
-
[[expiredRecordId, freshRecordId, adopterRecordId]],
|
|
2933
|
-
);
|
|
2934
|
-
expect(records.rows).toEqual([
|
|
2935
|
-
{ id: freshRecordId },
|
|
2936
|
-
{ id: adopterRecordId },
|
|
2937
|
-
]);
|
|
2938
|
-
const audits = await client.query<{
|
|
2939
|
-
planDigest: string;
|
|
2940
|
-
requests: string;
|
|
2941
|
-
}>(
|
|
2942
|
-
\`SELECT
|
|
2943
|
-
run.plan_digest AS "planDigest",
|
|
2944
|
-
count(request.request_ordinal)::text AS requests
|
|
2945
|
-
FROM performance_load_runs AS run
|
|
2946
|
-
LEFT JOIN performance_load_requests AS request
|
|
2947
|
-
ON request.plan_digest = run.plan_digest
|
|
2948
|
-
WHERE run.plan_digest = ANY($1::text[])
|
|
2949
|
-
GROUP BY run.plan_digest
|
|
2950
|
-
ORDER BY run.plan_digest\`,
|
|
2951
|
-
[[oldPlan, freshPlan]],
|
|
2952
|
-
);
|
|
2953
|
-
expect(audits.rows).toEqual([
|
|
2954
|
-
{ planDigest: freshPlan, requests: '1' },
|
|
2955
|
-
]);
|
|
2956
|
-
});
|
|
2957
|
-
});
|
|
2958
|
-
|
|
2959
|
-
it('durably retries deadline telemetry after deleting stale protected residue', async () => {
|
|
2960
|
-
const stalePlan = 'a'.repeat(64);
|
|
2961
|
-
const staleEffectId = 'b'.repeat(64);
|
|
2962
|
-
const atDeadlinePlan = 'c'.repeat(64);
|
|
2963
|
-
const atDeadlineEffectId = 'd'.repeat(64);
|
|
2964
|
-
const beforeDeadlinePlan = 'e'.repeat(64);
|
|
2965
|
-
const beforeDeadlineEffectId = 'f'.repeat(64);
|
|
2966
|
-
const staleRecordId = '10000000-0000-4000-8000-000000000004';
|
|
2967
|
-
for (const planDigest of [
|
|
2968
|
-
stalePlan,
|
|
2969
|
-
atDeadlinePlan,
|
|
2970
|
-
beforeDeadlinePlan,
|
|
2971
|
-
]) {
|
|
2972
|
-
touchedPlanDigests.add(planDigest);
|
|
2973
|
-
}
|
|
2974
|
-
await withClient(async (client) => {
|
|
2975
|
-
await client.query(
|
|
2976
|
-
\`INSERT INTO performance_load_async_effects
|
|
2977
|
-
(effect_id, plan_digest, run_id, expires_at)
|
|
2978
|
-
VALUES
|
|
2979
|
-
($1, $2, 'stale-deadline',
|
|
2980
|
-
clock_timestamp() - INTERVAL '25 hours'),
|
|
2981
|
-
($3, $4, 'exact-deadline',
|
|
2982
|
-
clock_timestamp() - INTERVAL '24 hours'),
|
|
2983
|
-
($5, $6, 'before-deadline',
|
|
2984
|
-
clock_timestamp() - INTERVAL '23 hours 59 minutes')\`,
|
|
2985
|
-
[
|
|
2986
|
-
staleEffectId,
|
|
2987
|
-
stalePlan,
|
|
2988
|
-
atDeadlineEffectId,
|
|
2989
|
-
atDeadlinePlan,
|
|
2990
|
-
beforeDeadlineEffectId,
|
|
2991
|
-
beforeDeadlinePlan,
|
|
2992
|
-
],
|
|
2993
|
-
);
|
|
2994
|
-
await client.query(
|
|
2995
|
-
\`INSERT INTO records
|
|
2996
|
-
(id, name, owner_id, run_scope, test_expires_at)
|
|
2997
|
-
VALUES ($1::uuid, 'ebk-protected-performance-load',
|
|
2998
|
-
'ebk-performance', $2, now() - INTERVAL '25 hours')\`,
|
|
2999
|
-
[staleRecordId, stalePlan],
|
|
3000
|
-
);
|
|
3001
|
-
});
|
|
3002
|
-
|
|
3003
|
-
const failedEmissions: Array<{ metricName?: string; value?: number }> = [];
|
|
3004
|
-
const failedHandler = createInboxCleanupHandler({
|
|
3005
|
-
logger: { error: vi.fn(), info: vi.fn() } as never,
|
|
3006
|
-
metrics: {
|
|
3007
|
-
emit: (metric: { metricName?: string; value?: number }) => {
|
|
3008
|
-
failedEmissions.push(metric);
|
|
3009
|
-
return metric.metricName ===
|
|
3010
|
-
'PerformanceLoadCleanupDeadlineBreaches'
|
|
3011
|
-
? undefined
|
|
3012
|
-
: ({} as never);
|
|
3013
|
-
},
|
|
3014
|
-
} as never,
|
|
3015
|
-
now: Date.now,
|
|
3016
|
-
withDatabase: (async (
|
|
3017
|
-
_context: unknown,
|
|
3018
|
-
_workload: unknown,
|
|
3019
|
-
operation: (client: Client) => Promise<unknown>,
|
|
3020
|
-
) => withClient(operation)) as never,
|
|
3021
|
-
});
|
|
3022
|
-
await expect(
|
|
3023
|
-
failedHandler({ id: 'performance-deadline-report-failure' }),
|
|
3024
|
-
).rejects.toThrow('Performance cleanup deadline metric delivery failed.');
|
|
3025
|
-
|
|
3026
|
-
await withClient(async (client) => {
|
|
3027
|
-
const state = await client.query<{
|
|
3028
|
-
effects: string;
|
|
3029
|
-
records: string;
|
|
3030
|
-
reports: string;
|
|
3031
|
-
resourceRefs: string[];
|
|
3032
|
-
}>(
|
|
3033
|
-
\`SELECT
|
|
3034
|
-
(SELECT count(*)::text
|
|
3035
|
-
FROM performance_load_async_effects
|
|
3036
|
-
WHERE effect_id = ANY($1::text[])) AS effects,
|
|
3037
|
-
(SELECT count(*)::text
|
|
3038
|
-
FROM records
|
|
3039
|
-
WHERE id = $2::uuid) AS records,
|
|
3040
|
-
(SELECT count(*)::text
|
|
3041
|
-
FROM cleanup_deadline_reports
|
|
3042
|
-
WHERE feature = 'performance-load') AS reports,
|
|
3043
|
-
(SELECT array_agg(resource_ref ORDER BY resource_ref)
|
|
3044
|
-
FROM cleanup_deadline_reports
|
|
3045
|
-
WHERE feature = 'performance-load') AS "resourceRefs"\`,
|
|
3046
|
-
[
|
|
3047
|
-
[staleEffectId, atDeadlineEffectId, beforeDeadlineEffectId],
|
|
3048
|
-
staleRecordId,
|
|
3049
|
-
],
|
|
3050
|
-
);
|
|
3051
|
-
expect(state.rows).toEqual([
|
|
3052
|
-
{
|
|
3053
|
-
effects: '0',
|
|
3054
|
-
records: '0',
|
|
3055
|
-
reports: '3',
|
|
3056
|
-
resourceRefs: [
|
|
3057
|
-
'async-effect:' + staleEffectId,
|
|
3058
|
-
'async-effect:' + atDeadlineEffectId,
|
|
3059
|
-
'record:' + staleRecordId,
|
|
3060
|
-
].sort(),
|
|
3061
|
-
},
|
|
3062
|
-
]);
|
|
3063
|
-
});
|
|
3064
|
-
expect(JSON.stringify(failedEmissions)).not.toContain(staleEffectId);
|
|
3065
|
-
expect(JSON.stringify(failedEmissions)).not.toContain(staleRecordId);
|
|
3066
|
-
expect(JSON.stringify(failedEmissions)).not.toContain(atDeadlineEffectId);
|
|
3067
|
-
expect(JSON.stringify(failedEmissions)).not.toContain(
|
|
3068
|
-
beforeDeadlineEffectId,
|
|
3069
|
-
);
|
|
3070
|
-
|
|
3071
|
-
const retryEmissions: Array<{ metricName?: string; value?: number }> = [];
|
|
3072
|
-
const retryHandler = createInboxCleanupHandler({
|
|
3073
|
-
logger: { error: vi.fn(), info: vi.fn() } as never,
|
|
3074
|
-
metrics: {
|
|
3075
|
-
emit: (metric: { metricName?: string; value?: number }) => {
|
|
3076
|
-
retryEmissions.push(metric);
|
|
3077
|
-
return {} as never;
|
|
3078
|
-
},
|
|
3079
|
-
} as never,
|
|
3080
|
-
now: Date.now,
|
|
3081
|
-
withDatabase: (async (
|
|
3082
|
-
_context: unknown,
|
|
3083
|
-
_workload: unknown,
|
|
3084
|
-
operation: (client: Client) => Promise<unknown>,
|
|
3085
|
-
) => withClient(operation)) as never,
|
|
3086
|
-
});
|
|
3087
|
-
await expect(
|
|
3088
|
-
retryHandler({ id: 'performance-deadline-report-retry' }),
|
|
3089
|
-
).rejects.toThrow('performance-load-cleanup-deadline-breached');
|
|
3090
|
-
expect(retryEmissions).toContainEqual(
|
|
3091
|
-
expect.objectContaining({
|
|
3092
|
-
metricName: 'PerformanceLoadCleanupDeadlineBreaches',
|
|
3093
|
-
value: 3,
|
|
3094
|
-
}),
|
|
3095
|
-
);
|
|
3096
|
-
expect(JSON.stringify(retryEmissions)).not.toContain(staleEffectId);
|
|
3097
|
-
expect(JSON.stringify(retryEmissions)).not.toContain(staleRecordId);
|
|
3098
|
-
expect(JSON.stringify(retryEmissions)).not.toContain(atDeadlineEffectId);
|
|
3099
|
-
expect(JSON.stringify(retryEmissions)).not.toContain(
|
|
3100
|
-
beforeDeadlineEffectId,
|
|
3101
|
-
);
|
|
3102
|
-
|
|
3103
|
-
await withClient(async (client) => {
|
|
3104
|
-
const reports = await client.query<{ count: string }>(
|
|
3105
|
-
\`SELECT count(*)::text AS count
|
|
3106
|
-
FROM cleanup_deadline_reports
|
|
3107
|
-
WHERE feature = 'performance-load'\`,
|
|
3108
|
-
);
|
|
3109
|
-
expect(reports.rows).toEqual([{ count: '0' }]);
|
|
3110
|
-
});
|
|
3111
|
-
await expect(
|
|
3112
|
-
retryHandler({ id: 'performance-deadline-after-ack' }),
|
|
3113
|
-
).resolves.toMatchObject({ reportedPerformanceDeadlineBreaches: 0 });
|
|
3114
|
-
});
|
|
3115
|
-
});
|
|
3116
|
-
`,
|
|
2197
|
+
...{},
|
|
3117
2198
|
'web/src/app/%5F%5Febk/performance/api-lambda/route.ts': `import 'server-only';
|
|
3118
2199
|
import { runPerformanceScenarioEndpoint } from '../handler';
|
|
3119
2200
|
|
|
@@ -3125,32 +2206,74 @@ export function GET(request: Request) {
|
|
|
3125
2206
|
import { runPerformanceScenarioEndpoint } from '../handler';
|
|
3126
2207
|
|
|
3127
2208
|
export function POST(request: Request) {
|
|
3128
|
-
return runPerformanceScenarioEndpoint('
|
|
2209
|
+
return runPerformanceScenarioEndpoint('${asyncAdapter}', request);
|
|
3129
2210
|
}
|
|
3130
2211
|
`,
|
|
3131
2212
|
'web/src/app/%5F%5Febk/performance/async-worker/cleanup/route.ts': `import 'server-only';
|
|
3132
2213
|
import { runPerformanceCleanupEndpoint } from '../../handler';
|
|
3133
2214
|
|
|
3134
2215
|
export function POST(request: Request) {
|
|
3135
|
-
return runPerformanceCleanupEndpoint('
|
|
2216
|
+
return runPerformanceCleanupEndpoint('${asyncAdapter}', request);
|
|
3136
2217
|
}
|
|
3137
2218
|
`,
|
|
3138
2219
|
'web/src/app/%5F%5Febk/performance/database/route.ts': `import 'server-only';
|
|
3139
2220
|
import { runPerformanceScenarioEndpoint } from '../handler';
|
|
3140
2221
|
|
|
3141
2222
|
export function POST(request: Request) {
|
|
3142
|
-
return runPerformanceScenarioEndpoint('
|
|
2223
|
+
return runPerformanceScenarioEndpoint('${databaseAdapter}', request);
|
|
3143
2224
|
}
|
|
3144
2225
|
`,
|
|
3145
2226
|
'web/src/app/%5F%5Febk/performance/database/cleanup/route.ts': `import 'server-only';
|
|
3146
2227
|
import { runPerformanceCleanupEndpoint } from '../../handler';
|
|
3147
2228
|
|
|
3148
2229
|
export function POST(request: Request) {
|
|
3149
|
-
return runPerformanceCleanupEndpoint('
|
|
2230
|
+
return runPerformanceCleanupEndpoint('${databaseAdapter}', request);
|
|
3150
2231
|
}
|
|
3151
2232
|
`,
|
|
3152
2233
|
'docs/runbooks/performance-capacity-cost.md': `# Performance, capacity, and cost
|
|
3153
2234
|
|
|
2235
|
+
${`The default database scenarios use DynamoDB, not PostgreSQL. The database
|
|
2236
|
+
request signal measures the complete protected write/consistent-read operation
|
|
2237
|
+
against a one-second budget; it is a latency proxy, not connection count or
|
|
2238
|
+
measured DynamoDB service saturation. The async signal measures this run's
|
|
2239
|
+
unprocessed synthetic effects against its configured maximum. Expired but
|
|
2240
|
+
uncleaned effects remain counted until cleanup, so the signal is conservative.
|
|
2241
|
+
The backlog observation is a run-bound sample shared for at most one second
|
|
2242
|
+
inside each warm worker process. Concurrent requests reuse that sample instead
|
|
2243
|
+
of rescanning the pending collection per request; separate processes may sample
|
|
2244
|
+
independently. This is a bounded operational signal, never authorization or a
|
|
2245
|
+
global account-wide counter. Cleanup and async processing invalidate the local
|
|
2246
|
+
sample; exact per-request identity and effect checks are never cached.
|
|
2247
|
+
Neither signal claims account-wide capacity. Cold Aurora resume and idle cost
|
|
2248
|
+
apply only after SQL is explicitly declared; default key-value tests do not
|
|
2249
|
+
prove that relational acceptance. The signed-request, release, target, quota,
|
|
2250
|
+
and exact run-cleanup requirements are unchanged.
|
|
2251
|
+
|
|
2252
|
+
Explicit run cleanup closes the exact run before removing effects in bounded
|
|
2253
|
+
chunks. A progress response is not acceptance: the harness follows signed
|
|
2254
|
+
continuations within its existing deadline and accepts only \`run-absent\` with
|
|
2255
|
+
zero remaining effects. If interrupted or timed out, retain the run identity
|
|
2256
|
+
and retry its protected cleanup; never reopen the closed run or fabricate an
|
|
2257
|
+
absence receipt. Expiry maintenance remains the bounded recovery path.
|
|
2258
|
+
|
|
2259
|
+
Native expiry cleanup drains bounded exact pages within a shared four-minute
|
|
2260
|
+
invocation budget. It inspects at most 10,000 provider receipts and 5,000
|
|
2261
|
+
performance records per invocation; limits and time exhaustion retain cursors
|
|
2262
|
+
and report continuation. Provider receipts are removed after thirty days only
|
|
2263
|
+
when terminal; uncertain effects stay retained for reconciliation. Performance
|
|
2264
|
+
effects expire after twenty-four hours, with request/run audit history retained
|
|
2265
|
+
for thirty days after run expiry. Logical request expiry, not physical deletion
|
|
2266
|
+
or DynamoDB TTL timing, prevents replay.
|
|
2267
|
+
|
|
2268
|
+
Overdue effect deletion and its deadline report commit atomically. Reports stay
|
|
2269
|
+
durable until metric emission and acknowledgement succeed; a lost acknowledgement
|
|
2270
|
+
may repeat the breach metric. A partial scan does not emit a fabricated zero
|
|
2271
|
+
backlog. Require complete-scan evidence and no continuation or pending deadline
|
|
2272
|
+
reports before retiring an old signing key. Explicit maintenance pauses retain
|
|
2273
|
+
their existing behavior and can delay cleanup; selecting a capacity profile
|
|
2274
|
+
does not resume this worker.
|
|
2275
|
+
|
|
2276
|
+
`}\
|
|
3154
2277
|
The generated policy is deliberately an unadopted seed. Replace example budgets,
|
|
3155
2278
|
unknown capacity values, owner, review date, and allocation drivers from actual
|
|
3156
2279
|
product requirements before protected promotion. Reliability remains authority
|
|
@@ -3163,7 +2286,14 @@ Keep warm/cold and cache hit/miss populations separate. Record p50, p95, and p99
|
|
|
3163
2286
|
where meaningful, achieved throughput, the first exhausted dependency, quota
|
|
3164
2287
|
headroom, and the scenario/tool/network limits. Estimates, test measurements,
|
|
3165
2288
|
and delayed actual billing are different provenance classes. Never label a
|
|
3166
|
-
forecast or
|
|
2289
|
+
forecast or rehearsal-stage measurement as production actual.
|
|
2290
|
+
|
|
2291
|
+
Generated Product Slices relay the transactional outbox every minute in
|
|
2292
|
+
production. Nonproduction stages use a fifteen-minute relay cadence so an
|
|
2293
|
+
idle Aurora Serverless v2 database can pass its five-minute auto-pause window.
|
|
2294
|
+
That cost-aware nonproduction default intentionally permits up to fifteen
|
|
2295
|
+
minutes of event-delivery latency; use an explicit protected design change if a
|
|
2296
|
+
nonproduction product requires production-like latency.
|
|
3167
2297
|
|
|
3168
2298
|
Local commands can validate policy, budgets, capacity, and tag coverage. They
|
|
3169
2299
|
cannot run protected load. The protected workflow must call
|
|
@@ -3171,9 +2301,15 @@ cannot run protected load. The protected workflow must call
|
|
|
3171
2301
|
must bind the exact candidate, target account, Region, endpoint, maximum
|
|
3172
2302
|
concurrency/rate/requests/duration/cost, stop conditions, cleanup, and emergency
|
|
3173
2303
|
termination. Production load is exceptional and requires explicit human
|
|
3174
|
-
evidence; prefer
|
|
2304
|
+
evidence; prefer the rehearsal stage, synthetics, canaries, and production observation.
|
|
2305
|
+
The dedicated protected performance role must allow \`ssm:GetParameter\` on
|
|
2306
|
+
the one exact retained \`/ebk/<stage>/workspace-owner\` parameter and must not
|
|
2307
|
+
allow owner-record mutation. Both the runner and cleanup recheck that record
|
|
2308
|
+
before their first remote application-data mutation, bind \`AWS_REGION\` to the
|
|
2309
|
+
claimed tuple, and then remove raw AWS session credentials from their own
|
|
2310
|
+
process environment before issuing HTTP load or cleanup requests.
|
|
3175
2311
|
The three base-Slice managed adapters use fixed API/Lambda, async-worker, and database
|
|
3176
|
-
request/cleanup paths. They remain disabled unless the deployed
|
|
2312
|
+
request/cleanup paths. They remain disabled unless the deployed ${rehearsalStage}
|
|
3177
2313
|
environment binds the exact plan, run, release, source commit, scenario, signal,
|
|
3178
2314
|
adapter, exact Slice URL, and deployment-bound HMAC key ID. The workflow obtains
|
|
3179
2315
|
only the current per-Slice signer from the exact AWSCURRENT Secrets Manager
|
|
@@ -3241,14 +2377,19 @@ construction; a separately modeled commercial billing-account provider is
|
|
|
3241
2377
|
required before those partitions can adopt this path. The protected Foundation
|
|
3242
2378
|
stack is the sole owner of the account monthly actual/forecast Budget. It
|
|
3243
2379
|
publishes the exact policy digest and monthly maximum through Foundation
|
|
3244
|
-
discovery.
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
2380
|
+
discovery. Production Foundation also owns the account's one AWS Services
|
|
2381
|
+
dimensional Cost Anomaly monitor and immediate SNS subscription; this
|
|
2382
|
+
AWS-managed monitor is supported by both Organizations management and member
|
|
2383
|
+
accounts. Its absolute-impact threshold is five percent of the reviewed
|
|
2384
|
+
monthly account maximum, rounded up to the nearest cent. Every protected
|
|
2385
|
+
Product plan must bind the Foundation cost authority and adopt the same maximum
|
|
2386
|
+
before creating a cost resource. Product stacks create no account anomaly
|
|
2387
|
+
resources, avoiding unsupported custom monitors, duplicate global alerts, and
|
|
2388
|
+
the one-per-account AWS Services monitor quota. The ${rehearsalStageTitle} Product stack creates
|
|
2389
|
+
the lower pilot monthly Budget filtered to the exact
|
|
2390
|
+
\`ebk:slice\` and \`ebk:stage=${rehearsalStage}\` allocation tags. Other stages
|
|
2391
|
+
outside the profile's rehearsal and production stages create none of
|
|
2392
|
+
these global billing resources.
|
|
3252
2393
|
|
|
3253
2394
|
Both Budgets and the anomaly subscription route only to the Foundation alert
|
|
3254
2395
|
topic and retain the policy digest, semantic route, and named owner in resource
|
|
@@ -3260,7 +2401,10 @@ automatic spend-changing response. Investigate through the named owner and
|
|
|
3260
2401
|
runbook, then use a separately approved owning tool for any intervention.
|
|
3261
2402
|
|
|
3262
2403
|
Every supported resource must carry the bounded workspace/Slice/stage/owner/
|
|
3263
|
-
|
|
2404
|
+
cost-allocation/managed-by/framework tags supplied by the provider baseline.
|
|
2405
|
+
Repository and production-profile tags are supplementary identity on generated
|
|
2406
|
+
resources that explicitly use \`createStandardResourceTags\`; coverage does not
|
|
2407
|
+
claim that SST-owned resources receive them.
|
|
3264
2408
|
Unsupported resources remain visible with a reason and shared-cost allocation
|
|
3265
2409
|
reference. Never use feature, user, tenant, request, work-item, payload, or raw
|
|
3266
2410
|
error identifiers as resource tags or metric dimensions.
|
|
@@ -3283,10 +2427,12 @@ counts, evidence digests, account, Region, stage, workspace, Slice, period, and
|
|
|
3283
2427
|
release from that validated evidence; clean generation reports the missing live
|
|
3284
2428
|
evidence as incomplete.
|
|
3285
2429
|
|
|
3286
|
-
The generated scenarios cover API/Lambda, async worker,
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
2430
|
+
The generated scenarios cover API/Lambda, async worker, and DynamoDB-backed
|
|
2431
|
+
database operations. Cold Aurora resume and idle cost are separate acceptance
|
|
2432
|
+
cases only when SQL is declared. A Service extension becomes managed when its
|
|
2433
|
+
Service is generated. Scenarios are disabled until deliberately adopted. A
|
|
2434
|
+
clean generated Slice therefore reports incomplete rather than claiming
|
|
2435
|
+
capacity, cost, or live load evidence.
|
|
3290
2436
|
`,
|
|
3291
2437
|
};
|
|
3292
2438
|
}
|