def patch(p, reps):
    b = open(p, 'rb').read().decode('utf-8')
    for old, new in reps:
        N = '\r\n' if b.count(old.replace('\n', '\r\n')) == 1 else '\n'
        old = old.replace('\n', N); new = new.replace('\n', N)
        assert b.count(old) == 1, (p, old[:80], b.count(old))
        b = b.replace(old, new)
    open(p, 'wb').write(b.encode('utf-8'))

patch('docs-site/src/self-update/overview.md', [
("""adapters leg of `spt update`) first asks the peers that hold a **newer** copy,
highest version first, and only then the adapter's own release; add""",
"""adapters leg of `spt update`) first asks the peers that hold a **newer** copy
(in source order, below, then highest version first), and only then the
adapter's own release; add"""),
("""from), or — for an unsigned adapter — only the fact that a paired peer sent it.
""",
"""from), or — for an unsigned adapter — only the fact that a paired peer sent it.

<!-- [doc->REQ-UPDATE-SOURCES-STORE] -->
<!-- [doc->REQ-UPDATE-SOURCES-LADDER-PUMP] -->
**Nodes remember who served them** *(since v0.73.0)*. When a release, its
docs or an adapter that a peer sent passes its checks, the node records that
peer as a *learned* source in `releases/sources.json`. You can also *pin* a
peer. Peers are asked in this order: pinned peers first, then learned ones
(the one that served most recently first), then every other peer. This list
only sets the order. Bytes from a pinned or learned peer are checked exactly
like bytes from any other peer, and a peer is recorded only after its bytes
pass. In the background update rounds, a peer that ranks lower is passed over
while a higher-ranked source has not been asked yet, and is asked in the next
round. It is never held waiting, and a source that cannot be reached does
not hold up anyone else.
"""),
])

p = 'traceable-reqs.toml'
b = open(p, 'rb').read()
old = b'  "REQ-UPDATE-SOURCES-STORE",\r\n'
assert b.count(old) == 1
b = b.replace(old, old + b'  "REQ-UPDATE-SOURCES-LADDER-PUMP",\r\n')
b += (b'\r\n[[requirements]]\r\nid = "REQ-UPDATE-SOURCES-LADDER-PUMP"\r\n'
      b'title = "The update pump asks by source class each round (releases#339): pinned, then learned, then other peers. A peer is skipped, never held, while a source of a strictly higher class is still owed an ask, and a skipped peer is asked the next round. A source leaves the owed set on its own ask, when its dial submit is refused, when its async dial fails, when no route leg resolves it, and unconditionally at round end. Only sources that are connected or dial-eligible are owed. Nothing in the pump ever blocks on another peer\'s in-flight dial, and the ladder is RAM-only (no ordering holds across a pump restart)."\r\n'
      b'required_stages = ["doc", "impl", "unit"]\r\n')
open(p, 'wb').write(b)
