@@ -203,32 +203,36 @@ want() {
203203 return 1
204204}
205205
206- # A hard failure anywhere outweighs a success line: assistants often retry and
207- # print both, and we care whether the run hit a wall at all.
206+ # Returns STATUS|CATEGORY|detail. The category is the trackable part: it says which
207+ # known failure mode was hit, so counts can be compared across runs and branches.
208+ # A hard failure anywhere outweighs a success line, since assistants often retry
209+ # and print both, and we care whether the run hit a wall at all.
208210classify () {
209211 local log=" $1 " rc=" $2 "
210- grep -qiE " unknown flag|unknown command" " $log " 2> /dev/null && { echo " FAIL|bad flag or unsupported command" ; return ; }
211- grep -qi " connection issue" " $log " 2> /dev/null && { echo " FAIL|connection issue (denied token-cache write?)" ; return ; }
212- grep -qiE " no profiles found|no active profile" " $log " 2> /dev/null && { echo " FAIL|no usable Foundry profile" ; return ; }
213- grep -qE " APP ID|App ID" " $log " 2> /dev/null && { echo " PASS|listed apps" ; return ; }
214- { [ " $rc " -eq 124 ] || [ " $rc " -eq 137 ]; } && { echo " TIMEOUT|exceeded ${TIMEOUT} s" ; return ; }
215- [ " $rc " -ne 0 ] && { echo " FAIL|exited $rc without reaching the tenant" ; return ; }
216- echo " UNKNOWN|finished but printed no app list"
212+ grep -qiE " unknown flag|unknown command" " $log " 2> /dev/null && { echo " FAIL|flag|rejected a CLI flag" ; return ; }
213+ grep -qi " connection issue" " $log " 2> /dev/null && { echo " FAIL|connection|connection issue (denied token-cache write?)" ; return ; }
214+ grep -qiE " no TTY available|could not open a new TTY|device not configured" " $log " 2> /dev/null && { echo " FAIL|tty|CLI demanded a TTY" ; return ; }
215+ grep -qiE " not inside a trusted directory|skip-git-repo-check" " $log " 2> /dev/null && { echo " FAIL|trust|refused to run in this directory" ; return ; }
216+ grep -qiE " no profiles found|no active profile" " $log " 2> /dev/null && { echo " FAIL|profile|no usable Foundry profile" ; return ; }
217+ grep -qE " APP ID|App ID" " $log " 2> /dev/null && { echo " PASS|ok|listed apps" ; return ; }
218+ { [ " $rc " -eq 124 ] || [ " $rc " -eq 137 ]; } && { echo " TIMEOUT|timeout|exceeded ${TIMEOUT} s" ; return ; }
219+ [ " $rc " -ne 0 ] && { echo " FAIL|other|exited $rc without reaching the tenant" ; return ; }
220+ echo " UNKNOWN|other|finished but printed no app list"
217221}
218222
219223head2 " Running"
220224info " tenant check: foundry apps list · timeout ${TIMEOUT} s · logs in ${LOG_DIR/# $HOME / \~ } "
221225printf ' \n'
222226
223- RESULTS=(); FAILURES=0; TESTED=0
227+ RESULTS=(); CATEGORIES=() ; FAILURES=0; TESTED=0
224228
225229for entry in " ${ASSISTANTS[@]} " ; do
226230 IFS=' |' read -r name bin source argv <<< " $entry"
227231 want " $name " || continue
228232
229233 if ! command -v " $bin " > /dev/null 2>&1 ; then
230234 printf ' %s%-16s SKIP%s %s not installed\n' " $DIM " " $name " " $RESET " " $bin "
231- RESULTS+=(" $name |SKIP|not installed|0|none" )
235+ RESULTS+=(" $name |SKIP|skip| not installed|0|none" )
232236 continue
233237 fi
234238
@@ -253,7 +257,7 @@ for entry in "${ASSISTANTS[@]}"; do
253257
254258 if [ " $source " = " ~/.agents/skills" ]; then unlink_repo_skills; fi
255259
256- IFS=' |' read -r status detail <<< " $(classify " $log " " $rc " )"
260+ IFS=' |' read -r status category detail <<< " $(classify " $log " " $rc " )"
257261 case " $status " in
258262 PASS) printf ' \r %s%-16s%s %s%sPASS%s %-42s %s%ss%s\n' \
259263 " $BOLD " " $name " " $RESET " " $BOLD " " $GREEN " " $RESET " " $detail " " $DIM " " $elapsed " " $RESET " ;;
@@ -266,25 +270,40 @@ for entry in "${ASSISTANTS[@]}"; do
266270 esac
267271 info " source: $source · log: ${log/# $HOME / \~ } "
268272
269- RESULTS+=(" $name |$status |$detail |$elapsed |$source " )
273+ [ " $status " != " PASS" ] && CATEGORIES+=(" $category " )
274+ RESULTS+=(" $name |$status |$category |$detail |$elapsed |$source " )
270275 TESTED=$(( TESTED+ 1 ))
271276done
272277
273278head2 " Summary"
274279if [ " $TESTED " -eq 0 ]; then
275280 printf ' no assistants tested\n'
276281elif [ " $FAILURES " -eq 0 ]; then
277- printf ' %sall %s tested assistant(s) reached the tenant%s\n' " $GREEN " " $TESTED " " $RESET "
282+ printf ' %s %s of %s reached the tenant%s\n' " $GREEN " " $TESTED " " $TESTED " " $RESET "
278283else
279- printf ' %s%s of %s failed%s\n' " $RED " " $FAILURES " " $TESTED " " $RESET "
280- # Only offer the token-cache explanation when a run actually hit that error.
281- if printf ' %s\n' " ${RESULTS[@]} " | grep -q " connection issue" ; then
282- info ' A "connection issue" failure means the sandbox denied the CLI its'
283- info ' token-cache write to ~/.config/foundry/ — see debugging-workflows.'
284+ printf ' %s%s of %s reached the tenant%s · %s%s failed%s\n' \
285+ " $GREEN " " $(( TESTED- FAILURES)) " " $TESTED " " $RESET " " $RED " " $FAILURES " " $RESET "
286+ printf ' \n %sfailures by cause%s\n' " $BOLD " " $RESET "
287+ # Counts per known failure mode, worth tracking run to run.
288+ printf ' %s\n' ${CATEGORIES[@]+" ${CATEGORIES[@]} " } | sort | uniq -c | sort -rn | while read -r n cat; do
289+ case " $cat " in
290+ connection) label=" connection issue — denied token-cache write" ; col=$RED ;;
291+ tty) label=" TTY demanded by the CLI" ; col=$MAGENTA ;;
292+ flag) label=" unsupported CLI flag" ; col=$YELLOW ;;
293+ trust) label=" refused to run in the test directory" ; col=$YELLOW ;;
294+ profile) label=" no usable Foundry profile" ; col=$YELLOW ;;
295+ timeout) label=" timed out" ; col=$YELLOW ;;
296+ * ) label=" other" ; col=$DIM ;;
297+ esac
298+ printf ' %s%s×%s %s%s%s\n' " $BOLD " " $n " " $RESET " " $col " " $label " " $RESET "
299+ done
300+ printf ' \n'
301+ if printf ' %s\n' ${CATEGORIES[@]+" ${CATEGORIES[@]} " } | grep -qx connection; then
302+ info ' A connection issue means the sandbox denied the CLI its token-cache'
303+ info ' write to ~/.config/foundry/ — see debugging-workflows.'
284304 [ " $EXPIRE_TOKEN " -eq 0 ] && info ' Re-run with --expire-token to force that path on every trial.'
285305 else
286- info ' No connection-issue failures — read the logs above; the cause is'
287- info ' something other than the token cache.'
306+ info ' No connection or TTY failures. Read the logs above.'
288307 fi
289308fi
290309
@@ -294,10 +313,10 @@ if [ -n "$SAVE_FILE" ]; then
294313 " $TIMEOUT " " $ISOLATE " " $EXPIRE_TOKEN "
295314 first=1
296315 for r in " ${RESULTS[@]} " ; do
297- IFS=' |' read -r n s d e src <<< " $r"
316+ IFS=' |' read -r n st cat d e src <<< " $r"
298317 [ $first -eq 0 ] && printf ' ,\n' ; first=0
299- printf ' {"assistant": "%s", "status": "%s", "detail": "%s", "seconds": %s, "source": "%s"}' \
300- " $n " " $s " " $d " " $e " " $src "
318+ printf ' {"assistant": "%s", "status": "%s", "category": "%s", " detail": "%s", "seconds": %s, "source": "%s"}' \
319+ " $n " " $st " " $cat " " $d " " $e " " $src "
301320 done
302321 printf ' \n ]\n}\n'
303322 } > " $SAVE_FILE "
0 commit comments