import os
root = r'C:\Users\decid\Documents\projects\spt-core\.worktrees\351-w4'


def edit(rel, pairs):
    p = os.path.join(root, rel)
    s = open(p, encoding='utf-8', newline='').read()
    N = '\r\n' if '\r\n' in s else '\n'
    for old, new in pairs:
        old = old.replace('\n', N)
        new = new.replace('\n', N)
        assert s.count(old) == 1, (rel, old[:60], s.count(old))
        s = s.replace(old, new)
    open(p, 'w', encoding='utf-8', newline='').write(s)


edit('docs-site/src/harness-contract/api.md', [(
'''([shells follow active](../shells/overview.md#shells-follow-active)). At that
instance it is live-only: never spooled into the owner's inbox, and dropped
with a diagnostic if the session isn't live. While the owner has **no** active
instance, it waits in the shell's outbound queue and drains in order when one
becomes active. Output: `SENSORY_DELIVERED:`, `SENSORY_DROPPED:`,
`SENSORY_QUEUED:` (exit 0), or `SENSORY_REFUSED:` (exit 1).''',
'''([shells follow active](../shells/overview.md#shells-follow-active)). At that
instance it is live-only, on this node or across nodes: it is never spooled
into the owner's inbox. A frame sent while an instance is active but its
session isn't live is dropped with a diagnostic. While the owner has **no**
active instance, it waits in the shell's outbound queue and drains in order
when one becomes active. A queued frame that then meets a session that isn't
live keeps its place until the session is live, and anything queued behind it
waits with it. Output: `SENSORY_DELIVERED:`, `SENSORY_DROPPED:`,
`SENSORY_QUEUED:` (exit 0), or `SENSORY_REFUSED:` (exit 1).''')])

edit('docs-site/src/shells/frames.md', [(
'''Delivered to the owner's **active** instance: live-only there, dropped with a
diagnostic when that session is not live, and never spooled into the owner's
inbox. While the owner has **no** active instance, the frame waits in the
shell's outbound queue with every other kind, in send order, and drains when
an instance becomes active. A queued frame may therefore be stale when it
arrives.''',
'''Delivered to the owner's **active** instance: live-only there, on this node
or across nodes, and never spooled into the owner's inbox. A frame sent while
that session is not live is dropped with a diagnostic. While the owner has
**no** active instance, the frame waits in the shell's outbound queue with
every other kind, in send order, and drains when an instance becomes active.
A queued frame that then meets a session that is not live keeps its place
until the session is live, and the text queued behind it waits with it. A
queued frame may therefore be stale when it arrives.

An owner node running an older spt-core has no live-only rule for a frame
that crossed nodes, and spools it into the inbox. That is a mixed-version
limit, and it ends when that node upgrades.'''),
('''  between the shell's node and the owner's shifts it by that skew. Older
  frames have no `sent-at`: treat it as absent, not as zero. The binary never composes this frame itself; it drives
the `api emit` surface and passes the payload **unescaped** — spt applies
the body encoding when it composes the frame.''',
'''  between the shell's node and the owner's shifts it by that skew. Older
  frames have no `sent-at`: treat it as absent, not as zero.

The binary never composes this frame itself; it drives the `api emit` surface
and passes the payload **unescaped** — spt applies the body encoding when it
composes the frame.''')])

edit('CONTEXT.md', [(
'''Ephemeral — delivered to the owner's **active** instance's live session, and dropped if that session isn't live. It is never spooled into the owner's inbox. The one exception is an active vacancy: then it waits in order with every other kind in the shell's outbound queue (*shells follow active*, releases#350), and a queued frame may be stale when it drains, which its own timestamp tells the consumer.''',
'''Ephemeral — delivered to the owner's **active** instance's live session, on this node or across nodes, and never spooled into the owner's inbox. A frame sent while that session isn't live is dropped. The one exception is an active vacancy: then it waits in order with every other kind in the shell's outbound queue (*shells follow active*, releases#350), and a queued frame may be stale when it drains, which its own timestamp tells the consumer. A queued frame that drains to a session that isn't live is HELD in its place, not dropped, and what is queued behind it waits with it (doyle gate ruling, 2026-09-27). An older owner node spools a crossing frame into the inbox: a mixed-version limit.''')])
print('ok')
