These raw log messages are meant to help Ambient developers figure out problems. You can ignore them.
{
"type": "executor_starts",
"name": "ambient-execute-plan",
"version": "0.14.0@c37ec71",
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 459454896
},
"log_source": "Plan"
}{
"type": "runnable_plan",
"steps": [
{
"action": "mkdir",
"pathname": "/ci"
},
{
"action": "mkdir",
"pathname": "/ci/artifacts"
},
{
"action": "tar_extract",
"archive": "/dev/vdc",
"directory": "/ci/src"
},
{
"action": "tar_extract",
"archive": "/dev/vdf",
"directory": "/ci/deps"
},
{
"action": "tar_extract",
"archive": "/dev/vde",
"directory": "/ci/cache"
},
{
"action": "shell",
"shell": "ln -sf /ci /workspace"
},
{
"action": "shell",
"shell": "git config --global user.name 'Ambient CI'"
},
{
"action": "shell",
"shell": "git config --global user.email ambient@example.com"
},
{
"action": "cargo_fmt"
},
{
"action": "cargo_clippy"
},
{
"action": "cargo_test"
},
{
"action": "tar_create",
"archive": "/dev/vde",
"directory": "/ci/cache"
},
{
"action": "tar_create",
"archive": "/dev/vdd",
"directory": "/ci/artifacts"
}
],
"executor_drive": "/dev/vdb",
"source_drive": "/dev/vdc",
"artifact_drive": "/dev/vdd",
"cache_drive": "/dev/vde",
"deps_drive": "/dev/vdf",
"workspace_dir": "/ci",
"source_dir": "/ci/src",
"deps_dir": "/ci/deps",
"cache_dir": "/ci/cache",
"artifacts_dir": "/ci/artifacts",
"envs": {},
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 462123103
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "mkdir",
"pathname": "/ci",
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 477011239
},
"log_source": "Plan"
}{
"type": "action_succeeded",
"action": "mkdir",
"pathname": "/ci",
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 488329253
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "mkdir",
"pathname": "/ci/artifacts",
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 488352259
},
"log_source": "Plan"
}{
"type": "action_succeeded",
"action": "mkdir",
"pathname": "/ci/artifacts",
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 488387987
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "tar_extract",
"archive": "/dev/vdc",
"directory": "/ci/src",
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 488565945
},
"log_source": "Plan"
}{
"type": "action_succeeded",
"action": "tar_extract",
"archive": "/dev/vdc",
"directory": "/ci/src",
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 508312535
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "tar_extract",
"archive": "/dev/vdf",
"directory": "/ci/deps",
"timestamp": {
"secs_since_epoch": 1777373129,
"nanos_since_epoch": 510983625
},
"log_source": "Plan"
}{
"type": "action_succeeded",
"action": "tar_extract",
"archive": "/dev/vdf",
"directory": "/ci/deps",
"timestamp": {
"secs_since_epoch": 1777373132,
"nanos_since_epoch": 168127080
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "tar_extract",
"archive": "/dev/vde",
"directory": "/ci/cache",
"timestamp": {
"secs_since_epoch": 1777373132,
"nanos_since_epoch": 170853328
},
"log_source": "Plan"
}{
"type": "action_succeeded",
"action": "tar_extract",
"archive": "/dev/vde",
"directory": "/ci/cache",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 504808603
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "shell",
"shell": "ln -sf /ci /workspace",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 504845137
},
"log_source": "Plan"
}{
"type": "start_program",
"argv": [
{
"Unix": [
98,
97,
115,
104
]
},
{
"Unix": [
45,
99
]
},
{
"Unix": [
115,
101,
116,
32,
45,
120,
101,
117,
111,
32,
112,
105,
112,
101,
102,
97,
105,
108,
10,
108,
110,
32,
45,
115,
102,
32,
47,
99,
105,
32,
47,
119,
111,
114,
107,
115,
112,
97,
99,
101,
10
]
}
],
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 504857341
},
"log_source": "Plan"
}{
"type": "program_succeeded",
"exit_code": 0,
"stdout": "",
"stderr": "+ ln -sf /ci /workspace\n",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 516506887
},
"log_source": "Plan"
}{
"type": "action_succeeded",
"action": "shell",
"shell": "ln -sf /ci /workspace",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 519179036
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "shell",
"shell": "git config --global user.name 'Ambient CI'",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 521488645
},
"log_source": "Plan"
}{
"type": "start_program",
"argv": [
{
"Unix": [
98,
97,
115,
104
]
},
{
"Unix": [
45,
99
]
},
{
"Unix": [
115,
101,
116,
32,
45,
120,
101,
117,
111,
32,
112,
105,
112,
101,
102,
97,
105,
108,
10,
103,
105,
116,
32,
99,
111,
110,
102,
105,
103,
32,
45,
45,
103,
108,
111,
98,
97,
108,
32,
117,
115,
101,
114,
46,
110,
97,
109,
101,
32,
39,
65,
109,
98,
105,
101,
110,
116,
32,
67,
73,
39,
10
]
}
],
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 524039131
},
"log_source": "Plan"
}{
"type": "program_succeeded",
"exit_code": 0,
"stdout": "",
"stderr": "+ git config --global user.name 'Ambient CI'\n",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 535069539
},
"log_source": "Plan"
}{
"type": "action_succeeded",
"action": "shell",
"shell": "git config --global user.name 'Ambient CI'",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 535092884
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "shell",
"shell": "git config --global user.email ambient@example.com",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 535098153
},
"log_source": "Plan"
}{
"type": "start_program",
"argv": [
{
"Unix": [
98,
97,
115,
104
]
},
{
"Unix": [
45,
99
]
},
{
"Unix": [
115,
101,
116,
32,
45,
120,
101,
117,
111,
32,
112,
105,
112,
101,
102,
97,
105,
108,
10,
103,
105,
116,
32,
99,
111,
110,
102,
105,
103,
32,
45,
45,
103,
108,
111,
98,
97,
108,
32,
117,
115,
101,
114,
46,
101,
109,
97,
105,
108,
32,
97,
109,
98,
105,
101,
110,
116,
64,
101,
120,
97,
109,
112,
108,
101,
46,
99,
111,
109,
10
]
}
],
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 535314724
},
"log_source": "Plan"
}{
"type": "program_succeeded",
"exit_code": 0,
"stdout": "",
"stderr": "+ git config --global user.email ambient@example.com\n",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 550579231
},
"log_source": "Plan"
}{
"type": "action_succeeded",
"action": "shell",
"shell": "git config --global user.email ambient@example.com",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 550599854
},
"log_source": "Plan"
}{
"type": "execute_action",
"action": "cargo_fmt",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 550604882
},
"log_source": "Plan"
}{
"type": "start_program",
"argv": [
{
"Unix": [
99,
97,
114,
103,
111
]
},
{
"Unix": [
45,
45,
118,
101,
114,
115,
105,
111,
110
]
}
],
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 551013090
},
"log_source": "Plan"
}{
"type": "program_succeeded",
"exit_code": 0,
"stdout": "cargo 1.94.0 (85eff7c80 2026-01-15)\n",
"stderr": "",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 615194938
},
"log_source": "Plan"
}{
"type": "start_program",
"argv": [
{
"Unix": [
99,
97,
114,
103,
111
]
},
{
"Unix": [
99,
108,
105,
112,
112,
121
]
},
{
"Unix": [
45,
45,
118,
101,
114,
115,
105,
111,
110
]
}
],
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 617962151
},
"log_source": "Plan"
}{
"type": "program_succeeded",
"exit_code": 0,
"stdout": "clippy 0.1.94 (4a4ef493e3 2026-03-02)\n",
"stderr": "",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 723095496
},
"log_source": "Plan"
}{
"type": "start_program",
"argv": [
{
"Unix": [
114,
117,
115,
116,
99
]
},
{
"Unix": [
45,
45,
118,
101,
114,
115,
105,
111,
110
]
}
],
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 723135881
},
"log_source": "Plan"
}{
"type": "program_succeeded",
"exit_code": 0,
"stdout": "rustc 1.94.0 (4a4ef493e 2026-03-02)\n",
"stderr": "",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 770643290
},
"log_source": "Plan"
}{
"type": "start_program",
"argv": [
{
"Unix": [
99,
97,
114,
103,
111
]
},
{
"Unix": [
102,
109,
116
]
},
{
"Unix": [
45,
45,
99,
104,
101,
99,
107
]
}
],
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 770685325
},
"log_source": "Plan"
}{
"type": "program_failed",
"exit_code": 1,
"stdout": "Diff in /ci/src/src/bin/rad-artifact.rs:175:\n let signer = profile.signer().map_err(error::Signer)?;\n match loc.command {\n LocationCommand::Add(cmd) => {\n- location_add(\n- cmd,\n- args.no_input,\n- &mut releases,\n- &repo,\n- &profile,\n- &signer,\n- )?;\n+ location_add(cmd, args.no_input, &mut releases, &repo, &profile, &signer)?;\n }\n LocationCommand::Remove(cmd) => {\n- location_remove(\n- cmd,\n- args.no_input,\n- &mut releases,\n- &repo,\n- &profile,\n- &signer,\n- )?;\n+ location_remove(cmd, args.no_input, &mut releases, &repo, &profile, &signer)?;\n }\n }\n if !args.no_sync {\nDiff in /ci/src/src/bin/rad-artifact.rs:201:\n }\n Command::Attest(cmd) => {\n let signer = profile.signer().map_err(error::Signer)?;\n- attest_artifact(\n- cmd,\n- args.no_input,\n- &mut releases,\n- &repo,\n- &profile,\n- &signer,\n- )?;\n+ attest_artifact(cmd, args.no_input, &mut releases, &repo, &profile, &signer)?;\n if !args.no_sync {\n announce(&profile, repo.id)?;\n }\nDiff in /ci/src/src/bin/rad-artifact.rs:215:\n }\n Command::Redact(cmd) => {\n let signer = profile.signer().map_err(error::Signer)?;\n- redact_artifact(\n- cmd,\n- args.no_input,\n- &mut releases,\n- &repo,\n- &profile,\n- &signer,\n- )?;\n+ redact_artifact(cmd, args.no_input, &mut releases, &repo, &profile, &signer)?;\n if !args.no_sync {\n announce(&profile, repo.id)?;\n }\nDiff in /ci/src/src/bin/rad-artifact.rs:441:\n let (id, cid) = match (release, revision, cid) {\n (Some(_), _, Some(cid)) | (_, Some(_), Some(cid)) => {\n let id = resolve_target_release(\n- release,\n- revision,\n- releases,\n- repo,\n- &delegates,\n- no_input,\n- aliases,\n+ release, revision, releases, repo, &delegates, no_input, aliases,\n )?;\n (id, cid)\n }\nDiff in /ci/src/src/bin/rad-artifact.rs:493:\n let (id, cid) = match (release, revision, cid) {\n (Some(_), _, Some(cid)) | (_, Some(_), Some(cid)) => {\n let id = resolve_target_release(\n- release,\n- revision,\n- releases,\n- repo,\n- &delegates,\n- no_input,\n- aliases,\n+ release, revision, releases, repo, &delegates, no_input, aliases,\n )?;\n (id, cid)\n }\nDiff in /ci/src/src/bin/rad-artifact.rs:603:\n let id = parse_release_id(s, repo)?;\n let r = releases\n .get(&id)\n- .map_err(|err| error::Find::LookupId { release_id: id, err })?\n+ .map_err(|err| error::Find::LookupId {\n+ release_id: id,\n+ err,\n+ })?\n .ok_or(error::Find::NoReleaseId(id))?;\n vec![(id, r)]\n }\nDiff in /ci/src/src/bin/rad-artifact.rs:628:\n all_authors,\n local: Some(local),\n };\n- let shown =\n- display::Releases::new(candidates.into_iter(), aliases, filters, true, repo, repo);\n+ let shown = display::Releases::new(candidates.into_iter(), aliases, filters, true, repo, repo);\n if use_pretty(pretty, json) {\n print!(\"{}\", shown.pretty(verbose));\n } else {\nDiff in /ci/src/src/bin/rad-artifact.rs:1007:\n repo: &Repository,\n aliases: &impl AliasStore,\n ) -> Result<ReleaseId, String> {\n- select_release(candidates, None, repo, aliases)?\n- .ok_or_else(|| \"no release selected\".into())\n+ select_release(candidates, None, repo, aliases)?.ok_or_else(|| \"no release selected\".into())\n }\n \n /// Show a multi-release picker. Returns `Some(id)` when the user\nDiff in /ci/src/src/bin/rad-artifact.rs:1295:\n name, commit_oid, ..\n } => {\n let short = &commit_oid.to_string()[..7];\n- let title =\n- display::CommitTitle::title(repo, commit_oid).unwrap_or_default();\n+ let title = display::CommitTitle::title(repo, commit_oid).unwrap_or_default();\n format!(\"{name} -> {short} {title}\")\n }\n Entry::Commit { oid } => {\nDiff in /ci/src/src/bin/rad-artifact.rs:1422:\n match releases.get(&id) {\n Ok(Some(_)) => Ok(id),\n Ok(None) => Err(error::Find::NoReleaseId(id).into()),\n- Err(err) => Err(error::Find::LookupId { release_id: id, err }.into()),\n+ Err(err) => Err(error::Find::LookupId {\n+ release_id: id,\n+ err,\n+ }\n+ .into()),\n }\n }\n (None, Some(rev)) => {\nDiff in /ci/src/src/bin/rad-artifact.rs:1450:\n /// `git revparse_single` accepts short OIDs, full OIDs, and any other\n /// ref name that points at the COB.\n fn parse_release_id(s: &str, repo: &Repository) -> Result<ReleaseId, error::Resolve> {\n- let object = repo.raw().revparse_single(s).map_err(|err| error::Resolve {\n- revision: s.to_owned(),\n- err,\n- })?;\n+ let object = repo\n+ .raw()\n+ .revparse_single(s)\n+ .map_err(|err| error::Resolve {\n+ revision: s.to_owned(),\n+ err,\n+ })?;\n Ok(cob::ObjectId::from(object.id()).into())\n }\n \nDiff in /ci/src/src/bin/rad-artifact.rs:1467:\n })?;\n if object.kind() == Some(ObjectType::Tag) {\n let tag_oid: Oid = object.id().into();\n- let peeled = object.peel(ObjectType::Commit).map_err(|err| error::Resolve {\n- revision: rev.to_owned(),\n- err,\n- })?;\n+ let peeled = object\n+ .peel(ObjectType::Commit)\n+ .map_err(|err| error::Resolve {\n+ revision: rev.to_owned(),\n+ err,\n+ })?;\n Ok(ResolvedRef {\n commit: peeled.id().into(),\n tag: Some(tag_oid),\nDiff in /ci/src/src/lib.rs:712:\n store: self,\n })\n }\n-\n }\n \n /// A `ReleaseMut` is a [`Release`] where the underlying `Release` can be\nDiff in /ci/src/src/lib.rs:972:\n \n /// Collect the delegate set for a Radicle storage repository for use\n /// with `find_unique_by_commit`.\n- fn delegates(\n- repo: &radicle::storage::git::Repository,\n- ) -> std::collections::BTreeSet<Did> {\n+ fn delegates(repo: &radicle::storage::git::Repository) -> std::collections::BTreeSet<Did> {\n use radicle::prelude::ReadRepository;\n repo.delegates().unwrap().into_iter().collect()\n }\nDiff in /ci/src/src/lib.rs:2002:\n node: _alice, repo, ..\n } = test::setup::NodeWithRepo::default();\n let test::setup::NodeWithRepo { node: bob, .. } = test::setup::NodeWithRepo::default();\n- let test::setup::NodeWithRepo { node: carol, .. } =\n- test::setup::NodeWithRepo::default();\n+ let test::setup::NodeWithRepo { node: carol, .. } = test::setup::NodeWithRepo::default();\n let oid = commit(&repo.backend, \"Test Commit\");\n let delegates = delegates(&repo);\n let mut releases = Releases::open(&*repo).unwrap();\n",
"stderr": "",
"timestamp": {
"secs_since_epoch": 1777373137,
"nanos_since_epoch": 976060276
},
"log_source": "Plan"
}{
"type": "action_failed",
"action": "cargo_fmt",
"timestamp": {
"secs_since_epoch": 1777373138,
"nanos_since_epoch": 86283791
},
"log_source": "Plan"
}{
"type": "executor_ends_in_failure",
"exit_code": 1,
"timestamp": {
"secs_since_epoch": 1777373138,
"nanos_since_epoch": 89799356
},
"log_source": "Plan"
}{
"request": "trigger",
"version": 1,
"event_type": "patch",
"repository": {
"id": "rad:z4VYyJ9KuwMNkXGQnmKuGPGKw3inv",
"name": "radicle-artifact",
"description": "A Radicle Collaborative Object (COB) for content-addressed release artifacts and their discovery locations",
"private": false,
"default_branch": "main",
"delegates": [
"did:key:z6MktwkohCx8aHZ1QCjVZUiLmX92oPZFxRiFZkbq32Tk5Tkm"
]
},
"action": "Updated",
"patch": {
"id": "38c7fa789850450f8936febdad50dfe59d89648f",
"author": {
"id": "did:key:z6MktwkohCx8aHZ1QCjVZUiLmX92oPZFxRiFZkbq32Tk5Tkm",
"alias": "2color"
},
"title": "Add support for tags in releases",
"state": {
"status": "open",
"conflicts": []
},
"before": "1af9b4fc79a1e5816b92292bab422287c2dc65a3",
"after": "1e72006266445d1db954f39c24c9979b78f61de8",
"commits": [
"1e72006266445d1db954f39c24c9979b78f61de8",
"c86237d54fecf046d6dc1721c5a2e2b3be86f63b",
"e2e9e721eae37358fffe4e18da3bc60a35fe96cf",
"b6c4673e57a15769fe40804b239b03eda9c15419",
"b9ed5aeaa4286301484782485668b25099c032b4",
"98e9c91a275c40b43c387def0fdfec63595e7341",
"41ab3b0563f37823fd25443b3250731cd327f1b7",
"4e7289ff8b89b55a9b6203e86620687860ab2b56",
"b98035f10aba068726bec077ded55ac78e514486",
"88e573e3df4c403fd1d251605c6943c98e97c34a",
"55899e0beea3b673c11a48c7debd60cbce7feee4",
"9876154252f0bfa228a6684fa6873cf9e156c7a4",
"09680ca0635cc64ebdae618c63b798af78b17c88",
"d8d7319f181c4f640a65a2e1ada5824e4903be96",
"35a619ce9659d3d971c179942f4e57f68dccf626",
"58dd5a7c4f6be9236bd656be066e5f64f3bccafa",
"479cd44bbe4721492964549b784806c071ca609a",
"acf7cc89bfd393f9ba4d3660c4fe5f5a4147081a",
"c0e2958fa068ac9c32ffaca65600b5a69269281b",
"b04d6befebf153c845a3e7b553cd65cf33b893ed",
"6796786e4047995656d118008aa5f576b4c60ac1"
],
"target": "1af9b4fc79a1e5816b92292bab422287c2dc65a3",
"labels": [],
"assignees": [],
"revisions": [
{
"id": "38c7fa789850450f8936febdad50dfe59d89648f",
"author": {
"id": "did:key:z6MktwkohCx8aHZ1QCjVZUiLmX92oPZFxRiFZkbq32Tk5Tkm",
"alias": "2color"
},
"description": "This patch adds support for linking artifacts to a specific annotated tags. \n\nImplemented with an optional tag OID to the release schema and changes both read/write semantics relating to releases. \n\nThe complexity introduced by this patch is offset by some UX improvements to help the user pick the release either interactively or with a new `—release` flag \n\n## Before\n- Users only had to think about artifact CIDs linked to commits, even though they were grouped by a release COB\n- Releases were transparent to the user. Commits with multiple releases due to concurrency were also transparent, relying on a tie-breaker algorithm to deterministically resolve the release\n- no way to associate releases and artifacts to a specific annotated tag\n- Release authors didn’t matter, authorship only mattered on the artifact level\n\n## After\n\n- Releases now have an optional tag OID field, allowing linking artifacts to a specific annotated tag. (Lightweight tags are not supported)\n- The `COMMIT` argument has been renamed `REVISION` to better reflect that it can be either a commit, tag or abbreviated OID.\n- The same commit can have more than one release. Release IDs are surfaced to the user: \n - `rad-artifact show|attest/redact/location add/location remove` now accept a `—release` flag to target a specific release. \n - `rad-artifact show <REVISION>` will return every release for a given revision\n- New interactive release picker for all write commands, e.g. `add, attest, redact, location add, location remove` ",
"base": "1af9b4fc79a1e5816b92292bab422287c2dc65a3",
"oid": "09680ca0635cc64ebdae618c63b798af78b17c88",
"timestamp": 1777298029
},
{
"id": "0d4d7667473c019f0e6b0cf9dfd53a3114fa04ba",
"author": {
"id": "did:key:z6MktwkohCx8aHZ1QCjVZUiLmX92oPZFxRiFZkbq32Tk5Tkm",
"alias": "2color"
},
"description": "refactor: drop find_or_create_by_oid; rename to by_commit\n\n- Drop Releases::find_or_create_by_oid. The CLI is the only caller\n and will own disambiguation directly, so the library no longer\n needs a combined lookup-or-create with delegate-bootstrap rules.\n- Rename find_unique_by_oid -> find_unique_by_commit and the\n iterator pair find_by_oid -> find_by_commit (FindByOid ->\n FindByCommit). \"Commit\" is more precise than \"oid\", which is\n also used for release ids.\n- Add find_by_release_id for symmetry with the by-commit lookups.\n- Update CLI add: compose find_unique_by_commit + create instead.\n Ambiguous lookups now surface as errors rather than being\n silently resolved, which is the right semantic for the upcoming\n picker-based disambiguation.\n\nWhy: find_or_create_by_oid silently discarded the caller's tag\nwhen an existing release was returned, so promoting an RC commit\nto a final release dropped the new tag. Pushing disambiguation\nto the CLI lets the user choose explicitly between reusing a\nrelease and creating a new one with the new tag.\n\n\nfeat: add --release flag and disambiguation picker\n\n- Add --release <id> to `add`, mutually exclusive with --revision.\n Targets an existing release directly, skipping commit/tag\n resolution and any disambiguation. Required to script add against\n a specific release when multiple exist for the same commit.\n- When --revision is given (or interactively picked) and multiple\n releases exist for the resolved commit, prompt the user to pick\n among them or to create a new release. The \"create new\" entry\n carries the resolved tag's short OID so the RC-promotion case\n (existing RC release on the same commit, new tag for the final\n release) is obvious in the picker.\n- In --no-input mode, ambiguity is a hard error that lists the\n candidate ids and tells the user to pass --release <id>. Single\n existing release is still reused silently; zero releases creates\n one with the resolved tag.\n\nWhy: the previous flow silently reused the first release found for\na commit and discarded the caller's tag, which corrupted the\nRC-promotion case (RC release inheriting a different final tag).\nPushing disambiguation up to the CLI lets the user choose\nexplicitly, and --release gives scripts an unambiguous target.\n\n\nfeat: prompt on single-release tag mismatch\n\nPreviously the picker only ran for >1 releases. A single existing\nrelease with a tag different from the supplied revision's tag (e.g.\nan RC release on the same commit, user runs --revision <final-tag>)\nsilently reused the RC release and dropped the new tag — the\noriginal RC-promotion footgun.\n\nNow also disambiguate when one release exists and its recorded tag\ndiffers from the supplied tag. The user can pick the existing\nrelease (accepting the tag as-is) or create a new release with the\nnew tag. When the user supplied no tag (bare commit), still reuse\nsilently — they didn't assert anything to contradict.\n\nIn --no-input mode this surfaces the same disambiguation error as\nthe multi-release case; rename AmbiguousReleases to\nNeedsDisambiguation since the message now covers single-mismatch\ntoo.\n\n\nfeat: surface tag name and creator in display\n\nPretty output for show/list now reads the annotated-tag name (the\nname field embedded in the tag object) and renders it as\n'tag v1.0 -> commit <short>' instead of 'tag <short-oid> -> ...',\nfalling back to the short OID when the tag object isn't present\nlocally. JSON output gains an optional `tag_name` field alongside\nthe existing `tag` OID.\n\nEach release now also shows its creator DID (with alias when\nknown) — meaningful now that the new picker UX lets multiple\nreleases per commit coexist, and the creator is the primary\ndisambiguator alongside the tag association.\n\nImplementation: parallel TagName trait next to CommitTitle, with\nimpls for Repository (reads tag name out of the tag object\ndirectly) and (). display::Release gains creator,\ncreator_alias, and tag_name fields; Releases::new picks up a\nTagName resolver alongside the existing CommitTitle one.\n\n\nrefactor: drop creation date from list/show output\n\nThe release header was getting noisy with id, ref, creator, date,\nand title; the creation timestamp adds little signal next to the\ntag/commit/creator triple and is still available in JSON via\ncreated_at. Removing it also drops the chrono dependency.\n\n\nfix: prefix release IDs with release\n\n\nfeat: extend --release flag to show/attest/redact/location\n\nMirrors the disambiguation hatch already present on `add` to every\nsubcommand that targets a single release. Each accepts either\n<revision> (the existing path; commit/tag resolution + delegate-\npriority canonicalization) or --release <id> (skips resolution and\naddresses the COB directly).\n\nWhen multiple non-delegate releases exist for a commit and there is\nno delegate-authored canonical, find_unique_by_commit returns\nAmbiguous; the error message now points the user at --release <id>.\n\nTwo CLI breaking changes for symmetry:\n- show <revision> stays positional but is now optional, paired with\n --release. Clap requires exactly one.\n- location add/remove move <revision> from a positional to a\n --revision flag. Required to coexist with the optional <url>\n positional under clap's positional-ordering constraints.\n\nInternals: a single resolve_target_release helper handles both\npaths, returning a unified ResolveTarget error that wraps the\nexisting Resolve and Find variants. Find gains NoReleaseId and\nLookupId for the by-id miss/IO cases.\n\n\nfeat: prompt to pick release on ambiguous revision lookup\n\nExtends the interactive picker UX to every revision-targeting\nsubcommand (show, attest, redact, location add, location remove).\nPreviously these commands surfaced find_unique_by_commit's\nAmbiguous error and required the user to re-run with --release\n<id>; now they list the candidate releases (id, tag, creator,\ntitle) and let the user pick inline.\n\nThe prompt only fires when stdin is a TTY and --no-input is not\nset; non-interactive callers still get the explicit error\npointing at --release <id>. The picker has no \"create new\" entry\nsince these commands act on existing releases.\n\nPlumbing: a new prompt::pick_existing_release reuses the\nformat_candidate helper from add's picker.\nresolve_target_release picks up no_input + AliasStore params and\nthe dispatch threads args.no_input + &profile through to each\ncaller.\n\n\nfeat: show every release for a revision\n\n`show <revision>` now returns every release recorded against the\nresolved commit instead of picking one canonical release. Multiple\nreleases per commit are now first-class (via the picker UX in\nadd) and the previous behaviour silently hid non-canonical COBs\nbehind delegate-priority.\n\nThe three-tier model is now:\n- list = every release in the repo\n- show <revision> = every release for this commit/tag\n- show --release <id> = this one release in detail\n\nJSON always emits an array, even with --release (single-element).\nPredictable shape over slight verbosity — consumers don't branch\non which input flag was used. Pretty output renders each release\nin turn, separated by a blank line.\n\nThe Ambiguous picker no longer fires on show since there's\nnothing to disambiguate; revision lookup just returns all hits.\n\n\nfix: accept short release ids on --release flag\n\nClap was parsing --release through ReleaseId's FromStr, which\ndelegates to ObjectId's hex parser and requires a full 40-char\nSHA-1; a 7-char prefix would fail at clap parse time before any\ngit lookup could resolve it.\n\nThe COB's first commit is a real git object, so we can lean on\nrevparse_single to disambiguate prefixes the same way users\nalready abbreviate commit OIDs. Switch every --release clap field\nto a String, route it through a new parse_release_id helper that\ncalls revparse_single on the repository's git backend, then turn\nthe resulting full Oid into a ReleaseId via ObjectId::from.\n\n\nrefactor: simplify\n\n- Drop Releases::find_by_release_id; it was a thin alias of get.\n Switch the three callers (add, show, resolve_target_release) to\n call get directly.\n- Fold Add::FindByCommit/Lookup/ReleaseNotFound into the existing\n Find error via Add::Find(#[from] Find). The three Add-specific\n variants duplicated Find::Lookup/LookupId/NoReleaseId variant\n for variant.\n- Pull resolve and format_did up to pub in display so the prompt\n module's format_candidate can reuse the existing DID rendering\n instead of inlining its own truncation. Same output, fewer\n divergent code paths.\n- Unify the two release pickers behind a private select_release\n helper. pick_release_or_create just appends an extra \"create\n new\" entry and remaps the index; pick_existing_release calls\n through with no extra entry. Removes the duplicated TTY check,\n label-build loop, and \"pass --release <id>\" error string.\n- Route show through display::Releases::new + pretty(). The inline\n loop in show duplicated the existing Releases construction; an\n into_inner() accessor on Releases lets show emit a bare-array\n JSON shape while reusing Releases::pretty for the pretty path.\n- Eliminate the find + get_mut double load in add --release.\n get_mut already errors NotFound; map that to Find::NoReleaseId\n inline.\n- Standardise on &impl AliasStore across the CLI command fns.\n add_artifact was the odd one out taking &Profile only for its\n AliasStore impl.\n\n\nfeat: show local user's artifacts and full CIDs\n\n- exempt the local user from the delegate-only author filter so users\n see their own contributions without passing --all-authors\n- render CIDs in full in show/list pretty output; verbose now only\n controls DID truncation, since CIDs are the primary copy target",
"base": "1af9b4fc79a1e5816b92292bab422287c2dc65a3",
"oid": "1e72006266445d1db954f39c24c9979b78f61de8",
"timestamp": 1777373116
}
]
}
}executor from config: /usr/bin/ambient-execute-plan executor from PATH: /usr/bin/ambient-execute-plan run CI for rad:z4VYyJ9KuwMNkXGQnmKuGPGKw3inv ERROR: CI run failed inside QEMU
<empty log>