prepare fleet identifier completion batch

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a053ff-1d6f-7fe2-ac1c-a6eb40a42a0c
This commit is contained in:
tegwick 2026-08-31 17:02:19 +02:00
parent c52d222cc6
commit 8f3b8ac2f6
8 changed files with 4691 additions and 8 deletions

View file

@ -0,0 +1,63 @@
# RMGR-DEC-2026-006 — Fleet-completion identifier cutover batch
```yaml
id: RMGR-DEC-2026-006
kind: decision
title: Approve deterministic identifier batch 0007 for fleet completion
status: open
decision_type: pending
owner: Bernd Worsch
repo: repo-manager
workplan: RMGR-WP-0005
workplan_task: RMGR-WP-0005-T04
requested_dispositions:
- approved
- revised
- rejected
source_plan: docs/evidence/RMGR-WP-0005-fleet-plan-2026-08-31-v2.json
source_plan_sha256: ab8ae2e55470553f105c6209d6aa4c7b828085bd6c71cec7b16173b8a19bef7b
batch_manifest: docs/evidence/RMGR-WP-0005-batch-0007-fleet-completion-preflight-2026-08-31.json
batch_sha256: c0cc496a06d9535a40840a0c7488cf365d8e47c5c58cc29aca72fb6d98273700
scope:
repositories:
- fin-hub
- net-kingdom
- prj-canon-federation
- prj-forgejo-org-refactor
- prj-state-hub-retirement
- prj-unattended-progress-company
- railiance-master
- railiance-telemetry
- rapp-qonto
- soul-frame
replacements: 85
assignments: 0
apply_authorized: false
approval_effect: >-
Approved authorizes repository-atomic, sequential forward cutover of exactly
the pinned batch in the railiance01 primary projection and each authoritative
repository file, subject to repeated no-drift checks and stopping at the
first failure. Revised or rejected authorizes no mutation.
rollback: >-
For a failing repository, reverse its file transaction if written, then
reverse its primary projection transaction using durable aliases. Repositories
already completed in the sequence remain completed unless a separate rollback
decision authorizes reversing them.
evidence: docs/evidence/RMGR-WP-0005-batch-0007-fleet-completion-readiness-2026-08-31.md
created: "2026-08-31"
updated: "2026-08-31T14:52:06.664545Z"
state_hub_decision_id: "b2b958bc-ecee-46ea-9bd2-6edd6afab7b9"
```
## Decision requested
Approve, revise, or reject the exact batch manifest and SHA-256 above. Approval
is limited to the ten named repositories, 85 replacement mappings, zero
assignments, and the `helixforge` namespace. It does not authorize a regenerated
plan, additional repositories, assignments, or a changed manifest.
The manifest remains fail-closed: any source fingerprint, Git state, projection
state, plan seal, or batch seal drift before a repository executes voids that
repository's execution and stops the sequence. Each successfully completed
repository is independently durable, pushed, and verified before the next one
begins.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,63 @@
# RMGR-WP-0005 batch 0007 fleet-completion readiness
Date: 2026-08-31
Decision: `RMGR-DEC-2026-006` (pending)
Source plan SHA-256: `ab8ae2e55470553f105c6209d6aa4c7b828085bd6c71cec7b16173b8a19bef7b`
Batch SHA-256: `c0cc496a06d9535a40840a0c7488cf365d8e47c5c58cc29aca72fb6d98273700`
## Outcome
Batch 0007 is ready for an explicit approve, revise, or reject decision. No
identifier mutation has run. The sealed batch contains ten clean,
Forgejo-synchronized repositories, 85 replacements, zero assignments, and 19
already-canonical records.
| Repository | Replace | Unchanged | Primary projection state |
| --- | ---: | ---: | --- |
| `fin-hub` | 13 | 0 | 13 legacy sources |
| `net-kingdom` | 16 | 19 | 16 legacy sources |
| `prj-canon-federation` | 13 | 0 | 13 legacy sources |
| `prj-forgejo-org-refactor` | 6 | 0 | 6 legacy sources |
| `prj-state-hub-retirement` | 8 | 0 | 8 legacy sources |
| `prj-unattended-progress-company` | 13 | 0 | 13 legacy sources |
| `railiance-master` | 3 | 0 | 3 legacy sources |
| `railiance-telemetry` | 4 | 0 | 4 legacy sources |
| `rapp-qonto` | 4 | 0 | 1 legacy source, 3 safe duplicate targets |
| `soul-frame` | 5 | 0 | 5 legacy sources |
## Preconditions closed
- A refreshed, non-mutating fleet scan covers 42 eligible repositories and 306
live records: 85 replacements, 6 assignments, and 215 unchanged records.
- `audit-core` received all six missing deterministic identifiers through its
ordinary reconciliation path and was pushed in commit `95dcb78`.
- The three `rapp-qonto` duplicate task targets have byte-equivalent business
payloads and no inbound task references. State Hub now coalesces only that
exact safe shape, retains durable aliases, and refuses divergent or referenced
duplicates.
- State Hub focused migration tests pass (19), its full suite passes (828), and
the dashboard production build succeeds. Repo Manager's full suite passes
(150) and Ruff is clean.
- State Hub commit `a7c91a6` is deployed on railiance01 and pinned by commit
`667ed28`; the live health endpoint reports the expected current schema.
- Fresh batch preflight reports `ok: true`, `ready_for_approval: true`, and no
source, Git, projection, collision, or status errors.
## Execution and rollback
Approval authorizes repository-atomic sequential execution, stopping on the
first failure. Before each repository, the executor repeats plan-seal, source,
Git, and primary-projection checks. It then updates the primary transaction,
rewrites the complete repository mapping atomically, commits and pushes the
authoritative file change, and verifies identifiers, relationships, aliases,
and consistency before continuing.
If a repository fails after its projection phase, reverse its file transaction
if written and then reverse its projection transaction through the durable
aliases. Repositories already completed remain valid independent cutovers;
reversing those would require a separate decision.
Canonical machine evidence:
- `docs/evidence/RMGR-WP-0005-fleet-plan-2026-08-31-v2.json`
- `docs/evidence/RMGR-WP-0005-batch-0007-fleet-completion-preflight-2026-08-31.json`

