From ddffaedcd07c7253e2a3873b091886976c53ec15 Mon Sep 17 00:00:00 2001 From: Speculator55005 <50082482+fas89@users.noreply.github.com> Date: Tue, 3 Nov 2026 23:42:35 +0100 Subject: [PATCH] docs(apply): build ids are checked before anything is applied Documents forge-cli #803: under --mode amend-and-build or replace-and-build, fluid apply checks id and every builds[].id against the build phase's rule before the apply hooks, tofu and any build, and refuses with apply_build_identifier_invalid. Adds a Build ids subsection and an errors-table row to cli/apply.md, and a bullet to upgrading.md. --- docs/cli/apply.md | 24 ++++++++++++++++++++++++ docs/upgrading.md | 9 +++++++++ 2 files changed, 33 insertions(+) diff --git a/docs/cli/apply.md b/docs/cli/apply.md index 3c25304..429ab45 100644 --- a/docs/cli/apply.md +++ b/docs/cli/apply.md @@ -197,6 +197,29 @@ The check runs after the [plan binding](#plan-binding) checks and the [mode gate There is no flag to skip the check. Run `fluid validate --env ` to see every error, fix them, and apply again. +### Build ids + +*On forge-cli `main`, not yet in a release ([forge-cli #803](https://github.com/Agenticstiger/forge-cli/pull/803)).* Under `--mode amend-and-build` or `replace-and-build`, `fluid apply` also checks `id` and every `builds[].id` right after the schema check. This happens on both engines, before the apply hooks, `tofu` and any build. + +The build phase keeps each build's run records, cursors and watermarks under `.fluid/runs///`, so its rule is narrower than the schema's. An id must start with a letter or `_`, use only letters, digits, `_`, `.` and `-`, and be at most 128 characters. The schema also accepts a leading digit and any length. So `fluid validate` and `fluid plan` pass an id such as `1orders`, and `fluid apply` refuses it: + +```bash +fluid apply contract.fluid.yaml --mode amend-and-build --yes +``` + +```text +❌ apply_build_identifier_invalid [ERR_APPLY_BUILD_IDENTIFIER_INVALID] + field: contract.id + value: '1orders' + hint: The build phase keeps each build's run records, cursors and watermarks under .fluid/runs///, so both ids must start with a letter or underscore, use only letters, digits, '_', '.' and '-', and be at most 128 characters. The contract schema allows more, so fluid validate and fluid plan accept it. Nothing was applied. + +💡 Suggestions: + • Rename the id to fit, for example orders_v1 instead of 1orders, and apply again + • A renamed id starts over: its builds get new cursors and watermarks under .fluid/runs/, and a renamed contract.id gets a new OpenTofu workdir under .fluid/iac// +``` + +Before this change only the build runner checked these ids. On the OpenTofu engine the runner starts after `tofu apply`, so the product was provisioned first, and the run then stopped with "Unexpected error". A mode without a build phase is not checked, and neither is a contract without `builds`. + ## Plan binding When you pass a saved plan (`runtime/plan.json`) instead of a contract, `apply` runs three gates on it before it builds or provisions anything, on both engines: @@ -578,6 +601,7 @@ Each failure prints the typed event name and an `[ERR_]` slug, and exits | `plan_env_mismatch` | A build mode is given an `--env` that differs from the plan's. | | `bundle_env_mismatch` | `--env` differs from the env a bundle was built for. | | `apply_build_id_requires_build_mode` | `--build-id` with a mode that runs no build. | +| `apply_build_identifier_invalid` | *(On forge-cli `main`, not yet in a release, [forge-cli #803](https://github.com/Agenticstiger/forge-cli/pull/803).)* A build mode, and an `id` or `builds[].id` the build phase cannot use. Nothing is applied. See [Build ids](#build-ids). | | `apply_mode_data_loss_blocked` | `replace` or `replace-and-build` without `--allow-data-loss`. | | `opentofu_data_loss_gate` | An OpenTofu plan destroys a resource and `--allow-data-loss` is not set. *(On forge-cli `main`, not yet in a release, [forge-cli #793](https://github.com/Agenticstiger/forge-cli/pull/793).)* Also a plan that changes the column types of a Glue table in place. | | `opentofu_plan_failed` | `tofu plan` failed. *(On forge-cli `main`, not yet in a release, [forge-cli #786](https://github.com/Agenticstiger/forge-cli/pull/786).)* A plan that failed on a held state lock suggests `tofu force-unlock `. | diff --git a/docs/upgrading.md b/docs/upgrading.md index 24618aa..b6cae46 100644 --- a/docs/upgrading.md +++ b/docs/upgrading.md @@ -611,6 +611,15 @@ These changes are merged and in no release yet. Most fail closed where a contrac that emits the scheduled Lambda warns `schedule_placeholder_lambda`: the function only logs its tasks, and the roles `fluid-workflow-execution` and `EventBridgeSchedulerRole` must already exist. See [Schedule names and refusals](./providers/aws.md#schedule-names-and-refusals). +- **A build mode refuses an id the build phase cannot use, before anything is applied** + ([#803](https://github.com/Agenticstiger/forge-cli/pull/803)). `fluid apply --mode + amend-and-build` and `replace-and-build` check `id` and every `builds[].id` before the apply + hooks, `tofu` and any build. Each id must start with a letter or `_`, use only letters, digits, + `_`, `.` and `-`, and be at most 128 characters. Such an id (`1orders`, or a longer one) passes + `fluid validate`. On the OpenTofu engine the product used to be provisioned and the run then + stopped with "Unexpected error". Now the run stops first with `apply_build_identifier_invalid`. + Rename the id. A renamed `id` gets a new `.fluid/iac//` workdir, and its builds + start without their cursors and watermarks. See [Build ids](./cli/apply.md#build-ids). - **`fluid doctor --strict` and a readable failed apply** ([#786](https://github.com/Agenticstiger/forge-cli/pull/786)). `fluid doctor --strict` exits `1` when the summary says "Action needed", copilot readiness included; the default exit code does not