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
|
`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
|
any database or file mutation. Repeat `--projection-api-base` for every hub in
|
||||||
the cutover. Each replacement is classified as `legacy_source`,
|
the cutover. Each replacement is classified as `legacy_source`,
|
||||||
`derived_target`, `both_present`, or `neither_present`. The first two may coexist
|
`derived_target`, `duplicate_target`, `both_present`, or `neither_present`. The
|
||||||
inside one repository-atomic migration: State Hub migrates legacy rows, verifies
|
first three may coexist inside one repository-atomic migration: State Hub
|
||||||
already-derived rows against their canonical record identity, and records the
|
migrates legacy rows, verifies already-derived rows against their canonical
|
||||||
same durable aliases for both. The latter two states are refused. Saved
|
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
|
projection endpoints are rechecked by `migration-batch-verify`; omitting the
|
||||||
option retains the offline source/Git-only planning mode. A projection-aware
|
option retains the offline source/Git-only planning mode. A projection-aware
|
||||||
batch containing UUID assignments fails closed until an assignment-specific
|
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
|
A projection may legitimately be mixed when forge reconciliation created
|
||||||
some deterministic targets before the sealed migration ran. Legacy-source
|
some deterministic targets before the sealed migration ran. Legacy-source
|
||||||
and derived-target are both convergent states; both-present and neither-
|
and derived-target are both convergent states. An exact task duplicate is
|
||||||
present are ambiguous and remain hard refusals.
|
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]] = []
|
projections: list[dict[str, Any]] = []
|
||||||
errors: list[dict[str, str]] = [
|
errors: list[dict[str, str]] = [
|
||||||
{
|
{
|
||||||
|
|
@ -422,7 +464,15 @@ def _projection_migration_preflight(
|
||||||
(200, 200): "both_present",
|
(200, 200): "both_present",
|
||||||
(404, 404): "neither_present",
|
(404, 404): "neither_present",
|
||||||
}.get(status_pair, "unexpected_status")
|
}.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 = {
|
check = {
|
||||||
"record_id": mapping.get("record_id"),
|
"record_id": mapping.get("record_id"),
|
||||||
"kind": mapping.get("kind"),
|
"kind": mapping.get("kind"),
|
||||||
|
|
@ -452,6 +502,7 @@ def _projection_migration_preflight(
|
||||||
for state in (
|
for state in (
|
||||||
"legacy_source",
|
"legacy_source",
|
||||||
"derived_target",
|
"derived_target",
|
||||||
|
"duplicate_target",
|
||||||
"both_present",
|
"both_present",
|
||||||
"neither_present",
|
"neither_present",
|
||||||
"unexpected_status",
|
"unexpected_status",
|
||||||
|
|
@ -463,8 +514,10 @@ def _projection_migration_preflight(
|
||||||
if convergent_states == {"legacy_source"}
|
if convergent_states == {"legacy_source"}
|
||||||
else "file_convergence"
|
else "file_convergence"
|
||||||
if convergent_states == {"derived_target"}
|
if convergent_states == {"derived_target"}
|
||||||
|
else "duplicate_convergence"
|
||||||
|
if convergent_states == {"duplicate_target"}
|
||||||
else "mixed_convergence"
|
else "mixed_convergence"
|
||||||
if convergent_states == {"legacy_source", "derived_target"}
|
if convergent_states
|
||||||
else "blocked"
|
else "blocked"
|
||||||
)
|
)
|
||||||
projections.append(
|
projections.append(
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,83 @@ def test_projection_preflight_accepts_mixed_convergent_states(monkeypatch) -> No
|
||||||
assert projection["state_counts"]["derived_target"] == 1
|
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:
|
def test_projection_migration_client_requires_primary_and_exact_seal(tmp_path: Path) -> None:
|
||||||
repo = tmp_path / "one"
|
repo = tmp_path / "one"
|
||||||
path = repo / "workplans" / "one.md"
|
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:
|
`railiance01` default is covered by the same change set. Evidence:
|
||||||
`docs/evidence/RMGR-WP-0005-batch-0006-reef-railiance-cutover-2026-08-31.md`.
|
`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
|
## Retire the interim rule
|
||||||
|
|
||||||
```task
|
```task
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue