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:
| Area | Build | Test |
|---|---|---|
| Microservice | bazel build //apps/microservices/merchant-api:core | bazel test //apps/microservices/merchant-api:core_test |
| Service image | bazel build //apps/microservices/merchant-api:image | Build the deployable tarball with bazel build //apps/microservices/merchant-api:image_tarball |
| Retail portal | bazel build //apps/websites/portals/retail:build | bazel test //apps/websites/portals/retail:test //apps/websites/portals/retail:lint |
| Support portal | bazel build //apps/websites/portals/support:build | bazel test //apps/websites/portals/support:test //apps/websites/portals/support:lint |
| Formal specifications | bazel build //apps/specifications/dafny:verify | Use the owning target returned by bazel query |
| Private docs | bazel build //docs/private-docs:build | Run 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:
| Mode | Use |
|---|---|
Plain bazel build or bazel test | Developer default. Prefer the BuildBuddy Linux executor and fall back locally; use the shared remote cache and upload local results. |
--config=no_remote_upload | Keep remote reads but do not upload local results on a constrained connection. |
--config=local | Disable remote execution for a target that requires local devices, host state, or a locally retained artifact. Remote cache configuration remains separate. |
--config=macos | Use the macOS sandbox path and local execution for Apple work. |
--config=android_x86_64 | Select the x86_64 Android NDK/platform configuration for an emulator (ARM64 is Bazel's unconditional default; no flag needed). |
--config=ci --config=rbe | CI 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.
| Workflow | Automatic boundary | Manual 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:
- Verify the responder roster and map each catalog
ownerto a real incident.io escalation schedule. Repository affiliation and Agent Portalagent_adminmembership are not on-call ownership. - Import each
services[].incidentrecord using the servicenameas its stable catalog key. Renderdashboardandlogsselectors with the operator-side subscription and resource-group values named by each selector; do not store unscoped portal blades. - Configure
incident_response.routesin declaration order because first match wins, then wire every concretesources[].alert_namefrom the actionable and non-actionable signal lists. - 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.shand 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, andapps/websites/portals/support/src/pages/GeofenceManagementPage.tsx. - For the current status service build and health endpoints, use
apps/microservices/status/BUILD.bazelandapps/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
--applyflag 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.