import os
os.chdir(r'C:\Users\decid\Documents\projects\spt-core\.worktrees\351-w0')

class F:
    def __init__(self, p):
        self.p = p
        raw = open(p, 'rb').read().decode('utf-8')
        self.crlf = '\r\n' in raw
        self.s = raw.replace('\r\n', '\n')
    def sub(self, a, b, n=1):
        c = self.s.count(a)
        assert c == n, (self.p, a[:80], c)
        self.s = self.s.replace(a, b)
    def save(self):
        out = self.s.replace('\n', '\r\n') if self.crlf else self.s
        open(self.p, 'wb').write(out.encode('utf-8'))

t = F('traceable-reqs.toml')
t.sub('''required_stages = ["impl", "unit"]  # ACTIVATED INSTANCE-AXES W0 (todlando 2026-09-26, releases#354).
''', '''required_stages = ["impl", "unit"]  # ACTIVATED INSTANCE-AXES W0 (todlando 2026-09-26, releases#354).

[[requirements]]
id = "REQ-SYNC-BOOTSTRAP-OWNER-SCOPE"
title = "A MIND THIS NODE HAS NO VISIBILITY ENTRY FOR IS PULLED UNDER THE OWNER'S SCOPE (releases#354, R4-8 ruled by doyle 2026-09-26): the requester side of the sync pull asks for a registry-named a-<id> bootstrap ref that it holds no visibility entry for whenever the peer is a roster member of a shared subnet, and the RESPONDER's gate (the owner's sync list, hidden means not synced) decides. A ref the requester does hold an entry for keeps the symmetric gate unchanged. Before this a node that never hosted an id could never receive its mind, so a span to it always refused for a missing mind. Every member now pulls every mind its owner exports to the subnet."
required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED INSTANCE-AXES W0 (todlando 2026-09-26, releases#354, R4-8).
''')
t.save()

v = F('crates/spt-store/src/visibility.rs')
v.sub('''    /// Whether the endpoint's mind **syncs** into the named subnet''', '''    /// Whether this node holds ANY visibility entry for `endpoint` — a sync
    /// list, a default-hide, or a per-subnet override. The sync pull's
    /// bootstrap leg keys on it: an endpoint this node never configured is one
    /// whose scope only its owner can state (REQ-SYNC-BOOTSTRAP-OWNER-SCOPE).
    // [impl->REQ-SYNC-BOOTSTRAP-OWNER-SCOPE]
    pub fn configures(&self, endpoint: &str) -> bool {
        self.sync_subnets.contains_key(endpoint)
            || self.default_hide.contains_key(endpoint)
            || self.overrides.contains_key(endpoint)
    }

    /// Whether the endpoint's mind **syncs** into the named subnet''')
v.save()

s = F('crates/spt-daemon/src/sync.rs')
s.sub('''/// Why a responder-side serve loop returned.''', '''impl SyncPolicy {
    /// The REQUESTER's gate for a registry-named bootstrap ref (R4-8). A mind
    /// this node holds no visibility entry for has no local scope to mirror:
    /// its owner's sync list is the scope (CONTEXT "Cross-node Psyche sync"),
    /// and the owner's node enforces it when it serves. So the requester asks
    /// whenever the peer is a roster member of a shared subnet and lets the
    /// responder's [`allows`](Self::allows) decide. Everything else — a
    /// configured id, a `p-` ref, machinery — takes the symmetric gate.
    // [impl->REQ-SYNC-BOOTSTRAP-OWNER-SCOPE]
    pub fn allows_bootstrap(&self, branch: &str, origin_node: &str) -> bool {
        match branch.strip_prefix("a-") {
            Some(id) if !self.vis.configures(id) => self
                .subnets
                .iter()
                .any(|(s, _)| self.roster.is_member(s, origin_node)),
            _ => self.allows(branch, origin_node),
        }
    }
}

/// Why a responder-side serve loop returned.''')
s.sub('''    // [unit->REQ-INST-5] the serve gate's decision table:''', '''    // [unit->REQ-SYNC-BOOTSTRAP-OWNER-SCOPE] the three legs of R4-8, each on
    // the side that decides it. (1) A fresh member with NO entry for the id
    // asks for the owner's mind; a stranger does not. (2) The owner's node
    // still refuses a mind it does not export to the subnet — the gate moved
    // to the responder, it did not vanish. (3) A mind its owner hides there is
    // never served. A requester that DOES configure the id keeps the
    // symmetric gate, so a local hide still means "do not pull".
    #[test]
    fn bootstrap_refs_are_scoped_by_the_owner() {
        let requester = policy("home", "owner");
        assert!(
            requester.allows_bootstrap("a-ling", "owner"),
            "a fresh member asks for a mind it never configured"
        );
        assert!(!requester.allows_bootstrap("a-ling", "stranger"), "not a member");
        assert!(
            !requester.allows("a-ling", "owner"),
            "control: the symmetric gate alone would never ask"
        );

        let mut owner = policy("home", "fresh");
        assert!(
            !owner.allows("a-ling", "fresh"),
            "the owner does not export ling to home: refused at the responder"
        );
        owner.vis.set_sync_subnets("ling", vec!["home".to_string()]);
        assert!(owner.allows("a-ling", "fresh"), "exported: served");
        owner.vis.set_override("ling", "home", Some(true));
        assert!(!owner.allows("a-ling", "fresh"), "hidden by its owner: never served");

        let mut configured = policy("home", "owner");
        configured.vis.set_override("ling", "home", Some(true));
        assert!(
            !configured.allows_bootstrap("a-ling", "owner"),
            "a requester that configured the id keeps the symmetric gate"
        );
        assert!(!requester.allows_bootstrap("machinery", "owner"));
    }

    // [unit->REQ-INST-5] the serve gate's decision table:''')
s.save()

p = F('crates/spt-daemon/src/pump/sync.rs')
p.sub('''        // Registry-derived bootstrap refs: minds named in the shared subnet
        // that this node never held locally.
        if let Some(snap) = self.registry.snapshot(subnet) {
            for id in snap.endpoint_ids() {
                let r = format!("a-{id}");
                if !want.contains(&r) && ctx.policy.allows(&r, peer_hex) {''', '''        // Registry-derived bootstrap refs: minds named in the shared subnet
        // that this node never held locally. Owner-scoped (R4-8): with no
        // local entry the owner's node decides when it serves.
        // [impl->REQ-SYNC-BOOTSTRAP-OWNER-SCOPE]
        if let Some(snap) = self.registry.snapshot(subnet) {
            for id in snap.endpoint_ids() {
                let r = format!("a-{id}");
                if !want.contains(&r) && ctx.policy.allows_bootstrap(&r, peer_hex) {''')
p.save()

r = F('crates/spt-daemon/tests/twohost_span.rs')
r.sub('''    // The explicit opt-in that lets B hold A's mind: the requester's sync gate
    // asks for a mind only when ITS OWN visibility lists the id's subnet, so a
    // node that never hosted the id pulls nothing without it (finding filed
    // with the gate, releases#354).
    let mut vis = VisibilityStore::load();
    vis.set_sync_subnets(ID, vec![rig.subnet.clone()]);
    vis.save().expect("opt B in to holding the mind");''', '''    // B configures NOTHING for the id: A's mind reaches it under A's own sync
    // scope (R4-8). `SPT_TWO_HOST_SPAN_SEED=1` is the CONTROL arm only — B
    // opts in explicitly, the way it had to before R4-8.
    if std::env::var("SPT_TWO_HOST_SPAN_SEED").as_deref() == Ok("1") {
        println!("TWOHOST_SPAN CONTROL ARM: B opts in to holding the mind");
        let mut vis = VisibilityStore::load();
        vis.set_sync_subnets(ID, vec![rig.subnet.clone()]);
        vis.save().expect("opt B in to holding the mind");
    }''')
r.sub('''    // ── Cell 0 — MIND: A's uid arrives in B's mind by replication.
    // [int->REQ-ENDPOINT-SPAN-VERB]''', '''    // ── Cell 0 — MIND: A's uid arrives in B's mind by replication, with B
    // holding no visibility entry for the id.
    // [int->REQ-ENDPOINT-SPAN-VERB] [int->REQ-SYNC-BOOTSTRAP-OWNER-SCOPE]''')
r.sub('''//! | 0 | MIND | B's context store reads A's uid for [`ID`] — by replication, never minted on B. |''', '''//! | 0 | MIND | B's context store reads A's uid for [`ID`] — by replication under A's own sync scope, B configuring nothing for it (R4-8), never minted on B. `SPT_TWO_HOST_SPAN_SEED=1` runs the pre-R4-8 opt-in as a control. |''')
r.save()

c = F('CONTEXT.md')
c.sub('''<!-- [doc->REQ-ENDPOINT-UID] -->
**endpoint uid**''', '''<!-- [doc->REQ-SYNC-BOOTSTRAP-OWNER-SCOPE] -->
**bootstrap pull (owner-scoped, R4-8)**:
A node pulls the mind of an endpoint it has never configured — no visibility entry for the id — whenever that id is named in a shared subnet's registry and the peer is a roster member there. The OWNER's sync list is the scope: the owner's node refuses a mind it does not export to that subnet, and a mind its owner hides there is never served. An id this node does configure keeps the symmetric gate. So every member of a subnet holds every mind exported to it, which is what lets `spt endpoint span` bring an instance up on a node that never hosted the endpoint.

<!-- [doc->REQ-ENDPOINT-UID] -->
**endpoint uid**''')
c.save()
print('ok')
