import io

p = 'crates/spt/src/api/nowsignal.rs'
s = io.open(p, encoding='utf-8').read()

old = '''        } else if seen.take_new(&key) {
            // NAME THE SUBJECT. A `RosterEntry` is a NODE (pubkey, subnet, and a
            // `label` that is its OS hostname) — this arm has no endpoint-level
            // join to distinguish, so the line says `node` and means it. The
            // unlabeled fallback SAYS it is a pubkey: a bare 12-hex prefix
            // standing where a name goes reads as an endpoint id to every reader
            // who has not opened this function.
            // [impl->REQ-NOW-SIGNAL-EDGE-SUBJECT-NAMING]
            let who = if m.label.is_empty() {
                format!(
                    "pubkey {}…",
                    m.pubkey_hex.chars().take(12).collect::<String>()
                )
            } else {
                m.label.clone()
            };
            out.push(format!("node {who} joined subnet {}", m.subnet));
        }
    }
    out
}
'''

new = '''        } else if seen.take_new(&key) {
            out.push(subnet_join_line(&m.label, &m.pubkey_hex, &m.subnet));
        }
    }
    out
}

/// Render one subnet-join line: `node <label> joined subnet <x>`.
///
/// **NAME THE SUBJECT.** A `RosterEntry` is a NODE (a node pubkey, a subnet, and
/// a `label` that is the member's OS hostname), so this arm is node-level only:
/// there is no endpoint-level join here to distinguish, and a node does not join
/// a subnet FROM another node. releases#11b's `z joined <subnet> from <node>`
/// names a data source that was never built, which is a board question rather
/// than a render bug — what IS fixable here is that the line say what its
/// subject is.
///
/// The unlabeled fallback SAYS it is a pubkey. A bare 12-hex prefix standing
/// where a name goes reads as an endpoint id to every reader who has not opened
/// this function.
// [impl->REQ-NOW-SIGNAL-EDGE-SUBJECT-NAMING]
fn subnet_join_line(label: &str, pubkey_hex: &str, subnet: &str) -> String {
    let who = if label.is_empty() {
        format!("pubkey {}…", pubkey_hex.chars().take(12).collect::<String>())
    } else {
        label.to_string()
    };
    format!("node {who} joined subnet {subnet}")
}
'''

assert s.count(old) == 1, 'render arm not found'
s = s.replace(old, new)

tail = "    /// One-lining bounds a category's text so no datum can shape the envelope."

tests = r'''    /// UPDATES tells a session its versions ONCE, and again only when one moves.
    ///
    /// Both arms are asserted together on purpose: "the second poll is empty"
    /// passes just as well against a category that emits nothing ever, and
    /// "it re-fires" is the half that proves the seen-set key CARRIES the
    /// version — which is the whole reason no event journal was built.
    // [unit->REQ-NOW-SIGNAL-UPDATES]
    #[test]
    fn updates_tells_a_session_once_and_again_when_a_version_moves() {
        let _home = crate::testutil::isolated_home();
        let session = session_id("updates");
        clear_session(&session);
        let ctx = Ctx {
            adapter: None,
            manifest: None,
            install_dir: None,
        };
        let input = PollInput {
            id: "updates-test",
            session: &session,
            user_input: "",
            agent_output: "",
        };

        let mut seen = SeenSet::load(&session, Category::Updates);
        let first = gather_updates(&ctx, &input, &mut seen);
        seen.flush();
        assert!(
            first.iter().any(|l| l.starts_with("spt-core ")),
            "a session is told the version it is RUNNING, once: {first:?}"
        );
        assert!(
            first.iter().any(|l| l.contains(env!("CARGO_PKG_VERSION"))),
            "the PRODUCT version leads, never the applied-update counter: {first:?}"
        );

        let mut seen = SeenSet::load(&session, Category::Updates);
        let second = gather_updates(&ctx, &input, &mut seen);
        seen.flush();
        assert!(
            second.is_empty(),
            "an unchanged version is not an update event: {second:?}"
        );

        // A session told about an OLDER version hears the new one: the key
        // carries the version, so a version that MOVED is a key that is new.
        clear_session(&session);
        let mut seen = SeenSet::load(&session, Category::Updates);
        seen.seed("core=0.0.0-what-this-session-was-told");
        let moved = gather_updates(&ctx, &input, &mut seen);
        assert!(
            moved.iter().any(|l| l.starts_with("spt-core ")),
            "the delta discipline IS the event detector: {moved:?}"
        );

        clear_session(&session);
    }

    /// SEAL_BRIEF is two sentences, once per session, and names the REAL verb.
    ///
    /// The command assertion is not decoration: the first draft of this text
    /// cited a `spt seal verify` that does not exist, and a payload whose whole
    /// job is telling an agent how to act is the worst possible place for an
    /// invented verb. This is that correction, made unable to regress silently.
    // [unit->REQ-NOW-SIGNAL-SEAL-BRIEF]
    #[test]
    fn the_seal_brief_is_two_sentences_told_once_and_names_the_real_verify_verb() {
        let _home = crate::testutil::isolated_home();
        let session = session_id("sealbrief");
        clear_session(&session);

        let mut seen = SeenSet::load(&session, Category::SealBrief);
        let first = gather_seal_brief(&mut seen);
        seen.flush();
        assert_eq!(first, vec![SEAL_BRIEF_TEXT.to_string()]);

        let mut seen = SeenSet::load(&session, Category::SealBrief);
        assert!(
            gather_seal_brief(&mut seen).is_empty(),
            "an agent that has been told does not need telling again"
        );

        // The operator's constraint, made executable rather than remembered.
        assert_eq!(
            SEAL_BRIEF_TEXT.matches('.').count(),
            2,
            "at most two short sentences — the operator's bound, verbatim"
        );
        assert!(
            !SEAL_BRIEF_TEXT.contains('\n'),
            "one line: the composer bounds the envelope, the payload does not"
        );
        assert!(
            SEAL_BRIEF_TEXT.contains("`spt api seal verify <token>`"),
            "the shipped verify surface"
        );
        assert!(
            !SEAL_BRIEF_TEXT.contains("`spt seal verify"),
            "`spt seal` is the MINT verb; verify lives under `api`"
        );
        assert!(
            SEAL_BRIEF_TEXT.contains(";;"),
            "and how to mint one — the shortform"
        );

        clear_session(&session);
    }

    /// The subnet-join line NAMES its subject, and its fallback says what it is.
    ///
    /// The arm reads a NODE record, so the line says `node`. releases#11b's
    /// "from <node>" half names an unbuilt data source and went back to the
    /// board; nothing is invented here to fill it.
    // [unit->REQ-NOW-SIGNAL-EDGE-SUBJECT-NAMING]
    #[test]
    fn a_subnet_join_line_names_the_node_and_labels_a_bare_pubkey() {
        assert_eq!(
            subnet_join_line("kitsubito", "ab12cd34ef567890", "spt-dev"),
            "node kitsubito joined subnet spt-dev"
        );
        let bare = subnet_join_line("", "ab12cd34ef567890", "spt-dev");
        assert_eq!(
            bare, "node pubkey ab12cd34ef56… joined subnet spt-dev",
            "an unlabeled member renders as a pubkey SAYING it is one"
        );
        assert!(
            !bare.starts_with("node ab12"),
            "a bare hex prefix where a name goes reads as an endpoint id"
        );
    }

'''

assert s.count(tail) == 1, 'test anchor not found'
s = s.replace(tail, tests + tail)
io.open(p, 'w', encoding='utf-8', newline='\n').write(s)
print('ok')
