This report explains the current worktree diff from top to bottom. It follows the execution path first, then explains every changed line and every deleted logical block.
Line references for p8-api/scripts/provision.sh refer to the deleted file as it existed at HEAD. Comments and blank lines do not execute, but their operational intent is included because they explain the design.
The change removes a p8-api-specific Terraform orchestrator and makes p8-api use the repository-wide per-module Terraform provisioner. The shared provisioner is extended so that it can supply API Gateway IDs from the cached environment configuration.
The four changed paths are:
p8-ai/deployments/variables.tf — comment-only clarification.
p8-api/scripts/provision.sh — entire file deleted.
p8-deployments/scripts/provision.sh — comment cleanup plus four new environment-to-Terraform mappings.
scripts/deployments/build_and_deploy.sh — remove the p8-api special branch and its caller function; update one packaging comment.
There are only five runtime additions in the diff: the four TF_VAR_* mappings. The main runtime change is caused by deleting the special deployment path.
p8-api is a repository containing modulesp8-api/module_conf.yaml lists nine modules, including:
p8-api/p8-profile-management
p8-api/p8-metrics
p8-api/p8-statistics
p8-api/p8-audit-trail
p8-api/p8-announcement
p8-api/p8-maker-checker
p8-api/p8-notification
p8-api/p8-integrations
p8-api/p8-ui-log-management
Each module has a Terraform directory:
p8-api/<module>/deployments/
Each module’s deployments/provision.sh is a symlink to:
p8-deployments/scripts/provision.sh
p8-api/deployments/build_and_deploy.sh is also a symlink, pointing to:
scripts/deployments/build_and_deploy.sh
So there is one generic orchestrator and one shared Terraform provisioner. The old p8-api/scripts/provision.sh was an exception to that structure.
repo: repository name, calculated by the generic script. For this run it is p8-api.
modules: module names selected from module_conf.yaml, or from --modules.
mode: normally build_and_deploy, publish_only, deploy, or deploy_local.
alias: environment name such as dev2.
region: AWS region.
TF_VAR_x: Terraform automatically reads an environment variable named TF_VAR_x as the value of Terraform variable x.
The old path was:
p8-api/deployments/build_and_deploy.sh
-> generic scripts/deployments/build_and_deploy.sh
-> deploy()
-> special p8-api branch
-> p8-api/scripts/provision.sh
-> parallel child-module provision.sh calls
-> p8-deployments/scripts/provision.sh
-> terraform init/apply
The generic script still handled the build phase. Only the deployment phase had a special branch for p8-api.
deploy() before the deletionAt scripts/deployments/build_and_deploy.sh:334-344, UI repositories use a GUI builder. Other repositories enter the generic module loop. Before this diff, there was an additional branch immediately after that generic branch:
elif [[ $repo == "p8-api" ]]; then
deploy_p8_api
When repo was p8-api, the generic per-module loop was bypassed and deploy_p8_api ran instead.
deploy_p8_api() callerThe deleted function was at old lines 407-430.
function deploy_p8_api() { defined the exception path.
if [[ $repo == "p8-api" ]]; then repeated the caller’s repository check. It was redundant but prevented the body from running for another repository.
init_deploy_status created or preserved the overall status file.
build_status=$(cat $status_file) copied that status into the local variable.
pushd ../scripts changed from p8-api/deployments to p8-api/scripts.
export P8_API_MODULES=$(printf '%s\n' "${modules[@]}" | tr '\n' ' ') converted the generic module selection into the environment variable expected by the old p8-api/scripts/provision.sh.
export P8_PRODUCT_VARIATION="$P8_PRODUCT_VARIATION" re-exported the product variant. This is effectively a no-op if it was already exported, but made the child script’s input explicit.
./provision.sh -a ... -r ... -m ... -rt ... launched the old p8-api orchestrator. Notice that its -m means deployment mode, not module selection.
|| echo 'failed' >$status_file converted any non-zero result into an overall failed status.
popd returned to p8-api/deployments.
build_status=$(cat $status_file) refreshed the result.
bash ./build_utils.sh bld_update 2 "overall_deployment" ... recorded one aggregate AWS-artifact deployment result.
return stopped the generic deploy() function from continuing into any other deployment logic.
Removing this function and its caller means p8-api now goes through the ordinary module loop.
p8-api/scripts/provision.shThe whole 326-line file was deleted. The following is the complete behavior of each logical section.
set -e, causing the script to stop when an unhandled command failed.
The four functions only formatted terminal output:
print_title: blue bold text.
print_message: purple text.
print_error: red ERROR: text.
print_warning: yellow WARNING: text.
Deleting them removes the old script’s presentation layer. The generic orchestrator and shared provisioner have their own output helpers.
is_deployable_module() was a copy of the function in scripts/deployments/build_and_deploy.sh.
module_conf.yaml files.
P8_SOLUTION_VARIATION, then P8_SolutionVariant, then P8_PRODUCT_VARIATION.
.modules["<module>"].allowed_on_condition from the repository config.
${!condition} read that variable. Only the literal string true allowed deployment; otherwise the module was skipped.
.variants[] list.
all.
This gate was not unique in policy; it duplicated the generic script’s gate. The new flow keeps the generic version and deletes this copy.
help() described the deleted interface.
-a, -r, -m, -rt, and --no-auto-approve.
p8-authorizer had to be applied first because modules read authorizer IDs from its Terraform remote state.
This interface no longer exists. The supported interface is the generic build_and_deploy.sh interface, plus the shared module provision.sh interface.
alias and region to empty values.
build_and_deploy.
P8_RELEASE_TAG.
--auto-approve.
The generic orchestrator now obtains these values from --env-name, --aws-region, --mode, and --publish-tags, then passes them to each module provisioner.
The while loop consumed the old script’s arguments.
-a stored the next argument as alias and shifted two arguments.
-r stored the next argument as region and shifted two.
-m stored the next argument as mode and shifted two.
-rt stored the next argument as release_tag and shifted two.
--no-auto-approve cleared the auto_approve string and shifted one.
-h/--help printed help and exited successfully.
The deleted script did not accept --modules; module selection came indirectly through P8_API_MODULES.
The script required both alias and region. If either was empty, it printed an error, printed help, and exited with status 1.
The generic entry point performs equivalent validation for env_name and aws_region.
This was the most important deleted runtime block.
The intent was to look up four values once before starting parallel module deployments:
admin REST API ID
trader REST API ID
admin /api resource ID
trader /api resource ID
The comments at lines 131-137 explain the performance reason: every route-tree module otherwise performs API Gateway name/path lookups, and many concurrent lookups can be throttled.
publish_only because live API routes are not created in that mode.
None for nonmatching pages.
_first_id(), which split whitespace into tokens, removed empty values and None, and selected the first remaining ID.
p8-<alias>-admin-api-<region>.
p8-<alias>-api-<region>.
/api in the admin REST API, but only if the admin API lookup succeeded.
TF_VAR_*, making them visible to child Terraform processes.
<lookup> when a value was empty.
The new design still obtains these values, but through the shared export_config.sh cache and the shared populate_tf_vars() function rather than through this p8-api-only block.
P8_API_MODULES could override the default list.
P8_API_MODULES into an array.
../module_conf.yaml.
The generic script now reads the same module_conf.yaml itself and supports --modules. The explicit p8-api-only validation is gone.
p8-api/deployments to the p8-api repository root.
lib.zip should have a freshly built lib/ directory, otherwise an old package or no package might be deployed.
module_publishes_package(), using grep to inspect Terraform files for lib.zip.
This preflight check is lost. The shared package_lambda_code() now logs and continues when ../lib is absent.
This block ran except in deploy mode.
missing_builds array.
lib/.
scripts/build.sh commands, using the module’s npm package name when available.
--modules.
After this diff, a missing lib/ does not stop all Terraform work before it starts. This is one of the concrete safeguards lost by deleting the orchestrator.
The old script tried to avoid provider-cache races before launching parallel modules.
terraform init operations could write or link the same cached provider and produce ETXTBSY (text file busy).
TF_PLUGIN_CACHE_DIR to $HOME/.terraform.d/plugin-cache and created it.
warm_plugin_cache() and its loop variable.
.terraform, ran terraform init -backend=false -input=false, and removed .terraform again if initialization succeeded.
This pre-warm pass is lost. The shared provisioner instead serializes each real terraform init with init_terraform_locked() at p8-deployments/scripts/provision.sh:101-113. That lock protects init-versus-init, not every possible init-versus-apply race.
$HOME/p8_build_info/build_logs/p8-api/.
success.
The per-module log directory and PID/status arrays are lost. The generic flow records deployment status through build_utils.sh while processing each module.
is_deployable_module().
skipped in the status array and did not start a child process.
The generic loop still performs a deployability check, so this behavior is retained through a different implementation.
This was the main deployment loop.
deployments/ directory.
lib.zip first, preventing a stale zip from surviving when lib/ disappeared.
lib/ into lib.zip, excluding source maps.
lib/ was missing but continued.
provision.sh with init apply, passing alias, region, mode, product variant, release tag, module name, and auto-approval.
The new generic loop still eventually runs each module’s provision.sh, and the shared provisioner still packages ../lib into ../lib.zip. The major differences are that packaging is now inside the shared provisioner and modules are not launched by this script in parallel.
wait returned zero.
wait failed.
This whole PID-based result collection is lost because the generic loop waits for each module’s provision call before starting the next one.
Success.
The generic script instead updates build status per module and later runs its normal end-of-build handling. The old p8-api-specific summary and log location disappear.
For normal build_and_deploy:
build_and_deploy.sh
-> build()
-> deploy()
-> for each selected module, in order:
call_hook pre_deploy
check module variant/feature gate
cd p8-api/<module>/deployments
shared provision.sh init apply
record module result with build_utils.sh
The relevant generic code is scripts/deployments/build_and_deploy.sh:326-403.
p8-trader-ui and p8-ui. p8-api no longer appears here.
modules and read each module’s build tool, relative path, artifact type, and API exposure flag from module_conf.yaml.
pre_deploy hook, if present.
deploy_local option to skip AWS artifacts.
deployments directory, and call:
./provision.sh \
-a "$env_name" \
-r "$aws_region" \
-m "$mode" \
-v "$P8_PRODUCT_VARIATION" \
-rt "$publish_tags" \
--module "${module#p8-}" \
--auto-approve init apply
${module#p8-} removes the p8- prefix. For example, p8-announcement becomes announcement, which is the Terraform module’s state/artifact name.
bld_update for the module deployment.
The key result is that all p8-api modules use the same invocation shape as other Terraform modules.
The only new executable additions are at p8-deployments/scripts/provision.sh:271-274:
"TF_VAR_admin_rest_api_id:admin_api_id"
"TF_VAR_trader_rest_api_id:trader_api_id"
"TF_VAR_admin_api_resource_id:admin_api_resource_id"
"TF_VAR_trader_api_resource_id:trader_api_resource_id"
Each string has the form:
Terraform environment variable : shell variable loaded from .envrc
The existing loop at lines 279-288 processes them:
:.
TF_VAR_* value indirectly with ${!tf_var}.
${!env_var}.
Therefore:
caller-provided TF_VAR_* value wins
otherwise cached .envrc value is used
otherwise Terraform receives the default empty string
These four lines replace the old p8-api-specific exports at deleted lines 164-167.
The shared exporter writes these values to /tmp/<alias>/.envrc:
admin_api_id
trader_api_id
admin_api_resource_id
trader_api_resource_id
Those values are produced by AWS API Gateway lookups in p8-deployments/scripts/export_config.sh and cached.
For each p8-api module, api_gateway.tf passes them to the route-tree module:
rest_api_id = each.key == "admin" ? var.admin_rest_api_id : var.trader_rest_api_id
parent_id = each.key == "admin" ? var.admin_api_resource_id : var.trader_api_resource_id
The route-tree module uses the supplied IDs when they are nonempty. If either is empty, it performs its own fallback data lookup by API name or resource path.
For p8-ai, the same variables already existed in p8-ai/deployments/variables.tf, and p8-ai/deployments/api_gateway.tf already passed them to the route-tree module. The new shared mappings make those variables populate from the shared cache there too.
p8-ai/deployments/variables.tfOld comment:
REST API ids/resource ids; empty => resolved by the p8-api orchestrator and passed as TF_VAR_*.
New comment:
REST API ids/resource ids; populated from the shared environment config.
No Terraform variable, default, resource, or behavior changes in this file. The old explanation became false after removing the p8-api orchestrator. The actual source is now the shared .envrc/populate_tf_vars path.
p8-deployments/scripts/provision.sh:83The phrase p8-api orchestrator becomes independent deployments.
This changes no shell behavior. It makes the locking comment apply to all callers, because the shared provisioner can be invoked concurrently by unrelated module or repository deployments.
p8-deployments/scripts/provision.sh:172The parenthetical example naming the p8-api orchestrator is removed. The rule remains: pre-set TF_VAR_* values are respected.
p8-deployments/scripts/provision.sh:180-182The old wording specifically mentioned REST API IDs exported by the p8-api orchestrator. It is replaced with generic wording saying caller-provided Terraform variables are respected.
Again, only comments changed in these locations.
scripts/deployments/build_and_deploy.sh:460-463The packaging comment formerly gave p8-api: deploy_p8_api as an example of a repository-level orchestrator. That example is removed because deploy_p8_api no longer exists.
The code itself is unchanged: if a repository has a scripts/ directory, it is still copied into the Terraform release package. This remains important because p8-api/scripts/export_config.sh must be available when the release is deployed.
The following behavior still exists, but through generic/shared code:
module_conf.yaml.
init, apply, and auto-approval.
lib/ into lib.zip.
apigw-route-tree.
publish_only, deploy, and deploy_local modes.
| Old behavior | After the diff |
| — | — |
| p8-api modules deployed in parallel | Generic loop deploys modules sequentially |
| API IDs looked up once directly by p8-api script | Values come through shared cached environment config |
| p8-api-specific module validation | No equivalent explicit upfront validation in the deleted wrapper |
Missing lib/ failed before any Terraform ran |
Shared provisioner logs missing lib/ and continues |
| Provider cache pre-warmed before fan-out | Each real terraform init relies on shared flock locking |
| One p8-api aggregate log directory | Generic build-info/module status handling |
P8_API_MODULES was exported to the old wrapper |
Generic --modules selection is used directly |
Direct invocation of p8-api/scripts/provision.sh |
That path no longer exists |
The largest safety concern is the missing-build check. The old wrapper deliberately prevented a deployment when a package-producing module had no lib/ directory. The shared provisioner has a more permissive behavior: it skips packaging and lets Terraform continue. That can be correct for image-based modules, but it is less protective for Lambda modules.
The repository already had a generic deployment architecture:
module deployments/provision.sh
-> shared p8-deployments provisioner
The p8-api wrapper duplicated several generic responsibilities, had its own module gate, its own package step, its own API lookup, and its own concurrency handling. The change consolidates those responsibilities:
The performance motivation remains the same: avoid repeated API Gateway lookups and provider-cache races. The implementation location changes from a p8-api-only wrapper to shared infrastructure.
lib/ before build_and_deploy or publish_only deployment, because the old hard failure is gone.
--modules <one-module> and confirm only that module is applied.
/tmp/<alias>/.envrc and confirm the exporter creates it and the four API IDs populate.
TF_VAR_trader_rest_api_id and confirm it is not overwritten by the cache.
publish_only and confirm it does not require live API IDs.
p8-api/scripts/export_config.sh must remain present in the packaged release.
p8-deployments/application/terraform-modules/apigw-route-tree/variables.tf, which still refer to the removed p8-api orchestrator. That file was not part of this diff.
The diff itself passes git diff --check; no deployment or Terraform execution was run while preparing this explanation.