Skip to content

Commit 037fef5

Browse files
feat(catalog): add st2 catalog migrate-ids
One atomic transaction that makes an existing catalog expressible in decision 0015's identity model without re-keying any durable state. - A live subject freezes its existing `<host>.<identity>` bus identity as its explicit `id`, so every runtime identifier, task ID, socket path, and declaration-anchored state path keeps its exact bytes. - A structurally archived subject freezes the same bytes when they remain unique across the combined live-and-archived set. An archived collision — the shape a re-projecting generator and an archiving supervisor produce together — receives a UUIDv7 in both its declaration and its tombstone, and the reassignment is recorded in `.st2/agent-id-migration.json` so a reader of a version-1 durable record never retypes colliding bytes into the wrong subject. - Supervisor references resolve against the combined *pre-migration* index and are rewritten to the parent's migrated ID in the same transaction. A missing or ambiguous reference refuses before any write with `legacy-supervisor-unresolved`. - The catalog must already admit: migration re-admits the whole live plane after its writes, and a plane that already fails admission would fail that re-admission for a reason migration did not cause, leaving every declaration rewritten and the generation unmoved. A dry run still reports its full plan. - `--resume` finishes an interrupted run and may only apply work the interrupted transaction planned. A plain rerun over a half-migrated plane refuses. Edits are span-bounded over exact source bytes through the authoring module's existing insertion helper, so comments, formatting, and every unrelated byte survive. TOML and JSON declarations refuse. A Nix-owned declaration IS migrated — the marker guards interactive authoring, not the one transaction that has to reach the whole plane — and the receipt names it so its generator can be taught to emit `id` before the next activation re-projects the file without one.
1 parent b750a8b commit 037fef5

4 files changed

Lines changed: 2065 additions & 6 deletions

File tree

src/agent_author.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,7 +1720,7 @@ fn verify_desired_state_candidate(
17201720
))
17211721
}
17221722

1723-
fn exact_agent_node<'a>(
1723+
pub(crate) fn exact_agent_node<'a>(
17241724
document: &'a KdlDocument,
17251725
expected_identity: &str,
17261726
expected_host: &str,
@@ -1764,7 +1764,7 @@ fn exact_agent_node<'a>(
17641764
}
17651765
}
17661766

1767-
fn agent_identity_parts(node: &KdlNode) -> (Option<String>, Option<String>) {
1767+
pub(crate) fn agent_identity_parts(node: &KdlNode) -> (Option<String>, Option<String>) {
17681768
let mut identity = node
17691769
.get(0)
17701770
.and_then(|value| value.as_string())
@@ -1793,7 +1793,7 @@ fn agent_identity_parts(node: &KdlNode) -> (Option<String>, Option<String>) {
17931793
(host, identity)
17941794
}
17951795

1796-
fn is_nix_managed(node: &KdlNode) -> bool {
1796+
pub(crate) fn is_nix_managed(node: &KdlNode) -> bool {
17971797
node.children().is_some_and(|children| {
17981798
children
17991799
.nodes()
@@ -1855,7 +1855,7 @@ fn parse_field_value(node: &KdlNode, field: PresentationField) -> Result<&str, A
18551855
})
18561856
}
18571857

1858-
fn quoted(value: &str) -> Result<String, AuthorError> {
1858+
pub(crate) fn quoted(value: &str) -> Result<String, AuthorError> {
18591859
serde_json::to_string(value).map_err(|error| {
18601860
AuthorError::new(
18611861
"unsafe-source-edit",
@@ -1900,7 +1900,7 @@ fn insert_field(
19001900
)
19011901
}
19021902

1903-
fn insert_node(text: &str, target: &KdlNode, authored: &str) -> Result<String, AuthorError> {
1903+
pub(crate) fn insert_node(text: &str, target: &KdlNode, authored: &str) -> Result<String, AuthorError> {
19041904
let span = target.span();
19051905
let start = span.offset();
19061906
let end = start + span.len();
@@ -2038,7 +2038,7 @@ fn remove_field(text: &str, node: &KdlNode) -> Result<String, AuthorError> {
20382038
Ok(replacement)
20392039
}
20402040

2041-
fn line_indent(text: &str, offset: usize) -> Option<String> {
2041+
pub(crate) fn line_indent(text: &str, offset: usize) -> Option<String> {
20422042
let prefix = text.get(..offset)?;
20432043
let start = prefix.rfind('\n').map_or(0, |newline| newline + 1);
20442044
let indent = prefix.get(start..)?;

0 commit comments

Comments
 (0)