p='crates/spt/src/cli.rs'
b=open(p,'rb').read(); crlf=b'\r\n' in b; s=b.decode().replace('\r\n','\n')
def rep(a,n,cnt=1):
    global s
    assert s.count(a)==cnt,(s.count(a),a)
    s=s.replace(a,n)
i=s.index('fn run_update_post_step(')
j=s.index('\n}\n',i)+3
body=s[i:j]
orig=body
def br(a,n,cnt=1):
    global body
    assert body.count(a)==cnt,(body.count(a),a)
    body=body.replace(a,n)
br(''') -> bool {
    let color = crate::helpfmt::stdout_color();
    let manifest_message = adapter_update_notice(manifest, color);
''',''') -> (bool, Option<String>) {
    let color = crate::helpfmt::stdout_color();
    let manifest_message = adapter_update_notice(manifest, color);
    // What was told, color-off: the divulge row folds it in (releases#337).
    // [impl->REQ-NOW-SIGNAL-UPDATE-DIVULGE]
    let told_message = || {
        if adapter_applied {
            adapter_update_notice(manifest, false)
        } else {
            None
        }
    };
''')
br('''        if adapter_applied {
            if let Some(notice) = manifest_message {
                spt_proto::cap_println!("{notice}");
            }
        }
        return true;
    };''','''        if adapter_applied {
            if let Some(notice) = manifest_message {
                spt_proto::cap_println!("{notice}");
            }
        }
        return (true, told_message());
    };''')
br('''            match post_step_notice(&out.stdout) {
                PostNotice::None => {}
                PostNotice::ManifestMessage => {
                    if let Some(notice) = manifest_message {
                        spt_proto::cap_println!("{notice}");
                    }
                }
                PostNotice::Custom(text) => {
                    spt_proto::cap_println!("{}", crate::helpfmt::render(text, color).trim_end());
                }
            }
            true
        }''','''            let told = match post_step_notice(&out.stdout) {
                PostNotice::None => None,
                PostNotice::ManifestMessage => {
                    if let Some(notice) = manifest_message {
                        spt_proto::cap_println!("{notice}");
                    }
                    adapter_update_notice(manifest, false)
                }
                PostNotice::Custom(text) => {
                    spt_proto::cap_println!("{}", crate::helpfmt::render(text, color).trim_end());
                    Some(crate::helpfmt::render(text, false).trim_end().to_string())
                }
            };
            (true, told)
        }''')
br('''            emit_fallback(adapter_applied, &manifest_message);
            false
        }''','''            emit_fallback(adapter_applied, &manifest_message);
            (false, told_message())
        }''',2)
s=s[:i]+body+s[j:]
rep('''        i32::from(!run_update_post_step(
            &manifest,
            &record.name,
            true,
            "",
            installed,
            std::path::Path::new(&record.source_dir),
        ))''','''        i32::from(!run_update_post_step(
            &manifest,
            &record.name,
            true,
            "",
            installed,
            std::path::Path::new(&record.source_dir),
        )
        .0)''')
rep('''        if !run_update_post_step(
            &effective_manifest,
            &record.name,
            adapter_applied,
            installed,
            &new_version,
            &post_install_dir,
        ) {
            return AdapterUpdateOutcome::Failed;
        }
        if adapter_applied {''','''        let (post_ok, told) = run_update_post_step(
            &effective_manifest,
            &record.name,
            adapter_applied,
            installed,
            &new_version,
            &post_install_dir,
        );
        // The CLI writer of the adapter's apply record (releases#337): the
        // swap above is committed whether or not the post-step passed, so the
        // move is recorded before the post-step verdict can return early.
        // [impl->REQ-NOW-SIGNAL-UPDATE-DIVULGE]
        if adapter_applied {
            record_adapter_apply(&record.name, installed, &new_version, told);
        }
        if !post_ok {
            return AdapterUpdateOutcome::Failed;
        }
        if adapter_applied {''')
rep('''/// The install source recorded for an adapter added with `--via-subnet`''','''/// An adapter's move as the divulge row reads it (releases#337): old and new
/// manifest versions, when, the node-served changelog page only when the new
/// manifest DECLARES one (its sidecar was rendered at registration), and the
/// post-update notice the apply printed. `None` when nothing moved. Pure.
// [impl->REQ-NOW-SIGNAL-UPDATE-DIVULGE]
fn adapter_apply_record(
    name: &str,
    old: &str,
    new: &str,
    at_ms: u64,
    declares_changelog: bool,
    node_port: Option<(&str, u16)>,
    notice: Option<String>,
) -> Option<spt_daemon::SubjectApply> {
    let (old, new) = (old.trim(), new.trim());
    if old.is_empty() || new.is_empty() || old == new {
        return None;
    }
    let changelog = match (declares_changelog, node_port) {
        (true, Some((node, port))) => {
            Some(spt_store::serving::adapter_changelog_url(node, port, name))
        }
        _ => None,
    };
    Some(spt_daemon::SubjectApply {
        old: old.to_string(),
        new: new.to_string(),
        at_ms,
        changelog,
        notice: notice.filter(|n| !n.trim().is_empty()),
    })
}

/// Write an adapter's move into the apply record, best-effort (a missing
/// record degrades the divulge row; it never fails the update). The changelog
/// declaration is read from the NEW registration, so the link follows the
/// manifest the adapter now runs.
// [impl->REQ-NOW-SIGNAL-UPDATE-DIVULGE]
fn record_adapter_apply(name: &str, old: &str, new: &str, notice: Option<String>) {
    let adapters = perch::adapters_dir();
    let declares = spt_runtime::registry::load_record(&adapters, name)
        .and_then(|record| spt_runtime::registry::load_manifest(&adapters, &record))
        .map(|m| m.adapter.changelog.is_some())
        .unwrap_or(false);
    let port = spt_daemon::servehost::docs_port(&spt_daemon::endpoint::seed_socket_name()).ok();
    let node = spt_store::hostlabel::os_hostname();
    let node_port = match (&node, port) {
        (Some(n), Some(p)) => Some((n.as_str(), p)),
        _ => None,
    };
    if let Some(apply) = adapter_apply_record(name, old, new, now_ms(), declares, node_port, notice) {
        let _ = releases_cache().record_subject_apply(&spt_daemon::subject_adapter(name), &apply);
    }
}

/// The install source recorded for an adapter added with `--via-subnet`''')
if crlf: s=s.replace('\n','\r\n')
open(p,'wb').write(s.encode())
