"""Retire the shortform-dispatch requirement family, BLOCK-AWARE.

A substring search for `id = "REQ-X"` matches a MENTION of that id inside another
requirement's title — these titles cross-reference each other constantly — so an
index-based edit silently rewrites the wrong requirement. It did exactly that on the
first attempt: REQ-HAZARD-STOPFAILURE-STUCK-BUSY was handed another requirement's text
and had its stages cleared. Split into blocks and match the block's OWN id line.
"""
import io, sys

p = r'C:\Users\decid\Documents\projects\spt-claude-code\traceable-reqs.toml'
NL = chr(10)
s = io.open(p, encoding='utf-8').read()

RETIRE = {
    'REQ-TAG-PEER-MESSAGING',
    'REQ-TAG-SEND-STAMP-EXPLICIT',
    'REQ-TAG-SEND-STAMP-PROBE',
    'REQ-TAG-SEND-FAILURE-LOUD',
    'REQ-TAG-SEND-QUEUED-VISIBLE',
    'REQ-TAG-SEND-VERDICT-NOT-CATCHALL',
    'REQ-TAG-SEND-PRETOOL-TRACE',
    'REQ-TAG-SEND-OUTCOME-LEDGER',
    'REQ-TAG-CONFIRM-NEXT-HOOK',
    'REQ-HAZARD-TAG-BODY-CODE-SPAN',
}

PREFIX = (
 "RETIRED 2026-08-29 by REQ-IO-COMPLIANCE-DECLARED (Release B): this adapter no longer parses or "
 "dispatches shortform - spt-core does, off the ingest payloads we report, and per-target outcomes "
 "surface through the now-signal DISPATCH_RESULTS category, which core documents as the only channel "
 "by design. The evidence this requirement described has been DELETED, not merely left untagged, so "
 "the stages are cleared rather than the requirement removed: what it protected is kept here as the "
 "reasoning that has to outlive the code. ORIGINAL: "
)

MARK = '[[requirements]]' + NL
head, _, rest = s.partition(MARK)
blocks = rest.split(MARK)

seen = set()
for bi, b in enumerate(blocks):
    first = b.split(NL, 1)[0]
    if not first.startswith('id = "'):
        continue
    rid = first[len('id = "'):].rstrip('"')
    if rid not in RETIRE:
        continue
    assert rid not in seen, 'duplicate block for ' + rid
    seen.add(rid)
    lines = b.split(NL)
    ti = [i for i, l in enumerate(lines) if l.startswith('title = "')]
    si = [i for i, l in enumerate(lines) if l.startswith('required_stages = ')]
    assert len(ti) == 1 and len(si) == 1, '%s: %d titles, %d stage lines' % (rid, len(ti), len(si))
    lines[ti[0]] = 'title = "' + PREFIX + lines[ti[0]][len('title = "'):]
    was = lines[si[0]][len('required_stages = '):]
    lines[si[0]] = ('required_stages = []  # RETIRED 2026-08-29 (Release B) - evidence deleted with '
                    'the local parser. WAS: ' + was)
    blocks[bi] = NL.join(lines)

missing = RETIRE - seen
assert not missing, 'never found: %s' % sorted(missing)

s = head + ''.join(MARK + b for b in blocks)
io.open(p, 'w', encoding='utf-8', newline=NL).write(s)
print('retired %d requirements, block-aware' % len(seen))
