import io

EDITS = [
    # ── the const itself, and the module doc that carried the phantom ──
    ('crates/spt-live/src/inject.rs', [
        ("""//! When spt feeds an agent context it did not itself author — the session-start
//! Psyche download, the echo-commune mirror, an incoming owl message — it records
//! a one-line context-injection entry to the endpoint's `digest.log`.""",
         """//! When spt feeds an agent context it did not itself author — the session-start
//! Psyche download, an incoming owl message — or produces a context artefact on
//! its behalf, as the echo-commune does, it records a one-line context-injection
//! entry to the endpoint's `digest.log`."""),
        ("""/// The spt context-injection subtypes (the `context_kind` discriminator values).
pub const KIND_PSYCHE_DOWNLOAD: &str = "psyche_download";
pub const KIND_ECHO_MIRROR: &str = "echo_mirror";
pub const KIND_OWL_MESSAGE: &str = "owl_message";""",
         """/// The spt context-injection subtypes (the `context_kind` discriminator values).
///
/// `echo_commune` was `echo_mirror` until releases#113. **Nothing ever mirrored**
/// — [`crate::echo::run_echo_commune`] writes the brief as a commune DROP FILE,
/// whose ingest feeds the durable context tiers read at resume, never the running
/// session's window; this function only appends a digest line. The old name
/// asserted a behaviour the code did not have, and the ticket that asked for that
/// behaviour to be removed was reading the name. It is renamed for what it is: a
/// record that an echo-commune brief was produced for this agent.
///
/// This is the digest's `context_kind` vocabulary, a different namespace from
/// `spt_proto`'s `EVENT_TYPE_ECHO_COMMUNE` wire type and from the manifest's
/// `[session.echo_commune]` role, which happen to spell the same word.
pub const KIND_PSYCHE_DOWNLOAD: &str = "psyche_download";
pub const KIND_ECHO_COMMUNE: &str = "echo_commune";
pub const KIND_OWL_MESSAGE: &str = "owl_message";"""),
    ]),
    # ── the call site + the sentence that was the only "mirror" in the tree ──
    ('crates/spt-live/src/echo.rs', [
        ("""    // Two-origin digest tap (REQ-TERM-7): record that spt mirrored an
    // echo-commune brief into the agent's context. Best-effort.
    crate::inject::record_context_injection(id, crate::inject::KIND_ECHO_MIRROR, &out.stdout);""",
         """    // Two-origin digest tap (REQ-TERM-7): record that an echo-commune brief was
    // PRODUCED for this agent. Best-effort.
    //
    // It is not mirrored into the running context and never was — the brief goes
    // to the drop file written above, whose ingest routes it into the durable
    // context tiers a later session resumes from. The comment that used to stand
    // here said "mirrored ... into the agent's context", and that sentence, plus
    // the `echo_mirror` kind name, is the entire basis on which releases#113
    // reported a behavioural divergence from legacy. Measured at 343df76e: there
    // is no such behaviour to diverge (releases#113 fork 2).
    crate::inject::record_context_injection(id, crate::inject::KIND_ECHO_COMMUNE, &out.stdout);"""),
    ]),
    ('crates/spt-live/src/lib.rs', [
        ("    record_context_injection, KIND_ECHO_MIRROR, KIND_OWL_MESSAGE, KIND_PSYCHE_DOWNLOAD,",
         "    record_context_injection, KIND_ECHO_COMMUNE, KIND_OWL_MESSAGE, KIND_PSYCHE_DOWNLOAD,"),
    ]),
    ('crates/spt-store/src/history.rs', [
        ("/// (`psyche_download` | `echo_mirror` | `owl_message`), `ts` an RFC3339-UTC",
         "/// (`psyche_download` | `echo_commune` | `owl_message`), `ts` an RFC3339-UTC"),
    ]),
    ('crates/spt-term/src/digest.rs', [
        ("    /// fed the agent (`psyche_download` | `echo_mirror` | `owl_message`), merged",
         "    /// fed the agent (`psyche_download` | `echo_commune` | `owl_message`), merged"),
    ]),
    ('crates/spt-term/src/projection.rs', [
        ("    /// The injection subtype (`psyche_download` | `echo_mirror` | `owl_message`).",
         "    /// The injection subtype (`psyche_download` | `echo_commune` | `owl_message`)."),
    ]),
    # ── ADR-0019: amended by REPLACEMENT, not annotated ──
    ('docs/adr/0019-digest-adapter-declared-extractor-session-spanning.md', [
        ("a new collapsible category with subtypes `psyche_download | echo_mirror | owl_message`",
         "a new collapsible category with subtypes `psyche_download | echo_commune | owl_message` "
         "(the middle subtype was named `echo_mirror` here until releases#113; nothing ever mirrored "
         "an echo-commune into a running context, and the name was read as a promise that it did)"),
    ]),
    ('docs-site/src/harness-contract/integration-checklist.md', [
        ("  (`kind`: `psyche_download` | `echo_mirror` | `owl_message`, plus `body`).",
         "  (`kind`: `psyche_download` | `echo_commune` | `owl_message`, plus `body`)."),
    ]),
    ('docs-site/src/reference/json-shapes.md', [
        ("| `Context` | **spt-injected** — context spt fed *to* the agent (psyche download, echo mirror, owl message); adapters never emit these | `kind` ∈ `psyche_download` \\| `echo_mirror` \\| `owl_message`; `body` (string); `ts` optional |",
         "| `Context` | **spt-injected** — context spt fed *to* the agent (psyche download, owl message) or produced for it (echo commune); adapters never emit these | `kind` ∈ `psyche_download` \\| `echo_commune` \\| `owl_message`; `body` (string); `ts` optional |"),
    ]),
]

for path, pairs in EDITS:
    s = io.open(path, encoding='utf-8').read()
    for old, new in pairs:
        assert s.count(old) == 1, f'{path}: {s.count(old)} matches for {old[:60]!r}'
        s = s.replace(old, new)
    io.open(path, 'w', encoding='utf-8', newline='\n').write(s)
    print('patched', path)

# nothing may still spell the old kind in code or live docs
import subprocess
print('--- residual echo_mirror ---')
