Skip to content

Accept a target's verified public host as the release indexing origin - #6071

Merged
shiny-code-app[bot] merged 3 commits into
mainfrom
work/cm346-live-indexing
Nov 12, 2026
Merged

shiny-code-app[bot] merged 3 commits into
mainfrom
work/cm346-live-indexing

Conversation

@shiny-code-app

@shiny-code-app shiny-code-app Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

The CM website's accepted release stopped after its provider deploy, and so did its automatic recovery, on "Release indexing binding is unverified: Website indexing route and provider target differ." The cause is in the release indexing gate, not in CM's records.

production_origin() returns the first recorded prod public host, which is the documented presentation origin. indexing_binding() then required that host to be a route-binding domain. Route reconcile builds route domains only from the tracked target's internal domains, and the public-host planner refuses any public host that is already an internal domain. So every prod release of a live Odoo site with public hosts failed this check, after the deploy and again in recovery. The unit fixture put the public host directly in the route binding, a state real records cannot reach. Diagnosis, record evidence and operation disposition are on #6070.

Change

  • The origin host is accepted when it is a route-binding domain, or a committed public host on the same tracked target with no pending public-host effect.
  • In the public-host case, the compose payload that indexing already fetches must hold exactly one current provider route for that host on the same compose target. It must match the web origin route's port and the shape the public-host planner records. The planner's matcher is now shared as public_host_route_matches.
  • The pre-mutation checkpoint repeats that provider-route check on its fresh payload, so a route removed between plan and write stops the effect.
  • Every other check is unchanged: route freshness, target-record projection equality, provider/category/type/name equality, runtime and artifact identity, reviewed binding digest, and initial-release qualification. The binding digest shape is unchanged, so existing reviewed plans keep their digests.
  • docs/odoo-website-settings.md states the origin rule.

This is a source fix only. It moves no release, record or production state. It does not continue, retry or re-accept the failed CM release.

Verification

  • Failing first: test_public_host_origin_beside_an_internal_route_domain_reaches_the_native_plan uses CM's record shape (internal route domain, public host origin) and failed before the change with the exact production error. test_public_host_route_removed_before_dispatch_refuses_before_effect_checkpoint failed (no refusal) before the checkpoint change.
  • Refusals: no route domain and no public host; a pending public-host effect; a missing, duplicate, wrong-compose or wrong-port provider route. Each stops before native execution.
  • Safety classification: release gate on the production promotion and recovery path. Whole modules run locally, 210 tests OK: tests.test_odoo_website_indexing tests.test_prelaunch_release_indexing tests.test_odoo_website_settings tests.test_client_release tests.test_odoo_accepted_first_empty tests.test_client_release_odoo_continuation tests.test_odoo_post_deploy tests.test_odoo_prod_promotion tests.test_odoo_prod_rollback tests.test_product_public_hosts. No authorization, secret or credential behavior is touched.
  • Whole-repository ruff format --check, ruff check and mypy control_plane tests pass. The new-comment check passes.
  • JetBrains: GREEN, native PyCharm, coverage complete, 0 findings on the three changed Python files (3 preexisting findings not counted).

Review by another model

OpenAI (Codex CLI; model not reported by the CLI), two rounds.

  • Round 1, should-fix: a committed public host does not prove the host is currently routed (failed removal, provider drift). Accepted: added the live provider-route check.
  • Round 1, should-fix: production backup restore (odoo_prod_backup_restore.py) and stable-lane repair (product_stable_lane_repair.py) also compare a possibly public lane URL against internal domains only. Declined here: those are pre-existing, on different paths and not triggered by this incident. Recorded on LIVE: qualify CM accepted release indexing target mismatch and preserve acceptance #6070 for separate tracking.
  • Round 1, minor: PublicHostEffect.host is not normalized. Declined: its only writer supplies normalized hosts, and production-origin equality already rejects other spellings.
  • Round 2, should-fix: the pre-mutation checkpoint did not recheck provider routing. Accepted, with a failing-first regression test.
  • Round 2 confirmed that the other guards and all six renamed matcher call sites are unchanged.

After deploy, requalify with odoo-website-indexing-readback for the CM prod lane. It must reach the native plan rather than this refusal.

Client test notes

Nothing for a Client to test. This fixes Launchplane's release gate and changes no website, setting or release acceptance.

Refs #6070

Removed: an impossible route-binding fixture state. Net lines: +146 (170 added, 24 removed): one gate predicate, a provider-route check and its checkpoint use, tests, and one doc paragraph.

The release indexing gate required the production public origin to be a
route-binding domain. Route bindings carry only the tracked target's internal
domains, and public hosts can never be internal domains, so every release of a
live Odoo site with public hosts stopped after the provider deploy, including
its automatic recovery.

