Files
gstack/bin/gstack-skill-end
T
Garry Tanandcapy-ai[bot] f592d67826 v1.91.111.0 fix(evals): four PR-gate background reds were a detector, an interface, a helper and a workflow-block defect (#3231)
* fix(evals): three PR-gate background reds were a detector, an interface and a helper defect

- docsync-fault-eval: a conditional mention (until/unless/once/when/before/if) of
  'Documentation is current' is not a false current claim; replay corpus for
  ship-docsync-launch-failure from PR run 38336400566 with derived refusals.
- gstack-skill-start/gstack-skill-end: --help prints usage and exits before any
  side effect (it used to start a session); the docsync interface admits the
  lifecycle helpers' own --help; captured run 38969924945 replays clean.
- qa deadline policy: listing the owned qa-reports/screenshots directory is
  bookkeeping (qa-only-no-fix, run 38969924945).

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(evals): the launch-failure corpus is a row in the docsync corpus test that owns docsync-fault-eval

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(evals): register the launch-failure corpus and docsync-store capture in their contracts

The B1 corpus contract wants its own detector-corpus-<case> replay test, so the
launch-failure corpus keeps one, listed in the test-of-test baseline beside its
sibling corpora; FREE_FIXTURES names both new fixtures' free consumers.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(review-army): the scope block prints the SCOPE_* signals specialist selection reads

The Detect stack and scope block sourced gstack-diff-scope silently, so an
agent that needed SCOPE_FRONTEND to pick specialists appended its own echo and
left the declared caller interface (ship-exploratory-plan-checks red in run
38981523623). The block now lists the sourced signals itself.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* v1.91.111.0 fix(evals): four PR-gate background reds were a detector, an interface, a helper and a workflow-block defect

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-17 00:56:33 +00:00

85 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# gstack-skill-end — skill-completion telemetry + artifacts-sync drain,
# consolidated (token-reduction Phase 1). Replaces the inline "Telemetry (run
# last)" fence and the skill-end brain-sync fence in every generated SKILL.md.
#
# The generated prose calls this once at workflow completion:
# gstack-skill-end --skill NAME --outcome success|error|abort|unknown \
# --session-id ID --tel-start EPOCH [--used-browse yes|no] \
# [--error-message MSG] [--failed-step STEP]
#
# SESSION_ID and TEL_START come from gstack-skill-start's echoed STATUS lines
# (inline shell vars never survived across Bash tool calls, so durations were
# already unreliable; passing them explicitly makes them real).
# Error style (F3): per-line `|| true`, never `set -e`.
SKILL_NAME="unknown"; OUTCOME="unknown"; SESSION_ID=""; TEL_START=""
USED_BROWSE="no"; ERROR_MESSAGE=""; FAILED_STEP=""
while [ $# -gt 0 ]; do
case "$1" in
--skill) SKILL_NAME="$2"; shift 2 ;;
--outcome) OUTCOME="$2"; shift 2 ;;
--session-id) SESSION_ID="$2"; shift 2 ;;
--tel-start) TEL_START="$2"; shift 2 ;;
--used-browse) USED_BROWSE="$2"; shift 2 ;;
--error-message) ERROR_MESSAGE="$2"; shift 2 ;;
--failed-step) FAILED_STEP="$2"; shift 2 ;;
-h|--help)
echo 'Usage: gstack-skill-end --skill NAME --outcome success|error|abort|unknown --session-id ID --tel-start EPOCH [--used-browse yes|no] [--error-message MSG] [--failed-step STEP]'
echo 'Records skill completion. --help records nothing.'
exit 0 ;;
*) shift ;;
esac
done
_SCRIPT_DIR=$(cd "$(dirname "$0")" 2>/dev/null && pwd)
_BIN="$_SCRIPT_DIR"
. "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; }
gstack_state_root_select
_GH="$_gstack_sr_root"
_TEL=$("$_BIN/gstack-config" get telemetry 2>/dev/null || echo off)
# Plan B1: an unattended session writes no usage, sends no telemetry and never
# drains or pushes the artifacts queue, whatever the inherited settings say. The
# upgrade offer it skipped at start becomes one line here, read from the
# update-check cache (no network) so the parent can act on it.
_SESSION_KIND=$("$_BIN/gstack-session-kind" 2>/dev/null || echo "interactive")
if [ "$_SESSION_KIND" = "unattended" ]; then
_TEL="off"
_CACHED_UPD=$(head -1 "$_GH/last-update-check" 2>/dev/null | tr -cd 'A-Za-z0-9._ ' || true)
case "$_CACHED_UPD" in
UPGRADE_AVAILABLE*) echo "UPGRADE_AVAILABLE: ${_CACHED_UPD##* }; run /gstack-upgrade"
echo "UPGRADE_COMMAND: $(cd "$_BIN/.." 2>/dev/null && pwd -P)/bin/gstack-upgrade" ;;
esac
echo "ARTIFACTS_SYNC: skipped (unattended session)"
fi
_TEL_END=$(date +%s)
case "$TEL_START" in ''|*[!0-9]*) TEL_START="$_TEL_END" ;; esac
_TEL_DUR=$(( _TEL_END - TEL_START ))
[ -n "$SESSION_ID" ] && rm -f "$_GH/analytics/.pending-$SESSION_ID" 2>/dev/null || true
# Record completion before the final drain, including its durable enqueue.
# The normal sync gates still decide publication: full may sync timelines,
# artifacts-only retains them locally, and unattended never enqueues or drains.
"$_BIN/gstack-timeline-log" '{"skill":"'"$SKILL_NAME"'","event":"completed","branch":"'"$(_b=$(git branch --show-current 2>/dev/null | tr -cd 'a-zA-Z0-9._/-'); echo "${_b:-unknown}")"'","outcome":"'"$OUTCOME"'","duration_s":"'"$_TEL_DUR"'","session":"'"$SESSION_ID"'"}' 2>/dev/null || true
# Skill-end artifacts sync (drain + push; formerly its own inline fence).
if [ "$_SESSION_KIND" != "unattended" ]; then
"$_BIN/gstack-brain-sync" --discover-new 2>/dev/null || true
"$_BIN/gstack-brain-sync" --once 2>/dev/null || true
fi
# Local analytics (gated on telemetry setting).
if [ "$_TEL" != "off" ]; then
echo '{"skill":"'"$SKILL_NAME"'","duration_s":"'"$_TEL_DUR"'","outcome":"'"$OUTCOME"'","browse":"'"$USED_BROWSE"'","session":"'"$SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$_GH/analytics/skill-usage.jsonl" 2>/dev/null || true
fi
# Remote telemetry (opt-in, requires binary).
if [ "$_TEL" != "off" ] && [ -x "$_BIN/gstack-telemetry-log" ]; then
"$_BIN/gstack-telemetry-log" \
--skill "$SKILL_NAME" --duration "$_TEL_DUR" --outcome "$OUTCOME" \
--used-browse "$USED_BROWSE" --session-id "$SESSION_ID" \
--error-message "$ERROR_MESSAGE" --failed-step "$FAILED_STEP" 2>/dev/null &
fi
echo "SKILL_END: recorded outcome=$OUTCOME duration_s=$_TEL_DUR"