thinkwork-cli 0.13.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -14
- package/dist/{api-client-4DZ266J5.js → api-client-4P4JZOBX.js} +3 -1
- package/dist/bowser-6Z6JFAIR.js +2822 -0
- package/dist/{chunk-Y2WHJECR.js → chunk-4OMDWYZQ.js} +5 -44
- package/dist/chunk-AD2NIWB5.js +6516 -0
- package/dist/chunk-DV3MRBR5.js +43 -0
- package/dist/chunk-EI5ZX7CN.js +522 -0
- package/dist/chunk-EUJ7X6YD.js +126 -0
- package/dist/chunk-GG5WKBOX.js +436 -0
- package/dist/chunk-I64EZSU5.js +358 -0
- package/dist/chunk-KMIJ5KGT.js +128 -0
- package/dist/chunk-MWQ7RO76.js +137 -0
- package/dist/chunk-OCPHU34C.js +996 -0
- package/dist/chunk-OLUQ4U2Z.js +1728 -0
- package/dist/chunk-XYM7PE2A.js +2264 -0
- package/dist/chunk-YQCYD6NE.js +3299 -0
- package/dist/cli.js +49156 -31257
- package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +0 -1
- package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +0 -1
- package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +0 -14
- package/dist/dist-es-2OTNTL4N.js +315 -0
- package/dist/dist-es-2XVAH4BQ.js +14726 -0
- package/dist/dist-es-3DPDUJAH.js +2000 -0
- package/dist/dist-es-BNZTBBVC.js +176 -0
- package/dist/dist-es-CD2RBDAC.js +88 -0
- package/dist/dist-es-I4FW57PS.js +88 -0
- package/dist/dist-es-KL7Y5NB2.js +377 -0
- package/dist/dist-es-KVFWJNDY.js +318 -0
- package/dist/dist-es-PS73DWNL.js +70 -0
- package/dist/dist-es-S3NZQFGT.js +170 -0
- package/dist/dist-es-SGCA4P32.js +48 -0
- package/dist/dist-es-WBM6J4RA.js +70 -0
- package/dist/dist-es-ZGVADYIF.js +485 -0
- package/dist/dist-es-ZKC2QKD2.js +377 -0
- package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
- package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
- package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
- package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
- package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
- package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
- package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
- package/dist/drizzle/0227_analyst_reader_role.sql +17 -20
- package/dist/drizzle/0230_analyst_rls.sql +28 -36
- package/dist/drizzle/0250_kg_schema_extraction.sql +27 -0
- package/dist/drizzle/0251_brain_stragglers.sql +21 -0
- package/dist/drizzle/0253_drop_brain_substrate.sql +2 -0
- package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
- package/dist/drizzle/0261_native_auth_control_plane.sql +332 -0
- package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
- package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
- package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
- package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
- package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
- package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
- package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
- package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
- package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
- package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
- package/dist/drizzle/0269_ontology_system_map.sql +31 -0
- package/dist/drizzle/0270_tool_execution_ledger.sql +115 -0
- package/dist/drizzle/0271_ontology_twin_declarations.sql +47 -0
- package/dist/drizzle/0272_identity_graph_projection_cursor.sql +23 -0
- package/dist/drizzle/0273_twin_materialization_suggestions.sql +29 -0
- package/dist/drizzle/0274_tenant_mcp_twin_keys.sql +59 -0
- package/dist/drizzle/0275_identity_bulk_rebuild_fence.sql +30 -0
- package/dist/drizzle/0276_tool_execution_ledger_allow_cascade_delete.sql +18 -0
- package/dist/drizzle/0277_knowledge_base_sources.sql +107 -0
- package/dist/drizzle/0278_kb_page_transcription.sql +55 -0
- package/dist/drizzle/0279_mcp_servers_off_plugin_provenance.sql +93 -0
- package/dist/drizzle/0280_work_item_external_refs_drop_plane_provider.sql +46 -0
- package/dist/drizzle/0281_tenant_mcp_twin_keys_expiry_suffix.sql +9 -0
- package/dist/drizzle/0282_tenant_mcp_twin_keys_grants.sql +24 -0
- package/dist/drizzle/0283_agents_agentcore_runtime_dispatch.sql +13 -0
- package/dist/drizzle/0284_user_brain_claims.sql +69 -0
- package/dist/drizzle/0285_tenant_mcp_twin_keys_trusted_subsystem.sql +30 -0
- package/dist/drizzle/0286_brain_analytics_key.sql +26 -0
- package/dist/drizzle/0287_brain_subject.sql +25 -0
- package/dist/drizzle/0288_multi_lane_identities.sql +25 -0
- package/dist/event-streams-7JNLJEEL.js +894 -0
- package/dist/event-streams-KDF5RWR6.js +1515 -0
- package/dist/loadSso-ETCXTR4I.js +576 -0
- package/dist/loadSso-UBD7KUHE.js +583 -0
- package/dist/plugins/README.md +2 -2
- package/dist/plugins/catalog/package.json +1 -5
- package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +6 -4
- package/dist/plugins/catalog/src/__tests__/catalog.test.ts +21 -21
- package/dist/plugins/catalog/src/__tests__/contracts.test.ts +102 -94
- package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +7 -8
- package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -20
- package/dist/plugins/catalog/src/contracts.ts +17 -179
- package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -24
- package/dist/plugins/n8n/test/integrated-app-contract.test.ts +1 -1
- package/dist/plugins/twenty/package.json +2 -1
- package/dist/plugins/twenty/scripts/LAMBDA_DEPLOY.md +114 -0
- package/dist/plugins/twenty/scripts/build-lambda.sh +29 -0
- package/dist/plugins/twenty/scripts/configure-product-views.ts +195 -0
- package/dist/plugins/twenty/scripts/lambda-handler.ts +49 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/load-attachments.test.ts +38 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +145 -2
- package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +397 -151
- package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +28 -129
- package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +10 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +13 -8
- package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +222 -2
- package/dist/plugins/twenty/scripts/lib/load-attachments.ts +29 -0
- package/dist/plugins/twenty/scripts/lib/load-records.ts +160 -43
- package/dist/plugins/twenty/scripts/lib/mappers.ts +368 -152
- package/dist/plugins/twenty/scripts/lib/members-ensure.ts +43 -268
- package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +57 -0
- package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +136 -31
- package/dist/plugins/twenty/scripts/migrate-lastmile.ts +254 -152
- package/dist/plugins/twenty/scripts/provision-twenty-members.ts +44 -1
- package/dist/plugins/twenty/scripts/purge-lastmile-import.ts +178 -0
- package/dist/plugins/twenty/scripts/restructure-products.ts +312 -0
- package/dist/plugins/twenty/scripts/retag-stage-values.ts +362 -0
- package/dist/plugins/twenty/test/manifest.test.ts +2 -4
- package/dist/scripts/post-deploy.sh +79 -1
- package/dist/signin-5QZNRSOO.js +821 -0
- package/dist/sso-oidc-XK673P54.js +837 -0
- package/dist/sts-OXI2UALF.js +1113 -0
- package/dist/sts-SQW4NBK3.js +1117 -0
- package/dist/terraform/examples/greenfield/main.tf +391 -176
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +26 -8
- package/dist/terraform/modules/app/agentcore-admin/main.tf +47 -0
- package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +39 -47
- package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +13 -66
- package/dist/terraform/modules/app/agentcore-identity/main.tf +253 -0
- package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +239 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +22 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_workload_identity.sh +19 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/ensure_workload_identity.sh +29 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +55 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +45 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +123 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/after.tf +15 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/before.tf +7 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-after.tf +8 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-before.tf +9 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-after.tf +3 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-before.tf +3 -0
- package/dist/terraform/modules/app/agentcore-identity/variables.tf +60 -0
- package/dist/terraform/modules/app/agentcore-memory/README.md +46 -9
- package/dist/terraform/modules/app/agentcore-memory/main.tf +27 -10
- package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +156 -24
- package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
- package/dist/terraform/modules/app/agentcore-pi/main.tf +42 -52
- package/dist/terraform/modules/app/agentcore-pi/outputs.tf +3 -3
- package/dist/terraform/modules/app/agentcore-pi/scripts/reconcile_pi_runtime.mjs +175 -0
- package/dist/terraform/modules/app/agentcore-pi/variables.tf +35 -28
- package/dist/terraform/modules/app/agentcore-platform/main.tf +68 -0
- package/dist/terraform/modules/app/agentcore-runtime/main.tf +4 -20
- package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
- package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
- package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
- package/dist/terraform/modules/app/capability-broker/main.tf +2 -2
- package/dist/terraform/modules/app/capability-broker/variables.tf +11 -0
- package/dist/terraform/modules/app/deployment-control-plane/README.md +264 -0
- package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +4 -1
- package/dist/terraform/modules/app/deployment-control-plane/main.tf +94 -0
- package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +5 -0
- package/dist/terraform/modules/app/deployment-control-plane/runner.py +3689 -233
- package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +2579 -140
- package/dist/terraform/modules/app/deployment-control-plane/variables.tf +33 -0
- package/dist/terraform/modules/app/lambda-api/auth-state.tf +72 -0
- package/dist/terraform/modules/app/lambda-api/chat-latency-observability.tf +466 -0
- package/dist/terraform/modules/app/lambda-api/dispatch-dlq.tf +55 -0
- package/dist/terraform/modules/app/lambda-api/handlers.tf +531 -619
- package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +350 -241
- package/dist/terraform/modules/app/lambda-api/main.tf +75 -13
- package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +3 -28
- package/dist/terraform/modules/app/lambda-api/oauth-secrets.tf +1 -2
- package/dist/terraform/modules/app/lambda-api/outputs.tf +17 -10
- package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
- package/dist/terraform/modules/app/lambda-api/turn-assertion.tf +45 -0
- package/dist/terraform/modules/app/lambda-api/variables.tf +307 -121
- package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/README.md +1 -1
- package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/main.tf +18 -18
- package/dist/terraform/modules/app/sandbox-log-scrubber/README.md +11 -10
- package/dist/terraform/modules/app/sandbox-log-scrubber/main.tf +5 -5
- package/dist/terraform/modules/app/static-site/main.tf +1 -1
- package/dist/terraform/modules/app/www-dns/main.tf +9 -27
- package/dist/terraform/modules/app/www-dns/variables.tf +4 -10
- package/dist/terraform/modules/data/aurora-postgres/README.md +34 -0
- package/dist/terraform/modules/data/aurora-postgres/alarms.tf +82 -0
- package/dist/terraform/modules/data/aurora-postgres/main.tf +27 -57
- package/dist/terraform/modules/data/aurora-postgres/outputs.tf +0 -9
- package/dist/terraform/modules/data/aurora-postgres/variables.tf +41 -0
- package/dist/terraform/modules/data/s3-buckets/main.tf +5 -6
- package/dist/terraform/modules/foundation/cognito/main.tf +367 -72
- package/dist/terraform/modules/foundation/cognito/outputs.tf +47 -0
- package/dist/terraform/modules/foundation/cognito/variables.tf +131 -9
- package/dist/terraform/modules/thinkwork/README.md +5 -1
- package/dist/terraform/modules/thinkwork/main.tf +459 -234
- package/dist/terraform/modules/thinkwork/outputs.tf +44 -62
- package/dist/terraform/modules/thinkwork/variables.tf +353 -89
- package/dist/terraform/schema.graphql +69 -36
- package/dist/workspace-defaults/files/INSTRUCTIONS.md +9 -11
- package/dist/workspace-defaults/files/MEMORY_GUIDE.md +38 -35
- package/dist/workspace-defaults/files/ROUTER.md +1 -1
- package/dist/workspace-defaults/files/TOOLS.md +9 -39
- package/dist/workspace-defaults/files/USER.md +1 -0
- package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +6 -3
- package/dist/workspace-defaults/files/catalog-skills/brain-brief-builder/SKILL.md +165 -0
- package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/SKILL.md +75 -0
- package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
- package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
- package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/workflow-authoring.md +46 -0
- package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +1 -1
- package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +22 -3
- package/package.json +3 -2
- package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +0 -11
- package/dist/plugins/company-data/README.md +0 -49
- package/dist/plugins/company-data/package.json +0 -21
- package/dist/plugins/company-data/src/index.ts +0 -30
- package/dist/plugins/company-data/src/manifest.ts +0 -26
- package/dist/plugins/company-data/test/manifest.test.ts +0 -116
- package/dist/plugins/company-data/tsconfig.json +0 -8
- package/dist/plugins/company-etl/README.md +0 -46
- package/dist/plugins/company-etl/package.json +0 -21
- package/dist/plugins/company-etl/src/index.ts +0 -29
- package/dist/plugins/company-etl/src/manifest.ts +0 -26
- package/dist/plugins/company-etl/test/manifest.test.ts +0 -108
- package/dist/plugins/company-etl/tsconfig.json +0 -8
- package/dist/plugins/lastmile/README.md +0 -50
- package/dist/plugins/lastmile/package.json +0 -23
- package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +0 -661
- package/dist/plugins/lastmile/src/api/tasks-adapter.ts +0 -572
- package/dist/plugins/lastmile/src/discovery.fixture.ts +0 -64
- package/dist/plugins/lastmile/src/index.ts +0 -46
- package/dist/plugins/lastmile/src/manifest.ts +0 -139
- package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +0 -266
- package/dist/plugins/lastmile/test/discovery.test.ts +0 -88
- package/dist/plugins/lastmile/tsconfig.json +0 -8
- package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +0 -409
- package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +0 -359
- package/dist/plugins/workos-auth/package.json +0 -22
- package/dist/plugins/workos-auth/src/index.ts +0 -30
- package/dist/plugins/workos-auth/src/manifest.ts +0 -40
- package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
- package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
- package/dist/plugins/workos-auth/tsconfig.json +0 -8
- package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +0 -61
- package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +0 -227
- package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +0 -277
- package/dist/terraform/modules/app/agentcore-code-interpreter/scripts/build_and_push_sandbox_base.sh +0 -70
- package/dist/terraform/modules/app/agentcore-harness/main.tf +0 -101
- package/dist/terraform/modules/app/agentcore-harness/outputs.tf +0 -9
- package/dist/terraform/modules/app/agentcore-harness/variables.tf +0 -25
- package/dist/terraform/modules/app/hindsight-memory/README.md +0 -89
- package/dist/terraform/modules/app/hindsight-memory/main.tf +0 -411
- package/dist/terraform/modules/data/bedrock-knowledge-base/main.tf +0 -102
- /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/outputs.tf +0 -0
- /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/sync-database.py +0 -0
- /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/test_sync_database.py +0 -0
- /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/variables.tf +0 -0
- /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/README.md +0 -0
- /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/main.tf +0 -0
- /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/outputs.tf +0 -0
- /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/variables.tf +0 -0
|
@@ -14,6 +14,12 @@ locals {
|
|
|
14
14
|
# deployment jobs — plan 2026-06-12-001 U10); the TWENTY config key is
|
|
15
15
|
# retired.
|
|
16
16
|
optional_integration_handler_names = concat(
|
|
17
|
+
var.auth_retirement_phase == "retired" ? [
|
|
18
|
+
# The native login UI never publishes this handler. It remains reachable
|
|
19
|
+
# only as an operator-controlled rollback seam through coexistence and
|
|
20
|
+
# cutover/soak, then Terraform removes the Lambda and routes atomically.
|
|
21
|
+
"workos-auth",
|
|
22
|
+
] : [],
|
|
17
23
|
var.deployment_control_plane_enabled ? [] : [
|
|
18
24
|
# Host-only onboarding/deployment API. Customer foundations disable the
|
|
19
25
|
# deployment control plane, so release-based customer installs must not
|
|
@@ -47,49 +53,59 @@ locals {
|
|
|
47
53
|
# The reader-coverage fixture test in apps/cli fails CI if a key in this
|
|
48
54
|
# map still has a direct process.env reader. Identity values (STAGE,
|
|
49
55
|
# AWS_ACCOUNT_ID, NODE_OPTIONS) and secrets (DATABASE_URL,
|
|
50
|
-
# API_AUTH_SECRET
|
|
56
|
+
# API_AUTH_SECRET) stay out of this map — identity stays
|
|
51
57
|
# env forever, secrets live in Secrets Manager (R4), never in the String
|
|
52
58
|
# document.
|
|
53
59
|
config_env = merge({
|
|
54
60
|
# THINK-173: PUBLIC verification key (not a secret) + the NAME of the
|
|
55
61
|
# private-key secret (resolved via runtime-config's secret loader —
|
|
56
62
|
# the PEM itself never enters the env or the String document).
|
|
57
|
-
CAPABILITY_SIGNING_PUBLIC_KEY
|
|
58
|
-
CAPABILITY_SIGNING_PRIVATE_KEY_SECRET
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
63
|
+
CAPABILITY_SIGNING_PUBLIC_KEY = var.capability_signing_public_key
|
|
64
|
+
CAPABILITY_SIGNING_PRIVATE_KEY_SECRET = var.capability_signing_private_key_secret
|
|
65
|
+
SUBSCRIPTION_TICKET_SIGNING_KEY_ID = var.subscription_ticket_signing_key_id
|
|
66
|
+
SUBSCRIPTION_TICKET_PUBLIC_KEYS = var.subscription_ticket_public_keys
|
|
67
|
+
SUBSCRIPTION_TICKET_PRIVATE_KEY_SECRET = var.subscription_ticket_private_key_secret
|
|
68
|
+
APPSYNC_API_ID = var.appsync_api_id
|
|
69
|
+
# THINK-585 U6 (KTD3): stage kill-switch for AgentCore Runtime chat
|
|
70
|
+
# dispatch. Empty when off (stripped from the document — getConfig sees
|
|
71
|
+
# unset). The per-agent agents.agentcore_runtime_dispatch flag gates on
|
|
72
|
+
# top; both must be on for a turn to ride the dispatcher.
|
|
73
|
+
AGENTCORE_RUNTIME_DISPATCH_ENABLED = var.agentcore_runtime_dispatch_enabled ? "true" : ""
|
|
74
|
+
# Neptune endpoint for the
|
|
75
|
+
# identity-graph-projector's nudge gate (THINK-339 U15: the twin READ
|
|
76
|
+
# Lambdas retired to the platform service; the write/projection lane
|
|
77
|
+
# stays product-side — the platform identity_sync pipeline invokes it).
|
|
78
|
+
# Document, not env: graphql-http's env sits near the 4KB ceiling.
|
|
79
|
+
# Readers use getConfig; env still wins on the VPC projector.
|
|
80
|
+
NEPTUNE_ENDPOINT = var.neptune_endpoint
|
|
81
|
+
# Consolidation U14: platform-served Brain MCP endpoint. When set,
|
|
82
|
+
# mcp-twin-provision registers the twin connector against it instead
|
|
83
|
+
# of the product /mcp/twin route. Empty = legacy default.
|
|
84
|
+
BRAIN_MCP_URL = var.brain_mcp_url
|
|
85
|
+
# THINK-781: Brain ops-api base URL + the agent-identity m2m secret the
|
|
86
|
+
# flagThreadToBrain resolver posts /flags with. NOT the /mcp lane pair
|
|
87
|
+
# above — POST /flags verifies against the Brain's operator pool, so it
|
|
88
|
+
# needs the etl-platform/agent/cognito-m2m-brain credential (scope
|
|
89
|
+
# etl-agent/tasks), not the brain-mcp platform-agent lane. Empty = the
|
|
90
|
+
# "Send to the Brain" action fails with "no Brain connection configured".
|
|
91
|
+
BRAIN_OPS_API_URL = var.brain_ops_api_url
|
|
92
|
+
BRAIN_OPS_M2M_SECRET_ARN = var.brain_ops_m2m_secret_arn
|
|
93
|
+
# Same class of bug, second instance (2026-07-22): a post-apply
|
|
94
|
+
# twin-export hook read BRAIN_ARTIFACTS_BUCKET from env it never had
|
|
95
|
+
# and silently returned skipped_no_bucket on every apply.
|
|
96
|
+
# Document-served so every api handler resolves it via getConfig; the
|
|
97
|
+
# handlers that already carry it as env keep winning.
|
|
98
|
+
BRAIN_ARTIFACTS_BUCKET = aws_s3_bucket.brain_artifacts.bucket
|
|
99
|
+
DATABASE_SECRET_ARN = var.graphql_db_secret_arn
|
|
100
|
+
DATABASE_HOST = var.db_cluster_endpoint
|
|
101
|
+
DATABASE_NAME = var.database_name
|
|
86
102
|
# THINK-280 U8: the LAST rollout gate. External capability search + the
|
|
87
103
|
# Inspector governed-runtime operation layer stay inert until the broker is
|
|
88
104
|
# enabled for the stage. Off by default — read via getConfig() (env-wins).
|
|
89
105
|
CAPABILITY_EXTERNAL_SEARCH_ENABLED = var.enable_capability_broker ? "true" : "false"
|
|
90
106
|
ENABLE_CAPABILITY_BROKER = var.enable_capability_broker ? "true" : "false"
|
|
91
107
|
# BUCKET_NAME and USER_POOL_ID were duplicate aliases of WORKSPACE_BUCKET
|
|
92
|
-
# and COGNITO_USER_POOL_ID; GRAPHQL_API_KEY
|
|
108
|
+
# and COGNITO_USER_POOL_ID; the legacy GRAPHQL_API_KEY alias is retired;
|
|
93
109
|
# THINKWORK_API_SECRET and EMAIL_HMAC_SECRET duplicated API_AUTH_SECRET
|
|
94
110
|
# (~310 serialized bytes total). graphql-http sits at Lambda's hard 4KB
|
|
95
111
|
# env ceiling (#2375) — every reader falls back to the canonical name.
|
|
@@ -101,9 +117,17 @@ locals {
|
|
|
101
117
|
COGNITO_AUTH_BASE_URL = local.mcp_oauth_cognito_base_url
|
|
102
118
|
MCP_OAUTH_CALLBACK_URL = "${local.mcp_oauth_api_base_url}/mcp/oauth/callback"
|
|
103
119
|
MCP_OAUTH_REVOCATIONS_TABLE = aws_dynamodb_table.mcp_oauth_revocations.name
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
# THINK-643: backing store for short-lived auth-flow state. While this is
|
|
121
|
+
# "postgres" the auth handlers never touch DynamoDB and AUTH_STATE_TABLE is
|
|
122
|
+
# empty (no table exists). Read via getConfig() — never process.env.
|
|
123
|
+
AUTH_STATE_STORE = var.auth_state_store
|
|
124
|
+
AUTH_STATE_TABLE = local.auth_state_enabled ? aws_dynamodb_table.auth_state[0].name : ""
|
|
125
|
+
# R16: comma-separated app-client allowlist. The optional console client id
|
|
126
|
+
# (U13) joins only when enabled; compact() drops the empty placeholder so
|
|
127
|
+
# the value is byte-identical to before while the console is off.
|
|
128
|
+
COGNITO_APP_CLIENT_IDS = join(",", compact([var.admin_client_id, var.mobile_client_id, var.console_client_id]))
|
|
129
|
+
APPSYNC_ENDPOINT = var.appsync_api_url
|
|
130
|
+
THINKWORK_API_URL = local.api_base_url
|
|
107
131
|
# Deterministic routines v1 (plan 2026-07-03-004 U6): activates the
|
|
108
132
|
# git-backed routine lifecycle tool suite on the admin-ops MCP server
|
|
109
133
|
# (routine_repo_list/read/commit, routine_run_fixtures, routine_runs).
|
|
@@ -137,13 +161,11 @@ locals {
|
|
|
137
161
|
# WORKSPACE_RENDERER_FUNCTION_NAME is derived from the per-stage naming
|
|
138
162
|
# convention by deriveFunctionName("workspace-renderer") — stored
|
|
139
163
|
# nowhere (R7).
|
|
140
|
-
WORKSPACE_BUCKET
|
|
141
|
-
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
|
|
145
|
-
AGENTCORE_MEMORY_ID = var.agentcore_memory_id
|
|
146
|
-
MEMORY_ENGINE = var.memory_engine
|
|
164
|
+
WORKSPACE_BUCKET = var.bucket_name
|
|
165
|
+
AGENTCORE_MEMORY_ID = var.agentcore_memory_id
|
|
166
|
+
# AgentCore managed memory is the only engine (THINK-407). The env var
|
|
167
|
+
# stays so the API's memory config seam keeps an explicit value.
|
|
168
|
+
MEMORY_ENGINE = "agentcore"
|
|
147
169
|
# CHAT_AGENT_INVOKE_FN_ARN (~112 serialized bytes) was dropped for the
|
|
148
170
|
# 4KB env ceiling (#2375): getChatAgentInvokeFnArn and managed-dispatch
|
|
149
171
|
# now derive the ARN from the deterministic naming pattern
|
|
@@ -159,7 +181,6 @@ locals {
|
|
|
159
181
|
# deploymentStatus reads ADMIN_URL directly — so the single canonical
|
|
160
182
|
# ADMIN_URL is sufficient. Re-add aliases only after env vars move to SSM.
|
|
161
183
|
ADMIN_URL = var.admin_url
|
|
162
|
-
DOCS_URL = var.docs_url
|
|
163
184
|
APPSYNC_REALTIME_URL = var.appsync_realtime_url
|
|
164
185
|
ECR_REPOSITORY_URL = var.ecr_repository_url
|
|
165
186
|
# Per-user OAuth wiring (Google Workspace today; Microsoft 365 follow-up).
|
|
@@ -231,18 +252,22 @@ locals {
|
|
|
231
252
|
# window (R8). Config-class keys live ONLY in the SSM runtime-config
|
|
232
253
|
# document now — adding a key here is guarded by the identity-allowlist
|
|
233
254
|
# fixture test in apps/cli (R10). Follow-up release: DATABASE_URL,
|
|
234
|
-
#
|
|
255
|
+
# API_AUTH_SECRET drops too (readers already resolve
|
|
235
256
|
# via Secrets Manager prefetch when the env copies are absent), bringing
|
|
236
257
|
# every handler under the ≤1KB R1 target.
|
|
237
258
|
common_env = {
|
|
238
259
|
STAGE = var.stage
|
|
239
260
|
DATABASE_URL = "postgresql://${var.db_username}:${urlencode(var.db_password)}@${var.db_cluster_endpoint}:5432/${var.database_name}?sslmode=no-verify"
|
|
240
|
-
APPSYNC_API_KEY = var.appsync_api_key
|
|
241
261
|
API_AUTH_SECRET = var.api_auth_secret
|
|
242
262
|
AWS_ACCOUNT_ID = var.account_id
|
|
243
263
|
NODE_OPTIONS = "--enable-source-maps"
|
|
244
264
|
}
|
|
245
265
|
|
|
266
|
+
# THINK-316 U1: the assertion mint runs on a sibling role and receives only
|
|
267
|
+
# the database connection plus immutable stage identity. In particular it
|
|
268
|
+
# does not inherit API_AUTH_SECRET or APPSYNC_API_KEY from common_env.
|
|
269
|
+
|
|
270
|
+
|
|
246
271
|
# Per-handler env-var overrides. ARNs are constructed from the naming
|
|
247
272
|
# pattern (same trick as the api-cross-function-invoke statement in
|
|
248
273
|
# iam-grouped.tf) so we don't introduce a self-referential dependency
|
|
@@ -256,39 +281,26 @@ locals {
|
|
|
256
281
|
}
|
|
257
282
|
|
|
258
283
|
handler_extra_env = {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
"
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
ANALYST_DB_USER = "analyst_reader"
|
|
280
|
-
}
|
|
281
|
-
# THINK-229 U5 — the connection reconciler probes the analyst_reader
|
|
282
|
-
# connection EXACTLY as the broker does (getAnalystReaderClient), so it
|
|
283
|
-
# needs the same IAM-connect config + the password-fallback secret. The
|
|
284
|
-
# shared lambda execution role already holds rds-db:connect on the
|
|
285
|
-
# analyst_reader dbuser (iam-grouped.tf, granted in U1), so no extra IAM.
|
|
286
|
-
"analyst-connection-reconciler" = {
|
|
287
|
-
ANALYST_READER_SECRET_ARN = var.analyst_reader_secret_arn
|
|
288
|
-
ANALYST_DB_CLUSTER_ENDPOINT = var.analyst_db_cluster_resource_id != "" ? var.db_cluster_endpoint : ""
|
|
289
|
-
ANALYST_DB_CLUSTER_RESOURCE_ID = var.analyst_db_cluster_resource_id
|
|
290
|
-
ANALYST_DB_NAME = var.database_name
|
|
291
|
-
ANALYST_DB_USER = "analyst_reader"
|
|
284
|
+
"skills" = {
|
|
285
|
+
AGENTCORE_IDENTITY_WORKLOAD_NAME = "thinkwork-${var.stage}-multiplayer-proof"
|
|
286
|
+
AGENTCORE_TWENTY_CREDENTIAL_PROVIDER_NAME = "thinkwork-${var.stage}-twenty-crm"
|
|
287
|
+
AGENTCORE_USER_OAUTH_RETURN_URL = "${local.mcp_oauth_api_base_url}/api/skills/mcp-oauth/agentcore/complete"
|
|
288
|
+
AGENTCORE_TWENTY_OAUTH_RESOURCE = "https://crm.thinkwork.ai/mcp"
|
|
289
|
+
}
|
|
290
|
+
"workos-auth" = {
|
|
291
|
+
# During cutover/soak the callback, bridge, and logout paths remain for
|
|
292
|
+
# already-issued state, but the handler independently refuses every new
|
|
293
|
+
# WorkOS authorize start. Terraform removes the handler in retired.
|
|
294
|
+
AUTH_RETIREMENT_PHASE = var.auth_retirement_phase
|
|
295
|
+
}
|
|
296
|
+
"public-auth-options" = {
|
|
297
|
+
AUTH_RETIREMENT_PHASE = var.auth_retirement_phase
|
|
298
|
+
}
|
|
299
|
+
"auth-me" = {
|
|
300
|
+
AUTH_MIGRATION_RECOVERY_DEADLINE = var.auth_migration_recovery_deadline
|
|
301
|
+
}
|
|
302
|
+
"auth-enrollment" = {
|
|
303
|
+
AUTH_MIGRATION_RECOVERY_DEADLINE = var.auth_migration_recovery_deadline
|
|
292
304
|
}
|
|
293
305
|
# THINK-246: customer stages cannot send as the dev fallback domain
|
|
294
306
|
# (noreply@agents.thinkwork.ai is only verified in the dev account) —
|
|
@@ -332,46 +344,6 @@ locals {
|
|
|
332
344
|
CAPABILITY_BROKER_VPCE_DNS = var.capability_broker_vpce_dns
|
|
333
345
|
CAPABILITY_BROKER_SESSION_TABLE = var.capability_broker_session_table
|
|
334
346
|
}
|
|
335
|
-
# Compounding Memory compile Lambda. Any Converse-compatible Bedrock
|
|
336
|
-
# model works; the planner + section-writer cap themselves at ~500
|
|
337
|
-
# records / 25 new pages per invocation so a 480 s timeout covers
|
|
338
|
-
# the worst case comfortably. Env vars come from variables so
|
|
339
|
-
# unrelated deploys don't wipe them back to defaults (the aggregation
|
|
340
|
-
# flag got reset on every terraform apply before this was pinned).
|
|
341
|
-
"wiki-compile" = {
|
|
342
|
-
BEDROCK_MODEL_ID = var.wiki_compile_model_id
|
|
343
|
-
WIKI_AGGREGATION_PASS_ENABLED = var.wiki_aggregation_pass_enabled
|
|
344
|
-
WIKI_DETERMINISTIC_LINKING_ENABLED = var.wiki_deterministic_linking_enabled
|
|
345
|
-
# Wiki pipeline source dispatch (plan 2026-06-09-004 U10):
|
|
346
|
-
# 'planner' (default, LLM compile) | 'graph' (deterministic
|
|
347
|
-
# graph→wiki materializer over the knowledge-graph mirror).
|
|
348
|
-
WIKI_SOURCE = var.wiki_source
|
|
349
|
-
# Name (not value) of the SecureString SSM parameter that holds the
|
|
350
|
-
# Google Places API key. wiki-compile fetches + caches on cold start.
|
|
351
|
-
# The parameter may contain a placeholder value at apply time — the
|
|
352
|
-
# Lambda logs and degrades gracefully if decryption returns empty.
|
|
353
|
-
GOOGLE_PLACES_SSM_PARAM_NAME = "/thinkwork/${var.stage}/google-places/api-key"
|
|
354
|
-
# THINK-200 chain: a successful compile Event-invokes okf-materialize
|
|
355
|
-
# so the OKF projection (and, chained, the Pi navigator's EFS view)
|
|
356
|
-
# stays current without manual invocation.
|
|
357
|
-
OKF_MATERIALIZE_FN_NAME = "thinkwork-${var.stage}-api-okf-materialize"
|
|
358
|
-
}
|
|
359
|
-
"ontology-scan" = {
|
|
360
|
-
BEDROCK_MODEL_ID = var.wiki_compile_model_id
|
|
361
|
-
}
|
|
362
|
-
"wiki-export" = {
|
|
363
|
-
WIKI_EXPORT_BUCKET = aws_s3_bucket.wiki_exports.bucket
|
|
364
|
-
BRAIN_ARTIFACTS_BUCKET = aws_s3_bucket.brain_artifacts.bucket
|
|
365
|
-
}
|
|
366
|
-
"okf-materialize" = {
|
|
367
|
-
BRAIN_ARTIFACTS_BUCKET = aws_s3_bucket.brain_artifacts.bucket
|
|
368
|
-
# THINK-200 chain: fresh bundles fan out to the EFS current view.
|
|
369
|
-
OKF_EFS_REFRESH_FN_NAME = "thinkwork-${var.stage}-api-okf-efs-refresh"
|
|
370
|
-
}
|
|
371
|
-
"okf-efs-refresh" = {
|
|
372
|
-
BRAIN_ARTIFACTS_BUCKET = aws_s3_bucket.brain_artifacts.bucket
|
|
373
|
-
OKF_EFS_ROOT = var.okf_efs_mount_path
|
|
374
|
-
}
|
|
375
347
|
# THINK-193 U1 (Codex F6): normalized evidence snapshots live in the
|
|
376
348
|
# encrypted brain-artifacts bucket under evidence-snapshots/ — Postgres
|
|
377
349
|
# keeps only the s3:// ref + hash. 30-day lifecycle expiration below.
|
|
@@ -402,56 +374,72 @@ locals {
|
|
|
402
374
|
CONTEXT_ENGINE_MEMORY_QUERY_MODE = "reflect"
|
|
403
375
|
CONTEXT_ENGINE_MEMORY_TIMEOUT_MS = "20000"
|
|
404
376
|
}
|
|
405
|
-
|
|
406
|
-
|
|
377
|
+
"agentcore-runtime-dispatch" = {
|
|
378
|
+
# THINK-585 U6: the dispatcher resolves the Pi runtime id from SSM
|
|
379
|
+
# (5-min cache) and derives the ARN from identity env. Stage-scoped
|
|
380
|
+
# param name is config, not identity — env is the right layer.
|
|
381
|
+
AGENTCORE_PI_RUNTIME_SSM_NAME = "/thinkwork/${var.stage}/agentcore/runtime-id-pi"
|
|
382
|
+
# THINK-909: runtime session scope. "thread" (default) keys the
|
|
383
|
+
# AgentCore session per thread — today's behavior. "user" keys it per
|
|
384
|
+
# (tenant, agent, user) so a new thread reuses the warm microVM, with
|
|
385
|
+
# an immediate per-thread fallback on a 409. Flip a stage to "user"
|
|
386
|
+
# ONLY after its Pi runtime image dual-accepts both session ids.
|
|
387
|
+
AGENTCORE_SESSION_SCOPE = var.agentcore_session_scope
|
|
388
|
+
}
|
|
407
389
|
"chat-agent-invoke" = {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
# THINK-
|
|
421
|
-
#
|
|
422
|
-
#
|
|
423
|
-
"
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
#
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
#
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
390
|
+
# THINK-324 C18: mint the signed-turn assertion with the active key.
|
|
391
|
+
AGENTCORE_TURN_ASSERTION_KMS_KEY_ID = local.turn_assertion_active_key_arn
|
|
392
|
+
# THINK-321 U5: stage gate for the Pi identity-resolution tools; the
|
|
393
|
+
# per-agent tool policy gates on top. Mirrored on wakeup-processor so
|
|
394
|
+
# wakeup turns carry the same payload flag (env-gated feature is dead
|
|
395
|
+
# in deployed stacks without the terraform var).
|
|
396
|
+
IDENTITY_RESOLUTION_ENABLED = tostring(var.identity_resolution_tool_enabled)
|
|
397
|
+
# THINK-311 U5: no HARNESS_RUNNER_FUNCTION_NAME env — derivable
|
|
398
|
+
# thinkwork-<stage>-api-* names never ride env (R1/R10 identity-only
|
|
399
|
+
# rule); resolveRuntimeFunctionName derives it from STAGE at call
|
|
400
|
+
# time, exactly like workspace-renderer.
|
|
401
|
+
}
|
|
402
|
+
# THINK-321 U5: wakeup turns read the same identity-resolution stage
|
|
403
|
+
# gate as chat-agent-invoke (both payload builders emit
|
|
404
|
+
# identity_resolution_enabled).
|
|
405
|
+
"wakeup-processor" = {
|
|
406
|
+
# THINK-324 C18: wakeup dispatches mint the same signed-turn assertion.
|
|
407
|
+
AGENTCORE_TURN_ASSERTION_KMS_KEY_ID = local.turn_assertion_active_key_arn
|
|
408
|
+
IDENTITY_RESOLUTION_ENABLED = tostring(var.identity_resolution_tool_enabled)
|
|
409
|
+
}
|
|
410
|
+
# THINK-324 C18/C19: the ledger endpoint verifies presented assertions
|
|
411
|
+
# with the cached public key of the same active mint key. Required mode:
|
|
412
|
+
# its only producer (the Pi tool-execution emitter) echoes the assertion
|
|
413
|
+
# since C18, so assertion-less ledger writes are refused. Verifier
|
|
414
|
+
# unavailability still degrades to bearer-only (never a write outage);
|
|
415
|
+
# a mint failure at dispatch costs that turn's evidence, logged loudly.
|
|
416
|
+
"tool-executions" = {
|
|
417
|
+
AGENTCORE_TURN_ASSERTION_KMS_KEY_ID = local.turn_assertion_active_key_arn
|
|
418
|
+
TURN_ASSERTION_REQUIRED = "true"
|
|
419
|
+
}
|
|
420
|
+
# THINK-324 C19: activity + finalize verify presented assertions
|
|
421
|
+
# (tolerant posture — legacy producers don't echo yet).
|
|
422
|
+
"chat-agent-activity" = {
|
|
423
|
+
AGENTCORE_TURN_ASSERTION_KMS_KEY_ID = local.turn_assertion_active_key_arn
|
|
424
|
+
}
|
|
425
|
+
"chat-agent-finalize" = {
|
|
426
|
+
AGENTCORE_TURN_ASSERTION_KMS_KEY_ID = local.turn_assertion_active_key_arn
|
|
427
|
+
}
|
|
428
|
+
# THINK-316 U5: the runner reads the server-only attested profile and
|
|
429
|
+
# invokes its named endpoint with a purpose-bound CUSTOM_JWT. It receives
|
|
430
|
+
# no Harness control-plane inputs or permissions.
|
|
431
|
+
# 240s: a sync memory retain (LLM extraction + consolidation) can exceed
|
|
432
|
+
# 60s; the client timeout must stay below the Lambda timeout.
|
|
433
|
+
# Company Brain U5: Neptune coordinates for the twin graph projector.
|
|
434
|
+
# Empty endpoint leaves the projector inert (nudge helper skips too).
|
|
435
|
+
"identity-graph-projector" = {
|
|
436
|
+
NEPTUNE_ENDPOINT = var.neptune_endpoint
|
|
437
|
+
NEPTUNE_PORT = "8182"
|
|
438
|
+
BRAIN_ARTIFACTS_BUCKET = aws_s3_bucket.brain_artifacts.bucket
|
|
439
|
+
# Bulk-rebuild lane (THINK-331): loader staging coordinates. Empty =
|
|
440
|
+
# bulk-rebuild mode returns a structured "not configured" error.
|
|
441
|
+
NEPTUNE_LOAD_BUCKET = var.neptune_load_bucket
|
|
442
|
+
NEPTUNE_LOADER_ROLE_ARN = var.neptune_loader_role_arn
|
|
455
443
|
}
|
|
456
444
|
# routine-task-python (Phase B U6) needs the AgentCore code-interpreter
|
|
457
445
|
# id + the per-stage S3 routine-output bucket. The interpreter id is
|
|
@@ -587,10 +575,17 @@ resource "aws_lambda_function" "skill_trust_runner" {
|
|
|
587
575
|
# Helper: creates Lambda functions from a local zip directory or release S3 keys
|
|
588
576
|
# ---------------------------------------------------------------------------
|
|
589
577
|
|
|
590
|
-
|
|
591
|
-
|
|
578
|
+
# The set of api handlers this module deploys (the for_each source for
|
|
579
|
+
# aws_lambda_function.handler). Hoisted into a local so the per-handler VPC
|
|
580
|
+
# placement map below (THINK-1082) can be built over the same names.
|
|
581
|
+
locals {
|
|
582
|
+
handler_names = local.deploy_lambda_handlers ? setsubtract(toset([
|
|
592
583
|
"graphql-http",
|
|
593
584
|
"chat-agent-invoke",
|
|
585
|
+
# THINK-585 U6: thin waiting dispatcher (InvokeAgentRuntime, held
|
|
586
|
+
# connection) + its DLQ redrive consumer (see dispatch-dlq.tf).
|
|
587
|
+
"agentcore-runtime-dispatch",
|
|
588
|
+
"agentcore-dispatch-dlq-redrive",
|
|
594
589
|
# Mobile agent harness: cloud Bedrock Converse proxy + completed-turn
|
|
595
590
|
# persistence. Routes for these live in local.api_routes; the function
|
|
596
591
|
# names must also be listed here (this set is the for_each source for
|
|
@@ -611,13 +606,6 @@ resource "aws_lambda_function" "handler" {
|
|
|
611
606
|
# Client Engagement app API. Calls Twenty REST API directly server-side;
|
|
612
607
|
# it is not backed by ThinkWork GraphQL or the agent MCP runtime.
|
|
613
608
|
"twenty-client-engagement",
|
|
614
|
-
# Desktop-local Pi tombstone endpoints. Kept temporarily so old packaged
|
|
615
|
-
# desktop clients receive a stable 410 while all supported Pi execution
|
|
616
|
-
# routes through managed AgentCore.
|
|
617
|
-
"desktop-runtime-session",
|
|
618
|
-
"desktop-workspace-prewarm",
|
|
619
|
-
"managed-delegation",
|
|
620
|
-
"desktop-eval-runs",
|
|
621
609
|
# chat-agent-finalize — POST /api/threads/{threadId}/finalize. The
|
|
622
610
|
# AgentCore runtime POSTs here at end-of-turn so the post-AgentCore
|
|
623
611
|
# bookkeeping (cost recording, message insert, AppSync notify,
|
|
@@ -626,6 +614,14 @@ resource "aws_lambda_function" "handler" {
|
|
|
626
614
|
# Bearer API_AUTH_SECRET. Idempotent on thread_turns.finalized_at
|
|
627
615
|
# (migration 0123). Plan: 2026-05-22-006.
|
|
628
616
|
"chat-agent-finalize",
|
|
617
|
+
# agents. The chat dispatch selector (resolveRuntimeFunctionName) routes
|
|
618
|
+
# a trial agent's turn here instead of the Pi container Lambda; the
|
|
619
|
+
# runner projects the payload into an AWS AgentCore Harness config,
|
|
620
|
+
# drives InvokeHarness, fulfills emit_document, and finalizes the turn
|
|
621
|
+
# via processFinalize. No API route — direct Event invoke only.
|
|
622
|
+
# THINK-316 U1: direct-invoke-only assertion mint. It derives all identity
|
|
623
|
+
# claims from the persisted turn tuple and signs with a dedicated KMS key;
|
|
624
|
+
# there is intentionally no public API Gateway route.
|
|
629
625
|
# canvas-refresh — headless Living Artifacts data-refresh (THINK-145 U6).
|
|
630
626
|
# Invoked RequestResponse by the refreshCanvasData mutation (graphql-http)
|
|
631
627
|
# and by job-trigger's canvas_refresh branch (U7). Re-runs the saved
|
|
@@ -659,7 +655,13 @@ resource "aws_lambda_function" "handler" {
|
|
|
659
655
|
"stripe-subscription",
|
|
660
656
|
"deployment-sessions",
|
|
661
657
|
"auth-me",
|
|
658
|
+
"auth-revoke",
|
|
659
|
+
"auth-enrollment",
|
|
660
|
+
"auth-subscription-ticket",
|
|
661
|
+
"appsync-subscription-authorizer",
|
|
662
|
+
"subscription-invalidation",
|
|
662
663
|
"public-auth-options",
|
|
664
|
+
"auth-provider-reconcile",
|
|
663
665
|
"workos-auth",
|
|
664
666
|
# Public artifact share links (THINK-208): GET /share/{token}, token
|
|
665
667
|
# verified in handler code (no gateway auth, uniform 404 on any miss).
|
|
@@ -675,6 +677,9 @@ resource "aws_lambda_function" "handler" {
|
|
|
675
677
|
"mcp-open-engine",
|
|
676
678
|
# THINK-280 U8: scoped external capability search MCP facade.
|
|
677
679
|
"mcp-capability-search",
|
|
680
|
+
# THINK-333 / consolidation U14: provisions the tenant Brain MCP
|
|
681
|
+
# connector against the platform endpoint (BRAIN_MCP_URL).
|
|
682
|
+
"mcp-twin-provision",
|
|
678
683
|
"activity",
|
|
679
684
|
"routines",
|
|
680
685
|
"budgets",
|
|
@@ -689,16 +694,7 @@ resource "aws_lambda_function" "handler" {
|
|
|
689
694
|
"webhooks-admin",
|
|
690
695
|
"webhook-deliveries-cleanup",
|
|
691
696
|
"skill-runs-reconciler",
|
|
692
|
-
# THINK-229 U5 — probes the analyst_reader connection (reachability, IAM
|
|
693
|
-
# auth, SELECT-grant introspection, schema drift; all read-only) every 30
|
|
694
|
-
# min and stamps the verdict onto runtime_metadata.analyst_probe so
|
|
695
|
-
# dispatch can withhold a failing/stale connection loudly.
|
|
696
|
-
"analyst-connection-reconciler",
|
|
697
697
|
"cron-stall-monitor",
|
|
698
|
-
# THINK-307: drains retry_queue rows the stall monitor enqueues. Built by
|
|
699
|
-
# scripts/build-lambdas.sh since PRD-09 but first registered here; its
|
|
700
|
-
# schedule ships DISABLED (var.retry_dispatcher_enabled default false).
|
|
701
|
-
"cron-retry-dispatcher",
|
|
702
698
|
"webhook-crm-opportunity",
|
|
703
699
|
"webhook-task-event",
|
|
704
700
|
"workspace-files",
|
|
@@ -706,8 +702,6 @@ resource "aws_lambda_function" "handler" {
|
|
|
706
702
|
# 2026-06-12-002 U4). Bearer API_AUTH_SECRET + x-tenant-id; the runtime
|
|
707
703
|
# fetch tool authorizes here, then downloads the returned S3 keys itself.
|
|
708
704
|
"workspace-fetch-source",
|
|
709
|
-
"knowledge-base-manager",
|
|
710
|
-
"knowledge-base-files",
|
|
711
705
|
"email-send",
|
|
712
706
|
"email-inbound",
|
|
713
707
|
"email-provider-webhook",
|
|
@@ -718,9 +712,7 @@ resource "aws_lambda_function" "handler" {
|
|
|
718
712
|
"msteams-install-complete",
|
|
719
713
|
"msteams-account-link-complete",
|
|
720
714
|
"github-app",
|
|
721
|
-
"memory",
|
|
722
715
|
"memory-retain",
|
|
723
|
-
"brain-dream-state",
|
|
724
716
|
"memory-stage-worker",
|
|
725
717
|
# THINK-193 U2 (Codex P1 #3): scheduled retry drainer for the retraction
|
|
726
718
|
# saga ledger. Claims due/stale memory_retraction_attempts rows with the
|
|
@@ -735,15 +727,15 @@ resource "aws_lambda_function" "handler" {
|
|
|
735
727
|
# terminal step event + SendTaskFailure. rate(15 minutes) schedule
|
|
736
728
|
# (dedicated resource below).
|
|
737
729
|
"memory-stage-sweeper",
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
"
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
"
|
|
730
|
+
# THINK-321 U7: bootstrap/drift identity matching job. Event-invoked by
|
|
731
|
+
# startIdentityMatchJob; the drift EventBridge Scheduler rule targets it
|
|
732
|
+
# directly (identity_drift_match_enabled, ships DISABLED).
|
|
733
|
+
"identity-match",
|
|
734
|
+
# Company Brain U5 (KTD-4): identity → twin graph projector. VPC-attached
|
|
735
|
+
# (Neptune). Event-invoked as a post-commit nudge by identity mutations;
|
|
736
|
+
# RequestResponse for the rebuild command. The per-tenant cursor row is
|
|
737
|
+
# the source of truth — missed nudges are harmless.
|
|
738
|
+
"identity-graph-projector",
|
|
747
739
|
"artifact-deliver",
|
|
748
740
|
"recipe-refresh",
|
|
749
741
|
"agent-skills-list",
|
|
@@ -830,16 +822,14 @@ resource "aws_lambda_function" "handler" {
|
|
|
830
822
|
# Admin-Ops MCP — JSON-RPC endpoint at POST /mcp/admin, exposes the
|
|
831
823
|
# @thinkwork/admin-ops package as MCP tools for managed agents.
|
|
832
824
|
"admin-ops-mcp",
|
|
833
|
-
# Analyst query broker — first-party MCP server at POST /mcp/analyst
|
|
834
|
-
# (THINK-228 U3). One tool, query: EXPLAIN-gated, extended-protocol
|
|
835
|
-
# single-statement SQL as the analyst_reader role; large results stage
|
|
836
|
-
# to S3 under analyst-staging/; every query emits a data.query_executed
|
|
837
|
-
# compliance audit event via POST /api/compliance/events.
|
|
838
|
-
"analyst-query-broker",
|
|
839
825
|
# MCP admin key management — per-tenant Bearer tokens for admin-ops.
|
|
840
826
|
# Admin-ops-mcp authenticates incoming tokens by sha256-hash lookup
|
|
841
827
|
# against tenant_mcp_admin_keys, populated by this handler's routes.
|
|
842
828
|
"mcp-admin-keys",
|
|
829
|
+
# Brain API key management — user-minted `tkt_` Bearer tokens for the
|
|
830
|
+
# platform Company Brain MCP. Create/revoke republish the hashed-key
|
|
831
|
+
# manifest the platform verifier reads (twin-mcp-keys/<tenantId>/).
|
|
832
|
+
"brain-api-keys",
|
|
843
833
|
# One-shot tenant provisioning: mints a tkm_ key + stores in Secrets
|
|
844
834
|
# Manager at thinkwork/<stage>/mcp/<tenantId>/admin-ops + upserts
|
|
845
835
|
# tenant_mcp_servers. SM IAM is already granted on thinkwork/* by
|
|
@@ -854,6 +844,16 @@ resource "aws_lambda_function" "handler" {
|
|
|
854
844
|
# Daily sweeper: auto-rejects MCP servers pending > 30 days. Triggered
|
|
855
845
|
# by EventBridge schedule (mcp-approval-sweeper-daily).
|
|
856
846
|
"mcp-approval-sweeper",
|
|
847
|
+
# Daily sweeper: cancels computer_approval inbox items past expires_at
|
|
848
|
+
# (or older than the TTL, for rows predating it). Keeps the approvals
|
|
849
|
+
# queue a list of live decisions instead of a months-deep graveyard.
|
|
850
|
+
"inbox-approval-sweeper",
|
|
851
|
+
# Hourly retention sweeper for auth_subscription_tickets. Tickets are
|
|
852
|
+
# single-use and expire 60s after mint but were never deleted; the
|
|
853
|
+
# table reached 551k rows / 306 MB (idx_scan=0) on a customer stage.
|
|
854
|
+
# Batched ctid DELETEs, 1h grace past expires_at. Triggered by
|
|
855
|
+
# EventBridge (aws_scheduler_schedule.auth_ticket_sweeper).
|
|
856
|
+
"auth-ticket-sweeper",
|
|
857
857
|
# Finance pilot U2 — thread-attachment upload (presign + finalize).
|
|
858
858
|
# presign issues a 5-min PUT URL the end-user client uses to push
|
|
859
859
|
# Excel/CSV bytes directly to S3; finalize sniffs magic bytes, scans
|
|
@@ -863,6 +863,11 @@ resource "aws_lambda_function" "handler" {
|
|
|
863
863
|
# threads.tenant_id lookup. Needs WORKSPACE_BUCKET env for S3.
|
|
864
864
|
"thread-attachments-presign",
|
|
865
865
|
"thread-attachments-finalize",
|
|
866
|
+
# Runtime-generated file registration (execute_code output_files).
|
|
867
|
+
# Bearer API_AUTH_SECRET + x-tenant-id; the Pi runtime uploads the
|
|
868
|
+
# sandbox file to the same staging prefix and registers it here with
|
|
869
|
+
# the same magic-byte + OOXML validation as finalize.
|
|
870
|
+
"thread-attachments-register",
|
|
866
871
|
# U9-remainder of finance pilot — tenant-pinned download endpoint.
|
|
867
872
|
# GET /api/threads/{tid}/attachments/{aid}/download returns a 302
|
|
868
873
|
# to a 5-minute presigned S3 GET URL with ResponseContentDisposition:
|
|
@@ -877,14 +882,10 @@ resource "aws_lambda_function" "handler" {
|
|
|
877
882
|
# POSTs one row per agent-session-start. Shared
|
|
878
883
|
# API_AUTH_SECRET bearer (runtime→API; no tenant OAuth).
|
|
879
884
|
"manifest-log",
|
|
880
|
-
#
|
|
881
|
-
#
|
|
882
|
-
#
|
|
883
|
-
|
|
884
|
-
# exclusively from the Ed25519-signed capability caller context (the
|
|
885
|
-
# CAPABILITY_SIGNING_PUBLIC_KEY in the shared runtime-config document
|
|
886
|
-
# verifies it); plaintext payload fields are never trusted.
|
|
887
|
-
"capability-control-service",
|
|
885
|
+
# Pi tool-execution ledger write endpoint (THINK-324 C17). The runtime
|
|
886
|
+
# POSTs paired started/terminal evidence rows per tool call. Shared
|
|
887
|
+
# API_AUTH_SECRET bearer (runtime→API; no tenant OAuth).
|
|
888
|
+
"tool-executions",
|
|
888
889
|
# SI-7 catalog-list read endpoint (plan §U15 pt 3/3). The runtime
|
|
889
890
|
# fetches the allowed builtin-tool slug set once per
|
|
890
891
|
# session-start + feature-flag-gated enforcement filter drops
|
|
@@ -924,7 +925,39 @@ resource "aws_lambda_function" "handler" {
|
|
|
924
925
|
# new standalone resource (see U8b plan operator-step section).
|
|
925
926
|
]), toset(local.optional_integration_handler_names)) : toset([])
|
|
926
927
|
|
|
928
|
+
# THINK-1082: one vpc_config per function, resolved here so the resource
|
|
929
|
+
# block stays a single dynamic block. Three shapes:
|
|
930
|
+
# - identity-graph-projector with Neptune wired: the Neptune subnets (the
|
|
931
|
+
# projector must reach the Neptune cluster), security groups = the
|
|
932
|
+
# Neptune client SGs UNION the api-lambda SGs when lambdas_in_vpc is on
|
|
933
|
+
# (the projector also opens DATABASE_URL, so it needs the DB grant too).
|
|
934
|
+
# - any handler when lambdas_in_vpc: the VPC subnets + api-lambda SGs.
|
|
935
|
+
# - otherwise null: no vpc_config, byte-identical to today.
|
|
936
|
+
handler_vpc = {
|
|
937
|
+
for name in local.handler_names : name => (
|
|
938
|
+
name == "identity-graph-projector" && local.neptune_vpc_enabled ? {
|
|
939
|
+
subnet_ids = var.neptune_subnet_ids
|
|
940
|
+
security_group_ids = distinct(concat(
|
|
941
|
+
var.neptune_security_group_ids,
|
|
942
|
+
var.lambdas_in_vpc ? var.vpc_security_group_ids : [],
|
|
943
|
+
))
|
|
944
|
+
} : var.lambdas_in_vpc ? {
|
|
945
|
+
subnet_ids = var.vpc_subnet_ids
|
|
946
|
+
security_group_ids = var.vpc_security_group_ids
|
|
947
|
+
} : null
|
|
948
|
+
)
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
resource "aws_lambda_function" "handler" {
|
|
953
|
+
for_each = local.handler_names
|
|
954
|
+
|
|
927
955
|
function_name = "thinkwork-${var.stage}-api-${each.key}"
|
|
956
|
+
# THINK-583 U3: publish a numbered version for the two chat-critical
|
|
957
|
+
# handlers only — provisioned concurrency requires a published version
|
|
958
|
+
# behind the `live` alias (resources below). Scoped so the other ~90
|
|
959
|
+
# handlers don't accumulate a version per apply.
|
|
960
|
+
publish = contains(local.provisioned_concurrency_handlers, each.key)
|
|
928
961
|
# S2 (THINK-193 U2): memory-retraction-drainer runs under a DEDICATED role
|
|
929
962
|
# so its destructive evidence-snapshot S3 capability (version enumeration +
|
|
930
963
|
# bulk version deletion) never leaks into the 90+ handlers on the shared
|
|
@@ -942,14 +975,10 @@ resource "aws_lambda_function" "handler" {
|
|
|
942
975
|
depends_on = [
|
|
943
976
|
aws_ssm_parameter.runtime_config,
|
|
944
977
|
aws_secretsmanager_secret_version.api_auth,
|
|
945
|
-
aws_secretsmanager_secret_version.appsync_api_key,
|
|
946
978
|
]
|
|
947
979
|
# eval-runner walks every test case sequentially, invoking an agent +
|
|
948
980
|
# waiting up to 2 min for spans to propagate per test, so a 10-test run
|
|
949
981
|
# can easily exceed the 30 s default. 900 s covers ~5-15 min sweeps.
|
|
950
|
-
# wiki-bootstrap-import runs a full Hindsight ingest for ~3,000 records;
|
|
951
|
-
# the LLM-backed retain path makes it the longest-running Lambda in the
|
|
952
|
-
# set. 900 s is Lambda's per-invocation max and matches eval-runner's ceiling.
|
|
953
982
|
# routine-task-python wraps a 300s sandbox session and needs headroom
|
|
954
983
|
# for the Start/Invoke/Stop/S3-offload round trip; 360s leaves ~60s
|
|
955
984
|
# for AWS-call setup and offload after the sandbox's own ceiling.
|
|
@@ -957,8 +986,16 @@ resource "aws_lambda_function" "handler" {
|
|
|
957
986
|
# validates the agent, builds the AgentCore invoke payload, dispatches
|
|
958
987
|
# Event-mode, and returns. Setup is ~5s in practice; 60s gives 12×
|
|
959
988
|
# headroom for transient slowness.
|
|
960
|
-
|
|
961
|
-
|
|
989
|
+
# reference QBR run was ~2 min; 900s is the ceiling — a longer run is a
|
|
990
|
+
# legitimate trial limitation, recorded, not engineered around).
|
|
991
|
+
timeout = each.key == "wakeup-processor" ? 300 : each.key == "chat-agent-invoke" ? 60 : each.key == "agentcore-runtime-dispatch" ? 900 : each.key == "agentcore-dispatch-dlq-redrive" ? 60 : each.key == "chat-agent-finalize" ? 60 : each.key == "workspace-event-dispatcher" ? 60 : each.key == "eval-runner" ? 900 : each.key == "eval-worker" ? 240 : each.key == "requester-memory-dreaming" ? 300 : each.key == "identity-match" ? 300 : each.key == "identity-graph-projector" ? 900 : each.key == "folder-bundle-import" ? 300 : each.key == "routine-task-python" ? 360 : each.key == "routine-exec-git" ? 360 : each.key == "job-trigger" ? 600 : each.key == "model-converse" ? 60 : each.key == "memory-retain" ? 300 : each.key == "memory-stage-worker" ? 900 : each.key == "memory-stage-sweeper" ? 120 : each.key == "auth-ticket-sweeper" ? 120 : each.key == "memory-retraction-drainer" ? 300 : each.key == "canvas-refresh" ? 120 : each.key == "document-conformance-judge" ? 300 : each.key == "workflow-step-dispatch" ? 600 : each.key == "workflow-execution-callback" ? 60 : each.key == "workflow-resume" ? 60 : 30
|
|
992
|
+
# THINK-583 U2: chat-agent-invoke and workspace-renderer get a full vCPU
|
|
993
|
+
# (1769 MB). At 256 MB (~1/7 vCPU) the parallelized setup awaits starved on
|
|
994
|
+
# CPU — per-leg timing showed three independent {1 DB read + 1 S3/Secrets
|
|
995
|
+
# read} legs each taking ~1.5 s in parallel while sequential stage-1 reads
|
|
996
|
+
# were fast. Memory is priced per GB-s, but wall-clock drops far more than
|
|
997
|
+
# 7x cost rises on these short, provisioned-concurrency-warmed functions.
|
|
998
|
+
memory_size = each.key == "graphql-http" ? 512 : each.key == "wakeup-processor" ? 512 : each.key == "workspace-event-dispatcher" ? 512 : each.key == "eval-runner" ? 512 : each.key == "eval-worker" ? 512 : each.key == "requester-memory-dreaming" ? 512 : each.key == "identity-match" ? 512 : each.key == "identity-graph-projector" ? min(8192, var.lambda_max_memory_mb) : each.key == "folder-bundle-import" ? 1024 : each.key == "chat-agent-invoke" ? 1769 : each.key == "workspace-renderer" ? 1769 : each.key == "agentcore-runtime-dispatch" ? 512 : 256
|
|
962
999
|
|
|
963
1000
|
filename = local.use_local_zips ? "${var.lambda_zips_dir}/${each.key}.zip" : null
|
|
964
1001
|
source_code_hash = local.use_local_zips ? filebase64sha256("${var.lambda_zips_dir}/${each.key}.zip") : null
|
|
@@ -976,14 +1013,7 @@ resource "aws_lambda_function" "handler" {
|
|
|
976
1013
|
# document-conformance-judge is also a single-writer: direct
|
|
977
1014
|
# process-and-complete with no in-flight claim status depends on never
|
|
978
1015
|
# having two sweepers race the same pending rows (THINK-189 KTD4).
|
|
979
|
-
|
|
980
|
-
# dedicated analyst_reader Postgres connection and runs model-authored
|
|
981
|
-
# SQL — the cap bounds both connection pressure and the blast radius of
|
|
982
|
-
# a runaway delegation (THINK-228 U3).
|
|
983
|
-
# analyst-connection-reconciler is capped at 1: the probe holds one
|
|
984
|
-
# analyst_reader connection and overlapping probes are pointless (the
|
|
985
|
-
# cluster-global reader has one grant surface / one live schema).
|
|
986
|
-
reserved_concurrent_executions = each.key == "compliance-outbox-drainer" ? 1 : each.key == "document-conformance-judge" ? 1 : each.key == "eval-worker" ? 40 : each.key == "analyst-query-broker" ? 4 : each.key == "analyst-connection-reconciler" ? 1 : -1
|
|
1016
|
+
reserved_concurrent_executions = each.key == "compliance-outbox-drainer" ? 1 : each.key == "document-conformance-judge" ? 1 : each.key == "eval-worker" ? 40 : -1
|
|
987
1017
|
|
|
988
1018
|
environment {
|
|
989
1019
|
variables = merge(
|
|
@@ -993,44 +1023,22 @@ resource "aws_lambda_function" "handler" {
|
|
|
993
1023
|
)
|
|
994
1024
|
}
|
|
995
1025
|
|
|
1026
|
+
# Company Brain U5 + THINK-1082: at most one vpc_config per function. The
|
|
1027
|
+
# placement (Neptune projector, whole-module VPC lane, or none) is resolved
|
|
1028
|
+
# in local.handler_vpc above; absent entirely when that entry is null.
|
|
996
1029
|
dynamic "vpc_config" {
|
|
997
|
-
for_each = each.key ==
|
|
998
|
-
|
|
999
|
-
content {
|
|
1000
|
-
subnet_ids = var.okf_efs_subnet_ids
|
|
1001
|
-
security_group_ids = var.okf_efs_security_group_ids
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
# Analyst data-path handlers get a stable NAT egress IP when
|
|
1006
|
-
# analyst_egress_subnet_ids is set — external Postgres sources behind an IP
|
|
1007
|
-
# allowlist admit that one EIP. Disjoint from the okf-efs-refresh block
|
|
1008
|
-
# above (a function takes at most one vpc_config).
|
|
1009
|
-
dynamic "vpc_config" {
|
|
1010
|
-
for_each = contains(local.analyst_vpc_handlers, each.key) && local.analyst_vpc_enabled ? [1] : []
|
|
1011
|
-
|
|
1012
|
-
content {
|
|
1013
|
-
subnet_ids = var.analyst_egress_subnet_ids
|
|
1014
|
-
security_group_ids = var.analyst_egress_security_group_ids
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
dynamic "file_system_config" {
|
|
1019
|
-
for_each = each.key == "okf-efs-refresh" && local.okf_efs_vpc_enabled ? [1] : []
|
|
1030
|
+
for_each = local.handler_vpc[each.key] == null ? [] : [local.handler_vpc[each.key]]
|
|
1020
1031
|
|
|
1021
1032
|
content {
|
|
1022
|
-
|
|
1023
|
-
|
|
1033
|
+
subnet_ids = vpc_config.value.subnet_ids
|
|
1034
|
+
security_group_ids = vpc_config.value.security_group_ids
|
|
1024
1035
|
}
|
|
1025
1036
|
}
|
|
1026
1037
|
|
|
1027
1038
|
lifecycle {
|
|
1028
1039
|
precondition {
|
|
1029
|
-
condition
|
|
1030
|
-
|
|
1031
|
-
alltrue([for id in var.okf_efs_mount_target_ids : id != ""])
|
|
1032
|
-
)
|
|
1033
|
-
error_message = "okf-efs-refresh requires an available EFS mount target dependency for every configured subnet."
|
|
1040
|
+
condition = local.lambda_vpc_inputs_complete
|
|
1041
|
+
error_message = "lambdas_in_vpc requires non-empty vpc_subnet_ids and vpc_security_group_ids."
|
|
1034
1042
|
}
|
|
1035
1043
|
}
|
|
1036
1044
|
|
|
@@ -1041,31 +1049,59 @@ resource "aws_lambda_function" "handler" {
|
|
|
1041
1049
|
}
|
|
1042
1050
|
|
|
1043
1051
|
# ---------------------------------------------------------------------------
|
|
1044
|
-
#
|
|
1052
|
+
# Warm sessions (THINK-583 U3): published version + `live` alias +
|
|
1053
|
+
# provisioned concurrency for chat-agent-invoke and workspace-renderer
|
|
1045
1054
|
# ---------------------------------------------------------------------------
|
|
1055
|
+
# KTD5: these two zip Lambdas ONLY — never the Pi Lambda (its warmth is
|
|
1056
|
+
# superseded by AgentCore session reuse, and deploy.yml publishes Pi code
|
|
1057
|
+
# to $LATEST out-of-band).
|
|
1046
1058
|
#
|
|
1047
|
-
#
|
|
1048
|
-
#
|
|
1049
|
-
#
|
|
1050
|
-
#
|
|
1051
|
-
#
|
|
1052
|
-
#
|
|
1053
|
-
#
|
|
1054
|
-
# Pin retries to 0 and route failures to a dedicated DLQ. The runner's
|
|
1055
|
-
# job-status short-circuit (running/succeeded/failed/skipped) is the
|
|
1056
|
-
# in-process protection against duplicate writebacks; this is the
|
|
1057
|
-
# infrastructure-level belt-and-suspenders.
|
|
1059
|
+
# Provisioned concurrency only serves invokes addressed to the alias, so
|
|
1060
|
+
# EVERY invoker resolves `<fn>:live` (graphql/utils.ts, mobile-turns/
|
|
1061
|
+
# managed-dispatch.ts, and the workspaceRendererFunctionName helpers in
|
|
1062
|
+
# chat-agent-invoke.ts / wakeup-processor.ts). The alias exists even when
|
|
1063
|
+
# the concurrency count is 0 — an alias with no PC config serves normally
|
|
1064
|
+
# from $LATEST-equivalent cold starts — so disabled stages keep working
|
|
1065
|
+
# unchanged and opt in purely by raising the count variable.
|
|
1058
1066
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1067
|
+
locals {
|
|
1068
|
+
provisioned_concurrency_handlers = toset([
|
|
1069
|
+
"chat-agent-invoke",
|
|
1070
|
+
"workspace-renderer",
|
|
1071
|
+
])
|
|
1072
|
+
provisioned_concurrency_counts = {
|
|
1073
|
+
"chat-agent-invoke" = var.chat_agent_invoke_provisioned_concurrency
|
|
1074
|
+
"workspace-renderer" = var.workspace_renderer_provisioned_concurrency
|
|
1066
1075
|
}
|
|
1067
1076
|
}
|
|
1068
1077
|
|
|
1078
|
+
resource "aws_lambda_alias" "live" {
|
|
1079
|
+
for_each = local.deploy_lambda_handlers ? local.provisioned_concurrency_handlers : toset([])
|
|
1080
|
+
|
|
1081
|
+
name = "live"
|
|
1082
|
+
description = "Warm-session alias (THINK-583 U3) — provisioned-concurrency target; all invokers alias-qualify."
|
|
1083
|
+
function_name = aws_lambda_function.handler[each.key].function_name
|
|
1084
|
+
function_version = aws_lambda_function.handler[each.key].version
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
resource "aws_lambda_provisioned_concurrency_config" "live" {
|
|
1088
|
+
# aws_lambda_provisioned_concurrency_config rejects a count of 0, so a
|
|
1089
|
+
# disabled handler simply has no config resource (the alias remains).
|
|
1090
|
+
for_each = local.deploy_lambda_handlers ? {
|
|
1091
|
+
for name in local.provisioned_concurrency_handlers :
|
|
1092
|
+
name => local.provisioned_concurrency_counts[name]
|
|
1093
|
+
if local.provisioned_concurrency_counts[name] > 0
|
|
1094
|
+
} : {}
|
|
1095
|
+
|
|
1096
|
+
function_name = aws_lambda_function.handler[each.key].function_name
|
|
1097
|
+
qualifier = aws_lambda_alias.live[each.key].name
|
|
1098
|
+
provisioned_concurrent_executions = each.value
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
# ---------------------------------------------------------------------------
|
|
1102
|
+
# Async retry configuration
|
|
1103
|
+
# ---------------------------------------------------------------------------
|
|
1104
|
+
|
|
1069
1105
|
# chat-agent-invoke retry-0 (plan 2026-05-22-006 U3). After the
|
|
1070
1106
|
# direct-callback finalize refactor, chat-agent-invoke is Event-mode-
|
|
1071
1107
|
# dispatched by the GraphQL resolver and itself dispatches AgentCore
|
|
@@ -1084,66 +1120,41 @@ resource "aws_lambda_function_event_invoke_config" "chat_agent_invoke" {
|
|
|
1084
1120
|
maximum_event_age_in_seconds = 3600
|
|
1085
1121
|
}
|
|
1086
1122
|
|
|
1087
|
-
|
|
1123
|
+
# THINK-583 U3: the resolver now Event-invokes the `live` alias, and async
|
|
1124
|
+
# invoke config is per-qualifier — without this duplicate on the alias the
|
|
1125
|
+
# alias path would regress to AWS's default 2 retries and the 5-min stall
|
|
1126
|
+
# cascade above could recur. Same retry-0 posture, pinned explicitly.
|
|
1127
|
+
resource "aws_lambda_function_event_invoke_config" "chat_agent_invoke_live" {
|
|
1088
1128
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1089
|
-
function_name = aws_lambda_function.handler["
|
|
1090
|
-
|
|
1091
|
-
maximum_event_age_in_seconds = 3600
|
|
1092
|
-
|
|
1093
|
-
destination_config {
|
|
1094
|
-
on_failure {
|
|
1095
|
-
destination = aws_sqs_queue.wiki_compile_dlq[0].arn
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
# Ontology suggestion scans are durable-job driven. Disable AWS async
|
|
1101
|
-
# retries so duplicate scan invocations do not create duplicate review
|
|
1102
|
-
# proposals; the scan job row is the retry/observability surface.
|
|
1103
|
-
resource "aws_sqs_queue" "ontology_scan_dlq" {
|
|
1104
|
-
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1105
|
-
name = "thinkwork-${var.stage}-ontology-scan-dlq"
|
|
1106
|
-
message_retention_seconds = 1209600 # 14 days
|
|
1107
|
-
|
|
1108
|
-
tags = {
|
|
1109
|
-
Name = "thinkwork-${var.stage}-ontology-scan-dlq"
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
resource "aws_lambda_function_event_invoke_config" "ontology_scan" {
|
|
1114
|
-
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1115
|
-
function_name = aws_lambda_function.handler["ontology-scan"].function_name
|
|
1129
|
+
function_name = aws_lambda_function.handler["chat-agent-invoke"].function_name
|
|
1130
|
+
qualifier = aws_lambda_alias.live["chat-agent-invoke"].name
|
|
1116
1131
|
maximum_retry_attempts = 0
|
|
1117
1132
|
maximum_event_age_in_seconds = 3600
|
|
1118
|
-
|
|
1119
|
-
destination_config {
|
|
1120
|
-
on_failure {
|
|
1121
|
-
destination = aws_sqs_queue.ontology_scan_dlq[0].arn
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
1133
|
}
|
|
1125
1134
|
|
|
1126
|
-
#
|
|
1127
|
-
#
|
|
1128
|
-
|
|
1135
|
+
# Identity match jobs (THINK-321 U7) are durable-job driven. Disable AWS
|
|
1136
|
+
# async retries so duplicate match invocations do not
|
|
1137
|
+
# double-write mappings/cases; identity.match_jobs is the retry/
|
|
1138
|
+
# observability surface.
|
|
1139
|
+
resource "aws_sqs_queue" "identity_match_dlq" {
|
|
1129
1140
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1130
|
-
name = "thinkwork-${var.stage}-
|
|
1141
|
+
name = "thinkwork-${var.stage}-identity-match-dlq"
|
|
1131
1142
|
message_retention_seconds = 1209600 # 14 days
|
|
1132
1143
|
|
|
1133
1144
|
tags = {
|
|
1134
|
-
Name = "thinkwork-${var.stage}-
|
|
1145
|
+
Name = "thinkwork-${var.stage}-identity-match-dlq"
|
|
1135
1146
|
}
|
|
1136
1147
|
}
|
|
1137
1148
|
|
|
1138
|
-
resource "aws_lambda_function_event_invoke_config" "
|
|
1149
|
+
resource "aws_lambda_function_event_invoke_config" "identity_match" {
|
|
1139
1150
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1140
|
-
function_name = aws_lambda_function.handler["
|
|
1151
|
+
function_name = aws_lambda_function.handler["identity-match"].function_name
|
|
1141
1152
|
maximum_retry_attempts = 0
|
|
1142
1153
|
maximum_event_age_in_seconds = 3600
|
|
1143
1154
|
|
|
1144
1155
|
destination_config {
|
|
1145
1156
|
on_failure {
|
|
1146
|
-
destination = aws_sqs_queue.
|
|
1157
|
+
destination = aws_sqs_queue.identity_match_dlq[0].arn
|
|
1147
1158
|
}
|
|
1148
1159
|
}
|
|
1149
1160
|
}
|
|
@@ -1167,7 +1178,7 @@ resource "aws_lambda_function_event_invoke_config" "routine_approval_callback" {
|
|
|
1167
1178
|
# memory-retain after every chat turn. AWS Lambda's default async-retry
|
|
1168
1179
|
# policy is 2 attempts; without overriding it, a transient failure on the
|
|
1169
1180
|
# canonical-transcript fetch or adapter write retries the entire writeback
|
|
1170
|
-
# and can multi-write the same per-turn document into
|
|
1181
|
+
# and can multi-write the same per-turn document into memory. The
|
|
1171
1182
|
# longest-suffix-prefix merge in memory-retain.ts dedupes content but the
|
|
1172
1183
|
# retain-cost path (Bedrock tokens charged in adapter.retainConversation)
|
|
1173
1184
|
# is NOT idempotent — retries multiply LLM cost. Per
|
|
@@ -1454,8 +1465,13 @@ locals {
|
|
|
1454
1465
|
# Public login capabilities. Unauthenticated by design; the handler
|
|
1455
1466
|
# resolves tenant-scoped OAuth options only from trusted API Gateway
|
|
1456
1467
|
# domain metadata and fails closed for unknown/shared hosts.
|
|
1457
|
-
"GET /api/auth/options"
|
|
1458
|
-
"OPTIONS /api/auth/options"
|
|
1468
|
+
"GET /api/auth/options" = "public-auth-options"
|
|
1469
|
+
"OPTIONS /api/auth/options" = "public-auth-options"
|
|
1470
|
+
# Operator/deployment-only metadata seam. The Lambda independently
|
|
1471
|
+
# verifies API_AUTH_SECRET and rejects raw secret values.
|
|
1472
|
+
"POST /api/auth/providers/reconcile" = "auth-provider-reconcile"
|
|
1473
|
+
# Rollback-only routes. No native client links to these, and the entire
|
|
1474
|
+
# handler is filtered from Lambda/API Gateway in the retired phase.
|
|
1459
1475
|
"GET /api/auth/workos/authorize" = "workos-auth"
|
|
1460
1476
|
"OPTIONS /api/auth/workos/authorize" = "workos-auth"
|
|
1461
1477
|
"GET /api/auth/workos/callback" = "workos-auth"
|
|
@@ -1472,21 +1488,6 @@ locals {
|
|
|
1472
1488
|
# Agent actions (start/stop/heartbeat/budget)
|
|
1473
1489
|
"ANY /api/agent-actions/{proxy+}" = "agent-actions"
|
|
1474
1490
|
|
|
1475
|
-
# Desktop-local Pi tombstones. Specific routes before broad REST handlers;
|
|
1476
|
-
# OPTIONS is handled inside the Lambda before auth.
|
|
1477
|
-
"POST /api/desktop/runtime-session" = "desktop-runtime-session"
|
|
1478
|
-
"OPTIONS /api/desktop/runtime-session" = "desktop-runtime-session"
|
|
1479
|
-
"POST /api/desktop/workspace-prewarm" = "desktop-workspace-prewarm"
|
|
1480
|
-
"OPTIONS /api/desktop/workspace-prewarm" = "desktop-workspace-prewarm"
|
|
1481
|
-
"POST /api/desktop/managed-delegation" = "managed-delegation"
|
|
1482
|
-
"OPTIONS /api/desktop/managed-delegation" = "managed-delegation"
|
|
1483
|
-
"POST /api/desktop/eval-runs" = "desktop-eval-runs"
|
|
1484
|
-
"OPTIONS /api/desktop/eval-runs" = "desktop-eval-runs"
|
|
1485
|
-
"POST /api/desktop/eval-runs/{runId}/sessions" = "desktop-eval-runs"
|
|
1486
|
-
"OPTIONS /api/desktop/eval-runs/{runId}/sessions" = "desktop-eval-runs"
|
|
1487
|
-
"POST /api/desktop/eval-runs/{runId}/results" = "desktop-eval-runs"
|
|
1488
|
-
"OPTIONS /api/desktop/eval-runs/{runId}/results" = "desktop-eval-runs"
|
|
1489
|
-
|
|
1490
1491
|
# Mobile agent harness model proxy (cloud Bedrock Converse). OPTIONS is
|
|
1491
1492
|
# handled inside the Lambda before auth.
|
|
1492
1493
|
"POST /api/model/converse" = "model-converse"
|
|
@@ -1555,14 +1556,10 @@ locals {
|
|
|
1555
1556
|
"GET /.well-known/oauth-authorization-server" = "mcp-oauth"
|
|
1556
1557
|
"GET /.well-known/openid-configuration" = "mcp-oauth"
|
|
1557
1558
|
"GET /mcp/oauth/jwks" = "mcp-oauth"
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
"GET /
|
|
1561
|
-
"
|
|
1562
|
-
"POST /mcp/oauth/revoke" = "mcp-oauth"
|
|
1563
|
-
"ANY /mcp/user-memory" = "mcp-user-memory"
|
|
1564
|
-
"ANY /mcp/context-engine" = "mcp-context-engine"
|
|
1565
|
-
"ANY /mcp/open-engine" = "mcp-open-engine"
|
|
1559
|
+
# THINK-316 U1: AgentCore CUSTOM_JWT discovery is deliberately isolated
|
|
1560
|
+
# under /agentcore so the existing user-memory OAuth issuer is unchanged.
|
|
1561
|
+
"GET /agentcore/.well-known/openid-configuration" = "mcp-oauth"
|
|
1562
|
+
"GET /agentcore/oauth/jwks" = "mcp-oauth"
|
|
1566
1563
|
# THINK-280 U8: scoped external capability search facade. The handler is
|
|
1567
1564
|
# inert unless CAPABILITY_EXTERNAL_SEARCH_ENABLED (gated on
|
|
1568
1565
|
# enable_capability_broker) is on — routing it while disabled returns an
|
|
@@ -1607,6 +1604,18 @@ locals {
|
|
|
1607
1604
|
"OPTIONS /api/deployment-sessions/{sessionId}/teardown" = "deployment-sessions"
|
|
1608
1605
|
"GET /api/auth/me" = "auth-me"
|
|
1609
1606
|
"OPTIONS /api/auth/me" = "auth-me"
|
|
1607
|
+
"POST /api/auth/revoke" = "auth-revoke"
|
|
1608
|
+
"OPTIONS /api/auth/revoke" = "auth-revoke"
|
|
1609
|
+
"POST /api/auth/subscription-ticket" = "auth-subscription-ticket"
|
|
1610
|
+
"OPTIONS /api/auth/subscription-ticket" = "auth-subscription-ticket"
|
|
1611
|
+
"POST /api/auth/enrollment/consume" = "auth-enrollment"
|
|
1612
|
+
"OPTIONS /api/auth/enrollment/consume" = "auth-enrollment"
|
|
1613
|
+
"POST /api/auth/enrollment/recover" = "auth-enrollment"
|
|
1614
|
+
"OPTIONS /api/auth/enrollment/recover" = "auth-enrollment"
|
|
1615
|
+
"POST /api/auth/enrollment/migrate" = "auth-enrollment"
|
|
1616
|
+
"OPTIONS /api/auth/enrollment/migrate" = "auth-enrollment"
|
|
1617
|
+
"POST /api/auth/enrollment/auto-link" = "auth-enrollment"
|
|
1618
|
+
"OPTIONS /api/auth/enrollment/auto-link" = "auth-enrollment"
|
|
1610
1619
|
"ANY /api/extensions/{extensionId}" = "extension-proxy"
|
|
1611
1620
|
"ANY /api/extensions/{extensionId}/{proxy+}" = "extension-proxy"
|
|
1612
1621
|
|
|
@@ -1665,9 +1674,6 @@ locals {
|
|
|
1665
1674
|
# Workspace files
|
|
1666
1675
|
"ANY /api/workspaces/{proxy+}" = "workspace-files"
|
|
1667
1676
|
|
|
1668
|
-
# Knowledge bases
|
|
1669
|
-
"ANY /api/knowledge-bases/{proxy+}" = "knowledge-base-files"
|
|
1670
|
-
|
|
1671
1677
|
# Email
|
|
1672
1678
|
"POST /api/email/send" = "email-send"
|
|
1673
1679
|
"POST /api/email/provider-webhook/{providerInstallId}" = "email-provider-webhook"
|
|
@@ -1689,7 +1695,6 @@ locals {
|
|
|
1689
1695
|
"POST /msteams/account-link/complete" = "msteams-account-link-complete"
|
|
1690
1696
|
|
|
1691
1697
|
# Memory
|
|
1692
|
-
"ANY /api/memory/{proxy+}" = "memory"
|
|
1693
1698
|
|
|
1694
1699
|
# Artifacts
|
|
1695
1700
|
"POST /api/artifacts/{proxy+}" = "artifact-deliver"
|
|
@@ -1755,20 +1760,6 @@ locals {
|
|
|
1755
1760
|
# retained as a break-glass superuser path for bootstrap/debug.
|
|
1756
1761
|
"POST /mcp/admin" = "admin-ops-mcp"
|
|
1757
1762
|
|
|
1758
|
-
# Analyst query broker — first-party MCP server exposing query
|
|
1759
|
-
# (THINK-228 U3). Callers present the tenant-wide broker service
|
|
1760
|
-
# credential as Bearer; SQL executes as the hardened analyst_reader
|
|
1761
|
-
# role. The seeded postgres-dev connector row points at this route.
|
|
1762
|
-
"POST /mcp/analyst" = "analyst-query-broker"
|
|
1763
|
-
|
|
1764
|
-
# Sourced analyst broker route (THINK-239) — the same handler serves a
|
|
1765
|
-
# registered EXTERNAL Postgres source at /mcp/analyst/<slug>. The broker
|
|
1766
|
-
# requires a signed caller context whose sourceClaims.slug matches the
|
|
1767
|
-
# path (the legacy bearer is never accepted here) and connects using the
|
|
1768
|
-
# per-source reader credential (thinkwork/<stage>/analyst/*, covered by
|
|
1769
|
-
# the shared secretsmanager:GetSecretValue on thinkwork/*).
|
|
1770
|
-
"POST /mcp/analyst/{sourceSlug}" = "analyst-query-broker"
|
|
1771
|
-
|
|
1772
1763
|
# MCP admin key management — per-tenant Bearer token CRUD. Tokens
|
|
1773
1764
|
# are shown ONCE at creation (POST returns raw value); server stores
|
|
1774
1765
|
# sha256 hash only. These specific routes take precedence over the
|
|
@@ -1778,6 +1769,15 @@ locals {
|
|
|
1778
1769
|
"GET /api/tenants/{tenantId}/mcp-admin-keys" = "mcp-admin-keys"
|
|
1779
1770
|
"DELETE /api/tenants/{tenantId}/mcp-admin-keys/{keyId}" = "mcp-admin-keys"
|
|
1780
1771
|
|
|
1772
|
+
"POST /api/tenants/{tenantId}/brain-api-keys" = "brain-api-keys"
|
|
1773
|
+
"GET /api/tenants/{tenantId}/brain-api-keys" = "brain-api-keys"
|
|
1774
|
+
"OPTIONS /api/tenants/{tenantId}/brain-api-keys" = "brain-api-keys"
|
|
1775
|
+
"DELETE /api/tenants/{tenantId}/brain-api-keys/{keyId}" = "brain-api-keys"
|
|
1776
|
+
# Per-key grants edit (twin-mcp-keys/v2): securityGroups +
|
|
1777
|
+
# kbCollections, republishing the manifest on change.
|
|
1778
|
+
"PATCH /api/tenants/{tenantId}/brain-api-keys/{keyId}" = "brain-api-keys"
|
|
1779
|
+
"OPTIONS /api/tenants/{tenantId}/brain-api-keys/{keyId}" = "brain-api-keys"
|
|
1780
|
+
|
|
1781
1781
|
# One-shot tenant provisioning for the admin-ops MCP. Mints a fresh
|
|
1782
1782
|
# tkm_ key + stores it in Secrets Manager at
|
|
1783
1783
|
# thinkwork/<stage>/mcp/<tenantId>/admin-ops + upserts the
|
|
@@ -1785,6 +1785,13 @@ locals {
|
|
|
1785
1785
|
# any agent that gets it assigned via agent_mcp_servers.
|
|
1786
1786
|
"POST /api/tenants/{tenantId}/mcp-admin-provision" = "mcp-admin-provision"
|
|
1787
1787
|
|
|
1788
|
+
# Digital Twin MCP provisioning (THINK-333 U4): mints the tkt_ key,
|
|
1789
|
+
# writes the secret, upserts the approved digital-twin connector row
|
|
1790
|
+
# (url_hash pinned), and materializes connectors/digital-twin/ into
|
|
1791
|
+
# every agent workspace. Re-run = rotate.
|
|
1792
|
+
"POST /api/tenants/{tenantId}/mcp-twin-provision" = "mcp-twin-provision"
|
|
1793
|
+
"OPTIONS /api/tenants/{tenantId}/mcp-twin-provision" = "mcp-twin-provision"
|
|
1794
|
+
|
|
1788
1795
|
# MCP server admin approval (plan §U11, SI-5). Externally-sourced MCP
|
|
1789
1796
|
# servers land with status='pending'; these routes flip them to
|
|
1790
1797
|
# approved/rejected. Cognito JWT only (mcp-approval handler rejects
|
|
@@ -1802,6 +1809,10 @@ locals {
|
|
|
1802
1809
|
"POST /api/threads/{threadId}/attachments/finalize" = "thread-attachments-finalize"
|
|
1803
1810
|
"OPTIONS /api/threads/{threadId}/attachments/finalize" = "thread-attachments-finalize"
|
|
1804
1811
|
|
|
1812
|
+
# Runtime-generated attachments (execute_code output_files). Shared
|
|
1813
|
+
# API_AUTH_SECRET; no browser callers, so no OPTIONS route.
|
|
1814
|
+
"POST /api/threads/{threadId}/attachments/register" = "thread-attachments-register"
|
|
1815
|
+
|
|
1805
1816
|
# U9-remainder of finance pilot — tenant-pinned download endpoint.
|
|
1806
1817
|
"GET /api/threads/{threadId}/attachments/{attachmentId}/download" = "thread-attachment-download"
|
|
1807
1818
|
"OPTIONS /api/threads/{threadId}/attachments/{attachmentId}/download" = "thread-attachment-download"
|
|
@@ -1816,12 +1827,20 @@ locals {
|
|
|
1816
1827
|
"POST /api/runtime/manifests" = "manifest-log"
|
|
1817
1828
|
"OPTIONS /api/runtime/manifests" = "manifest-log"
|
|
1818
1829
|
|
|
1830
|
+
# Pi tool-execution ledger (THINK-324 C17). The runtime POSTs paired
|
|
1831
|
+
# started/terminal evidence rows per tool call. Shared API_AUTH_SECRET;
|
|
1832
|
+
# no tenant OAuth.
|
|
1833
|
+
"POST /api/runtime/tool-executions" = "tool-executions"
|
|
1834
|
+
"OPTIONS /api/runtime/tool-executions" = "tool-executions"
|
|
1835
|
+
|
|
1819
1836
|
# SI-7 catalog-list read (plan §U15 pt 3/3). The runtime fetches
|
|
1820
1837
|
# the allowed slug set once per session-start. Shared API_AUTH_SECRET.
|
|
1821
1838
|
"GET /api/runtime/capability-catalog" = "capability-catalog-list"
|
|
1822
1839
|
"OPTIONS /api/runtime/capability-catalog" = "capability-catalog-list"
|
|
1823
1840
|
} : route_key => handler_name
|
|
1824
|
-
if !contains(local.optional_integration_handler_names, handler_name)
|
|
1841
|
+
if !contains(local.optional_integration_handler_names, handler_name) && (
|
|
1842
|
+
!startswith(route_key, "GET /agentcore/")
|
|
1843
|
+
)
|
|
1825
1844
|
} : {}
|
|
1826
1845
|
}
|
|
1827
1846
|
|
|
@@ -1842,6 +1861,16 @@ resource "aws_apigatewayv2_route" "handler" {
|
|
|
1842
1861
|
target = "integrations/${aws_apigatewayv2_integration.handler[each.key].id}"
|
|
1843
1862
|
}
|
|
1844
1863
|
|
|
1864
|
+
resource "aws_lambda_permission" "appsync_subscription_authorizer" {
|
|
1865
|
+
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1866
|
+
|
|
1867
|
+
statement_id = "AllowAppSyncSubscriptionAuthorization"
|
|
1868
|
+
action = "lambda:InvokeFunction"
|
|
1869
|
+
function_name = aws_lambda_function.handler["appsync-subscription-authorizer"].function_name
|
|
1870
|
+
principal = "appsync.amazonaws.com"
|
|
1871
|
+
source_arn = "arn:aws:appsync:${var.region}:${var.account_id}:apis/${var.appsync_api_id}"
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1845
1874
|
resource "aws_lambda_permission" "handler_apigw" {
|
|
1846
1875
|
for_each = local.deploy_lambda_handlers ? toset(distinct(values(local.api_routes))) : toset([])
|
|
1847
1876
|
|
|
@@ -1917,16 +1946,15 @@ resource "aws_scheduler_schedule" "wakeup_processor" {
|
|
|
1917
1946
|
}
|
|
1918
1947
|
}
|
|
1919
1948
|
|
|
1920
|
-
#
|
|
1921
|
-
#
|
|
1922
|
-
#
|
|
1923
|
-
|
|
1924
|
-
resource "aws_scheduler_schedule" "webhook_deliveries_cleanup" {
|
|
1949
|
+
# Replays durable authorization-revocation invalidations. The worker owns its
|
|
1950
|
+
# retry state in Aurora and suppresses tenant realtime fan-out until AppSync
|
|
1951
|
+
# confirms every sensitive subscription class has been invalidated.
|
|
1952
|
+
resource "aws_scheduler_schedule" "subscription_invalidation" {
|
|
1925
1953
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1926
1954
|
|
|
1927
|
-
name = "thinkwork-${var.stage}-
|
|
1955
|
+
name = "thinkwork-${var.stage}-subscription-invalidation"
|
|
1928
1956
|
group_name = "default"
|
|
1929
|
-
schedule_expression = "
|
|
1957
|
+
schedule_expression = "rate(1 minutes)"
|
|
1930
1958
|
state = "ENABLED"
|
|
1931
1959
|
|
|
1932
1960
|
flexible_time_window {
|
|
@@ -1934,51 +1962,42 @@ resource "aws_scheduler_schedule" "webhook_deliveries_cleanup" {
|
|
|
1934
1962
|
}
|
|
1935
1963
|
|
|
1936
1964
|
target {
|
|
1937
|
-
arn = aws_lambda_function.handler["
|
|
1965
|
+
arn = aws_lambda_function.handler["subscription-invalidation"].arn
|
|
1938
1966
|
role_arn = aws_iam_role.scheduler.arn
|
|
1967
|
+
input = jsonencode({ limit = 25 })
|
|
1968
|
+
|
|
1969
|
+
retry_policy {
|
|
1970
|
+
maximum_retry_attempts = 0
|
|
1971
|
+
}
|
|
1939
1972
|
}
|
|
1940
1973
|
}
|
|
1941
1974
|
|
|
1942
1975
|
# ---------------------------------------------------------------------------
|
|
1943
|
-
#
|
|
1944
|
-
# ---------------------------------------------------------------------------
|
|
1945
|
-
|
|
1946
|
-
# ---------------------------------------------------------------------------
|
|
1947
|
-
# Brain dream state — per-bank Hindsight consolidation with audit ledger
|
|
1948
|
-
# (THINK-133 U4). Retries are the ledger's job (staged plan -> atomic apply
|
|
1949
|
-
# -> applied markers; unfinished runs resume on the next tick), so Lambda
|
|
1950
|
-
# async retries stay at 0, mirroring memory-retain.
|
|
1976
|
+
# webhook_deliveries retention cron — daily delete of rows older than 90 days
|
|
1951
1977
|
# ---------------------------------------------------------------------------
|
|
1952
1978
|
|
|
1953
|
-
resource "
|
|
1954
|
-
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1955
|
-
function_name = aws_lambda_function.handler["brain-dream-state"].function_name
|
|
1956
|
-
maximum_retry_attempts = 0
|
|
1957
|
-
maximum_event_age_in_seconds = 3600
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
resource "aws_scheduler_schedule" "brain_dream_state" {
|
|
1979
|
+
resource "aws_scheduler_schedule" "webhook_deliveries_cleanup" {
|
|
1961
1980
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1962
1981
|
|
|
1963
|
-
name = "thinkwork-${var.stage}-
|
|
1982
|
+
name = "thinkwork-${var.stage}-webhook-deliveries-cleanup"
|
|
1964
1983
|
group_name = "default"
|
|
1965
|
-
schedule_expression =
|
|
1966
|
-
state =
|
|
1984
|
+
schedule_expression = "cron(0 4 * * ? *)" # daily at 04:00 UTC
|
|
1985
|
+
state = "ENABLED"
|
|
1967
1986
|
|
|
1968
1987
|
flexible_time_window {
|
|
1969
1988
|
mode = "OFF"
|
|
1970
1989
|
}
|
|
1971
1990
|
|
|
1972
1991
|
target {
|
|
1973
|
-
arn = aws_lambda_function.handler["
|
|
1992
|
+
arn = aws_lambda_function.handler["webhook-deliveries-cleanup"].arn
|
|
1974
1993
|
role_arn = aws_iam_role.scheduler.arn
|
|
1975
|
-
|
|
1976
|
-
retry_policy {
|
|
1977
|
-
maximum_retry_attempts = 0
|
|
1978
|
-
}
|
|
1979
1994
|
}
|
|
1980
1995
|
}
|
|
1981
1996
|
|
|
1997
|
+
# ---------------------------------------------------------------------------
|
|
1998
|
+
# Requester memory dreaming — broad per-user memory compaction/reflection sweep
|
|
1999
|
+
# ---------------------------------------------------------------------------
|
|
2000
|
+
|
|
1982
2001
|
resource "aws_scheduler_schedule" "requester_memory_dreaming" {
|
|
1983
2002
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
1984
2003
|
|
|
@@ -2041,20 +2060,12 @@ resource "aws_scheduler_schedule" "mcp_approval_sweeper" {
|
|
|
2041
2060
|
}
|
|
2042
2061
|
}
|
|
2043
2062
|
|
|
2044
|
-
|
|
2045
|
-
# skill_runs reconciler — transitions stuck-running rows to failed every 5 min.
|
|
2046
|
-
# Guards against agentcore Lambda crashes / OOMs that drop the
|
|
2047
|
-
# /api/skills/complete writeback and leave the row at 'running' forever,
|
|
2048
|
-
# which in turn blocks the dedup partial unique index from letting retries
|
|
2049
|
-
# through.
|
|
2050
|
-
# ---------------------------------------------------------------------------
|
|
2051
|
-
|
|
2052
|
-
resource "aws_scheduler_schedule" "skill_runs_reconciler" {
|
|
2063
|
+
resource "aws_scheduler_schedule" "inbox_approval_sweeper" {
|
|
2053
2064
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
2054
2065
|
|
|
2055
|
-
name = "thinkwork-${var.stage}-
|
|
2066
|
+
name = "thinkwork-${var.stage}-inbox-approval-sweeper"
|
|
2056
2067
|
group_name = "default"
|
|
2057
|
-
schedule_expression = "
|
|
2068
|
+
schedule_expression = "cron(30 4 * * ? *)" # daily at 04:30 UTC (offset from mcp-approval-sweeper)
|
|
2058
2069
|
state = "ENABLED"
|
|
2059
2070
|
|
|
2060
2071
|
flexible_time_window {
|
|
@@ -2062,53 +2073,50 @@ resource "aws_scheduler_schedule" "skill_runs_reconciler" {
|
|
|
2062
2073
|
}
|
|
2063
2074
|
|
|
2064
2075
|
target {
|
|
2065
|
-
arn = aws_lambda_function.handler["
|
|
2076
|
+
arn = aws_lambda_function.handler["inbox-approval-sweeper"].arn
|
|
2066
2077
|
role_arn = aws_iam_role.scheduler.arn
|
|
2067
2078
|
}
|
|
2068
2079
|
}
|
|
2069
2080
|
|
|
2070
|
-
#
|
|
2071
|
-
#
|
|
2072
|
-
#
|
|
2073
|
-
#
|
|
2074
|
-
#
|
|
2075
|
-
#
|
|
2076
|
-
#
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
# scheduler retries only adds redundant connections. A failure lands in the
|
|
2080
|
-
# DLQ for operator visibility instead.
|
|
2081
|
-
# ---------------------------------------------------------------------------
|
|
2081
|
+
# auth_subscription_tickets retention. Unlike the approval sweepers this is
|
|
2082
|
+
# a volume problem, not a queue-hygiene one: ~30 tickets/min are minted on
|
|
2083
|
+
# every connect + subscription registration and nothing deleted them
|
|
2084
|
+
# (551k rows / 306 MB and +24 MB/day on a customer stage, idx_scan=0).
|
|
2085
|
+
# Hourly rather than daily so each tick's backlog stays small enough that a
|
|
2086
|
+
# single batch usually drains it; the handler's own 45s budget bounds the
|
|
2087
|
+
# first few catch-up runs on a stage with an existing backlog.
|
|
2088
|
+
resource "aws_scheduler_schedule" "auth_ticket_sweeper" {
|
|
2089
|
+
count = local.deploy_lambda_handlers ? 1 : 0
|
|
2082
2090
|
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2091
|
+
name = "thinkwork-${var.stage}-auth-ticket-sweeper"
|
|
2092
|
+
group_name = "default"
|
|
2093
|
+
schedule_expression = "rate(1 hour)"
|
|
2094
|
+
state = "ENABLED"
|
|
2087
2095
|
|
|
2088
|
-
|
|
2089
|
-
|
|
2096
|
+
flexible_time_window {
|
|
2097
|
+
mode = "OFF"
|
|
2090
2098
|
}
|
|
2091
|
-
}
|
|
2092
2099
|
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
maximum_retry_attempts = 0
|
|
2097
|
-
maximum_event_age_in_seconds = 3600
|
|
2098
|
-
|
|
2099
|
-
destination_config {
|
|
2100
|
-
on_failure {
|
|
2101
|
-
destination = aws_sqs_queue.analyst_connection_reconciler_dlq[0].arn
|
|
2102
|
-
}
|
|
2100
|
+
target {
|
|
2101
|
+
arn = aws_lambda_function.handler["auth-ticket-sweeper"].arn
|
|
2102
|
+
role_arn = aws_iam_role.scheduler.arn
|
|
2103
2103
|
}
|
|
2104
2104
|
}
|
|
2105
2105
|
|
|
2106
|
-
|
|
2106
|
+
# ---------------------------------------------------------------------------
|
|
2107
|
+
# skill_runs reconciler — transitions stuck-running rows to failed every 5 min.
|
|
2108
|
+
# Guards against agentcore Lambda crashes / OOMs that drop the
|
|
2109
|
+
# /api/skills/complete writeback and leave the row at 'running' forever,
|
|
2110
|
+
# which in turn blocks the dedup partial unique index from letting retries
|
|
2111
|
+
# through.
|
|
2112
|
+
# ---------------------------------------------------------------------------
|
|
2113
|
+
|
|
2114
|
+
resource "aws_scheduler_schedule" "skill_runs_reconciler" {
|
|
2107
2115
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
2108
2116
|
|
|
2109
|
-
name = "thinkwork-${var.stage}-
|
|
2117
|
+
name = "thinkwork-${var.stage}-skill-runs-reconciler"
|
|
2110
2118
|
group_name = "default"
|
|
2111
|
-
schedule_expression = "rate(
|
|
2119
|
+
schedule_expression = "rate(5 minutes)"
|
|
2112
2120
|
state = "ENABLED"
|
|
2113
2121
|
|
|
2114
2122
|
flexible_time_window {
|
|
@@ -2116,12 +2124,8 @@ resource "aws_scheduler_schedule" "analyst_connection_reconciler" {
|
|
|
2116
2124
|
}
|
|
2117
2125
|
|
|
2118
2126
|
target {
|
|
2119
|
-
arn = aws_lambda_function.handler["
|
|
2127
|
+
arn = aws_lambda_function.handler["skill-runs-reconciler"].arn
|
|
2120
2128
|
role_arn = aws_iam_role.scheduler.arn
|
|
2121
|
-
|
|
2122
|
-
retry_policy {
|
|
2123
|
-
maximum_retry_attempts = 0
|
|
2124
|
-
}
|
|
2125
2129
|
}
|
|
2126
2130
|
}
|
|
2127
2131
|
|
|
@@ -2482,175 +2486,44 @@ resource "aws_scheduler_schedule" "stall_monitor" {
|
|
|
2482
2486
|
}
|
|
2483
2487
|
}
|
|
2484
2488
|
|
|
2485
|
-
# ---------------------------------------------------------------------------
|
|
2486
|
-
# Retry dispatcher — drains retry_queue rows the stall monitor enqueues and
|
|
2487
|
-
# re-runs genuinely stalled turns (THINK-307). First-ever scheduling of this
|
|
2488
|
-
# handler; state is var-driven and defaults DISABLED — never enable on a
|
|
2489
|
-
# stage before THINK-305/308/309 are live there (parent plan deploy ordering).
|
|
2490
|
-
# The 1-minute rate is fixed by design: the queue's own scheduled_at does the
|
|
2491
|
-
# pacing. Scheduler retries stay at 0 — the next 1-minute tick IS the retry.
|
|
2492
|
-
# ---------------------------------------------------------------------------
|
|
2493
|
-
|
|
2494
|
-
# Lambda async retries are disabled (mirrors memory-retraction-drainer): the
|
|
2495
|
-
# claim is a CAS UPDATE so a duplicate invocation only picks up new rows, and
|
|
2496
|
-
# the next 1-minute tick is the retry.
|
|
2497
|
-
resource "aws_lambda_function_event_invoke_config" "retry_dispatcher" {
|
|
2498
|
-
count = local.deploy_lambda_handlers ? 1 : 0
|
|
2499
|
-
function_name = aws_lambda_function.handler["cron-retry-dispatcher"].function_name
|
|
2500
|
-
maximum_retry_attempts = 0
|
|
2501
|
-
maximum_event_age_in_seconds = 3600
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
resource "aws_scheduler_schedule" "retry_dispatcher" {
|
|
2505
|
-
count = local.deploy_lambda_handlers ? 1 : 0
|
|
2506
|
-
|
|
2507
|
-
name = "thinkwork-${var.stage}-retry-dispatcher"
|
|
2508
|
-
group_name = "default"
|
|
2509
|
-
schedule_expression = "rate(1 minutes)"
|
|
2510
|
-
state = var.retry_dispatcher_enabled ? "ENABLED" : "DISABLED"
|
|
2511
|
-
|
|
2512
|
-
flexible_time_window {
|
|
2513
|
-
mode = "OFF"
|
|
2514
|
-
}
|
|
2515
|
-
|
|
2516
|
-
target {
|
|
2517
|
-
arn = aws_lambda_function.handler["cron-retry-dispatcher"].arn
|
|
2518
|
-
role_arn = aws_iam_role.scheduler.arn
|
|
2519
|
-
|
|
2520
|
-
retry_policy {
|
|
2521
|
-
maximum_retry_attempts = 0
|
|
2522
|
-
}
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
|
|
2526
2489
|
|
|
2527
2490
|
# ---------------------------------------------------------------------------
|
|
2528
2491
|
# Compounding Memory — nightly hygiene + export
|
|
2529
2492
|
# ---------------------------------------------------------------------------
|
|
2530
2493
|
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
flexible_time_window {
|
|
2540
|
-
mode = "OFF"
|
|
2541
|
-
}
|
|
2542
|
-
|
|
2543
|
-
target {
|
|
2544
|
-
arn = aws_lambda_function.handler["wiki-compile"].arn
|
|
2545
|
-
role_arn = aws_iam_role.scheduler.arn
|
|
2546
|
-
}
|
|
2547
|
-
}
|
|
2548
|
-
|
|
2549
|
-
# Observations → Knowledge Graph sweep (plan 2026-06-09-004 U5). Enumerates
|
|
2550
|
-
# tenants and runs an incremental observations ingest per tenant; the stable
|
|
2551
|
-
# source_ref's active-run dedupe drops overlap with operator-started runs and
|
|
2552
|
-
# the in-handler stale-run reaper clears stranded rows past the run ceiling.
|
|
2553
|
-
resource "aws_scheduler_schedule" "knowledge_graph_observations_ingest" {
|
|
2494
|
+
# Identity drift match sweep (THINK-321 U7 / KTD-7 — R10). Enumerates
|
|
2495
|
+
# tenants with registered identity sources and starts a per-tenant match
|
|
2496
|
+
# job; tenants with a pending/running job are skipped in the handler and
|
|
2497
|
+
# the job dedupe key drops same-bucket duplicate starts. Ships DISABLED —
|
|
2498
|
+
# enabled per stage via identity_drift_match_enabled once bootstrap has
|
|
2499
|
+
# been proven on the stage.
|
|
2500
|
+
resource "aws_scheduler_schedule" "identity_drift_match" {
|
|
2554
2501
|
count = local.deploy_lambda_handlers ? 1 : 0
|
|
2555
2502
|
|
|
2556
|
-
name = "thinkwork-${var.stage}-
|
|
2503
|
+
name = "thinkwork-${var.stage}-identity-drift-match"
|
|
2557
2504
|
group_name = "default"
|
|
2558
|
-
schedule_expression = "rate(
|
|
2559
|
-
|
|
2560
|
-
# only after a manual golden-set-validated run. Driven by the GHA
|
|
2561
|
-
# WIKI_KG_INGEST_ENABLED var.
|
|
2562
|
-
state = var.knowledge_graph_observations_ingest_enabled ? "ENABLED" : "DISABLED"
|
|
2505
|
+
schedule_expression = "rate(1 days)"
|
|
2506
|
+
state = var.identity_drift_match_enabled ? "ENABLED" : "DISABLED"
|
|
2563
2507
|
|
|
2564
2508
|
flexible_time_window {
|
|
2565
2509
|
mode = "OFF"
|
|
2566
2510
|
}
|
|
2567
2511
|
|
|
2568
2512
|
target {
|
|
2569
|
-
arn = aws_lambda_function.handler["
|
|
2513
|
+
arn = aws_lambda_function.handler["identity-match"].arn
|
|
2570
2514
|
role_arn = aws_iam_role.scheduler.arn
|
|
2571
|
-
input = jsonencode({
|
|
2515
|
+
input = jsonencode({ drift = true, trigger = "scheduled" })
|
|
2572
2516
|
|
|
2573
|
-
# Periodic idempotent worker: the next
|
|
2574
|
-
#
|
|
2575
|
-
#
|
|
2576
|
-
# volume that helped trip Lambda recursive-loop detection.
|
|
2517
|
+
# Periodic idempotent worker: the next daily tick IS the retry —
|
|
2518
|
+
# scheduler retries only stack invocations onto a self-correcting
|
|
2519
|
+
# cadence.
|
|
2577
2520
|
retry_policy {
|
|
2578
2521
|
maximum_retry_attempts = 0
|
|
2579
2522
|
}
|
|
2580
2523
|
}
|
|
2581
2524
|
}
|
|
2582
2525
|
|
|
2583
|
-
|
|
2584
|
-
count = local.deploy_lambda_handlers ? 1 : 0
|
|
2585
|
-
|
|
2586
|
-
name = "thinkwork-${var.stage}-wiki-lint"
|
|
2587
|
-
group_name = "default"
|
|
2588
|
-
schedule_expression = "cron(0 2 * * ? *)" # daily at 02:00 UTC
|
|
2589
|
-
state = "ENABLED"
|
|
2590
|
-
|
|
2591
|
-
flexible_time_window {
|
|
2592
|
-
mode = "OFF"
|
|
2593
|
-
}
|
|
2594
|
-
|
|
2595
|
-
target {
|
|
2596
|
-
arn = aws_lambda_function.handler["wiki-lint"].arn
|
|
2597
|
-
role_arn = aws_iam_role.scheduler.arn
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
|
|
2601
|
-
resource "aws_scheduler_schedule" "wiki_export" {
|
|
2602
|
-
count = local.deploy_lambda_handlers ? 1 : 0
|
|
2603
|
-
|
|
2604
|
-
name = "thinkwork-${var.stage}-wiki-export"
|
|
2605
|
-
group_name = "default"
|
|
2606
|
-
schedule_expression = "cron(0 3 * * ? *)" # daily at 03:00 UTC (after lint)
|
|
2607
|
-
state = "ENABLED"
|
|
2608
|
-
|
|
2609
|
-
flexible_time_window {
|
|
2610
|
-
mode = "OFF"
|
|
2611
|
-
}
|
|
2612
|
-
|
|
2613
|
-
target {
|
|
2614
|
-
arn = aws_lambda_function.handler["wiki-export"].arn
|
|
2615
|
-
role_arn = aws_iam_role.scheduler.arn
|
|
2616
|
-
}
|
|
2617
|
-
}
|
|
2618
|
-
|
|
2619
|
-
# S3 bucket for markdown vault exports. One bundle per (tenant, owner, date).
|
|
2620
|
-
# Retention is handled by the lifecycle rule below (30 days).
|
|
2621
|
-
resource "aws_s3_bucket" "wiki_exports" {
|
|
2622
|
-
bucket = "thinkwork-${var.stage}-wiki-exports"
|
|
2623
|
-
force_destroy = var.stage == "dev"
|
|
2624
|
-
|
|
2625
|
-
tags = {
|
|
2626
|
-
Name = "thinkwork-${var.stage}-wiki-exports"
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
resource "aws_s3_bucket_public_access_block" "wiki_exports" {
|
|
2631
|
-
bucket = aws_s3_bucket.wiki_exports.id
|
|
2632
|
-
block_public_acls = true
|
|
2633
|
-
block_public_policy = true
|
|
2634
|
-
ignore_public_acls = true
|
|
2635
|
-
restrict_public_buckets = true
|
|
2636
|
-
}
|
|
2637
|
-
|
|
2638
|
-
resource "aws_s3_bucket_lifecycle_configuration" "wiki_exports" {
|
|
2639
|
-
bucket = aws_s3_bucket.wiki_exports.id
|
|
2640
|
-
|
|
2641
|
-
rule {
|
|
2642
|
-
id = "expire-old-bundles"
|
|
2643
|
-
status = "Enabled"
|
|
2644
|
-
|
|
2645
|
-
filter {}
|
|
2646
|
-
|
|
2647
|
-
expiration {
|
|
2648
|
-
days = 30
|
|
2649
|
-
}
|
|
2650
|
-
}
|
|
2651
|
-
}
|
|
2652
|
-
|
|
2653
|
-
# Canonical ThinkWork Brain artifact store. Unlike wiki_exports, this bucket
|
|
2526
|
+
# Canonical ThinkWork Brain artifact store. This bucket
|
|
2654
2527
|
# is the durable replay/projection substrate for Brain source artifacts,
|
|
2655
2528
|
# ingestion manifests, migration snapshots, vault projections, and exports.
|
|
2656
2529
|
resource "aws_s3_bucket" "brain_artifacts" {
|
|
@@ -2773,7 +2646,7 @@ resource "aws_s3_bucket_lifecycle_configuration" "brain_artifacts" {
|
|
|
2773
2646
|
|
|
2774
2647
|
# THINK-193 U1 (Codex F6): normalized evidence snapshots are short-lived
|
|
2775
2648
|
# working copies — the durable record is the evidence row (hash + ref) and
|
|
2776
|
-
# the
|
|
2649
|
+
# the memory projection. Expire content after 30 days; the app mirrors
|
|
2777
2650
|
# this via memory_evidence_items.snapshot_expires_at.
|
|
2778
2651
|
rule {
|
|
2779
2652
|
id = "expire-evidence-snapshots"
|
|
@@ -2813,6 +2686,48 @@ resource "aws_s3_bucket_lifecycle_configuration" "brain_artifacts" {
|
|
|
2813
2686
|
noncurrent_days = 365
|
|
2814
2687
|
}
|
|
2815
2688
|
}
|
|
2689
|
+
|
|
2690
|
+
# THINK-630: async brain_ask task records are a polling buffer, not an
|
|
2691
|
+
# archive — they hold answer content and principal metadata, so they must
|
|
2692
|
+
# not accumulate. Seven days far exceeds any task's useful life. The
|
|
2693
|
+
# brain-mcp module (company-brain repo) deliberately does NOT manage this
|
|
2694
|
+
# bucket's lifecycle (it would silently drop the rules above); this stack
|
|
2695
|
+
# is the bucket's single lifecycle author.
|
|
2696
|
+
rule {
|
|
2697
|
+
id = "expire-brain-ask-tasks"
|
|
2698
|
+
status = "Enabled"
|
|
2699
|
+
|
|
2700
|
+
filter {
|
|
2701
|
+
prefix = "brain-ask-tasks/"
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
expiration {
|
|
2705
|
+
days = 7
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
noncurrent_version_expiration {
|
|
2709
|
+
noncurrent_days = 7
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
# THINK-629 C2: ask exchange records (follow-up continuity) age out the
|
|
2714
|
+
# same way — the durable record is the thread itself.
|
|
2715
|
+
rule {
|
|
2716
|
+
id = "expire-brain-ask-exchanges"
|
|
2717
|
+
status = "Enabled"
|
|
2718
|
+
|
|
2719
|
+
filter {
|
|
2720
|
+
prefix = "brain-ask-exchanges/"
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
expiration {
|
|
2724
|
+
days = 7
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
noncurrent_version_expiration {
|
|
2728
|
+
noncurrent_days = 7
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2816
2731
|
}
|
|
2817
2732
|
|
|
2818
2733
|
data "aws_iam_policy_document" "brain_artifacts_bucket" {
|
|
@@ -2897,33 +2812,6 @@ resource "aws_iam_role_policy" "scheduler_invoke" {
|
|
|
2897
2812
|
# SSM Parameters — Lambda ARNs for cross-function invocation
|
|
2898
2813
|
# ---------------------------------------------------------------------------
|
|
2899
2814
|
|
|
2900
|
-
########################################################################
|
|
2901
|
-
# SecureString parameter for the Google Places API key. wiki-compile reads
|
|
2902
|
-
# this on cold start via loadGooglePlacesClientFromSsm() and caches the
|
|
2903
|
-
# client at module scope. When google_places_api_key is empty (the
|
|
2904
|
-
# default), we seed the parameter with a placeholder so the Lambda init
|
|
2905
|
-
# path can distinguish "unconfigured" (skip Google entirely, degrade
|
|
2906
|
-
# gracefully) from "configured but wrong" (log + skip). lifecycle.ignore_
|
|
2907
|
-
# changes on `value` lets ops rotate via
|
|
2908
|
-
# aws ssm put-parameter --overwrite \
|
|
2909
|
-
# --name /thinkwork/<stage>/google-places/api-key \
|
|
2910
|
-
# --type SecureString --value <KEY>
|
|
2911
|
-
# without terraform fighting it on the next apply.
|
|
2912
|
-
########################################################################
|
|
2913
|
-
|
|
2914
|
-
resource "aws_ssm_parameter" "google_places_api_key" {
|
|
2915
|
-
name = "/thinkwork/${var.stage}/google-places/api-key"
|
|
2916
|
-
type = "SecureString"
|
|
2917
|
-
value = var.google_places_api_key != "" ? var.google_places_api_key : "PLACEHOLDER_SET_VIA_CLI"
|
|
2918
|
-
description = "Google Places API (New) key consumed by wiki-compile. See docs/plans/2026-04-21-005-feat-wiki-place-capability-v2-plan.md Unit 4."
|
|
2919
|
-
|
|
2920
|
-
lifecycle {
|
|
2921
|
-
# Allow `aws ssm put-parameter --overwrite` to stick across applies.
|
|
2922
|
-
# New-key rotation or initial population by ops should happen via CLI,
|
|
2923
|
-
# not via terraform var.
|
|
2924
|
-
ignore_changes = [value]
|
|
2925
|
-
}
|
|
2926
|
-
}
|
|
2927
2815
|
|
|
2928
2816
|
########################################################################
|
|
2929
2817
|
# SecureString parameter for the graphql-http Lambda's OWN Cloudflare
|
|
@@ -2967,8 +2855,10 @@ resource "aws_ssm_parameter" "cloudflare_namespace_token" {
|
|
|
2967
2855
|
|
|
2968
2856
|
resource "aws_ssm_parameter" "lambda_arns" {
|
|
2969
2857
|
for_each = local.deploy_lambda_handlers ? {
|
|
2970
|
-
|
|
2971
|
-
|
|
2858
|
+
# THINK-583 U3: alias-qualified so the SSM-fallback path in
|
|
2859
|
+
# getChatAgentInvokeFnArn (graphql/utils.ts) also lands on the
|
|
2860
|
+
# provisioned-concurrency alias, not $LATEST.
|
|
2861
|
+
"chat-agent-invoke-fn-arn" = aws_lambda_alias.live["chat-agent-invoke"].arn
|
|
2972
2862
|
"job-schedule-manager-fn-arn" = aws_lambda_function.handler["job-schedule-manager"].arn
|
|
2973
2863
|
"memory-retain-fn-arn" = aws_lambda_function.handler["memory-retain"].arn
|
|
2974
2864
|
"eval-runner-fn-arn" = aws_lambda_function.handler["eval-runner"].arn
|
|
@@ -3027,6 +2917,17 @@ resource "aws_lambda_function" "compliance_anchor" {
|
|
|
3027
2917
|
COMPLIANCE_ANCHOR_OBJECT_LOCK_MODE = var.compliance_anchor_object_lock_mode
|
|
3028
2918
|
}
|
|
3029
2919
|
}
|
|
2920
|
+
|
|
2921
|
+
# THINK-1082: this function opens a database connection (see env above), so
|
|
2922
|
+
# the whole-module VPC lane covers it too. Absent when lambdas_in_vpc is off.
|
|
2923
|
+
dynamic "vpc_config" {
|
|
2924
|
+
for_each = var.lambdas_in_vpc ? [1] : []
|
|
2925
|
+
|
|
2926
|
+
content {
|
|
2927
|
+
subnet_ids = var.vpc_subnet_ids
|
|
2928
|
+
security_group_ids = var.vpc_security_group_ids
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
3030
2931
|
}
|
|
3031
2932
|
|
|
3032
2933
|
resource "aws_sqs_queue" "compliance_anchor_dlq" {
|
|
@@ -3333,6 +3234,17 @@ resource "aws_lambda_function" "compliance_export_runner" {
|
|
|
3333
3234
|
DATABASE_NAME = var.database_name
|
|
3334
3235
|
}
|
|
3335
3236
|
}
|
|
3237
|
+
|
|
3238
|
+
# THINK-1082: this function opens a database connection (see env above), so
|
|
3239
|
+
# the whole-module VPC lane covers it too. Absent when lambdas_in_vpc is off.
|
|
3240
|
+
dynamic "vpc_config" {
|
|
3241
|
+
for_each = var.lambdas_in_vpc ? [1] : []
|
|
3242
|
+
|
|
3243
|
+
content {
|
|
3244
|
+
subnet_ids = var.vpc_subnet_ids
|
|
3245
|
+
security_group_ids = var.vpc_security_group_ids
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3336
3248
|
}
|
|
3337
3249
|
|
|
3338
3250
|
# SQS → Lambda event source mapping. batch_size=1 so each export is a
|