Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions scripts/canary-rollout.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,14 @@ _registered_reusables_for_host() {
_jq -r --arg h "$1" '[.agents[]? | select(.host==$h) | .reusable // empty] | unique | .[]'
}

# _unmanaged_reusables_for_host <host> — reusable paths on <host> INTENTIONALLY out of the
# ring-gate model, recorded in the `unmanaged` block (#651): single-hop channel reusables,
# frozen-major `@vN` infra, or dispatch-only workflows. drift excludes these so its
# "unregistered" signal only flags reusables that genuinely still need onboarding.
_unmanaged_reusables_for_host() {
_jq -r --arg h "$1" '[.unmanaged[]? | select(.host==$h) | .reusable // empty] | unique | .[]'
Comment thread
don-petry marked this conversation as resolved.
}

# _agents_for_reusable <host> <path> — the registry agent name(s) whose (host,reusable)
# match, joined by ", " (for the missing-file finding message).
_agents_for_reusable() {
Expand Down Expand Up @@ -1061,23 +1069,27 @@ cmd_drift() {
while IFS= read -r host; do
[ -z "$host" ] && continue
echo "──────── host: $host ────────"
local present registered unregistered missing p agents
local present registered unmanaged_r unregistered missing p agents
if ! present="$(_gh_list_reusables "$host")"; then
# Could not read the host's workflows dir — skip it rather than false-flag every
# registered reusable as missing-file. Read-only + best-effort: a warning, not a failure.
echo "::warning::drift $host: could not enumerate .github/workflows (API error / no access) — skipping host this cycle"
continue
fi
registered="$(_registered_reusables_for_host "$host")"
local reg_arr=() pres_arr=() reg_str="" pres_str=""
unmanaged_r="$(_unmanaged_reusables_for_host "$host")"
local reg_arr=() pres_arr=() um_arr=() reg_str="" pres_str="" um_str=""
if [ -n "$registered" ]; then mapfile -t reg_arr <<< "$registered"; fi
if [ -n "$present" ]; then mapfile -t pres_arr <<< "$present"; fi
if [ -n "$unmanaged_r" ]; then mapfile -t um_arr <<< "$unmanaged_r"; fi
[ "${#reg_arr[@]}" -gt 0 ] && reg_str=" ${reg_arr[*]}"
[ "${#pres_arr[@]}" -gt 0 ] && pres_str=" ${pres_arr[*]}"
[ "${#um_arr[@]}" -gt 0 ] && um_str=" ${um_arr[*]}"
echo " registered reusables (${#reg_arr[@]}):$reg_str"
echo " present *-reusable.yml (${#pres_arr[@]}):$pres_str"
# unregistered = present on the host but not in the registry.
unregistered="$(set_difference "$present" "$registered")"
[ "${#um_arr[@]}" -gt 0 ] && echo " unmanaged (intentional, out of ring gate) (${#um_arr[@]}):$um_str"
# unregistered = present on the host, minus registered agents AND intentionally-unmanaged (#651).
unregistered="$(set_difference "$(set_difference "$present" "$registered")" "$unmanaged_r")"
Comment thread
don-petry marked this conversation as resolved.
Comment on lines 1089 to +1092
while IFS= read -r p; do
[ -z "$p" ] && continue
echo "::warning::DRIFT[unregistered] $host: $p present on host but absent from canary-rings.json (no cut/soak/gate/dashboard until registered)"
Expand Down
17 changes: 17 additions & 0 deletions standards/canary-rings.json
Original file line number Diff line number Diff line change
Expand Up @@ -593,5 +593,22 @@
}
}
}
},
"unmanaged": {
"add-to-project": {
"host": "petry-projects/.github",
"reusable": ".github/workflows/add-to-project-reusable.yml",
"reason": "Single-hop @add-to-project/stable channel (5 consumers); low-risk project-automation plumbing, intentionally out of the full ring gate (#651)."
},
"claude-code": {
"host": "petry-projects/.github",
"reusable": ".github/workflows/claude-code-reusable.yml",
"reason": "Frozen-major @v2 base wrapper \u2014 not a canary-promoted agent."
},
"pr-auto-review": {
"host": "petry-projects/.github",
"reusable": ".github/workflows/pr-auto-review-reusable.yml",
"reason": "Frozen-major @v2 review-dispatcher infra \u2014 not a canary-promoted agent."
}
}
}
23 changes: 23 additions & 0 deletions tests/canary_rollout.bats
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,29 @@ _drift_rings_one_agent() {
[[ "$output" != *"ci.yml present on host"* ]]
}

@test "orchestrator: drift excludes an intentionally-unmanaged reusable (#651)" {
# Registry: dev-lead agent + an `unmanaged` entry for foo-reusable.yml on .github-private.
DRIFT_RINGS="$BATS_TEST_TMPDIR/drift-rings-um.json"
jq '{version, description, org_infra_repos, member_tokens,
agents: {"dev-lead": .agents["dev-lead"]},
unmanaged: {"foo": {"host":"petry-projects/.github-private","reusable":".github/workflows/foo-reusable.yml","reason":"single-hop infra (#651)"}}}' \
"$RINGS" > "$DRIFT_RINGS"
# host has dev-lead (registered) + foo (unmanaged) + bar (genuinely unregistered)
_drift_stub '[
{"type":"file","name":"dev-lead-reusable.yml","path":".github/workflows/dev-lead-reusable.yml"},
{"type":"file","name":"foo-reusable.yml","path":".github/workflows/foo-reusable.yml"},
{"type":"file","name":"bar-reusable.yml","path":".github/workflows/bar-reusable.yml"}
]' '[]'
run env CANARY_RINGS="$DRIFT_RINGS" bash "$ORCH" drift
[ "$status" -eq 0 ]
# foo is reported as unmanaged, NOT flagged as unregistered drift
[[ "$output" == *"unmanaged (intentional"* ]]
[[ "$output" != *"DRIFT[unregistered] petry-projects/.github-private: .github/workflows/foo-reusable.yml"* ]]
# bar (neither registered nor unmanaged) IS still flagged, and it's the ONLY one
[[ "$output" == *"DRIFT[unregistered] petry-projects/.github-private: .github/workflows/bar-reusable.yml"* ]]
[[ "$output" == *"1 unregistered"* ]]
}

@test "orchestrator: drift flags a registry entry whose reusable file no longer exists on the host (missing-file)" {
# Registry has 'ghost' pointing at a reusable that is NOT present on the host.
DRIFT_RINGS="$BATS_TEST_TMPDIR/drift-ghost.json"
Expand Down
Loading