Skip to content

chore(deps)(deps-dev): bump vitest from 4.1.0 to 4.1.7 in the vitest group across 1 directory#28

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/vitest-ecf7382d62
Open

chore(deps)(deps-dev): bump vitest from 4.1.0 to 4.1.7 in the vitest group across 1 directory#28
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/vitest-ecf7382d62

Conversation

@dependabot
Copy link
Copy Markdown

@dependabot dependabot Bot commented on behalf of github May 25, 2026

Bumps the vitest group with 1 update in the / directory: vitest.

Updates vitest from 4.1.0 to 4.1.7

Release notes

Sourced from vitest's releases.

v4.1.7

   🐞 Bug Fixes

    View changes on GitHub

v4.1.6

   🐞 Bug Fixes

   🏎 Performance

    View changes on GitHub

v4.1.5

   🚀 Experimental Features

   🐞 Bug Fixes

    View changes on GitHub

v4.1.4

   🚀 Experimental Features

... (truncated)

Commits
  • a09d472 chore: release v4.1.7
  • a8fd24c chore: release v4.1.6
  • 18af98c fix(browser): simplify orchestrator otel carrier (#10285)
  • 3188260 feat(browser): provide project reference in ToMatchScreenshotResolvePath (#...
  • e399846 chore: release v4.1.5
  • 7dc6d54 Revert "fix: respect diff config options in soft assertions (#8696)"
  • 9787ded fix: respect diff config options in soft assertions (#8696)
  • 325463a fix(ast-collect): recognize _vi_import prefix in static test discovery (#10...
  • 0e0ff41 feat(coverage): istanbul to support instrumenter option (#10119)
  • 663b99f fix: alias agent reporter to minimal (#10157)
  • Additional commits viewable in compare view

@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels May 25, 2026
julia-kafarska added a commit that referenced this pull request May 25, 2026
* fix(canvas): correct snap target + drag-snap stickiness for Custom Domain rows

Two bugs in connection drag:
1. dragCompatibility positions used getPortAnchorPoint (schema's
   side-distribution math) instead of getSocketCanvasPosition, so the
   snap target Y on Custom Domain row ports drifted progressively
   from the visible dot (~50px on row 0, ~0px on the last row).
2. snap was computed from currentPoint, which itself is set to the
   snapped port's position. Distance-to-self stayed at 0 so the snap
   locked onto the first port that ever won. Added cursorPoint to
   DrawingConnectionState and compute snap from it; currentPoint
   remains the visible (snapped or cursor) wire endpoint.

* refactor(secret-store): schema-driven 1->N deploy expansion

Properties + deploy model rebuilt around the canonical schema:

- Properties: name -> "Store name"; secrets list -> new `secret_bindings`
  field with two inputs per row (env-var key ← upstream ref); auto_rotate
  dropped (was inert + wrong-scoped). Bindings explained: the block does
  NOT hold secret values — values live in the cloud secret manager.
- Schema: add optional `iceType` and `deployExpansion` to
  HighLevelResource. Secret Store declares
  `deployExpansion: { partitionBy: 'bindings', nameFrom: { field: 'ref',
  fallback: 'key' }, labelFrom: 'key', tagPerEntry: ... }`.
- Lookup: getHighLevelResourceByIceType helper with a cached index.
- Generic pass: new deploy/passes/deploy-expansion.ts emits one cloud
  resource per partition entry, dedup'd within/across blocks, forwarding
  provider-shaped properties verbatim. Knows nothing about secrets.
- Translator: the previous `if (iceType === 'Security.Secret')` branch
  is replaced with `if (schemaResource?.deployExpansion)` — cardinal
  rule, no iceType hardcoded in cross-cutting code.

Adding AWS Secrets Manager or Azure Key Vault requires only an extractor
+ handler for the provider's resource type. Adding a new expanding block
requires only a `deployExpansion` declaration on its schema entry.

* refactor(canvas-renderer): drop hardcoded iceType branches via SPECIAL_NODE_RENDERERS table

Audit item #11 — cardinal rule violation. The dispatcher had three
hardcoded `if (iceType === 'X')` branches for Custom Domain, Reroute,
and Private Network, each wiring a bespoke component with its own
prop set + innerKey formula.

Consolidated into a single declarative `SPECIAL_NODE_RENDERERS` table
keyed by iceType, with factory entries that own their own component
AND innerKey formula. The dispatcher iterates this table generically
— no iceType-specific code paths remain. Adding a new bespoke renderer
extends the table; the dispatcher stays unchanged.

Dispatch order preserved by construction: the special table is
consulted BEFORE the container check so PrivateNetwork (a container
we render with a custom header) and Reroute (which the classifier
calls a container despite being a pass-through dot) hit their
bespoke factories first.

Tests: locked-in entries list + per-entry contract (element + innerKey)
+ innerKey-changes-on-relevant-data assertions for Custom Domain
(routes count) and PrivateNetwork (ingress mode).

* refactor(canvas-path): drop hardcoded iceType in socket-position via BESPOKE_SOCKET_POSITIONS table

Audit item #12 — cardinal rule violation. `getSocketCanvasPosition`
had an `if (iceType === 'Network.CustomDomain' && socketId.startsWith
('domain-out-'))` branch that resolved the bespoke row-Y for per-route
ports.

Consolidated into a `BESPOKE_SOCKET_POSITIONS` table keyed by iceType,
with resolver entries returning `Point | null` (null = fall through to
the standard layout). The dispatcher iterates this table generically
— no iceType branches in the resolver function. New bespoke layouts
register here; dispatch stays unchanged.

Tests: locked-in entries list, per-resolver contract (returns null on
miss), and dispatcher behaviour (bespoke hit, fall-through, dangling
socket id).

* refactor(properties): schema-drive tab visibility + deployment-target skip

Audit item #13 — cardinal rule violation. The tab builder and the
deployment-target card both branched on hardcoded iceType strings:

  - build-visible-tabs.ts:41-46 — config tab visible for 4 iceTypes
  - build-visible-tabs.ts:53    — domain tab visible for 2 iceTypes
  - build-visible-tabs.ts:56    — source tab visible for Source.Repository
  - node-properties-section.tsx:166 — deployment target hidden for 2 iceTypes

Consolidated into a single declarative table
`BLOCK_PROPERTY_PANEL_CONFIGS` keyed by iceType, with per-block
`forceTabs` and `skipDeploymentTarget` flags. Both the builder and the
panel iterate this table generically — no iceType branches remain.
Adding a bespoke panel experience adds an entry; both call sites pick
it up.

Per-tab SECTION rendering (CustomDomainPanel, EnvVarsEditor, etc.)
inside the panel body is still iceType-conditioned — covered by audit
item #14 in the next commit, which extends this same config table.

* refactor(properties): schema-drive per-tab section dispatch via SECTION_COMPONENTS

Audit item #14 — cardinal rule violation. The panel body had six
hardcoded `iceType === 'X'` branches choosing which bespoke section
component to render inside which tab:

  - domain tab: PublicEndpointDomainSection / CustomDomainPanel
  - config tab: EnvVarsEditor / CustomDomainPanel / PrivateNetworkPanel
                / MonitoringLogSection
  - source tab: SourceRepositorySection
  - config tab fallback: SourceRepositorySection when no source tab

Extended BLOCK_PROPERTY_PANEL_CONFIGS with a `sections: Record<TabId,
SectionId[]>` field. Each iceType declares which sections render under
which tabs; the new SECTION_COMPONENTS factory map renders them.
`renderSectionsForTab(iceType, tab, ctx)` is the generic dispatcher
the JSX calls — no iceType branches remain.

Dropped the dead `visibleTabs.length <= 1 && iceType === 'Source.
Repository'` config-tab fallback: with the source tab now always forced
for that block via forceTabs, the fallback could never fire.

Tests: per-iceType set + section-id-tab validity check.

* refactor(canvas-sizing): schema-drive bespoke node sizing via BESPOKE_NODE_SIZING table

Audit item #16 — cardinal rule violation. computeNodeSizes had three
hardcoded iceType checks driving the width/height/fold dispatch:

  - isCustomDomain = iceType === 'Network.CustomDomain'
  - isPrivateNetwork = isPrivateNetworkIce(iceType)
  - isCronJob = iceType === 'Compute.CronJob'

Plus 4 nested ternaries threading those flags through width, height,
expandedHeight, and visualHeight.

Consolidated into BESPOKE_NODE_SIZING — a Record<iceType,
BespokeSizingEntry> where each entry owns its width function, height
function, and an `alwaysExpanded` flag that opts the block out of
folding (so dynamic content like Custom Domain route slots can't
collapse to a pill).

The dispatcher does a single table lookup, falls through to the
compact-node helpers when no bespoke entry exists, and respects
`alwaysExpanded` uniformly. No iceType branches remain.

Tests: locked-in entries list + alwaysExpanded invariant.

* refactor(deploy/edge-classifier): schema-drive isolation + standalone classification

Audit items #5 + #6 — cardinal rule violations. Three hardcoded
iceType checks in cross-cutting classifier code:

  - edge-classifier.ts:65  — `parent.data?.iceType === 'Network.PrivateNetwork'`
                             in the ancestor walk
  - edge-classifier.ts:90  — guard: `iceType !== 'Network.CustomDomain'`
  - edge-classifier.ts:93  — `parent.iceType !== 'Network.PrivateNetwork'`
                             in the standalone-mode check

Introduced `BLOCK_DEPLOY_CLASSIFIERS` — a per-iceType flag table with
two flags:

  - `isolatesNetworkContext`: this iceType is a network-isolation
    container (services nested inside should be internal-only)
  - `metadataOnlyWhenStandalone`: this iceType has two deploy modes
    based on parent context (metadata-only standalone vs. deployable
    when nested in an isolation container)

Renamed predicates to match the generic shape:
  - `hasPrivateNetworkAncestor` -> `hasNetworkIsolatingAncestor`
  - `isCustomDomainStandalone`  -> `isStandaloneMetadataOnly`

Old names kept as `@deprecated` aliases so external callers and tests
don't break. Card-translator call sites switched to the new names.
Adding a new isolation container or a new standalone/nested block
adds a table entry; classifier code stays unchanged.

* refactor(deploy/passes): schema-drive public-ingress detection + domain propagation

Audit items #7 + #8 — cardinal rule violations in two passes:

  - pass-1-5-endpoint-wiring.ts:107-114 — inline `isEndpointIceType`
    branched on Network.PublicEndpoint AND Network.CustomDomain (with
    nested-in-PrivateNetwork check) to identify ingress endpoints
  - pass-1-45-domain-propagation.ts:55-58 — hardcoded srcIce / dstIce
    === 'Network.CustomDomain' to route domain propagation

Extended BLOCK_DEPLOY_CLASSIFIERS with two new flags:

  - `publicIngressMode`: 'always' (PublicEndpoint) or
    'when-nested-in-isolated-network' (CustomDomain — only counts as
    ingress when nested inside an isolatesNetworkContext container)
  - `isDomainPropagator`: true for CustomDomain — generic name so any
    future domain-source block can flow through the same pass

Added generic `isPublicIngressNode(node, allNodes)` predicate to
edge-classifier that reads the flag table. Refactored pass-1-5 to
call it; pass-1-45 reads `isDomainPropagator` directly. No iceType
strings remain in either pass.

Tests: 3 new flag assertions + 5 new isPublicIngressNode behaviour
cases (always-mode, standalone CD, nested-in-isolated-network, nested-
in-non-isolation, plain compute).

* refactor(deploy/security-rules): schema-drive iceType classifiers via SECURITY_ROLES table

Audit item #15 — cardinal rule violation. The pre-deploy security
scanner had 9+ tiny iceType-comparing classifier functions
(`isDatabase`, `isStorage`, `isGateway`, `isService`, `isAuth`,
`isSecret`, `isMonitoring`, `isVpc`, `isSubnet`, `isPrivateNetwork`,
`isVpcLike`), each inlining its own `iceType === 'X'` check.

Consolidated into a schema-shaped role table:

  - `SECURITY_ROLES_BY_ICE_TYPE`: per-iceType role list
  - `SECURITY_ROLES_BY_PREFIX`: category-prefix inheritance
    (Database./Compute./Monitoring.* automatically pick up their role
    without per-iceType table edits)
  - `hasSecurityRole(iceType, role)`: the single lookup function the
    classifier readers call

Classifier functions remain as thin one-line role readers; rule
evaluation code is unchanged. New blocks that need a security role
add an entry to the table.

Split the previous `isVpcLike` into two distinct roles:
`isolatesNestedChildren` (VPC + Subnet + PrivateNetwork — used by the
ancestor check) and `topLevelNetworkBoundary` (VPC + PrivateNetwork
only — used by Rule 6, where a Subnet at the canvas root doesn't
isolate anything). The original code conflated these into a single
overloaded helper.

* refactor(classifiers): unify connection-rules + propagation-rules iceType classifiers via shared @ice/constants table

Audit items #9 + #10 — cardinal rule violations across two packages.
Both `@ice/types/connection-rules/predicates.ts` and
`@ice/core/compute/propagation-rules.ts` had ~15 identical-ish
classifier functions (isBackend, isFrontend, isDatabase, isCache,
isStorage, isQueue, isSecrets, isCustomDomain, …), each duplicating
the same regex + prefix + exact-match bodies. The propagation-rules
copy carried a comment apologising for the duplication ("Minimal
copies of the classifiers from @ice/types/connection-rules. Kept
local to avoid cross-package moduleResolution conflicts.").

Introduced `@ice/constants/block-classifiers.ts` as the single source
of truth — a three-tier role table:

  - `BLOCK_ROLES_BY_ICE_TYPE`: exact iceType -> roles
  - `BLOCK_ROLES_BY_PREFIX`:   category prefix -> role (Compute.*,
                               Database.*, Storage.*, Messaging.*,
                               Monitoring.*, Log.*)
  - `BLOCK_ROLES_BY_REGEX`:    legacy provider-specific iceTypes
                               (PostgreSQL/Redis/Bucket/Worker/…)
                               authored under varied namespaces

`hasBlockRole(t, role)` queries all three tiers. Both packages import
it — `predicates.ts` and `propagation-rules.ts` predicate bodies are
now one-line lookups, no iceType strings remain in classifier code.

Adding a new role/iceType binding edits ONE table; both connection-
rules and propagation-rules pick it up automatically.

Tests: full equivalence preserved (4664 tests pass) + new
block-classifiers test suite covering exact / prefix / regex /
composite / negative cases + table integrity.

* refactor(deploy): dedup SERVICE_BACKEND_ICE_TYPES via shared serviceBackend role

Audit items #17 + #18 — duplicated static set in two cross-cutting
locations:

  - edge-classifier.ts:34-40 — exported SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS
  - pass-1-5-endpoint-wiring.ts:188-194 — local SERVICE_BACKEND_ICE_TYPES

Both held the same 5 iceTypes (Compute.Container/BackendAPI/SSRSite/
Worker/ServerlessFunction). Two copies, two sources of drift.

Added a new `serviceBackend` role to the shared classifier table in
@ice/constants. The 5 iceTypes register the role via
BLOCK_ROLES_BY_ICE_TYPE — Compute.StaticSite is intentionally
excluded (compiles to backendBucket via Firebase Hosting, not a NEG).

- edge-classifier exports SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS as a
  thin materialisation derived from the role table (kept for callers
  that want `.has(t)` membership).
- pass-1-5-endpoint-wiring.ts now uses `hasBlockRole(t, 'serviceBackend')`
  directly; its inline duplicate set is gone.

New iceTypes register the role in ONE table; both consumers pick it up.

* refactor(translator): drop hardcoded iceType + provider branches via type-map + override table

Audit items #1 + #2 — two critical violations in the otherwise-
provider-agnostic translator:

  - card-translator.ts:227 — `ice_type === 'Network.CustomDomain'
    ? 'gcp.compute.globalForwardingRule' : type_map[ice_type]`
    (iceType AND GCP-specific in one cross-cutting line)
  - card-translator.ts:313-322 — `if (gcp_type === 'gcp.run.service')
    ... else if (gcp_type === 'aws.ecs.service') ... else if
    (gcp_type === 'azure.containerapp.containerApp') ...` cascade
    applying provider-specific internal-mode mutations inline

#1: Added Network.CustomDomain to each provider's type-map (mirrors
PublicEndpoint — the nested CD acts as the network's gateway and
compiles to the same ingress chain on every provider; standalone CDs
are filtered earlier by isStandaloneMetadataOnly). Translator now does
a plain `type_map[ice_type]` lookup — no iceType branches.

#2: Introduced `internal-ingress-overrides.ts` — a per-provider
mutator table keyed by resolved resource type:

  - gcp.run.service                      -> ingress=internal-and-cloud-load-balancing, allow_unauthenticated=false
  - aws.ecs.service                      -> assign_public_ip=false, internal=true
  - azure.containerapp.containerApp      -> ingress_external=false

Translator calls `applyInternalIngressOverride(resource_type, props)`
generically. The `SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS.has(t)` set
membership is replaced with `hasBlockRole(t, 'serviceBackend')` per
the earlier dedup commit. No provider strings or iceType strings
appear in the translator's body.

New providers add an override entry; the translator stays unchanged.

Tests: existing type-map entry counts bumped by 1 + new CustomDomain
mapping assertions per provider + new internal-ingress-overrides
suite (table contents + per-provider behaviour + no-op fallthrough).

* refactor(deploy): drop hardcoded Compute.StaticSite in storage extractor + endpoint pass

Audit items #3 + #4 — last two cardinal-rule violations:

  - pass-1-5-endpoint-wiring.ts:204 — `if (be.targetIceType === 'Compute.StaticSite')`
    skipped LB wiring for static-site backends (GCP-Firebase-Hosting-specific behaviour)
  - extractors/network.ts:25 — `iceType === 'Compute.StaticSite'` flipped a Storage.Bucket
    extractor's `public_access` + `website_hosting` when the bucket backs a static site

Two schema-shaped declarations replace them, each scoped to its
natural layer:

  #3 -> `self-serving-resources.ts`: a new `SELF_SERVING_PUBLIC_RESOURCES`
       set keyed by RESOLVED PROVIDER RESOURCE TYPE (gcp.firebase.hosting
       today; future: aws.amplify.app, azure.staticwebapps.staticSite).
       The endpoint-wiring pass reads `targetGraphNode.type` and calls
       `isSelfServingPublicResource(...)` — no iceType strings.

  #4 -> New `publicWebsiteSource` role on the shared
       `BLOCK_ROLES_BY_ICE_TYPE` table. Compute.StaticSite registers
       this role; the storage extractor reads it via
       `hasBlockRole(iceType, 'publicWebsiteSource')`. Adding a future
       static-site-style block (Compute.JamstackSite, …) adds one
       table entry — extractor stays unchanged.

Tests:
  - existing pass-1-5 fixtures updated to mark static-site graph nodes
    with `type: 'gcp.firebase.hosting'` (the resolved type the new
    check reads); behavioural assertions unchanged
  - new self-serving-resources test suite covering registered +
    negative cases

With this commit, every audit item in the schema-driven-refactor
punch list is shipped.

* refactor(deploy/aws): modularise AWSDeployer to mirror gcp/ shape

Phase 0 of the AWS deploy buildout. The previous 496-LOC monolithic
aws-deployer.ts is replaced with the same dispatch shape the GCP
deployer uses:

  providers/aws/
    aws-deployer.ts   — thin dispatcher + HANDLER_REGISTRY map
    types.ts          — AWSHandlerContext + AWSResourceHandler
    sdk-loader.ts     — load_aws_sdk + initialize_aws_clients + destroy
    index.ts          — barrel
    handlers/
      ec2.ts          — migrated from aws-deployer.ts (no behaviour change)
      s3.ts           — migrated (account-id suffix arrives in commit #8)
      lambda.ts       — migrated (S3-ref only; auto-build in commit #28)

The old `providers/aws-deployer.ts` becomes a re-export shim so the
existing import paths in `providers/index.ts` and the test suite keep
resolving without edits.

Cardinal-rule schema-driven: HANDLER_REGISTRY is the single declarative
fact for "which handler runs for which resource type". The dispatcher
iterates it generically; no `if (type === 'aws.X')` branches. Adding
the next ~17 AWS services is now register-an-entry + drop-a-file.

Behaviour preserved verbatim — all 64 existing AWS deployer tests pass
unchanged (one minor wording fix in the dispatcher to match the
original "Unsupported resource type for creation/update/deletion"
phrasing the test suite pins).

* feat(deploy/aws): extractors for compute (ecs.service, lambda.function, events.rule)

Phase 1 commit 1/5 — first AWS extractor module.

  extractors/aws/compute.ts (new):
    - extract_ecs_service_properties   ← Compute.Container, Compute.BackendAPI,
                                          Compute.SSRSite, Compute.Worker
    - extract_lambda_function_properties ← Compute.ServerlessFunction
    - extract_events_rule_properties    ← Compute.CronJob

  extractors/dispatch.ts:
    Register the 3 extractors under their resolved aws.* resource types.
    Adds the first AWS section to PROPERTY_EXTRACTORS.

Provider parity notes (extractor only — handlers come later):
  - ECS multi-port uses the shared parse_exposed_ports() so the canvas
    contract matches what Cloud Run sees today.
  - Lambda accepts the nested code.{s3Bucket,s3Key} shape AND falls
    through to the flat s3_bucket / s3_key fields for back-compat with
    the existing Lambda test harness. Auto-build from Source.Repository
    lands in commit #28.
  - EventBridge cron is the 6-field format (not unix 5-field). The
    named "daily"/"hourly"/"weekly"/"monthly" presets that GCP Cloud
    Scheduler accepts are normalised to the AWS expression so cards
    stay provider-portable.

Tests: 24 new assertions covering defaults, passthrough, exposed_ports
parsing, code-source shape variants, cron preset normalisation. The
dispatch table test gets a new shape — counts GCP entries (27)
separately from AWS (>=3, will grow with commits #3#6), accepts
aws.* keys in the {provider}.{service}.{kind} regex.

* feat(deploy/aws): extractors for database (rds, dynamodb, elasticache, docdb)

Phase 1 commit 2/5.

  extractors/aws/database.ts (new):
    - extract_rds_db_instance_properties      ← Database.PostgreSQL, MySQL
    - extract_dynamodb_table_properties       ← Database.DynamoDB
    - extract_elasticache_cluster_properties  ← Database.Redis
    - extract_docdb_cluster_properties        ← Database.MongoDB

  extractors/dispatch.ts: register all 4 under aws.* resource types.

Provider parity:
  - RDS engine + version inferred from iceType + runtime string, same
    rule the GCP Cloud SQL extractor uses -> cards stay portable.
  - master_user_password defaults to '' so the handler fails loudly
    rather than provisioning RDS / DocDB with no real credential.
  - ElastiCache exposes ELASTICACHE_REDIS_SIZE_MAP for the canvas
    M-series enum (M1 -> cache.t3.micro, M5 -> cache.m5.xlarge ×2 for HA
    parity with GCP STANDARD_HA).
  - DynamoDB defaults to PAY_PER_REQUEST (AWS-recommended for new
    workloads); PROVISIONED branch emits RCU/WCU only when set.

15 new test assertions across the four resources covering engine
detection, version extraction, size-enum translation, billing-mode
branching, and password defaults.

* feat(deploy/aws): extractors for network (s3, apigateway, cloudfront, elbv2)

Phase 1 commit 3/5.

  extractors/aws/network.ts (new):
    - extract_s3_bucket_properties             ← Storage.Bucket / Storage.ObjectStorage / Compute.StaticSite
    - extract_api_gateway_rest_api_properties  ← Network.Gateway
    - extract_cloudfront_distribution_properties ← Network.PublicEndpoint / Network.CustomDomain
    - extract_elbv2_load_balancer_properties   ← Network.LoadBalancer

  extractors/dispatch.ts: register all 4 under aws.* resource types.

Cross-provider parity:
  - S3 reads the publicWebsiteSource role from the shared block-
    classifier table; same flip-policy the GCP cloud_storage extractor
    uses for Compute.StaticSite. Plain Storage.Bucket stays private.
  - CloudFront defaults to HTTPS + auto-cert + PriceClass_100 (most-
    common cost-aware preset). Cert provisioning in us-east-1 is the
    handler's job in commit #19.
  - ELBv2 defaults to internet-facing ALB on HTTPS:443; flips to
    `internal` scheme when `internal: true` (parity with the
    INTERNAL_INGRESS_OVERRIDES table semantics).

11 new tests + dispatch table assertion updated (the previous
"aws.s3.bucket is intentionally absent" assertion is replaced with
a generic "aws.unknown.thing" check now that S3 has landed).

* feat(deploy/aws): extractors for ancillary (sqs, sns, cognito, secrets, cw-logs)

Phase 1 commit 4/5.

  extractors/aws/ancillary.ts (new):
    - extract_sqs_queue_properties                ← Messaging.Queue
    - extract_sns_topic_properties                ← Messaging.Topic / CloudPubSub
    - extract_cognito_user_pool_properties        ← Security.Identity
    - extract_secrets_manager_secret_properties   ← Security.Secret
    - extract_cloudwatch_log_group_properties     ← Monitoring.Log

  extractors/dispatch.ts: register all 5 under aws.* resource types.

Notable:
  - SQS content_based_deduplication is only emitted on FIFO queues
    (AWS rejects the field on standard SQS).
  - Secrets Manager extractor forwards data.secrets as `bindings` —
    same shape the schema-declared deploy-expansion pass already uses
    for GCP Secret Manager. Adding AWS doesn't require translator
    changes; the same expansion branch fires.
  - Cognito reads both signInProviders (canvas camelCase) and
    sign_in_providers (snake) so projects authored with either work.

14 new test assertions.

* feat(deploy/aws): extractors for AI/analytics (opensearch, bedrock, sagemaker, redshift)

Phase 1 commit 5/5 — last extractor module. Every aws.* resource type
in AWS_TYPE_MAP now has a registered property extractor.

  extractors/aws/ai.ts (new):
    - extract_opensearch_domain_properties    ← AI.VectorDB
    - extract_bedrock_endpoint_properties     ← AI.LLMGateway
    - extract_sagemaker_endpoint_properties   ← AI.ModelServing
    - extract_redshift_cluster_properties     ← Analytics.DataWarehouse

  extractors/dispatch.ts: register all 4 under aws.* resource types.

Notable defaults:
  - OpenSearch starts cost-conscious: single t3.small.search node with
    encryption-at-rest + node-to-node encryption on. Production users
    flip dedicated_master_enabled + bump instance_count ≥ 3.
  - Bedrock defaults to on-demand Claude 3 Haiku (zero provisioned
    model units -> handler emits no resource). Provisioned throughput
    fires only when model_units > 0.
  - SageMaker defaults to a real-time ml.t2.medium endpoint.
  - Redshift defaults to a single-node dc2.large with the no-default-
    password invariant the RDS + DocDB extractors share.

12 new test assertions. With this commit Phase 1 is complete:
PROPERTY_EXTRACTORS table now has 27 GCP + 20 AWS entries.

* feat(deploy/aws): shared infra — STS account-id resolver + IAM ensure-role helper

Phase 2 commit 1 — the shared helpers later handlers depend on.

  providers/aws/account.ts (new):
    - create_account_id_resolver(region): memoised STS GetCallerIdentity
      caller. First call hits STS, subsequent calls return cached value.
      Concurrent first-calls coalesce into one STS request. Throws a
      clear "install @aws-sdk/client-sts" message when SDK is absent.

  providers/aws/iam-roles.ts (new):
    - ensureManagedRole(region, roleName, trustPolicyJson, managedPolicyArn):
      idempotent GetRole -> CreateRole-on-NoSuchEntity -> AttachRolePolicy
      pattern. Returns the role ARN. Tolerates already-attached
      policies (AlreadyExists swallowed; any other error fatal).
    - ensureEcsTaskExecutionRole(region): convenience wrapper for the
      standard Fargate execution role (consumed by the ECS handler in
      commit #23).

  providers/aws/types.ts:
    AWSHandlerContext gains `ensure_account_id: AccountIdResolver` —
    handlers `await ctx.ensure_account_id()` to get the cached id.

  providers/aws/aws-deployer.ts:
    initialize() wires the resolver into the context. A pre-init stub
    throws "called before initialize()" if a handler tries to use it
    out of band.

  providers/aws/index.ts: re-export the new helpers.

Tests: 9 new — memoisation, concurrent-call coalescing, missing-SDK
error path, missing-Account-field error path, ensureManagedRole
happy-path + create-on-miss + IAM-SDK-missing path.

* feat(deploy/aws): s3 handler — account-id suffix + publicWebsite bucket policy

Handler #8 in Phase 2.

Two upgrades over the Phase 0 baseline:

  1. **Account-id suffix.** S3 bucket names are globally unique
     across all AWS accounts. The handler awaits ctx.ensure_account_id()
     and appends `-{accountId}` to the translator's resource name
     before any SDK call. `ice-myapp-bucket` becomes
     `ice-myapp-bucket-111122223333`, eliminating the global-collision
     class. The provider_id ARN carries the post-suffix name so
     update + delete round-trip cleanly (bucket_name_from_arn parses
     it back out).

  2. **publicWebsite policy.** When the extractor sets `public_access`
     + `website_hosting` (today only Compute.StaticSite triggers this
     via the publicWebsiteSource role from the shared classifier
     table), the handler runs a 4-step create:
       CreateBucket
         -> PutPublicAccessBlock (loosen account-default block)
         -> PutBucketPolicy      (attach the public-read policy)
         -> PutBucketWebsite     (set index/404 pages)
     Plain Storage.Bucket skips all three follow-up commands.

Tests:
  - Existing test harness extended with a makeStsModule mock + a
    FAKE_ACCOUNT_ID constant; the makeFullRegistry now installs STS
    alongside the SDK clients.
  - All existing S3 ARN assertions updated to expect the suffixed form.
  - 3 new tests: account-id suffix lock-in, public-website 4-step
    sequence with policy + website config, plain-bucket negative path.

64 -> 67 AWS deployer tests passing.

* feat(deploy/aws): lambda handler — fail-fast role + code-source validation

Handler #9 in Phase 2.

Hardens the existing Lambda S3-ref handler with two pre-create
validations that turn cryptic AWS API errors into clear messages:

  1. **IAM role required.** The AWS SDK returns "Could not find
     resource ..." when CreateFunction is called with an empty Role
     ARN. The handler now refuses up front with:
     "Lambda function requires an IAM execution role ARN
     (properties.role). Wire one in or use the auto-role helper."

  2. **Code source required.** When neither s3_bucket + s3_key NOR a
     base64 zip_file is supplied, the handler refuses with:
     "Lambda function code source is missing. Provide
     properties.code.{s3Bucket,s3Key} or zip_file (auto-build from
     Source.Repository lands in a later commit)."

Both checks fire before any SDK call, so the failure surfaces in the
deployer's `error` field with full context instead of as an opaque
AWS error.

Tests updated so happy-path Lambda create tests now pass both role
and code source. 2 new tests pin the fail-fast paths.

* feat(deploy/aws): cloudwatch-logs handler + shared _result helpers

Handler #10 in Phase 2.

  providers/aws/handlers/cloudwatch-logs.ts (new):
    - aws.cloudwatch.logGroup handler — CreateLogGroup +
      PutRetentionPolicy (when retention_in_days set) on create.
      PutRetentionPolicy on update. DeleteLogGroup on delete.

  providers/aws/handlers/_result.ts (new):
    - ok / err / sdkMissing helpers shared across all AWS handlers.
      Stops the per-handler result/fail boilerplate copy-paste.

  providers/aws/sdk-loader.ts: load @aws-sdk/client-cloudwatch-logs
    under the 'cloudwatch-logs' client key.

  providers/aws/aws-deployer.ts: register cloudwatch_logs_handler
    in HANDLER_REGISTRY.

Tests: 3 new — create-with-retention, create-without-retention skips
PutRetentionPolicy, delete sequence. Test harness extended with
makeCloudWatchLogsModule + corresponding FakeImportRegistry entry.

* feat(deploy/aws): secrets-manager handler + shared test harness

Handler #11 in Phase 2.

  providers/aws/handlers/secrets-manager.ts (new):
    - aws.secretsmanager.secret handler. Mirrors the GCP Secret
      Manager contract: the schema-declared deploy-expansion pass
      emits one Secret per binding row; this handler just creates /
      updates / deletes ONE. Values are NOT written (operators
      populate via AWS console/CLI — same security tradeoff as GCP).
    - delete uses ForceDeleteWithoutRecovery=true (skips the 30-day
      recovery window — appropriate when ICE removes the binding).

  providers/aws/sdk-loader.ts: load @aws-sdk/client-secrets-manager
    under the 'secrets-manager' client key.

  providers/aws/aws-deployer.ts: register secrets_manager_handler.

  providers/__tests__/_aws-test-harness.ts (new):
    Extracts the Function-constructor stub + generic SDK-mock factory
    out of the original aws-deployer.test.ts so per-handler test
    files stay small. Strips the trailing 'Command' from command
    class names when building the __cmd label so assertions read the
    operation name (`CreateSecret`, not `CreateSecretCommand`).

  providers/__tests__/aws-secrets-manager.test.ts (new): 4 focused
    tests — create returns the SDK ARN, update + delete sequences,
    SDK-not-installed path.

* feat(deploy/aws): sqs handler — CreateQueue/SetQueueAttributes/DeleteQueue, FIFO .fifo suffix

Handler #12 in Phase 2. Standard + FIFO queues. FIFO queues get the
.fifo suffix appended to the name automatically (AWS enforces). 3
focused tests.

* feat(deploy/aws): sns handler — CreateTopic/SetTopicAttributes/DeleteTopic, FIFO .fifo suffix

* feat(deploy/aws): dynamodb handler — CreateTable + key schema + PITR

* feat(deploy/aws): elasticache handler — single-node + replication-group paths

* feat(deploy/aws): rds handler — no-default-password gate + provisioning poll

Handler #16 in Phase 2. CreateDBInstance + 20-min status-poll loop
that respects ctx.abort_signal and reports progress via on_step.
Refuses to create when master_user_password is empty (parity with
the extractor's no-default-password invariant).

* feat(deploy/aws): docdb handler — cluster + per-instance creation

* feat(deploy/aws): cognito handler — user pool with password policy + MFA

* feat(deploy/aws): cloudfront handler — us-east-1 ACM cert + minimal distribution

Handler #19. CloudFront requires ACM certs in us-east-1 regardless
of deploy region; the handler spins up a one-shot ACM client pinned
to us-east-1 for RequestCertificate, then attaches the ARN to the
distribution's ViewerCertificate. Falls back to CloudFrontDefaultCertificate
when ACM SDK is absent.

* feat(deploy/aws): elbv2 handler — LB + skeleton target group

* feat(deploy/aws): api-gateway handler — REST API + default-stage deployment

* feat(deploy/aws): events-rule handler (CronJob) — PutRule + PutTargets

* feat(deploy/aws): ecs handler — auto-cluster + task role + service create

Handler #23. Compute.Container 'just works' on AWS — the handler
idempotently bootstraps ecsTaskExecutionRole + ice-default-cluster
before RegisterTaskDefinition + CreateService. Mirrors the GCP
Cloud Run UX (no cluster to think about).

* feat(deploy/aws): opensearch handler — CreateDomain with cluster/EBS/encryption config

* feat(deploy/aws): bedrock handler — on-demand no-op + provisioned-throughput create

* feat(deploy/aws): sagemaker handler — EndpointConfig + Endpoint, requires model_name

* feat(deploy/aws): redshift handler — CreateCluster + no-default-password gate

* feat(deploy/aws): lambda auto-build from Source.Repository

Phase 3 (commit #28). When a Compute.ServerlessFunction block has a
connected Source.Repository AND no explicit S3 ref, the handler
auto-builds the zip and uploads it before CreateFunction:

  1. git clone --depth 1 --branch <branch> <repo>
  2. npm install --omit=dev (skipped if no package.json)
  3. zip -qr function.zip .
  4. PutObject to ice-bootstrap-{accountId}-{region}/lambda/{name}/{ts}.zip
     (HeadBucket -> CreateBucket if absent)
  5. Stamp s3_bucket + s3_key onto properties and continue.

Local-only — assumes git/npm/zip on the deploy host. AWS CodeBuild
integration deferred to a future commit. Existing manual S3-ref + zip
paths are unchanged; the auto-build branch only fires when
`properties.repository` is set AND no explicit code source exists.

* test(deploy/aws): unskip AWS Type Map block + end-to-end coverage

Phase 4 commit #29. With every aws.* resource type registered in
PROPERTY_EXTRACTORS (commits #2#6), the AWS Type Map test block can
finally turn on. Expanded the iceType matrix from 5 to 19 entries
covering every AWS-mapped block.

New end-to-end test wires Compute.StaticSite + Security.Secret (with
two bindings — exercising the schema-declared deploy-expansion pass)
+ Database.PostgreSQL into a single translator call, asserts the
resulting graph has 4 deployables resolving to s3.bucket /
secretsmanager.secret×2 / rds.dbInstance. The Azure block remains
skipped (deferred to a future Azure handler buildout).

* docs(deploy/aws): provider notes — quirks, assumptions, deferred work

Phase 4 commit #30 — final commit of the AWS buildout.

providers/aws/README.md documents the AWS-specific decisions the 30
commits in this series bake in:

  - architecture (mirrors gcp/, schema-driven HANDLER_REGISTRY)
  - S3 account-id suffix
  - CloudFront us-east-1 cert
  - ECS auto-cluster + task role
  - RDS / DocDB / Redshift no-default-password invariant
  - RDS provisioning poll
  - Lambda auto-build flow (git + npm + zip + bootstrap S3)
  - Bedrock on-demand no-op
  - Secrets Manager values-never-written contract
  - SQS / SNS .fifo suffix
  - SDK packages as optional peer deps
  - test harness layout
  - deferred work (VPC blocks, CodeBuild, drift detection, LocalStack)

Read this before changing any AWS handler.

* feat(aws): selectively enable safe categories via feature flags

Flip PROVIDER_FLAGS.aws.enabled to true with a hand-picked category
map (Storage, Messaging, Cache, Monitoring, Security, Source, Config).
Compute / Frontend / Scheduler / Network / Database / AI / Analytics
stay gated until their concrete unblockers land — ECS VPC blocks,
CloudFront cert-validation flow, update-paths, etc.

README.md gets a Rollout state table documenting why each gated
category is held back and what unblocks it.

Integrity test in packages/constants asserts the per-category map
stays exhaustive, so future CategoryId additions force a deliberate
on/off decision here.

* fix(palette): enable provider dropdown items when any block is available

Replace the project-provider lock on the palette provider dropdown
with an availability check: a provider option is selectable iff at
least one concept has it in providers and its category is enabled
for that provider.

Before: in a GCP project, AWS was greyed in the palette dropdown
even after AWS feature-flag enabled — so users couldn't browse the
AWS catalog from a GCP project.

After: AWS opens as long as it has any available block under the
current PROVIDER_FLAGS — drag-into-project compatibility remains
enforced at the canvas-drop layer.

availableProviderIds is derived in resource-palette.tsx from the
unfiltered component list using isCategoryEnabledForProvider — same
schema-driven gate the component filter already uses.

* docs(architecture): explain how canvas edges become cloud infra

New page docs/architecture/connections-to-cloud.md walks the five-layer
pipeline (connection-rules -> propagation -> type-maps -> extractors ->
handlers) and grounds it with two worked GCP examples:

- Storage.Bucket -> Compute.BackendAPI: env-var injection + IAM binding,
  no edge resource in GCP.
- Compute.CronJob -> Compute.BackendAPI: Cloud Scheduler HTTP target +
  run.invoker IAM binding.

Links the new page from architecture/README.md and the existing
core-engine.md "Computing flows" section so readers landing on either
find their way to the deep dive.

* docs(architecture): explain how canvas edges become cloud infra
julia-kafarska added a commit that referenced this pull request May 25, 2026
* fix(canvas): correct snap target + drag-snap stickiness for Custom Domain rows

Two bugs in connection drag:
1. dragCompatibility positions used getPortAnchorPoint (schema's
   side-distribution math) instead of getSocketCanvasPosition, so the
   snap target Y on Custom Domain row ports drifted progressively
   from the visible dot (~50px on row 0, ~0px on the last row).
2. snap was computed from currentPoint, which itself is set to the
   snapped port's position. Distance-to-self stayed at 0 so the snap
   locked onto the first port that ever won. Added cursorPoint to
   DrawingConnectionState and compute snap from it; currentPoint
   remains the visible (snapped or cursor) wire endpoint.

* refactor(secret-store): schema-driven 1→N deploy expansion

Properties + deploy model rebuilt around the canonical schema:

- Properties: name → "Store name"; secrets list → new `secret_bindings`
  field with two inputs per row (env-var key ← upstream ref); auto_rotate
  dropped (was inert + wrong-scoped). Bindings explained: the block does
  NOT hold secret values — values live in the cloud secret manager.
- Schema: add optional `iceType` and `deployExpansion` to
  HighLevelResource. Secret Store declares
  `deployExpansion: { partitionBy: 'bindings', nameFrom: { field: 'ref',
  fallback: 'key' }, labelFrom: 'key', tagPerEntry: ... }`.
- Lookup: getHighLevelResourceByIceType helper with a cached index.
- Generic pass: new deploy/passes/deploy-expansion.ts emits one cloud
  resource per partition entry, dedup'd within/across blocks, forwarding
  provider-shaped properties verbatim. Knows nothing about secrets.
- Translator: the previous `if (iceType === 'Security.Secret')` branch
  is replaced with `if (schemaResource?.deployExpansion)` — cardinal
  rule, no iceType hardcoded in cross-cutting code.

Adding AWS Secrets Manager or Azure Key Vault requires only an extractor
+ handler for the provider's resource type. Adding a new expanding block
requires only a `deployExpansion` declaration on its schema entry.

* refactor(canvas-renderer): drop hardcoded iceType branches via SPECIAL_NODE_RENDERERS table

Audit item #11 — cardinal rule violation. The dispatcher had three
hardcoded `if (iceType === 'X')` branches for Custom Domain, Reroute,
and Private Network, each wiring a bespoke component with its own
prop set + innerKey formula.

Consolidated into a single declarative `SPECIAL_NODE_RENDERERS` table
keyed by iceType, with factory entries that own their own component
AND innerKey formula. The dispatcher iterates this table generically
— no iceType-specific code paths remain. Adding a new bespoke renderer
extends the table; the dispatcher stays unchanged.

Dispatch order preserved by construction: the special table is
consulted BEFORE the container check so PrivateNetwork (a container
we render with a custom header) and Reroute (which the classifier
calls a container despite being a pass-through dot) hit their
bespoke factories first.

Tests: locked-in entries list + per-entry contract (element + innerKey)
+ innerKey-changes-on-relevant-data assertions for Custom Domain
(routes count) and PrivateNetwork (ingress mode).

* refactor(canvas-path): drop hardcoded iceType in socket-position via BESPOKE_SOCKET_POSITIONS table

Audit item #12 — cardinal rule violation. `getSocketCanvasPosition`
had an `if (iceType === 'Network.CustomDomain' && socketId.startsWith
('domain-out-'))` branch that resolved the bespoke row-Y for per-route
ports.

Consolidated into a `BESPOKE_SOCKET_POSITIONS` table keyed by iceType,
with resolver entries returning `Point | null` (null = fall through to
the standard layout). The dispatcher iterates this table generically
— no iceType branches in the resolver function. New bespoke layouts
register here; dispatch stays unchanged.

Tests: locked-in entries list, per-resolver contract (returns null on
miss), and dispatcher behaviour (bespoke hit, fall-through, dangling
socket id).

* refactor(properties): schema-drive tab visibility + deployment-target skip

Audit item #13 — cardinal rule violation. The tab builder and the
deployment-target card both branched on hardcoded iceType strings:

  - build-visible-tabs.ts:41-46 — config tab visible for 4 iceTypes
  - build-visible-tabs.ts:53    — domain tab visible for 2 iceTypes
  - build-visible-tabs.ts:56    — source tab visible for Source.Repository
  - node-properties-section.tsx:166 — deployment target hidden for 2 iceTypes

Consolidated into a single declarative table
`BLOCK_PROPERTY_PANEL_CONFIGS` keyed by iceType, with per-block
`forceTabs` and `skipDeploymentTarget` flags. Both the builder and the
panel iterate this table generically — no iceType branches remain.
Adding a bespoke panel experience adds an entry; both call sites pick
it up.

Per-tab SECTION rendering (CustomDomainPanel, EnvVarsEditor, etc.)
inside the panel body is still iceType-conditioned — covered by audit
item #14 in the next commit, which extends this same config table.

* refactor(properties): schema-drive per-tab section dispatch via SECTION_COMPONENTS

Audit item #14 — cardinal rule violation. The panel body had six
hardcoded `iceType === 'X'` branches choosing which bespoke section
component to render inside which tab:

  - domain tab: PublicEndpointDomainSection / CustomDomainPanel
  - config tab: EnvVarsEditor / CustomDomainPanel / PrivateNetworkPanel
                / MonitoringLogSection
  - source tab: SourceRepositorySection
  - config tab fallback: SourceRepositorySection when no source tab

Extended BLOCK_PROPERTY_PANEL_CONFIGS with a `sections: Record<TabId,
SectionId[]>` field. Each iceType declares which sections render under
which tabs; the new SECTION_COMPONENTS factory map renders them.
`renderSectionsForTab(iceType, tab, ctx)` is the generic dispatcher
the JSX calls — no iceType branches remain.

Dropped the dead `visibleTabs.length <= 1 && iceType === 'Source.
Repository'` config-tab fallback: with the source tab now always forced
for that block via forceTabs, the fallback could never fire.

Tests: per-iceType set + section-id-tab validity check.

* refactor(canvas-sizing): schema-drive bespoke node sizing via BESPOKE_NODE_SIZING table

Audit item #16 — cardinal rule violation. computeNodeSizes had three
hardcoded iceType checks driving the width/height/fold dispatch:

  - isCustomDomain = iceType === 'Network.CustomDomain'
  - isPrivateNetwork = isPrivateNetworkIce(iceType)
  - isCronJob = iceType === 'Compute.CronJob'

Plus 4 nested ternaries threading those flags through width, height,
expandedHeight, and visualHeight.

Consolidated into BESPOKE_NODE_SIZING — a Record<iceType,
BespokeSizingEntry> where each entry owns its width function, height
function, and an `alwaysExpanded` flag that opts the block out of
folding (so dynamic content like Custom Domain route slots can't
collapse to a pill).

The dispatcher does a single table lookup, falls through to the
compact-node helpers when no bespoke entry exists, and respects
`alwaysExpanded` uniformly. No iceType branches remain.

Tests: locked-in entries list + alwaysExpanded invariant.

* refactor(deploy/edge-classifier): schema-drive isolation + standalone classification

Audit items #5 + #6 — cardinal rule violations. Three hardcoded
iceType checks in cross-cutting classifier code:

  - edge-classifier.ts:65  — `parent.data?.iceType === 'Network.PrivateNetwork'`
                             in the ancestor walk
  - edge-classifier.ts:90  — guard: `iceType !== 'Network.CustomDomain'`
  - edge-classifier.ts:93  — `parent.iceType !== 'Network.PrivateNetwork'`
                             in the standalone-mode check

Introduced `BLOCK_DEPLOY_CLASSIFIERS` — a per-iceType flag table with
two flags:

  - `isolatesNetworkContext`: this iceType is a network-isolation
    container (services nested inside should be internal-only)
  - `metadataOnlyWhenStandalone`: this iceType has two deploy modes
    based on parent context (metadata-only standalone vs. deployable
    when nested in an isolation container)

Renamed predicates to match the generic shape:
  - `hasPrivateNetworkAncestor` → `hasNetworkIsolatingAncestor`
  - `isCustomDomainStandalone`  → `isStandaloneMetadataOnly`

Old names kept as `@deprecated` aliases so external callers and tests
don't break. Card-translator call sites switched to the new names.
Adding a new isolation container or a new standalone/nested block
adds a table entry; classifier code stays unchanged.

* refactor(deploy/passes): schema-drive public-ingress detection + domain propagation

Audit items #7 + #8 — cardinal rule violations in two passes:

  - pass-1-5-endpoint-wiring.ts:107-114 — inline `isEndpointIceType`
    branched on Network.PublicEndpoint AND Network.CustomDomain (with
    nested-in-PrivateNetwork check) to identify ingress endpoints
  - pass-1-45-domain-propagation.ts:55-58 — hardcoded srcIce / dstIce
    === 'Network.CustomDomain' to route domain propagation

Extended BLOCK_DEPLOY_CLASSIFIERS with two new flags:

  - `publicIngressMode`: 'always' (PublicEndpoint) or
    'when-nested-in-isolated-network' (CustomDomain — only counts as
    ingress when nested inside an isolatesNetworkContext container)
  - `isDomainPropagator`: true for CustomDomain — generic name so any
    future domain-source block can flow through the same pass

Added generic `isPublicIngressNode(node, allNodes)` predicate to
edge-classifier that reads the flag table. Refactored pass-1-5 to
call it; pass-1-45 reads `isDomainPropagator` directly. No iceType
strings remain in either pass.

Tests: 3 new flag assertions + 5 new isPublicIngressNode behaviour
cases (always-mode, standalone CD, nested-in-isolated-network, nested-
in-non-isolation, plain compute).

* refactor(deploy/security-rules): schema-drive iceType classifiers via SECURITY_ROLES table

Audit item #15 — cardinal rule violation. The pre-deploy security
scanner had 9+ tiny iceType-comparing classifier functions
(`isDatabase`, `isStorage`, `isGateway`, `isService`, `isAuth`,
`isSecret`, `isMonitoring`, `isVpc`, `isSubnet`, `isPrivateNetwork`,
`isVpcLike`), each inlining its own `iceType === 'X'` check.

Consolidated into a schema-shaped role table:

  - `SECURITY_ROLES_BY_ICE_TYPE`: per-iceType role list
  - `SECURITY_ROLES_BY_PREFIX`: category-prefix inheritance
    (Database./Compute./Monitoring.* automatically pick up their role
    without per-iceType table edits)
  - `hasSecurityRole(iceType, role)`: the single lookup function the
    classifier readers call

Classifier functions remain as thin one-line role readers; rule
evaluation code is unchanged. New blocks that need a security role
add an entry to the table.

Split the previous `isVpcLike` into two distinct roles:
`isolatesNestedChildren` (VPC + Subnet + PrivateNetwork — used by the
ancestor check) and `topLevelNetworkBoundary` (VPC + PrivateNetwork
only — used by Rule 6, where a Subnet at the canvas root doesn't
isolate anything). The original code conflated these into a single
overloaded helper.

* refactor(classifiers): unify connection-rules + propagation-rules iceType classifiers via shared @ice/constants table

Audit items #9 + #10 — cardinal rule violations across two packages.
Both `@ice/types/connection-rules/predicates.ts` and
`@ice/core/compute/propagation-rules.ts` had ~15 identical-ish
classifier functions (isBackend, isFrontend, isDatabase, isCache,
isStorage, isQueue, isSecrets, isCustomDomain, …), each duplicating
the same regex + prefix + exact-match bodies. The propagation-rules
copy carried a comment apologising for the duplication ("Minimal
copies of the classifiers from @ice/types/connection-rules. Kept
local to avoid cross-package moduleResolution conflicts.").

Introduced `@ice/constants/block-classifiers.ts` as the single source
of truth — a three-tier role table:

  - `BLOCK_ROLES_BY_ICE_TYPE`: exact iceType → roles
  - `BLOCK_ROLES_BY_PREFIX`:   category prefix → role (Compute.*,
                               Database.*, Storage.*, Messaging.*,
                               Monitoring.*, Log.*)
  - `BLOCK_ROLES_BY_REGEX`:    legacy provider-specific iceTypes
                               (PostgreSQL/Redis/Bucket/Worker/…)
                               authored under varied namespaces

`hasBlockRole(t, role)` queries all three tiers. Both packages import
it — `predicates.ts` and `propagation-rules.ts` predicate bodies are
now one-line lookups, no iceType strings remain in classifier code.

Adding a new role/iceType binding edits ONE table; both connection-
rules and propagation-rules pick it up automatically.

Tests: full equivalence preserved (4664 tests pass) + new
block-classifiers test suite covering exact / prefix / regex /
composite / negative cases + table integrity.

* refactor(deploy): dedup SERVICE_BACKEND_ICE_TYPES via shared serviceBackend role

Audit items #17 + #18 — duplicated static set in two cross-cutting
locations:

  - edge-classifier.ts:34-40 — exported SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS
  - pass-1-5-endpoint-wiring.ts:188-194 — local SERVICE_BACKEND_ICE_TYPES

Both held the same 5 iceTypes (Compute.Container/BackendAPI/SSRSite/
Worker/ServerlessFunction). Two copies, two sources of drift.

Added a new `serviceBackend` role to the shared classifier table in
@ice/constants. The 5 iceTypes register the role via
BLOCK_ROLES_BY_ICE_TYPE — Compute.StaticSite is intentionally
excluded (compiles to backendBucket via Firebase Hosting, not a NEG).

- edge-classifier exports SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS as a
  thin materialisation derived from the role table (kept for callers
  that want `.has(t)` membership).
- pass-1-5-endpoint-wiring.ts now uses `hasBlockRole(t, 'serviceBackend')`
  directly; its inline duplicate set is gone.

New iceTypes register the role in ONE table; both consumers pick it up.

* refactor(translator): drop hardcoded iceType + provider branches via type-map + override table

Audit items #1 + #2 — two critical violations in the otherwise-
provider-agnostic translator:

  - card-translator.ts:227 — `ice_type === 'Network.CustomDomain'
    ? 'gcp.compute.globalForwardingRule' : type_map[ice_type]`
    (iceType AND GCP-specific in one cross-cutting line)
  - card-translator.ts:313-322 — `if (gcp_type === 'gcp.run.service')
    ... else if (gcp_type === 'aws.ecs.service') ... else if
    (gcp_type === 'azure.containerapp.containerApp') ...` cascade
    applying provider-specific internal-mode mutations inline

#1: Added Network.CustomDomain to each provider's type-map (mirrors
PublicEndpoint — the nested CD acts as the network's gateway and
compiles to the same ingress chain on every provider; standalone CDs
are filtered earlier by isStandaloneMetadataOnly). Translator now does
a plain `type_map[ice_type]` lookup — no iceType branches.

#2: Introduced `internal-ingress-overrides.ts` — a per-provider
mutator table keyed by resolved resource type:

  - gcp.run.service                      → ingress=internal-and-cloud-load-balancing, allow_unauthenticated=false
  - aws.ecs.service                      → assign_public_ip=false, internal=true
  - azure.containerapp.containerApp      → ingress_external=false

Translator calls `applyInternalIngressOverride(resource_type, props)`
generically. The `SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS.has(t)` set
membership is replaced with `hasBlockRole(t, 'serviceBackend')` per
the earlier dedup commit. No provider strings or iceType strings
appear in the translator's body.

New providers add an override entry; the translator stays unchanged.

Tests: existing type-map entry counts bumped by 1 + new CustomDomain
mapping assertions per provider + new internal-ingress-overrides
suite (table contents + per-provider behaviour + no-op fallthrough).

* refactor(deploy): drop hardcoded Compute.StaticSite in storage extractor + endpoint pass

Audit items #3 + #4 — last two cardinal-rule violations:

  - pass-1-5-endpoint-wiring.ts:204 — `if (be.targetIceType === 'Compute.StaticSite')`
    skipped LB wiring for static-site backends (GCP-Firebase-Hosting-specific behaviour)
  - extractors/network.ts:25 — `iceType === 'Compute.StaticSite'` flipped a Storage.Bucket
    extractor's `public_access` + `website_hosting` when the bucket backs a static site

Two schema-shaped declarations replace them, each scoped to its
natural layer:

  #3 → `self-serving-resources.ts`: a new `SELF_SERVING_PUBLIC_RESOURCES`
       set keyed by RESOLVED PROVIDER RESOURCE TYPE (gcp.firebase.hosting
       today; future: aws.amplify.app, azure.staticwebapps.staticSite).
       The endpoint-wiring pass reads `targetGraphNode.type` and calls
       `isSelfServingPublicResource(...)` — no iceType strings.

  #4 → New `publicWebsiteSource` role on the shared
       `BLOCK_ROLES_BY_ICE_TYPE` table. Compute.StaticSite registers
       this role; the storage extractor reads it via
       `hasBlockRole(iceType, 'publicWebsiteSource')`. Adding a future
       static-site-style block (Compute.JamstackSite, …) adds one
       table entry — extractor stays unchanged.

Tests:
  - existing pass-1-5 fixtures updated to mark static-site graph nodes
    with `type: 'gcp.firebase.hosting'` (the resolved type the new
    check reads); behavioural assertions unchanged
  - new self-serving-resources test suite covering registered +
    negative cases

With this commit, every audit item in the schema-driven-refactor
punch list is shipped.

* refactor(deploy/aws): modularise AWSDeployer to mirror gcp/ shape

Phase 0 of the AWS deploy buildout. The previous 496-LOC monolithic
aws-deployer.ts is replaced with the same dispatch shape the GCP
deployer uses:

  providers/aws/
    aws-deployer.ts   — thin dispatcher + HANDLER_REGISTRY map
    types.ts          — AWSHandlerContext + AWSResourceHandler
    sdk-loader.ts     — load_aws_sdk + initialize_aws_clients + destroy
    index.ts          — barrel
    handlers/
      ec2.ts          — migrated from aws-deployer.ts (no behaviour change)
      s3.ts           — migrated (account-id suffix arrives in commit #8)
      lambda.ts       — migrated (S3-ref only; auto-build in commit #28)

The old `providers/aws-deployer.ts` becomes a re-export shim so the
existing import paths in `providers/index.ts` and the test suite keep
resolving without edits.

Cardinal-rule schema-driven: HANDLER_REGISTRY is the single declarative
fact for "which handler runs for which resource type". The dispatcher
iterates it generically; no `if (type === 'aws.X')` branches. Adding
the next ~17 AWS services is now register-an-entry + drop-a-file.

Behaviour preserved verbatim — all 64 existing AWS deployer tests pass
unchanged (one minor wording fix in the dispatcher to match the
original "Unsupported resource type for creation/update/deletion"
phrasing the test suite pins).

* feat(deploy/aws): extractors for compute (ecs.service, lambda.function, events.rule)

Phase 1 commit 1/5 — first AWS extractor module.

  extractors/aws/compute.ts (new):
    - extract_ecs_service_properties   ← Compute.Container, Compute.BackendAPI,
                                          Compute.SSRSite, Compute.Worker
    - extract_lambda_function_properties ← Compute.ServerlessFunction
    - extract_events_rule_properties    ← Compute.CronJob

  extractors/dispatch.ts:
    Register the 3 extractors under their resolved aws.* resource types.
    Adds the first AWS section to PROPERTY_EXTRACTORS.

Provider parity notes (extractor only — handlers come later):
  - ECS multi-port uses the shared parse_exposed_ports() so the canvas
    contract matches what Cloud Run sees today.
  - Lambda accepts the nested code.{s3Bucket,s3Key} shape AND falls
    through to the flat s3_bucket / s3_key fields for back-compat with
    the existing Lambda test harness. Auto-build from Source.Repository
    lands in commit #28.
  - EventBridge cron is the 6-field format (not unix 5-field). The
    named "daily"/"hourly"/"weekly"/"monthly" presets that GCP Cloud
    Scheduler accepts are normalised to the AWS expression so cards
    stay provider-portable.

Tests: 24 new assertions covering defaults, passthrough, exposed_ports
parsing, code-source shape variants, cron preset normalisation. The
dispatch table test gets a new shape — counts GCP entries (27)
separately from AWS (>=3, will grow with commits #3#6), accepts
aws.* keys in the {provider}.{service}.{kind} regex.

* feat(deploy/aws): extractors for database (rds, dynamodb, elasticache, docdb)

Phase 1 commit 2/5.

  extractors/aws/database.ts (new):
    - extract_rds_db_instance_properties      ← Database.PostgreSQL, MySQL
    - extract_dynamodb_table_properties       ← Database.DynamoDB
    - extract_elasticache_cluster_properties  ← Database.Redis
    - extract_docdb_cluster_properties        ← Database.MongoDB

  extractors/dispatch.ts: register all 4 under aws.* resource types.

Provider parity:
  - RDS engine + version inferred from iceType + runtime string, same
    rule the GCP Cloud SQL extractor uses → cards stay portable.
  - master_user_password defaults to '' so the handler fails loudly
    rather than provisioning RDS / DocDB with no real credential.
  - ElastiCache exposes ELASTICACHE_REDIS_SIZE_MAP for the canvas
    M-series enum (M1 → cache.t3.micro, M5 → cache.m5.xlarge ×2 for HA
    parity with GCP STANDARD_HA).
  - DynamoDB defaults to PAY_PER_REQUEST (AWS-recommended for new
    workloads); PROVISIONED branch emits RCU/WCU only when set.

15 new test assertions across the four resources covering engine
detection, version extraction, size-enum translation, billing-mode
branching, and password defaults.

* feat(deploy/aws): extractors for network (s3, apigateway, cloudfront, elbv2)

Phase 1 commit 3/5.

  extractors/aws/network.ts (new):
    - extract_s3_bucket_properties             ← Storage.Bucket / Storage.ObjectStorage / Compute.StaticSite
    - extract_api_gateway_rest_api_properties  ← Network.Gateway
    - extract_cloudfront_distribution_properties ← Network.PublicEndpoint / Network.CustomDomain
    - extract_elbv2_load_balancer_properties   ← Network.LoadBalancer

  extractors/dispatch.ts: register all 4 under aws.* resource types.

Cross-provider parity:
  - S3 reads the publicWebsiteSource role from the shared block-
    classifier table; same flip-policy the GCP cloud_storage extractor
    uses for Compute.StaticSite. Plain Storage.Bucket stays private.
  - CloudFront defaults to HTTPS + auto-cert + PriceClass_100 (most-
    common cost-aware preset). Cert provisioning in us-east-1 is the
    handler's job in commit #19.
  - ELBv2 defaults to internet-facing ALB on HTTPS:443; flips to
    `internal` scheme when `internal: true` (parity with the
    INTERNAL_INGRESS_OVERRIDES table semantics).

11 new tests + dispatch table assertion updated (the previous
"aws.s3.bucket is intentionally absent" assertion is replaced with
a generic "aws.unknown.thing" check now that S3 has landed).

* feat(deploy/aws): extractors for ancillary (sqs, sns, cognito, secrets, cw-logs)

Phase 1 commit 4/5.

  extractors/aws/ancillary.ts (new):
    - extract_sqs_queue_properties                ← Messaging.Queue
    - extract_sns_topic_properties                ← Messaging.Topic / CloudPubSub
    - extract_cognito_user_pool_properties        ← Security.Identity
    - extract_secrets_manager_secret_properties   ← Security.Secret
    - extract_cloudwatch_log_group_properties     ← Monitoring.Log

  extractors/dispatch.ts: register all 5 under aws.* resource types.

Notable:
  - SQS content_based_deduplication is only emitted on FIFO queues
    (AWS rejects the field on standard SQS).
  - Secrets Manager extractor forwards data.secrets as `bindings` —
    same shape the schema-declared deploy-expansion pass already uses
    for GCP Secret Manager. Adding AWS doesn't require translator
    changes; the same expansion branch fires.
  - Cognito reads both signInProviders (canvas camelCase) and
    sign_in_providers (snake) so projects authored with either work.

14 new test assertions.

* feat(deploy/aws): extractors for AI/analytics (opensearch, bedrock, sagemaker, redshift)

Phase 1 commit 5/5 — last extractor module. Every aws.* resource type
in AWS_TYPE_MAP now has a registered property extractor.

  extractors/aws/ai.ts (new):
    - extract_opensearch_domain_properties    ← AI.VectorDB
    - extract_bedrock_endpoint_properties     ← AI.LLMGateway
    - extract_sagemaker_endpoint_properties   ← AI.ModelServing
    - extract_redshift_cluster_properties     ← Analytics.DataWarehouse

  extractors/dispatch.ts: register all 4 under aws.* resource types.

Notable defaults:
  - OpenSearch starts cost-conscious: single t3.small.search node with
    encryption-at-rest + node-to-node encryption on. Production users
    flip dedicated_master_enabled + bump instance_count ≥ 3.
  - Bedrock defaults to on-demand Claude 3 Haiku (zero provisioned
    model units → handler emits no resource). Provisioned throughput
    fires only when model_units > 0.
  - SageMaker defaults to a real-time ml.t2.medium endpoint.
  - Redshift defaults to a single-node dc2.large with the no-default-
    password invariant the RDS + DocDB extractors share.

12 new test assertions. With this commit Phase 1 is complete:
PROPERTY_EXTRACTORS table now has 27 GCP + 20 AWS entries.

* feat(deploy/aws): shared infra — STS account-id resolver + IAM ensure-role helper

Phase 2 commit 1 — the shared helpers later handlers depend on.

  providers/aws/account.ts (new):
    - create_account_id_resolver(region): memoised STS GetCallerIdentity
      caller. First call hits STS, subsequent calls return cached value.
      Concurrent first-calls coalesce into one STS request. Throws a
      clear "install @aws-sdk/client-sts" message when SDK is absent.

  providers/aws/iam-roles.ts (new):
    - ensureManagedRole(region, roleName, trustPolicyJson, managedPolicyArn):
      idempotent GetRole → CreateRole-on-NoSuchEntity → AttachRolePolicy
      pattern. Returns the role ARN. Tolerates already-attached
      policies (AlreadyExists swallowed; any other error fatal).
    - ensureEcsTaskExecutionRole(region): convenience wrapper for the
      standard Fargate execution role (consumed by the ECS handler in
      commit #23).

  providers/aws/types.ts:
    AWSHandlerContext gains `ensure_account_id: AccountIdResolver` —
    handlers `await ctx.ensure_account_id()` to get the cached id.

  providers/aws/aws-deployer.ts:
    initialize() wires the resolver into the context. A pre-init stub
    throws "called before initialize()" if a handler tries to use it
    out of band.

  providers/aws/index.ts: re-export the new helpers.

Tests: 9 new — memoisation, concurrent-call coalescing, missing-SDK
error path, missing-Account-field error path, ensureManagedRole
happy-path + create-on-miss + IAM-SDK-missing path.

* feat(deploy/aws): s3 handler — account-id suffix + publicWebsite bucket policy

Handler #8 in Phase 2.

Two upgrades over the Phase 0 baseline:

  1. **Account-id suffix.** S3 bucket names are globally unique
     across all AWS accounts. The handler awaits ctx.ensure_account_id()
     and appends `-{accountId}` to the translator's resource name
     before any SDK call. `ice-myapp-bucket` becomes
     `ice-myapp-bucket-111122223333`, eliminating the global-collision
     class. The provider_id ARN carries the post-suffix name so
     update + delete round-trip cleanly (bucket_name_from_arn parses
     it back out).

  2. **publicWebsite policy.** When the extractor sets `public_access`
     + `website_hosting` (today only Compute.StaticSite triggers this
     via the publicWebsiteSource role from the shared classifier
     table), the handler runs a 4-step create:
       CreateBucket
         → PutPublicAccessBlock (loosen account-default block)
         → PutBucketPolicy      (attach the public-read policy)
         → PutBucketWebsite     (set index/404 pages)
     Plain Storage.Bucket skips all three follow-up commands.

Tests:
  - Existing test harness extended with a makeStsModule mock + a
    FAKE_ACCOUNT_ID constant; the makeFullRegistry now installs STS
    alongside the SDK clients.
  - All existing S3 ARN assertions updated to expect the suffixed form.
  - 3 new tests: account-id suffix lock-in, public-website 4-step
    sequence with policy + website config, plain-bucket negative path.

64 → 67 AWS deployer tests passing.

* feat(deploy/aws): lambda handler — fail-fast role + code-source validation

Handler #9 in Phase 2.

Hardens the existing Lambda S3-ref handler with two pre-create
validations that turn cryptic AWS API errors into clear messages:

  1. **IAM role required.** The AWS SDK returns "Could not find
     resource ..." when CreateFunction is called with an empty Role
     ARN. The handler now refuses up front with:
     "Lambda function requires an IAM execution role ARN
     (properties.role). Wire one in or use the auto-role helper."

  2. **Code source required.** When neither s3_bucket + s3_key NOR a
     base64 zip_file is supplied, the handler refuses with:
     "Lambda function code source is missing. Provide
     properties.code.{s3Bucket,s3Key} or zip_file (auto-build from
     Source.Repository lands in a later commit)."

Both checks fire before any SDK call, so the failure surfaces in the
deployer's `error` field with full context instead of as an opaque
AWS error.

Tests updated so happy-path Lambda create tests now pass both role
and code source. 2 new tests pin the fail-fast paths.

* feat(deploy/aws): cloudwatch-logs handler + shared _result helpers

Handler #10 in Phase 2.

  providers/aws/handlers/cloudwatch-logs.ts (new):
    - aws.cloudwatch.logGroup handler — CreateLogGroup +
      PutRetentionPolicy (when retention_in_days set) on create.
      PutRetentionPolicy on update. DeleteLogGroup on delete.

  providers/aws/handlers/_result.ts (new):
    - ok / err / sdkMissing helpers shared across all AWS handlers.
      Stops the per-handler result/fail boilerplate copy-paste.

  providers/aws/sdk-loader.ts: load @aws-sdk/client-cloudwatch-logs
    under the 'cloudwatch-logs' client key.

  providers/aws/aws-deployer.ts: register cloudwatch_logs_handler
    in HANDLER_REGISTRY.

Tests: 3 new — create-with-retention, create-without-retention skips
PutRetentionPolicy, delete sequence. Test harness extended with
makeCloudWatchLogsModule + corresponding FakeImportRegistry entry.

* feat(deploy/aws): secrets-manager handler + shared test harness

Handler #11 in Phase 2.

  providers/aws/handlers/secrets-manager.ts (new):
    - aws.secretsmanager.secret handler. Mirrors the GCP Secret
      Manager contract: the schema-declared deploy-expansion pass
      emits one Secret per binding row; this handler just creates /
      updates / deletes ONE. Values are NOT written (operators
      populate via AWS console/CLI — same security tradeoff as GCP).
    - delete uses ForceDeleteWithoutRecovery=true (skips the 30-day
      recovery window — appropriate when ICE removes the binding).

  providers/aws/sdk-loader.ts: load @aws-sdk/client-secrets-manager
    under the 'secrets-manager' client key.

  providers/aws/aws-deployer.ts: register secrets_manager_handler.

  providers/__tests__/_aws-test-harness.ts (new):
    Extracts the Function-constructor stub + generic SDK-mock factory
    out of the original aws-deployer.test.ts so per-handler test
    files stay small. Strips the trailing 'Command' from command
    class names when building the __cmd label so assertions read the
    operation name (`CreateSecret`, not `CreateSecretCommand`).

  providers/__tests__/aws-secrets-manager.test.ts (new): 4 focused
    tests — create returns the SDK ARN, update + delete sequences,
    SDK-not-installed path.

* feat(deploy/aws): sqs handler — CreateQueue/SetQueueAttributes/DeleteQueue, FIFO .fifo suffix

Handler #12 in Phase 2. Standard + FIFO queues. FIFO queues get the
.fifo suffix appended to the name automatically (AWS enforces). 3
focused tests.

* feat(deploy/aws): sns handler — CreateTopic/SetTopicAttributes/DeleteTopic, FIFO .fifo suffix

* feat(deploy/aws): dynamodb handler — CreateTable + key schema + PITR

* feat(deploy/aws): elasticache handler — single-node + replication-group paths

* feat(deploy/aws): rds handler — no-default-password gate + provisioning poll

Handler #16 in Phase 2. CreateDBInstance + 20-min status-poll loop
that respects ctx.abort_signal and reports progress via on_step.
Refuses to create when master_user_password is empty (parity with
the extractor's no-default-password invariant).

* feat(deploy/aws): docdb handler — cluster + per-instance creation

* feat(deploy/aws): cognito handler — user pool with password policy + MFA

* feat(deploy/aws): cloudfront handler — us-east-1 ACM cert + minimal distribution

Handler #19. CloudFront requires ACM certs in us-east-1 regardless
of deploy region; the handler spins up a one-shot ACM client pinned
to us-east-1 for RequestCertificate, then attaches the ARN to the
distribution's ViewerCertificate. Falls back to CloudFrontDefaultCertificate
when ACM SDK is absent.

* feat(deploy/aws): elbv2 handler — LB + skeleton target group

* feat(deploy/aws): api-gateway handler — REST API + default-stage deployment

* feat(deploy/aws): events-rule handler (CronJob) — PutRule + PutTargets

* feat(deploy/aws): ecs handler — auto-cluster + task role + service create

Handler #23. Compute.Container 'just works' on AWS — the handler
idempotently bootstraps ecsTaskExecutionRole + ice-default-cluster
before RegisterTaskDefinition + CreateService. Mirrors the GCP
Cloud Run UX (no cluster to think about).

* feat(deploy/aws): opensearch handler — CreateDomain with cluster/EBS/encryption config

* feat(deploy/aws): bedrock handler — on-demand no-op + provisioned-throughput create

* feat(deploy/aws): sagemaker handler — EndpointConfig + Endpoint, requires model_name

* feat(deploy/aws): redshift handler — CreateCluster + no-default-password gate

* feat(deploy/aws): lambda auto-build from Source.Repository

Phase 3 (commit #28). When a Compute.ServerlessFunction block has a
connected Source.Repository AND no explicit S3 ref, the handler
auto-builds the zip and uploads it before CreateFunction:

  1. git clone --depth 1 --branch <branch> <repo>
  2. npm install --omit=dev (skipped if no package.json)
  3. zip -qr function.zip .
  4. PutObject to ice-bootstrap-{accountId}-{region}/lambda/{name}/{ts}.zip
     (HeadBucket → CreateBucket if absent)
  5. Stamp s3_bucket + s3_key onto properties and continue.

Local-only — assumes git/npm/zip on the deploy host. AWS CodeBuild
integration deferred to a future commit. Existing manual S3-ref + zip
paths are unchanged; the auto-build branch only fires when
`properties.repository` is set AND no explicit code source exists.

* test(deploy/aws): unskip AWS Type Map block + end-to-end coverage

Phase 4 commit #29. With every aws.* resource type registered in
PROPERTY_EXTRACTORS (commits #2#6), the AWS Type Map test block can
finally turn on. Expanded the iceType matrix from 5 to 19 entries
covering every AWS-mapped block.

New end-to-end test wires Compute.StaticSite + Security.Secret (with
two bindings — exercising the schema-declared deploy-expansion pass)
+ Database.PostgreSQL into a single translator call, asserts the
resulting graph has 4 deployables resolving to s3.bucket /
secretsmanager.secret×2 / rds.dbInstance. The Azure block remains
skipped (deferred to a future Azure handler buildout).

* docs(deploy/aws): provider notes — quirks, assumptions, deferred work

Phase 4 commit #30 — final commit of the AWS buildout.

providers/aws/README.md documents the AWS-specific decisions the 30
commits in this series bake in:

  - architecture (mirrors gcp/, schema-driven HANDLER_REGISTRY)
  - S3 account-id suffix
  - CloudFront us-east-1 cert
  - ECS auto-cluster + task role
  - RDS / DocDB / Redshift no-default-password invariant
  - RDS provisioning poll
  - Lambda auto-build flow (git + npm + zip + bootstrap S3)
  - Bedrock on-demand no-op
  - Secrets Manager values-never-written contract
  - SQS / SNS .fifo suffix
  - SDK packages as optional peer deps
  - test harness layout
  - deferred work (VPC blocks, CodeBuild, drift detection, LocalStack)

Read this before changing any AWS handler.

* feat(aws): selectively enable safe categories via feature flags

Flip PROVIDER_FLAGS.aws.enabled to true with a hand-picked category
map (Storage, Messaging, Cache, Monitoring, Security, Source, Config).
Compute / Frontend / Scheduler / Network / Database / AI / Analytics
stay gated until their concrete unblockers land — ECS VPC blocks,
CloudFront cert-validation flow, update-paths, etc.

README.md gets a Rollout state table documenting why each gated
category is held back and what unblocks it.

Integrity test in packages/constants asserts the per-category map
stays exhaustive, so future CategoryId additions force a deliberate
on/off decision here.

* fix(palette): enable provider dropdown items when any block is available

Replace the project-provider lock on the palette provider dropdown
with an availability check: a provider option is selectable iff at
least one concept has it in providers and its category is enabled
for that provider.

Before: in a GCP project, AWS was greyed in the palette dropdown
even after AWS feature-flag enabled — so users couldn't browse the
AWS catalog from a GCP project.

After: AWS opens as long as it has any available block under the
current PROVIDER_FLAGS — drag-into-project compatibility remains
enforced at the canvas-drop layer.

availableProviderIds is derived in resource-palette.tsx from the
unfiltered component list using isCategoryEnabledForProvider — same
schema-driven gate the component filter already uses.

* docs(architecture): explain how canvas edges become cloud infra

New page docs/architecture/connections-to-cloud.md walks the five-layer
pipeline (connection-rules → propagation → type-maps → extractors →
handlers) and grounds it with two worked GCP examples:

- Storage.Bucket → Compute.BackendAPI: env-var injection + IAM binding,
  no edge resource in GCP.
- Compute.CronJob → Compute.BackendAPI: Cloud Scheduler HTTP target +
  run.invoker IAM binding.

Links the new page from architecture/README.md and the existing
core-engine.md "Computing flows" section so readers landing on either
find their way to the deep dive.

* fix(typecheck): unblock blocks + templates + core deploy-expansion

- deploy-expansion: use get_node_by_name for name-based dedup; has_node
  expects a branded NodeId, not a plain string.
- requirements.test: vitest needs `beforeEach` in the named imports
  (was previously globalised but tsc no longer sees it).
- validate.test: annotate `.map((c) => ...)` callbacks; vitest's bare
  `ReturnType<typeof vi.spyOn>` no longer carries the called-fn signature
  so the implicit-any error fires.

* fix(typecheck): unblock packages/ui + packages/web

Sweep the workspace's pre-existing typecheck errors so the whole repo
compiles cleanly under tsc --noEmit:

- packages/constants: re-export IntegrationStatus from the barrel so
  packages/ui/src/store/slices/integrations-slice.ts resolves.
- vitest type tightening: `vi.fn(() => ...)` infers Parameters as [],
  breaking `.mock.calls[i][j]` indexing. Widen to (..._args: unknown[])
  on the mock decls that get indexed (deploy-panel, requirements-
  section, deploy-diagnosis, inline-table-view, axios-instance,
  use-cost-calculation, use-computing-flows, template-picker,
  invite-accept).
- stopPropagation event mocks: vitest no longer accepts
  `{ stopPropagation: vi.fn() } as React.MouseEvent` without an unknown
  intermediate. Sweep through compact-node / custom-domain / group-node
  / log-node / palette / inline-table tests.
- KNOWN_MOCKS includes: cast through unknown[] in canvas-context-menu
  and inline-table-view test helpers.
- block-summary-card: import CanvasNode from ../../../svg-canvas (the
  path resolved one level too shallow).
- blueprints test: import BlockBlueprint from ../types not ../../types.
- group-node + region-label test fixtures: type 'container' (the
  CanvasNode union doesn't include 'group' or 'region' yet).
- reroute-node: switch sockets prop from SocketDef[] to PortDef[] with
  role: 'any' to match TypedSockets' contract.
- use-wizard-state: add missing 'name' field on EnvironmentPreset
  fixture.
- store/index.test: cast resolveFirst to its original closure type so
  optional-call type-narrows correctly.
- use-mouse-handlers test: drop minZoom/maxZoom (not in
  UseMouseHandlersDeps).
- deploy-diagnosis: widen the diagnosis state shape; replace
  setImmediate with setTimeout(resolve, 0) — Node's setImmediate isn't
  surfaced in the test types.

* docs(architecture): explain how canvas edges become cloud infra

* docs(readme): link AWS rollout state + connections-to-cloud page

- root README: sharpen "AWS — in progress" to mention the handler /
  extractor count and link the staged-rollout table in the AWS README.
- docs/README: add connections-to-cloud to the architecture mermaid
  and to the contributors table.

* docs(aws): reflect handler buildout + staged rollout

- provider-status: AWS matrix entry now lists the 17 handlers + 20
  extractors and the per-category feature-flag state instead of the
  stale "EC2 / S3 / Lambda only" copy.
- deploying-to-aws: drop the dead reference to "provider-status.md - to
  be added" (the doc exists now), fix the broken handlers-source link
  (handlers live at packages/core/src/deploy/providers/aws/, not
  packages/providers/aws/), fix the broken architecture.md anchor.
- Add a quirks section pointing operators at the AWS README for S3
  account-id suffix, CloudFront us-east-1 cert pin, ECS auto-cluster,
  RDS password gate + provisioning poll, Lambda auto-build, FIFO
  suffix. Update the "known gaps" list to match the deferred items in
  the AWS README (VPC blocks, CodeBuild, update paths, LocalStack).
Bumps the vitest group with 1 update in the / directory: [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `vitest` from 4.1.0 to 4.1.7
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.7/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: vitest
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot changed the title chore(deps)(deps-dev): bump vitest from 4.1.0 to 4.1.7 in the vitest group chore(deps)(deps-dev): bump vitest from 4.1.0 to 4.1.7 in the vitest group across 1 directory May 28, 2026
@dependabot dependabot Bot force-pushed the dependabot/npm_and_yarn/vitest-ecf7382d62 branch from c090ce5 to 78154b4 Compare May 28, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants