Allow bound historical suffix tasks during normal sync

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a087d8-d22d-7d11-8169-bf22a729dff1
This commit is contained in:
tegwick 2026-09-09 22:31:14 +02:00
parent 5ad49dd79e
commit 3db3e7e297
6 changed files with 241 additions and 6 deletions

View file

@ -0,0 +1,59 @@
{
"ok": true,
"repo": "/home/worsch/repo-manager",
"revision": "5ad49dd79e0ebc2f46bf5df68d2c1a079dc358c7",
"cutover_commit": "329af60753b20896f30f098e8f75074652780032",
"commit_count": 100,
"assistants": {
"claude-code": {
"commit_count": 15,
"models": [
"opus"
],
"sessions": [
"f2bff2d5-e9b2-4338-92ca-10282a927006",
"f40c8f53-fb65-4980-9d29-bcdb3dd946f7"
],
"processes": [
"2583210@bnt-lap001",
"272883@bnt-lap001"
]
},
"codex": {
"commit_count": 84,
"models": [
"gpt-5.6-luna",
"gpt-5.6-sol",
"gpt-6-astra"
],
"sessions": [
"01a023c0-a0a3-7c03-b395-5a0d2757214d",
"01a028f0-a42f-7582-89a8-ebaad7343834",
"01a02b22-9638-76d2-bbff-b7ea1770b118",
"01a053ff-1d6f-7fe2-ac1c-a6eb40a42a0c",
"01a070b5-4994-7271-bd8b-7c3dbcedec4b",
"01a07ff8-19d0-7820-b4d0-1353833cb7fc"
],
"processes": []
},
"grok": {
"commit_count": 1,
"models": [],
"sessions": [
"01a04996-76e8-7f53-b971-1885cfbed436"
],
"processes": []
}
},
"interleaved_sessions": [
[
"01a023c0-a0a3-7c03-b395-5a0d2757214d",
"01a028f0-a42f-7582-89a8-ebaad7343834"
]
],
"unattributed": {
"before_cutover": 0,
"after_cutover": 0,
"known_automation": 0
}
}

View file

@ -6,7 +6,7 @@
id: RMGR-IN-0001
kind: intake
title: Validate assistant provenance on a natural multi-session window
status: open
status: closed
origin: residual
origin_ref: RMGR-WP-0009
priority: low
@ -15,8 +15,10 @@ description: When two coding-assistant sessions naturally commit to one reposito
run rmgr assistant-provenance report and retain the non-secret interleaving evidence.
Do not manufacture or infer a collision.
created: '2026-08-21T20:09:23.942286+00:00'
updated: '2026-08-21T20:09:23.942286+00:00'
updated: '2026-09-09T20:31:04.003556Z'
state_hub_intake_id: "01a025f3-40b0-7243-8002-dbe4609a6245"
closed_at: '2026-09-09T20:31:04.003556Z'
outcome: Natural multi-session evidence captured in docs/evidence/2026-09-09-natural-assistant-provenance.json.
```
## RMGR-IN-0002 — Assign dormant shared prefixes before their next allocation
@ -45,7 +47,7 @@ state_hub_intake_id: "01a02611-a663-7712-bd4b-e39c13e7bf20"
id: RMGR-IN-0003
kind: intake
title: Scope normal sync identity validation to actionable records
status: open
status: closed
origin: residual
origin_ref: RMGR-WP-0005
priority: low
@ -57,6 +59,14 @@ description: Normal rmgr sync currently refuses net-kingdom because the archived
visible as conformance evidence but do not block deterministic assignment or
forge-derived reconciliation of unrelated canonical records.
created: '2026-08-31T17:30:00+00:00'
updated: '2026-08-31T17:30:00+00:00'
updated: '2026-09-09T20:31:04.003556Z'
state_hub_intake_id: "4f1d9836-e0a6-56ea-bf19-2587c153f338"
closed_at: '2026-09-09T20:31:04.003556Z'
outcome: Implemented and verified in RMGR-WP-0015.
```
2026-09-09 resolutions: RMGR-IN-0001 is evidenced by
`docs/evidence/2026-09-09-natural-assistant-provenance.json`: 100 existing
commits, three assistants, and one naturally interleaved session pair. This
is a Git sequence signal, not proof of concurrent writes or a collision.
RMGR-IN-0003 is implemented and verified in RMGR-WP-0015.

View file

@ -850,10 +850,37 @@ def ensure_missing_work_record_identifiers(
repo_root = repo_root.resolve()
namespace = namespace or load_fleet_namespace()
identity = scan_record_identities(repo_root)
if identity["invalid_identifiers"] or identity["identity_collisions"]:
# Completed, already-bound suffix tasks are historical evidence, not
# allocation candidates. Keep conformance reporting strict while allowing
# ordinary registration to preserve those bindings. Local aliases still
# require the explicit parent allowlist in the kind registry.
historical_sources: set[str] = set()
for path in iter_workplan_files(repo_root):
parsed = parse_workplan_file(path, repo_root=repo_root)
if parsed.status not in {"finished", "archived", "completed"} or not parsed.id:
continue
for number, task in enumerate(parsed.tasks, start=1):
if task.status not in {"done", "cancel"} or not task.state_hub_task_id:
continue
if not re.fullmatch(re.escape(parsed.id) + r"-T[0-9]{2}[a-z]", task.id or ""):
continue
try:
uuid.UUID(task.state_hub_task_id)
except ValueError:
continue
historical_sources.add(f"{parsed.path}#task-block-{number}")
invalid = [
item for item in identity["invalid_identifiers"]
if item["source"] not in historical_sources
]
historical = [
item for item in identity["invalid_identifiers"]
if item["source"] in historical_sources
]
if invalid or identity["identity_collisions"]:
raise ValueError(
"work-record identities are not safe to derive: "
f"invalid={identity['invalid_identifiers']!r}, "
f"invalid={invalid!r}, "
f"collisions={identity['identity_collisions']!r}"
)
@ -926,6 +953,7 @@ def ensure_missing_work_record_identifiers(
"repo": repo_root.name,
"namespace": namespace,
"assignments": assignments,
"historical_invalid_identifiers": historical,
"files_changed": sorted(str(path.relative_to(repo_root)) for path in rendered),
}

View file

@ -0,0 +1,63 @@
from pathlib import Path
import pytest
from repo_manager.identifiers import ensure_missing_work_record_identifiers
from repo_manager.record_identity import scan_record_identities
def _sources(root: Path, *, status='completed', task_status='done',
task_id='NK-WP-0003-T08a', binding='22222222-2222-4222-8222-222222222222'):
archive = root / 'workplans' / 'archived' / 'NK-WP-0003.md'
archive.parent.mkdir(parents=True)
archive.write_text(
f'---\nid: NK-WP-0003\nstatus: {status}\n'
'state_hub_workstream_id: "11111111-1111-4111-8111-111111111111"\n---\n'
f'\n```task\nid: {task_id}\nstatus: {task_status}\n'
f'state_hub_task_id: "{binding}"\n```\n'
)
live = root / 'workplans' / 'NK-WP-0099.md'
live.write_text('---\nid: NK-WP-0099\nstatus: active\n---\n'
'\n```task\nid: NK-WP-0099-T01\nstatus: todo\n```\n')
return archive, live
@pytest.mark.parametrize('status', ['finished', 'archived', 'completed'])
def test_historical_warning_preserves_source_and_allows_allocation(tmp_path, status):
archive, live = _sources(tmp_path, status=status)
before = {p: p.read_bytes() for p in (archive, live)}
preview = ensure_missing_work_record_identifiers(tmp_path, execute=False)
assert all(p.read_bytes() == content for p, content in before.items())
result = ensure_missing_work_record_identifiers(tmp_path)
assert result['assignments'] == preview['assignments']
assert {x['record_id'] for x in result['assignments']} == {'NK-WP-0099', 'NK-WP-0099-T01'}
assert archive.read_bytes() == before[archive]
assert result['historical_invalid_identifiers'] == scan_record_identities(tmp_path)['invalid_identifiers']
assert result['historical_invalid_identifiers'][0]['id'] == 'NK-WP-0003-T08a'
assert not scan_record_identities(tmp_path)['ok']
assert ensure_missing_work_record_identifiers(tmp_path)['assignments'] == []
@pytest.mark.parametrize('kwargs', [
{'status': 'active'}, {'status': 'unknown'}, {'task_status': 'todo'},
{'binding': ''}, {'binding': 'not-a-uuid'}, {'task_id': 'T08a'},
{'task_id': 'T01'}, {'task_id': 'NK-WP-0099-T08a'},
])
def test_unsafe_history_refuses_before_any_allocation(tmp_path, kwargs):
paths = _sources(tmp_path, **kwargs)
before = {p: p.read_bytes() for p in paths}
with pytest.raises(ValueError, match='identities are not safe'):
ensure_missing_work_record_identifiers(tmp_path)
assert all(p.read_bytes() == content for p, content in before.items())
def test_historical_collision_still_blocks(tmp_path):
archive, live = _sources(tmp_path)
duplicate = archive.with_name('duplicate.md')
duplicate.write_text(archive.read_text().replace(
'22222222-2222-4222-8222-222222222222',
'33333333-3333-4333-8333-333333333333'))
before = live.read_bytes()
with pytest.raises(ValueError, match='collisions='):
ensure_missing_work_record_identifiers(tmp_path)
assert live.read_bytes() == before

View file

@ -0,0 +1,27 @@
---
id: RMGR-WP-ADHOC-2026-09-09
type: workplan
title: "Validate natural assistant provenance"
domain: infotech
repo: repo-manager
status: finished
owner: codex
created: "2026-09-09"
updated: "2026-09-09"
state_hub_workstream_id: "b4258afa-f8db-51a3-957d-f5aae3531117"
---
## Capture the natural multi-session window
```task
id: RMGR-WP-ADHOC-2026-09-09-T01
status: done
priority: low
state_hub_task_id: "714af2ff-83ac-5dc6-a070-8eb5bf547090"
```
Resolved RMGR-IN-0001 by running the existing assistant provenance report over
100 commits ending at 5ad49dd79e0ebc2f46bf5df68d2c1a079dc358c7.
Evidence: docs/evidence/2026-09-09-natural-assistant-provenance.json.
The existing history contains three assistants and one naturally interleaved
session pair. No collision or concurrent-write claim is inferred.

View file

@ -0,0 +1,48 @@
---
id: RMGR-WP-0015
type: workplan
title: "Preserve bound historical suffix tasks during normal sync"
domain: infotech
repo: repo-manager
status: finished
owner: codex
topic_slug: infotech
created: "2026-09-09"
updated: "2026-09-09"
state_hub_workstream_id: "20b82674-0459-5075-9fc9-8f95ccb940bb"
---
Origin: RMGR-IN-0003. Net Kingdom has already repaired the original T08a
source label, but the general ordinary-registration refusal remains.
## Scope the ordinary registration gate
```task
id: RMGR-WP-0015-T01
status: done
priority: medium
state_hub_task_id: "b45b78c9-720b-50fe-86de-d263f8a9e813"
```
Preserve existing UUIDs on parent-qualified TNN suffix tasks marked done/cancel
in finished, archived, or legacy completed workplans. Report their invalid
labels in the assignment receipt and retain strict conformance diagnostics.
Do not allocate historical UUIDs, accept unknown local aliases, or bypass any
identity collision. Active or unbound invalid records still fail before writes.
## Prove preservation and rejection boundaries
```task
id: RMGR-WP-0015-T02
status: done
priority: medium
state_hub_task_id: "46f87efc-363b-5345-bea9-8bf8b99596a4"
```
Cover unrelated canonical allocation, unchanged historical source bytes,
idempotency, dry run, invalid/missing UUIDs, active records, local aliases,
and collisions. Run the complete suite and a read-only Net Kingdom preflight.
Validation: 181 tests passed; targeted Ruff checks passed. Net Kingdom
read-only identifier preflight passed with no assignments or file changes.
RMGR-IN-0003 resolved; no implementation residuals.