-
Notifications
You must be signed in to change notification settings - Fork 0
FSM design-doctor: route every noQuestion ai:design row back to ai:needs-work #242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
56f9888
d6b7efa
2f721af
a44ddba
1a24703
89ab94a
de1050f
77b666b
90d6761
1ecf131
3d9e455
259e4f1
9a34981
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| #!/usr/bin/env bash | ||
| # design-doctor.sh — the FSM doctor pass for the design lane (#241): route every ai:design PR | ||
| # with NO live trusted design question back to ai:needs-work, with the trusted work order | ||
| # (re-flag or proceed) posted at the current head. Detection is next_design's own classifier; | ||
| # the whole pass is ONE tested subcommand (`pr-review-report design-doctor`) and this wrapper | ||
| # only adds what a bare cron invocation cannot: the install-dir env, the org scope from | ||
| # cron.env, stamped logging, and a flock so overlapping ticks never stack. | ||
| # Installed on a daily cron; see crontab (README "Schedule & controls"). | ||
| # Packaged as a flake output (`packages.design-doctor`); `gh` and the binary come from the | ||
| # flake's locked nixpkgs. errexit is turned back off — writeShellApplication forces it, but this | ||
| # script reads the subcommand's exit status as data to log before passing it on. | ||
| set +o errexit | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Files matching design-doctor.sh:\n'
fd -a 'design-doctor\.sh$' . || true
printf '\nGit status/stat:\n'
git diff --stat || true
for f in $(fd 'design-doctor\.sh$' .); do
printf '\n### %s\n' "$f"
wc -l "$f"
sed -n '1,120p' "$f" | cat -n
done
printf '\nSearch timeout usage and flock setup:\n'
rg -n "set \+o errexit|timeout |flock|PR_ASSIGNEE|design-doctor" .Repository: rainlanguage/issue-pr-cron Length of output: 19258 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
path = Path("design-doctor.sh")
src = path.read_text()
print("global_errexit_disabled=", bool(re.search(r"""set\s+[\da-z]*\+o\s+errexit""", src)))
print("errexit_reenabled=", bool(re.search(r"""set\s+[\da-z]*-o\s+errexit""", src)))
lock_line = next((i,l) for i,l in enumerate(src.splitlines(),1) if 'exec 9>"$DIR/.design-doctor.lock"' in l)
print("lock_line=%d" % lock_line[0], lock_line[1])
flock_line = next((i,l) for i,l in enumerate(src.splitlines(),1) if 'flock -n 9 ||' in l)
print("flock_line=%d" % flock_line[0], flock_line[1])
# Show whether no errexit leaves lock setup non-fatal when using || and then exiting.
print("flock_or_exit_is_always_0=", flock_line[1].strip().endswith('|| { log "skipped: a previous tick still holds the lock"; exit 0; }'))
print("exec_redirect_fails_without_errexit_and_reaches_flock_", True)
# Check for any remaining setup failures protected inside critical path:
for i,l in enumerate(src.splitlines(),1):
if l and not l.strip().startswith("#"):
if i < lock_line[0]:
if re.search(r"""(!.*&&|&&.*|or\(|&&|if\b|trap\b|exit\b|set\b)""", l):
print("pre-LOCK guard at %d: %s" % (i,l.strip()))
PYRepository: rainlanguage/issue-pr-cron Length of output: 743 Keep strict failure handling enabled. With global Suggested status handling-set +o errexit
+set -euo pipefail
...
-timeout "$DOCTOR_MAXTIME" pr-review-report design-doctor "$@"
-rc=$?
+if timeout "$DOCTOR_MAXTIME" pr-review-report design-doctor "$@"; then
+ rc=0
+else
+ rc=$?
+fi🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
|
|
||
| # --- locate the install dir + bare-cron env (mirrors refresh-human-queue.sh) --- | ||
| # $0 is a read-only nix store path, so the install dir comes from the crontab's $CRON_DIR, | ||
| # defaulting to the working directory for an interactive run from the checkout. | ||
| DIR="${CRON_DIR:-$PWD}" | ||
| : "${HOME:=$(getent passwd "$(id -un)" | cut -d: -f6)}"; export HOME | ||
| : "${USER:=$(id -un)}"; export USER | ||
| : "${LOGNAME:=$USER}"; export LOGNAME | ||
|
|
||
| # Every line is stamped, same format as the other cron logs, so design-doctor.log can answer | ||
| # "when did this last run / fail". Everything goes to stderr, one stream, so the crontab's | ||
| # `>> …log 2>&1` preserves the order. | ||
| log() { echo "$(date -u +%FT%TZ) design-doctor: $*" >&2; } | ||
|
|
||
| cd "$DIR" || { log "install dir '$DIR' is not usable — set CRON_DIR to the checkout"; exit 1; } | ||
|
|
||
| # --- deployment config (defaults here; override in ./cron.env) --- | ||
| # A hard cap, as both model runners carry (MAXTIME=3h, REVIEW_MAXTIME=2h): an unattended writer | ||
| # with no cap can hold its flock for ever, and every later tick then logs "a previous tick still | ||
| # holds the lock" while nothing drains. This pass is a bounded number of `gh` calls, so its cap is | ||
| # small — long enough for a large backlog on a slow API, short enough that a wedged tick is gone | ||
| # before the next one. | ||
| DOCTOR_MAXTIME="30m" # hard cap per tick | ||
|
|
||
| # Org scope + fleet: single source is cron.env (same as the producer/vetter/refresher). PR_ASSIGNEE | ||
| # is what the pass calls "ours" — it withholds rows outside the fleet rather than routing them into | ||
| # a state no actor enumerates. | ||
| # shellcheck disable=SC1091 | ||
| [ -f cron.env ] && . ./cron.env | ||
| : "${ORGS:=rainlanguage cyclofinance S01-Issuer}"; export ORGS | ||
| export PR_ASSIGNEE | ||
|
Comment on lines
+37
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
rg -n -C 8 'PR_ASSIGNEE|design-doctor' pr-review-report-rs/src/main.rs design-doctor.shRepository: rainlanguage/issue-pr-cron Length of output: 27853 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '--- relevant source slices ---\n'
sed -n '28149,28385p' pr-review-report-rs/src/main.rs
printf '\n--- pr_assignee usages in design doctor tests/logic ---\n'
rg -n 'pr_assignee\(|author|The fleet|fleet|NotOurFleet|not our' pr-review-report-rs/src/main.rs
printf '\n--- behavioral probe of Rust env-resolution and whitespace trim if present in helper context ---\n'
python3 - <<'PY'
# Read-only probe matching the Rust behavior described in source:
# std::env::var falls back only if the variable is absent, not if it is present and empty.
cases = {
'absent': None,
'empty': '',
'zero_length_quoted_like': '',
'single_whitespace': ' ',
'valid': 'thedavidmeister',
}
for name, value in cases.items():
pr_assignee = value if value is not None else 'thedavidmeister'
print(f'{name}: PR_ASSIGNEE={value!r} -> pr_assignee()={pr_assignee!r}')
PYRepository: rainlanguage/issue-pr-cron Length of output: 255 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
# Check whether PR_ASSIGNEE is required/fails closed elsewhere in the shell wrapper or tests.
printf '--- PR_ASSIGNEE references ---\n'
rg -n -E 'PR_ASSIGNEE|export PR_ASSIGNEE|non-empty|require|missing|unset|cron.env' design-doctor.sh pr-review-report-rs/src/main.rs README.md crontab . 2>/dev/null | head -n 200Repository: rainlanguage/issue-pr-cron Length of output: 255 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
echo '--- relevant source slices ---'
sed -n '28149,28385p' pr-review-report-rs/src/main.rs
echo
echo '--- pr_assignee usages in design doctor tests/logic ---'
rg -n 'pr_assignee\(|author|The fleet|fleet|NotOurFleet|not our' pr-review-report-rs/src/main.rs
echo
echo '--- behavioral probe of Rust env-resolution and whitespace trim if present in helper context ---'
python3 - <<'PY'
# Read-only probe matching the Rust env-resolution semantics in source:
# std::env::var returns Err when the variable is absent and Some("") when it is present but empty.
# A ".trim().parse()" fallback then returns the default only for absent keys.
def pr_assignee(value):
if value is None:
return 'thedavidmeister'
return value
for name, value in [
('absent', None),
('empty', ''),
('single_whitespace', ' '),
('valid', 'thedavidmeister'),
('nonexistent_assigned', ''):
pass
]:
print(f'{name}: PR_ASSIGNEE={value!r} -> pr_assignee()={pr_assignee(value)!r}')
PYRepository: rainlanguage/issue-pr-cron Length of output: 42554 Fail closed when
🤖 Prompt for AI Agents |
||
|
|
||
| # --- kill switch --- | ||
| # The producer's own flag, not a third one. The README documents "Pause: touch DISABLED" directly | ||
| # beneath this cron's line, so an operator halting the pipeline believes everything is stopped — | ||
| # and this pass STRIPS LABELS and POSTS TRUSTED COMMENTS across every org in ORGS. A writer that | ||
| # ignores the pause is the one runner whose ticks a halted operator cannot undo. | ||
| if [ -f "$DIR/DISABLED" ]; then | ||
| log "SKIP: DISABLED flag present" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # flock so overlapping ticks never stack. | ||
| exec 9>"$DIR/.design-doctor.lock" | ||
| flock -n 9 || { log "skipped: a previous tick still holds the lock"; exit 0; } | ||
|
|
||
| log "tick start (cap $DOCTOR_MAXTIME)" | ||
| timeout "$DOCTOR_MAXTIME" pr-review-report design-doctor "$@" | ||
| rc=$? | ||
| [ "$rc" -eq 124 ] && log "TIMED OUT after $DOCTOR_MAXTIME — the tick was cut off; rows it had not reached are re-enumerated next tick" | ||
| log "tick end (rc=$rc)" | ||
| exit "$rc" | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🔵 Trivial
Make the cron timezone explicit.
The documentation states 04:00 UTC, but
0 4 * * *uses the cron daemon's local timezone unless the host or crontab sets UTC. Add an explicit UTC setting or verify that every deployment host uses UTC.🤖 Prompt for AI Agents