File diff suppressed because it is too large Load diff

View file

@ -80,10 +80,13 @@ origin. The batch records these facts and its own SHA-256 seal, but always emits
`apply_authorized: false`. An explicit decision must cite that batch hash before
any database or file mutation. Repeat `--projection-api-base` for every hub in
the cutover. Each replacement is classified as `legacy_source`,
`derived_target`, `both_present`, or `neither_present`. The first two may coexist
inside one repository-atomic migration: State Hub migrates legacy rows, verifies
already-derived rows against their canonical record identity, and records the
same durable aliases for both. The latter two states are refused. Saved
`derived_target`, `duplicate_target`, `both_present`, or `neither_present`. The
first three may coexist inside one repository-atomic migration: State Hub
migrates legacy rows, verifies already-derived rows against their canonical
record identity, and may coalesce a `duplicate_target` task only when both
business payloads are equal and the legacy row has zero inbound references.
Other both-present and all neither-present states are refused. Durable aliases
are recorded for every converged replacement. Saved
projection endpoints are rechecked by `migration-batch-verify`; omitting the
option retains the offline source/Git-only planning mode. A projection-aware
batch containing UUID assignments fails closed until an assignment-specific

View file

@ -375,9 +375,51 @@ def _projection_migration_preflight(
A projection may legitimately be mixed when forge reconciliation created
some deterministic targets before the sealed migration ran. Legacy-source
and derived-target are both convergent states; both-present and neither-
present are ambiguous and remain hard refusals.
and derived-target are both convergent states. An exact task duplicate is
also convergent when the legacy row has no conflicting canonical identity
and both API representations have identical business fields; State Hub
rechecks that equivalence and proves the legacy row is unreferenced inside
the apply transaction. Other both-present and all neither-present states
remain hard refusals.
"""
duplicate_fields = (
"workplan_id",
"title",
"description",
"status",
"priority",
"assignee",
"due_date",
"blocking_reason",
"needs_human",
"intervention_note",
"parent_task_id",
)
def mergeable_task_duplicate(
mapping: dict[str, Any], current: httpx.Response, derived: httpx.Response
) -> bool:
if mapping.get("kind") != "task":
return False
try:
legacy_payload = current.json()
derived_payload = derived.json()
except ValueError:
return False
record_id = mapping.get("record_id")
return (
isinstance(legacy_payload, dict)
and isinstance(derived_payload, dict)
and legacy_payload.get("id") == mapping.get("current_uuid")
and derived_payload.get("id") == mapping.get("derived_uuid")
and legacy_payload.get("record_id") in {None, record_id}
and derived_payload.get("record_id") == record_id
and all(
legacy_payload.get(field) == derived_payload.get(field)
for field in duplicate_fields
)
)
projections: list[dict[str, Any]] = []
errors: list[dict[str, str]] = [
{
@ -422,7 +464,15 @@ def _projection_migration_preflight(
(200, 200): "both_present",
(404, 404): "neither_present",
}.get(status_pair, "unexpected_status")
check_ok = state in {"legacy_source", "derived_target"}
if state == "both_present" and mergeable_task_duplicate(
mapping, current, derived
):
state = "duplicate_target"
check_ok = state in {
"legacy_source",
"derived_target",
"duplicate_target",
}
check = {
"record_id": mapping.get("record_id"),
"kind": mapping.get("kind"),
@ -452,6 +502,7 @@ def _projection_migration_preflight(
for state in (
"legacy_source",
"derived_target",
"duplicate_target",
"both_present",
"neither_present",
"unexpected_status",
@ -463,8 +514,10 @@ def _projection_migration_preflight(
if convergent_states == {"legacy_source"}
else "file_convergence"
if convergent_states == {"derived_target"}
else "duplicate_convergence"
if convergent_states == {"duplicate_target"}
else "mixed_convergence"
if convergent_states == {"legacy_source", "derived_target"}
if convergent_states
else "blocked"
)
projections.append(

View file

@ -74,6 +74,83 @@ def test_projection_preflight_accepts_mixed_convergent_states(monkeypatch) -> No
assert projection["state_counts"]["derived_target"] == 1
def test_projection_preflight_accepts_equivalent_task_duplicate(monkeypatch) -> None:
mapping = {
"action": "replace",
"kind": "task",
"record_id": "ONE-WP-0001-T01",
"current_uuid": "22222222-2222-4222-8222-222222222222",
"derived_uuid": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
}
shared = {
"workplan_id": "11111111-1111-4111-8111-111111111111",
"title": "Equivalent task",
"description": "Same source",
"status": "todo",
"priority": "high",
"assignee": None,
"due_date": None,
"blocking_reason": None,
"needs_human": False,
"intervention_note": None,
"parent_task_id": None,
}
def projection_get(self, url):
value = str(url)
derived = value.endswith(mapping["derived_uuid"])
return httpx.Response(
200,
json={
**shared,
"id": mapping["derived_uuid"] if derived else mapping["current_uuid"],
"record_id": mapping["record_id"] if derived else None,
},
request=httpx.Request("GET", url),
)
monkeypatch.setattr(httpx.Client, "get", projection_get)
result = _projection_migration_preflight([mapping], ["http://hub.test"])
assert result["ok"] is True
projection = result["projections"][0]
assert projection["mode"] == "duplicate_convergence"
assert projection["state_counts"]["duplicate_target"] == 1
def test_projection_preflight_rejects_divergent_task_duplicate(monkeypatch) -> None:
mapping = {
"action": "replace",
"kind": "task",
"record_id": "ONE-WP-0001-T01",
"current_uuid": "22222222-2222-4222-8222-222222222222",
"derived_uuid": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
}
def projection_get(self, url):
value = str(url)
derived = value.endswith(mapping["derived_uuid"])
return httpx.Response(
200,
json={
"id": mapping["derived_uuid"] if derived else mapping["current_uuid"],
"record_id": mapping["record_id"] if derived else None,
"workplan_id": "11111111-1111-4111-8111-111111111111",
"title": "Derived" if derived else "Legacy",
"status": "todo",
"priority": "high",
"needs_human": False,
},
request=httpx.Request("GET", url),
)
monkeypatch.setattr(httpx.Client, "get", projection_get)
result = _projection_migration_preflight([mapping], ["http://hub.test"])
assert result["ok"] is False
assert result["projections"][0]["state_counts"]["both_present"] == 1
def test_projection_migration_client_requires_primary_and_exact_seal(tmp_path: Path) -> None:
repo = tmp_path / "one"
path = repo / "workplans" / "one.md"

View file

@ -676,6 +676,24 @@ the CLI default misspelled the primary label as `railliance01`; the corrected
`railiance01` default is covered by the same change set. Evidence:
`docs/evidence/RMGR-WP-0005-batch-0006-reef-railiance-cutover-2026-08-31.md`.
**Fleet-completion batch 0007 prepared (2026-08-31):** a fresh non-mutating
plan now covers 42 eligible repositories and 306 live records: 85 replacements,
6 assignments, and 215 unchanged. `audit-core` completed all six assignments
through ordinary deterministic reconciliation and pushed commit `95dcb78`.
The remaining action is therefore exactly 85 replacements across ten clean,
synchronized repositories.
Three `rapp-qonto` tasks existed under both their legacy and deterministic UUIDs
with identical business payloads and no inbound task references. State Hub now
coalesces only that proven-safe duplicate shape transactionally, retains durable
aliases, and refuses referenced or divergent duplicates; the capability is live
on railiance01 from State Hub commit `a7c91a6` (deployment pin `667ed28`). Full
State Hub and Repo Manager test suites pass. Fresh preflight is clean and ready,
but mutation remains unauthorized pending `RMGR-DEC-2026-006`. Exact batch
seal: `c0cc496a06d9535a40840a0c7488cf365d8e47c5c58cc29aca72fb6d98273700`.
Evidence:
`docs/evidence/RMGR-WP-0005-batch-0007-fleet-completion-readiness-2026-08-31.md`.
## Retire the interim rule
```task