Skip to main content

Repository operations

Run repository commands from the workspace root. Bazel is the supported build and test interface; do not replace a Bazel target with direct Gradle, Maven, npm, or pnpm build commands.

Choose the narrowest target

Discover labels before guessing:

bazel query //apps/microservices/merchant-api:all
bazel query 'tests(//apps/websites/portals/retail:all)'

Common target shapes are:

AreaBuildTest
Microservicebazel build //apps/microservices/merchant-api:corebazel test //apps/microservices/merchant-api:core_test
Service imagebazel build //apps/microservices/merchant-api:imageBuild the deployable tarball with bazel build //apps/microservices/merchant-api:image_tarball
Retail portalbazel build //apps/websites/portals/retail:buildbazel test //apps/websites/portals/retail:test //apps/websites/portals/retail:lint
Support portalbazel build //apps/websites/portals/support:buildbazel test //apps/websites/portals/support:test //apps/websites/portals/support:lint
Formal specificationsbazel build //apps/specifications/dafny:verifyUse the owning target returned by bazel query
Private docsbazel build //docs/private-docs:buildRun the focused documentation checks described below

Package wildcards are appropriate only when a change crosses multiple targets:

bazel test --build_tests_only //apps/microservices/...
bazel test --build_tests_only //apps/websites/...

Do not start with //... for routine development. The CI workflows split the repository by execution requirements, and a local all-repository command can include Android, Apple, documentation, network, or manually tagged work that needs a different host or configuration.

Bazel execution policy

The checked-in .bazelrc and buildbuddy.bazelrc define these modes:

