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:
parent
c52d222cc6
commit
8f3b8ac2f6
8 changed files with 4691 additions and 8 deletions
|
|
@ -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
|
|
@ -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`
|
||||
3240
docs/evidence/RMGR-WP-0005-fleet-plan-2026-08-31-v2.json
Normal file
3240
docs/evidence/RMGR-WP-0005-fleet-plan-2026-08-31-v2.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue