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
11 changes: 6 additions & 5 deletions bin/fm-contributions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# fm-contributions.sh snapshot <input.json> [--all]
# fm-contributions.sh poll
# fm-contributions.sh pending
# fm-contributions.sh verdict <task> <url> <judged-head> <source-url> <actor> <summary>
# fm-contributions.sh verdict <task> <url> <judged-head> <source-url> <captain|fleet|maintainer|nobody> <summary>
# fm-contributions.sh ack <task> <url> <event-token>
# fm-contributions.sh arm [--if-owned]
#
Expand All @@ -23,9 +23,10 @@
# checks/reviews). Checks are normalized by name, id, started_at, status and
# conclusion; projection picks the newest attempt per distinct name. The last
# observation's lane names also disclose a lane absent from the next head.
# A verdict records the EXACT judged head, source URL, actor and summary. A
# comment's arrival time never supplies its judged head. Record a prose verdict
# only after its source identifies that head; otherwise leave it unbound and
# A verdict records the EXACT judged head, source URL, actor and summary. The
# actor is exactly one of captain, fleet, maintainer or nobody; any other value
# is refused. A comment's arrival time never supplies its judged head. Record a
# prose verdict only after its source identifies that head; otherwise leave it unbound and
# triage its signal. Formal reviews carry GitHub's own commit_id. Neither kind
# can grant merge authority. Captain-actor prose requires an existing live hold;
# an eligible merge remains a captain call, never an automatic forge action.
Expand Down Expand Up @@ -473,7 +474,7 @@ case "${1:-}" in
else
[ "$#" -eq 4 ] || fail 'verdict needs judged-head, source-url, actor and summary'
fm_pr_head_valid "$1" || fail 'an exact judged commit is required'
case "$3" in captain|fleet|maintainer|nobody) ;; *) fail 'invalid required actor' ;; esac
case "$3" in captain|fleet|maintainer|nobody) ;; *) fail "invalid required actor '$3'; expected one of: captain, fleet, maintainer, nobody" ;; esac
case "$2" in "$url"\#*) ;; *) fail 'verdict source must be a comment or review on this contribution' ;; esac
jq --arg head "$1" --arg source "$2" --arg actor "$3" --arg summary "$4" \
'.verdict={head:$head,source:$source,actor:$actor,summary:$summary}' "$TMP/row.json" > "$TMP/update.json"
Expand Down
28 changes: 27 additions & 1 deletion tests/fm-contributions.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,32 @@ test_verdict_retains_judged_head() {
pass 'recorded judgment keeps its exact head and is stale immediately on a published replacement'
}

test_verdict_actor_values_are_discoverable() {
local home help out actor
home=$(new_home verdict-actors)
forge_home "$home"
with_home "$home" "$ROOT/bin/fm-pr-check.sh" delivery https://github.com/o/r/pull/8 >/dev/null \
|| fail 'could not register delivery before judging its head'
help=$("$ROOT/bin/fm-contributions.sh" --help) || fail 'verdict help did not print'
out=$(with_home "$home" "$ROOT/bin/fm-contributions.sh" verdict delivery https://github.com/o/r/pull/8 "$HEAD_A" \
https://github.com/o/r/pull/8#issuecomment-99 bogus 'no such actor' 2>&1) \
&& fail 'an unknown actor was accepted'
[ "$(printf '%s\n' "$help" | sed -n '/^ fm-contributions.sh verdict /p')" = \
' fm-contributions.sh verdict <task> <url> <judged-head> <source-url> <captain|fleet|maintainer|nobody> <summary>' ] \
|| fail "help usage does not name exactly the accepted actors: $help"
[ "$(printf '%s\n' "$help" | sed -n '/^actor is exactly one of /p')" = \
'actor is exactly one of captain, fleet, maintainer or nobody; any other value' ] \
|| fail "help explanation does not name exactly the accepted actors: $help"
[ "$out" = "fm-contributions: invalid required actor 'bogus'; expected one of: captain, fleet, maintainer, nobody" ] \
|| fail "refusal does not name exactly the accepted actors: $out"
for actor in captain fleet maintainer nobody; do
with_home "$home" "$ROOT/bin/fm-contributions.sh" verdict delivery https://github.com/o/r/pull/8 "$HEAD_A" \
https://github.com/o/r/pull/8#issuecomment-99 "$actor" 'documented actor' >/dev/null \
|| fail "documented actor $actor was refused"
done
pass 'verdict help and refusal name exactly the actors the command accepts'
}

test_observed_replacement_refreshes_verdict() {
local home
home=$(new_home observed-replacement)
Expand Down Expand Up @@ -1066,7 +1092,7 @@ test_late_owner_keeps_failure_episode_suppressed() {
}

failures=0
for test_name in test_actor_coverage test_stale_verdict test_unchecked_is_not_silence test_newest_check_has_no_verdict test_comment_wake test_review_wake test_inline_wake test_ready_issue_wake test_fresh_issue_requires_maintainer test_missing_lane_remains_missing test_partial_freshness_keeps_measured_rows test_malformed_record_cannot_prove_silence test_issue_timeline_and_exact_ack test_verdict_retains_judged_head test_observed_replacement_refreshes_verdict test_unobserved_head_leaves_verdict_unknown test_away_yolo_is_fleet_work test_away_yolo_cross_home_is_fleet_work test_retired_and_unsupported_coverage test_unsupported_forge_is_not_fleet_work test_held_unsupported_forge_is_not_captain_work test_shared_contribution_signal_wakes_once test_watcher_keeps_diagnostics_separate_from_contribution_wakes test_expired_child_unsupported_forge_stays_unmeasured test_watcher_surfaces_new_contribution_once test_home_summary_coverage test_unreadable_pending_is_not_empty test_record_task_identity_matches_dirname_basename test_read_only_views_create_no_state test_budget_refusal_between_calls test_budget_bounded_call_timeout test_genuine_failure_near_deadline_is_unavailable test_shared_url_observed_once test_terminal_contribution_settles test_late_owner_inherits_terminal_observation test_interrupted_multi_owner_poll_settles_every_owner test_done_task_open_pr_still_observed test_reservation_defers_later_url_when_fifteen_seconds_do_not_remain test_three_second_pr_reads_complete_fresh_in_one_cycle test_slow_read_deadline_kill_is_budget_refusal test_unmeasured_url_does_not_starve_the_tail test_budget_is_cut_down_to_the_watcher_check_bound test_arm_plumbs_a_configured_budget_into_the_check_shim test_unavailable_forge_records_error_and_wakes_once_per_episode test_late_owner_keeps_failure_episode_suppressed; do
for test_name in test_actor_coverage test_stale_verdict test_unchecked_is_not_silence test_newest_check_has_no_verdict test_comment_wake test_review_wake test_inline_wake test_ready_issue_wake test_fresh_issue_requires_maintainer test_missing_lane_remains_missing test_partial_freshness_keeps_measured_rows test_malformed_record_cannot_prove_silence test_issue_timeline_and_exact_ack test_verdict_retains_judged_head test_verdict_actor_values_are_discoverable test_observed_replacement_refreshes_verdict test_unobserved_head_leaves_verdict_unknown test_away_yolo_is_fleet_work test_away_yolo_cross_home_is_fleet_work test_retired_and_unsupported_coverage test_unsupported_forge_is_not_fleet_work test_held_unsupported_forge_is_not_captain_work test_shared_contribution_signal_wakes_once test_watcher_keeps_diagnostics_separate_from_contribution_wakes test_expired_child_unsupported_forge_stays_unmeasured test_watcher_surfaces_new_contribution_once test_home_summary_coverage test_unreadable_pending_is_not_empty test_record_task_identity_matches_dirname_basename test_read_only_views_create_no_state test_budget_refusal_between_calls test_budget_bounded_call_timeout test_genuine_failure_near_deadline_is_unavailable test_shared_url_observed_once test_terminal_contribution_settles test_late_owner_inherits_terminal_observation test_interrupted_multi_owner_poll_settles_every_owner test_done_task_open_pr_still_observed test_reservation_defers_later_url_when_fifteen_seconds_do_not_remain test_three_second_pr_reads_complete_fresh_in_one_cycle test_slow_read_deadline_kill_is_budget_refusal test_unmeasured_url_does_not_starve_the_tail test_budget_is_cut_down_to_the_watcher_check_bound test_arm_plumbs_a_configured_budget_into_the_check_shim test_unavailable_forge_records_error_and_wakes_once_per_episode test_late_owner_keeps_failure_episode_suppressed; do
( "$test_name" ) || failures=$((failures + 1))
done
[ "$failures" -eq 0 ] || fail "$failures contribution regressions"
Loading