ModeUse
Plain bazel build or bazel testDeveloper default. Prefer the BuildBuddy Linux executor and fall back locally; use the shared remote cache and upload local results.
--config=no_remote_uploadKeep remote reads but do not upload local results on a constrained connection.
--config=localDisable remote execution for a target that requires local devices, host state, or a locally retained artifact. Remote cache configuration remains separate.
--config=macosUse the macOS sandbox path and local execution for Apple work.
--config=android_x86_64Select the x86_64 Android NDK/platform configuration for an emulator (ARM64 is Bazel's unconditional default; no flag needed).
--config=ci --config=rbeCI role plus remote execution. Use --config=ci --config=local for CI with local execution, or --config=rbe for ordinary remote development.

For normal local Android work, use the wrapper so Android analysis has an isolated output base and the artifact is retained locally:

scripts/bazel-android.sh build //apps/android:android_app_local_staging

Set BAZEL_ANDROID_CONFIG=android_x86_64 before the wrapper only for an x86_64 emulator target. See Testing strategy for focused test and evidence policy.

Local runtime operations

scripts/local-validation.sh is the only user-facing lifecycle for the integrated local stack:

./scripts/local-validation.sh doctor
./scripts/local-validation.sh up
./scripts/local-validation.sh smoke all
./scripts/local-validation.sh ports

Rebuild or restart only the changed component:

./scripts/local-validation.sh rebuild merchant-api
./scripts/local-validation.sh restart retail
./scripts/local-validation.sh logs merchant-api

These commands operate on local emulators, containers, generated environment files, and provider stubs. They do not deploy to staging or production. See Local development and manual QA for the lifecycle, ports, and manual paths.

Focused documentation validation

Use the checked-in QA helper only for focused documentation contracts; it is not a stack lifecycle:

./scripts/local-validation/qa.sh test docs-index
./scripts/local-validation/qa.sh test docs-render
bazel build //docs/private-docs:build

The Bazel docs build intentionally runs locally in CI with remote and disk caches disabled because Docusaurus needs network-capable local execution.

CI and deployment workflows

Treat the workflow files, not copied shell snippets, as the deployment implementation.

WorkflowAutomatic boundaryManual or release side effects
.github/workflows/bazel-build.yml (CI)Tests non-deploy targets on qualifying pull requests and main pushes.workflow_dispatch reruns validation; it does not deploy.
.github/workflows/container-images-deploy.yml (Build Container Images and Deploy)Pull requests test services. main pushes build/publish changed images, deploy staging services, and run staging smoke. Published releases enter release and production lanes.Dispatch inputs can publish Azure images, apply PostgreSQL revisions, seed a baseline, or promote production. These are operator-only actions.
.github/workflows/cloudflare-workers.yml (Deploy Websites to Cloudflare Pages (staging from main, production from release))Pull requests build sites; main pushes deploy changed sites to staging; a published release deploys production.deploy_production=true is a web-only production deployment. The unchecked default deploys staging.
.github/workflows/android.yml (Build and Test Android App)Runs for qualifying pull requests and main pushes, daily, and for published releases.Manual dispatch defaults to Firebase App Distribution enabled and Play publishing disabled. Review every input before dispatch.
.github/workflows/docs.yml (Deploy Docs to Cloudflare Pages)Builds and deploys private docs from qualifying main pushes.Manual dispatch deploys the private documentation site.
.github/workflows/sdk-publish.yml (Publish SDKs)A published release resolves one SDK version and publishes the configured SDK families.Manual dry_run defaults to true; changing it to false uploads registry artifacts. See the SDK release checklist first.

A successful pull-request build is not deployment approval. Production runs use protected environments, release events, or explicit dispatch inputs and must be started only by an authorized operator with an approved change and rollback plan.

Staging observation

For a non-mutating preview of the staging readiness probe plan:

SMOKE_PREFLIGHT_ONLY=1 scripts/staging-cloud-smoke-readiness.sh

A normal run defaults to project peaksuite-staging, region us-east1, performs Cloud Run/resource/log and public health checks, and skips credentialed probes whose inputs are absent:

scripts/staging-cloud-smoke-readiness.sh

Keep PROJECT_ID or GOOGLE_CLOUD_PROJECT unset unless intentionally targeting another non-production project. Leave MANAGEMENT_TOKEN, MERCHANT_TOKEN, terminal activation inputs, RECEIPT_EMAIL, and RECEIPT_PHONE unset for observation-only use; supplying them enables credentialed or side-effecting probes. Never point this script at production as a convenience check.

Incident response

infra/tf/gcp/service-catalog.json is the canonical machine-readable incident catalog. It owns service tiers and internal responder groups, environment-scoped Azure dashboard and Log Analytics selectors, alert-source classifications, and ordered routing rules. Validate the catalog against the current deployment, Terraform, monitoring, and documentation sources with:

python3 tools/incident/validate_incident_config.py
# Remote validation:
bazel test //tools/incident:validate_incident_config_test

Activation state and operator steps

incident.io is not activated from this repository. Real incident.io service resource IDs, escalation schedule IDs, and verified responder owners have not been supplied. The catalog contains internal routing names and operator inputs, not proof of a live on-call roster. Provider mutation is restricted to an authorized operator; repository automation must not create or update incident.io resources.

After those real IDs and owners exist, an authorized operator must:

  1. Verify the responder roster and map each catalog owner to a real incident.io escalation schedule. Repository affiliation and Agent Portal agent_admin membership are not on-call ownership.
  2. Import each services[].incident record using the service name as its stable catalog key. Render dashboard and logs selectors with the operator-side subscription and resource-group values named by each selector; do not store unscoped portal blades.
  3. Configure incident_response.routes in declaration order because first match wins, then wire every concrete sources[].alert_name from the actionable and non-actionable signal lists.
  4. Prove routing and ownership in incident.io before revising the catalog's activation.status; do not commit guessed or placeholder provider IDs.

Staging is always non-paging. A WARNING signal is non-actionable P3 and non-paging unless a separate, measured production-impact signal matches a later production route. The first scheduled-job failure and raw Azure threshold signals remain non-paging until separately correlated sustained impact exists. The catalog and validator are authoritative for the exact source names, priorities, urgency, deduplication, and recovery windows.

Production recovery limits

The container deployment workflow has no single-service production rollback. Supplying azure_image_tag alone publishes or selects images but does not update running production Container Apps. An approved production dispatch with promote_azure_images_without_migrations=true force-promotes the selected tag across all production Container Apps; it is not a targeted rollback. A non-prerelease published release can also apply canonical PostgreSQL revisions, run the production Terrakube workspace, and force-promote all production Container Apps.

Use either all-service path only when that blast radius is acceptable. Otherwise, ship a forward fix through staging and a later approved release. Keep database recovery forward-only unless a dedicated down-revision is separately reviewed and approved.

Current operational source pointers

  • For Android production signing custody, rotation, and compromise response, use apps/android/docs/keystore-custody.md; do not restore copied keystore procedures here.
  • For authorized Cloud Run revision pruning, read infra/scripts/cleanup-cloud-run-revisions.sh and its current help before acting.
  • For terminal enrollment and merchant-safe health checks, start with Terminal provisioning. Current Support Portal device and geofence behavior lives in apps/websites/portals/support/src/config/portal.ts, apps/websites/portals/support/src/pages/TerminalsPage.tsx, and apps/websites/portals/support/src/pages/GeofenceManagementPage.tsx.
  • For the current status service build and health endpoints, use apps/microservices/status/BUILD.bazel and apps/microservices/status/src/main/java/com/myriad/status/controller/HealthController.kt.

Destructive-operation boundaries

  • Do not run terraform apply, Terrakube apply, Cloud Run deployment, registry publication, SDK publication, or a production workflow dispatch without explicit authorization.
  • Do not enable apply_azure_migrations, seed_azure_baseline, or production-promotion inputs while investigating or observing an environment.
  • Do not run a schema migration or database-reset script merely to make an application test pass. Local test data is disposable; staging and production data are not.
  • Cloud Spanner reset scripts are dry-run by default where documented, but an --apply flag is still a real destructive action. Follow Database reset and reinstall.
  • Build deployable artifacts locally when useful, but publish or sign them only through the approved release lane.