Repository navigation
feat(validate,plan): warn about an id the build phase refuses - #813
Merged
Merged
Conversation
The schema's $defs.identifier admits ids the build phase refuses: a leading digit (1orders) or more than 128 characters. fluid apply in a build mode refuses such an id before it applies anything (#803), but fluid validate and fluid plan said nothing, so the first sign was a failed apply. The two grammars stay different by decision. For a contract with builds, both now warn and name the id, using the rule apply uses (build_runners._ids.validate_build_ids): - validate adds a ValidationResult warning, so plain validate passes and --strict fails (founder's call). It runs with the other 0.7.x contract rules, on a contract file and on a bundle's resolved contract. If the check itself crashes, that is reported as a warning. - plan prints the warning and still writes plan.json, whatever its --mode (founder's call). It runs after the gate plan shares with apply, not inside it, so apply keeps its typed CLIError. IDENT_RULE states the grammar in words, and both the new warning and apply's hint use it. The hint said validate and plan "accept" such an id; it now says they only warn about it.
…d id Review follow-ups to the build-id warning: - validate runs its contract rules on a contract the schema refused too, so the warning could say "The contract schema allows more" about an id the schema had just refused (id: 123). The text now only says what the build phase needs and that fluid apply in a build mode refuses the id. - plan prints the warning the way validate prints its warnings: literal, soft_wrap (the terminal wraps, so Rich never breaks a line inside the id) and no highlighter.
📄 Documentation ReminderThis PR appears to be missing a documentation reference. Our docs live in a separate repo. Please update the PR description with one of:
See the Contributing Guide for details. |
…i-8a5b12 # Conflicts: # CHANGELOG.md
fas89
added a commit
that referenced
this pull request
Nov 4, 2026
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fluid validateandfluid plannow warn when a contract withbuildshas acontract.idor abuilds[].idthat the build phase refuses: a leading digit (1orders) or more than 128 characters. The schema's$defs.identifieradmits such ids. Since #803,fluid applyin a build mode refuses them before it applies anything, but validate and plan said nothing. On 2026-11-03 the founder decided to keep the two grammars as they are and to warn early instead.Behaviour
fluid validate: a normal validation warning. Plain validate exits0,--strictexits1(founder's call), and--format jsonlists it underwarnings. It runs with the other 0.7.x contract rules, so a contract file and a bundle's resolved contract both get it. Workspace mode runs only the schema check, as it already documents.fluid plan: prints the warning and still writesplan.jsonwith exit0, whatever--modesays (founder's call). It runs after_gate_contract_for_plan_or_apply, not inside it, because apply shares that gate and keeps its typedERR_APPLY_BUILD_IDENTIFIER_INVALID.buildsis not checked, an empty id is skipped, and only the first failing id is named.How
build_runners/_ids.py:build_id_warning(contract)wrapsvalidate_build_ids, the rule apply and the build runner already use, and returns the text.IDENT_RULEputs the grammar in words for the warning and for apply's hint.cli/validate.py::_build_id_check, next to_databricks_binding_check. If the check itself crashes, that is reported as a warning, never swallowed.cli/plan.py::_warn_unusable_build_idsprints withcprint_literal, because the id is contract data, not markup. There is nowarn()log event: the console prints WARNING events as JSON lines, so the text would appear twice.Gates
Borrow: in-repo reuse.
validate_build_idsis the rule. The validate side followscontinuous_trigger_warningsand the helper shape of_databricks_binding_check. There is nothing external to borrow: this is message text over an existing validator.Defect scan (diff-scoped; a finding counts only if it is reproduced): one low finding, reproduced and fixed in 950b9e3. Validate runs contract rules on a contract the schema refused too, so on
id: 123the warning said "The contract schema allows more". The text no longer makes that claim, and a test pins it. The hunter also confirmed--envoverlays (an overlay that sets or fixes the id), plan followed byapply plan.json --dry-run, both build modes, the.tgzbundle,--quiet,--verbose,--format json, and ids with[/]or[red]. Mutation checks showed the tests catch awarn()double print andcprintinstead ofcprint_literal.Security review: no findings.
_IDENT_RE,validate_identifierandvalidate_build_idsare unchanged, and apply and the build runner still enforce them. Crafted ids (ESC/OSC sequences,\nlog forging, Rich[link=...]markup, U+202E,token=...) print escaped byrepr, with markup off on every path and redaction still applied. Cost is linear in the id length. One informational note, adopted in 950b9e3: plan now prints withhighlight=False, soft_wrap=True, as validate does.Live test, real
fluidCLI on the merged tree from a scratch directory (plan and anid: 123contract run again after 950b9e3):validatewithid: 1ordersvalidate --strictwithid: 1ordersvalidate --strictwith a 129-character build idvalidate --strict, clean contractvalidate --strict,id: 1ordersand no buildsvalidate --format jsonwarningsplan --mode amend-and-buildplan.jsonwrittenvalidate --stricton the.tgzbundleplanon the.tgzbundleapply --mode amend-and-buildERR_APPLY_BUILD_IDENTIFIER_INVALIDwith the new hintTests: the new
tests/cli/test_validate_plan_build_ids_warning.pyhas 35 tests, and every one that expects a warning failed before the change. 31 touched suites: 731 passed, 31 skipped. After 950b9e3 the affected suites ran again: 284 passed. Full suite, run the way CI runs it: 32,987 passed. The 8 failures and 2 errors (dlt dotenv allow-list, DuckDB sandbox temp roots, the startup-budget compat gate, the live Claude CLI test, two CI-script imports) fail the same way on a clean export of the base commit 61ccba5, so they come from this local environment.Lint & Format battery: whole-tree ruff, the dead-code gate, black 24.10.0, license headers and the writer test, lint-imports (both configs), product guardrail, and detect-secrets-hook on the changed files.
Startup budget:
tests/perf/test_startup_budget.pygives the same numbers as a clean main export (1030 / 1932 modules; the same three local-venv failures on both).No contract shipped in the repo triggers the warning (76 contracts scanned, 37 with builds).
Documentation
It fixes the apply.md "Build ids" sentence from Agenticstiger/forge_docs#186, which said validate and plan accept such ids, and the hint text shown there. It also adds a validate.md section, "An id the build phase refuses", a plan.md note and an upgrading.md entry.