p='crates/spt-runtime/src/registry.rs'
b=open(p,'rb').read(); crlf=b'\r\n' in b; s=b.decode().replace('\r\n','\n')
a='''    // [unit->REQ-INSTALL-4] an invalid manifest records nothing — the
    // validate-first rule (manifest-first, then install).'''
assert s.count(a)==1
s=s.replace(a,'''    const HARNESS_WITH_CHANGELOG: &str = r#"
[adapter]
name = "clog"
kind = "harness"
version = "1.2.0"
min_spt_core_version = "0.1.0"
summary = "A test adapter that ships its own changelog."
changelog = "docs/CHANGELOG.md"
"#;

    // [unit->REQ-ADAPTER-CHANGELOG] a declared changelog is rendered ONCE at
    // registration into core's sidecar (adapters/<name>/changelog.html) — real
    // HTML from the markdown, not the markdown bytes — and a re-registration
    // whose manifest drops the declaration retires the page.
    #[test]
    fn register_renders_declared_changelog_and_retires_it_when_dropped() {
        let tmp = tempfile::tempdir().unwrap();
        let adapters = tmp.path().join("adapters");
        let src = seed_source(tmp.path(), "clog-src", HARNESS_WITH_CHANGELOG);
        std::fs::create_dir_all(src.join("docs")).unwrap();
        std::fs::write(
            src.join("docs").join("CHANGELOG.md"),
            "# Changelog\n\n## 1.2.0\n\n- **Fixed** the <thing>\n",
        )
        .unwrap();
        register_with_core(&adapters, &src, 1, "0.1.0").expect("declared + present registers");
        let page = std::fs::read_to_string(adapters.join("clog").join("changelog.html"))
            .expect("the sidecar is written at registration");
        assert!(page.contains("<h1>Changelog</h1>"), "rendered, not raw: {page}");
        assert!(page.contains("<h2>1.2.0</h2>"), "{page}");
        assert!(page.contains("<strong>Fixed</strong>"), "{page}");
        assert!(page.contains("<title>clog changelog</title>"), "{page}");
        assert!(!page.contains("## 1.2.0"), "no markdown source leaks through: {page}");

        // The same adapter re-registered WITHOUT the key: the page goes away.
        std::fs::write(
            src.join("manifest.toml"),
            HARNESS_WITH_CHANGELOG.replace("changelog = \\"docs/CHANGELOG.md\\"\n", ""),
        )
        .unwrap();
        register_with_core(&adapters, &src, 2, "0.1.0").expect("undeclared registers");
        assert!(
            !adapters.join("clog").join("changelog.html").exists(),
            "dropping the declaration retires the rendered page"
        );
    }

    // [unit->REQ-ADAPTER-CHANGELOG] the loud arm: a declared changelog that is
    // MISSING from the installed tree, or not UTF-8 text, refuses the whole
    // registration with the typed error BEFORE any write — no record dir, no
    // half-installed adapter whose page would serve broken.
    #[test]
    fn register_refuses_a_declared_changelog_that_is_missing_or_unreadable() {
        let tmp = tempfile::tempdir().unwrap();
        let adapters = tmp.path().join("adapters");
        let src = seed_source(tmp.path(), "clog-src", HARNESS_WITH_CHANGELOG);
        let err = register_with_core(&adapters, &src, 1, "0.1.0")
            .expect_err("a declared changelog absent from the tree must refuse");
        match &err {
            RegistryError::Changelog { adapter, path, why } => {
                assert_eq!(adapter, "clog");
                assert_eq!(path, "docs/CHANGELOG.md");
                assert!(why.contains("not present"), "{why}");
            }
            other => panic!("expected Changelog, got {other:?}"),
        }
        assert!(err.to_string().starts_with("ADAPTER_CHANGELOG_UNREADABLE:clog:"), "{err}");
        assert!(!adapters.join("clog").exists(), "refused before the first write");

        std::fs::create_dir_all(src.join("docs")).unwrap();
        std::fs::write(src.join("docs").join("CHANGELOG.md"), [0xff, 0xfe, 0x00, 0x80]).unwrap();
        let err = register_with_core(&adapters, &src, 1, "0.1.0")
            .expect_err("non-UTF-8 bytes are not markdown");
        assert!(matches!(err, RegistryError::Changelog { .. }), "{err:?}");
        assert!(!adapters.join("clog").exists(), "refused before the first write");
    }

    // [unit->REQ-ADAPTER-CHANGELOG] the common case: an adapter declaring
    // neither key registers exactly as before and gets no page.
    #[test]
    fn register_without_changelog_declaration_writes_no_page() {
        let tmp = tempfile::tempdir().unwrap();
        let adapters = tmp.path().join("adapters");
        let src = seed_source(tmp.path(), "ef-src", HARNESS_EQUAL_FLOOR);
        let (_, manifest) = register_with_core(&adapters, &src, 1, "0.25.0").unwrap();
        assert_eq!(manifest.adapter.summary, None);
        assert_eq!(manifest.adapter.changelog, None);
        assert!(adapters.join("equalfloor").join("record.toml").exists());
        assert!(!adapters.join("equalfloor").join("changelog.html").exists());
    }

'''+a)
if crlf: s=s.replace('\n','\r\n')
open(p,'wb').write(s.encode())