The origin host is now accepted when it is a route domain or a committed
public host on the same tracked target with no pending public-host effect.
All other binding, route, target and runtime checks are unchanged.
A committed public host alone does not prove the host is still routed to the
production compose. When the indexing origin is a public host rather than a
route-binding domain, the existing compose payload must hold exactly one route
for it on the same target, matching the web origin route's port and the shape
the public-host planner records. The planner's matcher is shared.
The pre-mutation checkpoint refetched the compose payload but compared only
its server, app name and environment. A public-host route removed or moved
between plan and write now stops the effect before it starts.
@shiny-code-app

Copy link
Copy Markdown
Contributor Author

Review result: weighed
Head: 6ff5d64

Weighed review by another model for head 6ff5d64.

Reviewer: OpenAI through the Codex CLI, two rounds. The CLI did not report the model name. Author: Anthropic Claude Opus 5.5.

  • Round 1, should-fix, accepted: a committed public host does not prove current routing. Fixed in d87ba76. The public-host branch now requires one matching live provider route on the same compose target.
  • Round 1, should-fix, declined for this PR: backup restore and stable-lane repair also compare a lane URL against internal domains only. They are pre-existing, on different paths and not triggered by this incident. Recorded on LIVE: qualify CM accepted release indexing target mismatch and preserve acceptance #6070 for separate tracking.
  • Round 1, minor, declined: PublicHostEffect.host is not normalized. Its only writer supplies normalized hosts, and production-origin equality rejects other spellings.
  • Round 2, should-fix, accepted: the pre-mutation checkpoint did not recheck provider routing. Fixed in 6ff5d64 with a regression test that failed before the fix.
  • Round 2 found the other guards and all six renamed matcher call sites unchanged.

No finding remains open. Local evidence: 210 tests across the whole touched safety modules pass; whole-repository ruff and mypy pass; native PyCharm inspection GREEN with complete coverage.

@shiny-code-app

Copy link
Copy Markdown
Contributor Author

Held for the coherent-system lead under https://github.com/cbusillo/direction/issues/189#issuecomment-6838490931 . The Director's decision and the Milestone Supervisor's specific instruction supersede this source-fix/landing assignment. Source issue 6070 now continues DIAGNOSIS ONLY. No Ready, train admission, merge or deployment is assigned for this guard proposal.

Preserve current head 6ff5d64, source/review/test evidence and the author's worktree/claim custody. The proposal is being held as a draft; no engineering-ready or current-head CI claim is made by this hold. Do not convert it back or start another guard/release-path slice before coordination with coherent-system lead df6bf4cb-3ef0-4e62-b927-1784fc180aff on cbusillo/direction#189.

The confirmed failure, provider effects, incomplete original recovery and sibling host/route comparisons feed that lead's map. No live record write, Client contact, release retry, new request/key or acceptance is authorized. Real live-breakage and merge-train work retain the Director's exception, but this specific worker is diagnosis-only until that owner coordinates any change. Removed: the earlier Ready/landing authorization. Net lines: 0 additional source from this hold.

@shiny-code-app

Copy link
Copy Markdown
Contributor Author

Nothing here is waiting on a person or event.

@shiny-code-app
shiny-code-app Bot marked this pull request as ready for review November 12, 2026 23:46
@shiny-code-app

Copy link
Copy Markdown
Contributor Author

My host draft hold on PR #6071 is lifted for the coherent-system lead's live CM recovery assignment. This supersedes my earlier draft-hold instruction for this PR, following the explicit decision https://github.com/cbusillo/direction/issues/189#issuecomment-6839242245 and the worker's request #6070 (comment). I removed the draft state through the GitHub identity wrapper because the maintained PR helper has no separate draft-state toggle. This is not a checked Ready handoff or train admission.

The assigned owner is worker 3ec6ca46-e814-4921-8b5d-f056fc416a75 under coherent-system lead df6bf4cb-3ef0-4e62-b927-1784fc180aff. It owns current-head validation, full candidate CI, the checked Ready handoff, merge train and normal deployment under that decision. My closed diagnostic worker remains closed, and no competing author or operator is assigned by this lead.

After containing activation, that same worker owns the supported inert indexing read and, only if it passes, the separately assigned one rollback to the last accepted artifact, bound to the proper accepted decision. A failed rollback returns to the coherent-system lead without retry. No data restore, Justin re-release, new invitation or Client contact is authorized by lifting this hold. Candidate-startup database effects remain UNKNOWN. The siblings and missing inert rollback plan stay in the coherent redesign.

Removed: this lead's host draft hold for the expressly assigned live recovery fix. Net lines: 0 source lines.

@shiny-code-app

Copy link
Copy Markdown
Contributor Author

Ready for the merge train

Head: 6ff5d64

@shiny-code-app

shiny-code-app Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor Author

Launchplane completed the merge-train step for this pull request.

Launchplane finished the merge-train step for this pull request.

Launchplane manages this comment and will update it as the train moves.

shiny-code-app Bot added a commit that referenced this pull request Nov 12, 2026
@shiny-code-app
shiny-code-app Bot merged commit 7dcc86b into main Nov 12, 2026
49 checks passed
@shiny-code-app
shiny-code-app Bot deleted the work/cm346-live-indexing branch November 12, 2026 23:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants