"""Remove hook.rs's send fan-out, outcome tallies, and the whole shortform-confirm surface."""
import io

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


def cut(a, b, repl=''):
    """Replace the span from the line containing marker `a` through the line containing `b`."""
    global s
    ia = s.index(a)
    ib = s.index(b, ia) + len(b)
    # extend to end of line
    ib = s.index(NL, ib)
    # extend back to start of line
    ia = s.rindex(NL, 0, ia) + 1
    s = s[:ia] + repl + s[ib + 1:]


def sub(a, b, n=1):
    global s
    assert s.count(a) == n, 'anchor count %d (want %d) for %r' % (s.count(a), n, a[:80])
    s = s.replace(a, b)


# ---- 1. the tally declarations + stamp probe + send fan-out + confirm build ----------------------
start = '    // Peer sends: one `spt send` per (section \u00d7 target); self-targets dropped; results tallied.'
end = '''    } else {
        None
    };
'''
ia = s.index(start)
ib = s.index(end, ia) + len(end)
replacement = '''    // PEER SENDS ARE CORE'S NOW. Everything between this comment and the commune loop below used to
    // be the dispatch: a `spt send` per (section \u00d7 target), five outcome tallies kept apart so a
    // verdict never claimed more than it measured, the stamp probe, the outcome ledger, and the
    // shortform confirm built out of all of it. It is deleted rather than disabled, because the
    // published rule is that the declaration and the deletion ride the SAME change — an adapter
    // holding a second copy of the grammar is precisely the double-send window `[io] compliance`
    // exists to close, and a disabled parser is still a parser one edit away from firing.
    //
    // spt-core parses `@<...@>` out of the payloads this hook reports at the ingest edges (the UPS
    // `state busy`, the mid-turn `--mid` spans, and the Stop closer), and per-target outcomes reach
    // the author through the now-signal's DISPATCH_RESULTS category — which core documents as "the
    // only channel, by design", the reason our own richer confirm surface went with it rather than
    // standing beside it. [impl->REQ-IO-COMPLIANCE-DECLARED]
'''
s = s[:ia] + replacement + s[ib:]

# ---- 2. ScanOutcome loses `confirm` --------------------------------------------------------------
sub('''#[derive(Default)]
struct ScanOutcome {
    confirm: Option<ScanConfirm>,''', '''#[derive(Default)]
struct ScanOutcome {''')

sub('''    env.write_adapter_state(&rel, &new_cursor.to_string());
    let authored =
        texts.into_iter().filter(|t| crate::tag_scan::commune_body(t).is_none()).collect();
    ScanOutcome { confirm, authored }''', '''    env.write_adapter_state(&rel, &new_cursor.to_string());
    let authored =
        texts.into_iter().filter(|t| crate::tag_scan::commune_body(t).is_none()).collect();
    ScanOutcome { authored }''')

io.open(p, 'w', encoding='utf-8', newline=NL).write(s)
print('stage 1 done — fan-out + confirm build removed, ScanOutcome.confirm dropped')
