From 364a1384314e9aabc877909413b9f79501164238 Mon Sep 17 00:00:00 2001 From: NagyVikt Date: Sat, 18 Apr 2026 15:37:12 +0200 Subject: [PATCH] Keep agent branch labels readable while preserving uniqueness for long names Long Codex snapshot and task labels were producing very long branch names, which made local branch handling noisy and brittle. This change compacts agent/snapshot/task slugs with configurable limits and adds a checksum suffix so shortened names remain collision-resistant. Tests now assert the checksum-bearing format and branch-length bounds. Constraint: Branch names must remain deterministic and shell-safe across install templates Rejected: Keep full snapshot+task slugs in branch names | exceeds practical branch length in real sessions Confidence: high Scope-risk: narrow Directive: Keep script and template branch-naming logic in lockstep to avoid setup/runtime drift Tested: node --test test/install.test.js Not-tested: Full multi-repo end-to-end branch-start flow in a real Codex workspace --- scripts/agent-branch-start.sh | 74 ++++++++++++++++++++++--- templates/scripts/agent-branch-start.sh | 74 ++++++++++++++++++++++--- test/install.test.js | 31 ++++++++++- 3 files changed, 163 insertions(+), 16 deletions(-) diff --git a/scripts/agent-branch-start.sh b/scripts/agent-branch-start.sh index 5a81f1e..0860726 100755 --- a/scripts/agent-branch-start.sh +++ b/scripts/agent-branch-start.sh @@ -105,6 +105,68 @@ sanitize_slug() { printf '%s' "$slug" } +sanitize_optional_slug() { + local raw="$1" + local fallback="${2:-snapshot}" + if [[ -z "$raw" ]]; then + printf '' + return 0 + fi + sanitize_slug "$raw" "$fallback" +} + +normalize_positive_int() { + local raw="$1" + local fallback="$2" + if [[ "$raw" =~ ^[0-9]+$ ]] && [[ "$raw" -gt 0 ]]; then + printf '%s' "$raw" + return 0 + fi + printf '%s' "$fallback" +} + +shorten_slug() { + local slug="$1" + local raw_max="$2" + local max_len + max_len="$(normalize_positive_int "$raw_max" "32")" + if [[ "${#slug}" -le "$max_len" ]]; then + printf '%s' "$slug" + return 0 + fi + local shortened="${slug:0:max_len}" + shortened="$(printf '%s' "$shortened" | sed -E 's/-+$//')" + if [[ -z "$shortened" ]]; then + shortened="${slug:0:max_len}" + fi + printf '%s' "$shortened" +} + +checksum_slug_suffix() { + local raw="$1" + local checksum + checksum="$(printf '%s' "$raw" | cksum | awk '{print $1}')" + printf '%s' "${checksum:0:6}" +} + +compose_branch_descriptor() { + local snapshot_slug="$1" + local task_slug="$2" + local snapshot_max task_max task_part snapshot_part checksum_input checksum_part + snapshot_max="$(normalize_positive_int "${MUSAFETY_BRANCH_SNAPSHOT_SLUG_MAX:-18}" "18")" + task_max="$(normalize_positive_int "${MUSAFETY_BRANCH_TASK_SLUG_MAX:-36}" "36")" + task_part="$(shorten_slug "$task_slug" "$task_max")" + if [[ -n "$snapshot_slug" ]]; then + snapshot_part="$(shorten_slug "$snapshot_slug" "$snapshot_max")" + checksum_input="${snapshot_slug}--${task_slug}" + checksum_part="$(checksum_slug_suffix "$checksum_input")" + printf '%s-%s-%s' "$snapshot_part" "$task_part" "$checksum_part" + return 0 + fi + checksum_part="$(checksum_slug_suffix "$task_slug")" + printf '%s-%s' "$task_part" "$checksum_part" +} + normalize_bool() { local raw="${1:-}" local fallback="${2:-0}" @@ -896,15 +958,13 @@ else fi task_slug="$(sanitize_slug "$TASK_NAME" "task")" -agent_slug="$(sanitize_slug "$AGENT_NAME" "agent")" +agent_slug_raw="$(sanitize_slug "$AGENT_NAME" "agent")" +agent_slug="$(shorten_slug "$agent_slug_raw" "${MUSAFETY_BRANCH_AGENT_SLUG_MAX:-24}")" snapshot_name="$(resolve_active_codex_snapshot_name)" -snapshot_slug="$(sanitize_slug "$snapshot_name" "")" +snapshot_slug="$(sanitize_optional_slug "$snapshot_name" "snapshot")" +branch_descriptor="$(compose_branch_descriptor "$snapshot_slug" "$task_slug")" timestamp="$(date +%Y%m%d-%H%M%S)" -if [[ -n "$snapshot_slug" ]]; then - branch_name_base="agent/${agent_slug}/${snapshot_slug}-${task_slug}" -else - branch_name_base="agent/${agent_slug}/${task_slug}" -fi +branch_name_base="agent/${agent_slug}/${branch_descriptor}" branch_name="$branch_name_base" worktree_root="${repo_root}/${WORKTREE_ROOT_REL}" diff --git a/templates/scripts/agent-branch-start.sh b/templates/scripts/agent-branch-start.sh index 9c99e6d..125abf5 100755 --- a/templates/scripts/agent-branch-start.sh +++ b/templates/scripts/agent-branch-start.sh @@ -86,6 +86,68 @@ sanitize_slug() { printf '%s' "$slug" } +sanitize_optional_slug() { + local raw="$1" + local fallback="${2:-snapshot}" + if [[ -z "$raw" ]]; then + printf '' + return 0 + fi + sanitize_slug "$raw" "$fallback" +} + +normalize_positive_int() { + local raw="$1" + local fallback="$2" + if [[ "$raw" =~ ^[0-9]+$ ]] && [[ "$raw" -gt 0 ]]; then + printf '%s' "$raw" + return 0 + fi + printf '%s' "$fallback" +} + +shorten_slug() { + local slug="$1" + local raw_max="$2" + local max_len + max_len="$(normalize_positive_int "$raw_max" "32")" + if [[ "${#slug}" -le "$max_len" ]]; then + printf '%s' "$slug" + return 0 + fi + local shortened="${slug:0:max_len}" + shortened="$(printf '%s' "$shortened" | sed -E 's/-+$//')" + if [[ -z "$shortened" ]]; then + shortened="${slug:0:max_len}" + fi + printf '%s' "$shortened" +} + +checksum_slug_suffix() { + local raw="$1" + local checksum + checksum="$(printf '%s' "$raw" | cksum | awk '{print $1}')" + printf '%s' "${checksum:0:6}" +} + +compose_branch_descriptor() { + local snapshot_slug="$1" + local task_slug="$2" + local snapshot_max task_max task_part snapshot_part checksum_input checksum_part + snapshot_max="$(normalize_positive_int "${MUSAFETY_BRANCH_SNAPSHOT_SLUG_MAX:-18}" "18")" + task_max="$(normalize_positive_int "${MUSAFETY_BRANCH_TASK_SLUG_MAX:-36}" "36")" + task_part="$(shorten_slug "$task_slug" "$task_max")" + if [[ -n "$snapshot_slug" ]]; then + snapshot_part="$(shorten_slug "$snapshot_slug" "$snapshot_max")" + checksum_input="${snapshot_slug}--${task_slug}" + checksum_part="$(checksum_slug_suffix "$checksum_input")" + printf '%s-%s-%s' "$snapshot_part" "$task_part" "$checksum_part" + return 0 + fi + checksum_part="$(checksum_slug_suffix "$task_slug")" + printf '%s-%s' "$task_part" "$checksum_part" +} + normalize_bool() { local raw="${1:-}" local fallback="${2:-0}" @@ -350,15 +412,13 @@ else fi task_slug="$(sanitize_slug "$TASK_NAME" "task")" -agent_slug="$(sanitize_slug "$AGENT_NAME" "agent")" +agent_slug_raw="$(sanitize_slug "$AGENT_NAME" "agent")" +agent_slug="$(shorten_slug "$agent_slug_raw" "${MUSAFETY_BRANCH_AGENT_SLUG_MAX:-24}")" snapshot_name="$(resolve_active_codex_snapshot_name)" -snapshot_slug="$(sanitize_slug "$snapshot_name" "")" +snapshot_slug="$(sanitize_optional_slug "$snapshot_name" "snapshot")" +branch_descriptor="$(compose_branch_descriptor "$snapshot_slug" "$task_slug")" timestamp="$(date +%Y%m%d-%H%M%S)" -if [[ -n "$snapshot_slug" ]]; then - branch_name_base="agent/${agent_slug}/${snapshot_slug}-${task_slug}" -else - branch_name_base="agent/${agent_slug}/${task_slug}" -fi +branch_name_base="agent/${agent_slug}/${branch_descriptor}" branch_name="$branch_name_base" branch_suffix=2 diff --git a/test/install.test.js b/test/install.test.js index d37546e..6c917b4 100644 --- a/test/install.test.js +++ b/test/install.test.js @@ -1016,7 +1016,7 @@ OUT { env: { PATH: `${fakeBin}:${process.env.PATH || ''}` } }, ); assert.equal(result.status, 0, result.stderr || result.stdout); - assert.match(result.stdout, /Created branch: agent\/planner\/zeus-edix-hu-restore-snapshot(?:-\d+)?/); + assert.match(result.stdout, /Created branch: agent\/planner\/zeus-edix-hu-restore-snapshot-[0-9]{6}(?:-\d+)?/); }); test('setup agent-branch-start supports explicit snapshot override without codex-auth', () => { @@ -1033,7 +1033,34 @@ test('setup agent-branch-start supports explicit snapshot override without codex { env: { MUSAFETY_CODEX_AUTH_SNAPSHOT: 'Prod Snapshot One' } }, ); assert.equal(result.status, 0, result.stderr || result.stdout); - assert.match(result.stdout, /Created branch: agent\/bot\/prod-snapshot-one-ship-fix(?:-\d+)?/); + assert.match(result.stdout, /Created branch: agent\/bot\/prod-snapshot-one-ship-fix-[0-9]{6}(?:-\d+)?/); +}); + +test('setup agent-branch-start compacts long snapshot/task names for readable branch labels', () => { + const repoDir = initRepo(); + + let result = runNode(['setup', '--target', repoDir], repoDir); + assert.equal(result.status, 0, result.stderr || result.stdout); + seedCommit(repoDir); + + result = runCmd( + 'bash', + [ + 'scripts/agent-branch-start.sh', + 'rust-layer-phase7-dashboard-read-name-columns-and-badges', + 'codex-admin-recodee-com', + 'dev', + ], + repoDir, + { env: { MUSAFETY_CODEX_AUTH_SNAPSHOT: 'Zeus Portasmosonmagyarovar Hu Snapshot' } }, + ); + assert.equal(result.status, 0, result.stderr || result.stdout); + const createdBranch = extractCreatedBranch(result.stdout); + assert.match(createdBranch, /^agent\/codex-admin-recodee-com\/[a-z0-9-]+$/); + assert.ok(createdBranch.length <= 100, `branch should stay compact, got: ${createdBranch}`); + const branchLeaf = createdBranch.split('/').pop() || ''; + assert.ok(branchLeaf.length <= 70, `branch leaf should stay compact, got: ${branchLeaf}`); + assert.match(branchLeaf, /^zeus-portasmosonma-rust-layer-phase7-dashboard-read-name-[0-9]{6}(?:-\d+)?$/); }); test('setup agent-branch-start supports optional OpenSpec auto-bootstrap toggles', () => {