forgedock 1.19.0 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/bin/engine/phases.mjs +4 -2
- package/bin/engine/telemetry-seam.mjs +1 -1
- package/bin/engine-cli.mjs +40 -1
- package/bin/engine.mjs +48 -3
- package/bin/forgedock.mjs +1 -1
- package/bin/lean/effects.mjs +51 -0
- package/bin/lean/lean.mjs +352 -0
- package/bin/lean/lean.test.mjs +525 -0
- package/bin/lean/prompts.mjs +62 -0
- package/bin/lean/risk.mjs +49 -0
- package/bin/runner.mjs +99 -6
- package/commands/orchestrate/phase-4-execution.md +1 -1
- package/commands/review-pr-agents/protocols.md +19 -0
- package/commands/review-pr.md +7 -6
- package/commands/work-on/build/architect.md +1 -1
- package/commands/work-on/build/implement.md +9 -1
- package/commands/work-on/build/validate.md +14 -7
- package/commands/work-on/build.md +118 -8
- package/commands/work-on/close.md +9 -4
- package/commands/work-on/remediate.md +11 -4
- package/commands/work-on/review.md +12 -4
- package/commands/work-on.md +4 -4
- package/docs/CONFIG.md +8 -1
- package/docs/RELEASE-NOTES.md +21 -0
- package/docs/TELEMETRY.md +2 -2
- package/docs/WORK-ON-RUNTIME.md +11 -3
- package/package.json +2 -2
- package/scripts/architect-resume-match.test.sh +12 -3
- package/scripts/build-knowledge-index.mjs +8 -5
- package/scripts/builder-resume-match.test.sh +12 -3
- package/scripts/calibration.mjs +5 -2
- package/scripts/check-spec-markers.sh +2 -0
- package/scripts/ci-local/lib.mjs +11 -3
- package/scripts/ci-local/run.mjs +155 -49
- package/scripts/ci-local/scoping.mjs +27 -4
- package/scripts/ci-local.sh +3 -2
- package/scripts/ci-local.test.sh +189 -0
- package/scripts/classify-finding.sh +1 -1
- package/scripts/file-deferred-followups.sh +91 -30
- package/scripts/file-deferred-followups.test.sh +101 -8
- package/scripts/lib/telemetry.sh +2 -0
- package/scripts/review-finalize.sh +101 -12
- package/scripts/review-finalize.test.sh +136 -5
- package/scripts/review-roster.sh +18 -5
- package/scripts/review-roster.test.sh +57 -1
- package/scripts/selfreview-plan.sh +86 -0
- package/scripts/selfreview-plan.test.sh +90 -0
- package/scripts/spawn-depth-check.sh +5 -4
- package/scripts/spawn-depth-check.test.sh +3 -0
- package/scripts/telemetry.test.sh +8 -0
- package/scripts/transition-label.sh +26 -0
- package/scripts/verify-phase-trail.test.sh +6 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# selfreview-plan.sh — build-time self-review plan: run or skip, and which roster (forge#3971).
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
#
|
|
6
|
+
# Pure decision script: flags in, key=value lines out. No network, no git, no eval; every flag value is data.
|
|
7
|
+
# It calls scripts/review-roster.sh (resolved through forge_resolve, never from the repo under build) on the staged
|
|
8
|
+
# diff's file list so the self-review roster equals the roster /review-pr would pick for the same diff.
|
|
9
|
+
#
|
|
10
|
+
# Usage: selfreview-plan.sh --files-file PATH|- [--changed-lines N] [--changed-files N] [--contract-flags "HIGH_RISK ..."]
|
|
11
|
+
# [--spec-cli true|false] [--review-depth STANDARD|EXTENDED] [--scores "AUTH=n ..."]
|
|
12
|
+
# [--agent-available true|false] [--tree HASH] [--done-trees "HASH HASH ..."]
|
|
13
|
+
# Env: FORGE_SELFREVIEW=off|0|false|disabled operator off switch
|
|
14
|
+
# Output (stdout, always all four lines):
|
|
15
|
+
# SELFREVIEW=run|skip SKIP_REASON=<reason or empty> TIER=<roster tier or empty> SELECTED_AGENTS=<domains>
|
|
16
|
+
# Skip reasons (first match wins): disabled, empty-diff, docs-only, no-agent-tool, already-done, roster-unavailable,
|
|
17
|
+
# small-security-only (small tier, Security-only roster, no path or contract trigger fired).
|
|
18
|
+
# Exit: 0 for every parseable call, including every degrade-to-skip path (self-review never blocks build); 2 on an unknown flag.
|
|
19
|
+
# Bash 3.2 portable (no mapfile, associative arrays, grep -P).
|
|
20
|
+
set -u
|
|
21
|
+
|
|
22
|
+
FILES_FILE=""; LINES=""; NFILES=""; CFLAGS=""; SPEC_CLI=false; DEPTH=STANDARD; SCORES=""
|
|
23
|
+
AGENT_AVAILABLE=true; TREE=""; DONE_TREES=""
|
|
24
|
+
|
|
25
|
+
while [ $# -gt 0 ]; do
|
|
26
|
+
case "$1" in
|
|
27
|
+
--files-file) FILES_FILE="${2:-}"; shift 2 ;;
|
|
28
|
+
--changed-lines) LINES="${2:-}"; shift 2 ;;
|
|
29
|
+
--changed-files) NFILES="${2:-}"; shift 2 ;;
|
|
30
|
+
--contract-flags) CFLAGS="${2:-}"; shift 2 ;;
|
|
31
|
+
--spec-cli) SPEC_CLI="${2:-false}"; shift 2 ;;
|
|
32
|
+
--review-depth) DEPTH="${2:-STANDARD}"; shift 2 ;;
|
|
33
|
+
--scores) SCORES="${2:-}"; shift 2 ;;
|
|
34
|
+
--agent-available) AGENT_AVAILABLE="${2:-true}"; shift 2 ;;
|
|
35
|
+
--tree) TREE="${2:-}"; shift 2 ;;
|
|
36
|
+
--done-trees) DONE_TREES="${2:-}"; shift 2 ;;
|
|
37
|
+
*) echo "selfreview-plan: unknown argument: $1" >&2; exit 2 ;;
|
|
38
|
+
esac
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
emit() { # <run|skip> <skip reason> <tier> <agents>
|
|
42
|
+
printf 'SELFREVIEW=%s\nSKIP_REASON=%s\nTIER=%s\nSELECTED_AGENTS=%s\n' "$1" "$2" "$3" "$4"
|
|
43
|
+
exit 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
case "$(printf '%s' "${FORGE_SELFREVIEW:-}" | tr '[:upper:]' '[:lower:]')" in
|
|
47
|
+
off|0|false|disabled|no) emit skip disabled "" "" ;;
|
|
48
|
+
esac
|
|
49
|
+
|
|
50
|
+
FILES=""
|
|
51
|
+
if [ "$FILES_FILE" = "-" ]; then FILES=$(cat)
|
|
52
|
+
elif [ -n "$FILES_FILE" ] && [ -f "$FILES_FILE" ]; then FILES=$(cat "$FILES_FILE"); fi
|
|
53
|
+
FILES=$(printf '%s\n' "$FILES" | grep -v '^[[:space:]]*$' || true)
|
|
54
|
+
|
|
55
|
+
[ -n "$FILES" ] || emit skip empty-diff "" ""
|
|
56
|
+
|
|
57
|
+
# Docs-only: every file is documentation. commands/**, .agents/** and skills/** are executable spec, never docs.
|
|
58
|
+
CODE_FILES=$(printf '%s\n' "$FILES" | grep -vE '^(docs/|README|CHANGELOG|LICENSE|NOTICE)|\.(md|txt|rst)$' || true)
|
|
59
|
+
SPEC_FILES=$(printf '%s\n' "$FILES" | grep -E '^(commands|\.agents|skills)/.*\.md$' || true)
|
|
60
|
+
[ -n "$CODE_FILES" ] || [ -n "$SPEC_FILES" ] || emit skip docs-only "" ""
|
|
61
|
+
|
|
62
|
+
[ "$AGENT_AVAILABLE" = "true" ] || emit skip no-agent-tool "" ""
|
|
63
|
+
|
|
64
|
+
if [ -n "$TREE" ]; then
|
|
65
|
+
for _t in $DONE_TREES; do
|
|
66
|
+
[ "$_t" = "$TREE" ] && emit skip already-done "" ""
|
|
67
|
+
done
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
type forge_resolve >/dev/null 2>&1 || { setopt nonomatch 2>/dev/null || true; _SELF_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd -P)"; for _r in "$(cygpath -u "${FORGEDOCK_HOME:-}" 2>/dev/null || printf %s "${FORGEDOCK_HOME:-}")" "${CLAUDE_PLUGIN_ROOT:-}" "${FORGE_ROOT:-}" "${FORGE_HOME:-}" "$(readlink -f "$HOME/.claude/commands/work-on.md" 2>/dev/null | sed 's|/commands/work-on\.md$||')" "$(head -n 1 "${CODEX_HOME:-$HOME/.codex}/forge-home" 2>/dev/null)" "$HOME/.claude/plugins/marketplaces/forgedock" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}"/plugins/cache/forgedock/forgedock/* "$HOME/.claude"/plugins/cache/forgedock/forgedock/* "$_SELF_ROOT"; do case "$_r" in /*) [ -f "$_r/scripts/lib/forge-resolve.sh" ] && { . "$_r/scripts/lib/forge-resolve.sh"; break; };; esac; done; type forge_resolve >/dev/null 2>&1 || forge_resolve() { :; }; } # allowlist:portability — canonical resolver block; readlink -f is guarded (2>/dev/null) and optional
|
|
71
|
+
ROSTER_SCRIPT=$(forge_resolve review-roster.sh)
|
|
72
|
+
[ -n "$ROSTER_SCRIPT" ] && [ -f "$ROSTER_SCRIPT" ] || emit skip roster-unavailable "" ""
|
|
73
|
+
|
|
74
|
+
set -- --files-file - --contract-flags "$CFLAGS" --spec-cli "$SPEC_CLI" --review-depth "$DEPTH"
|
|
75
|
+
[ -n "$LINES" ] && set -- "$@" --changed-lines "$LINES"
|
|
76
|
+
[ -n "$NFILES" ] && set -- "$@" --changed-files "$NFILES"
|
|
77
|
+
[ -n "$SCORES" ] && set -- "$@" --scores "$SCORES"
|
|
78
|
+
OUT=$(printf '%s\n' "$FILES" | bash "$ROSTER_SCRIPT" "$@" 2>/dev/null) || emit skip roster-unavailable "" ""
|
|
79
|
+
|
|
80
|
+
SEL=$(printf '%s\n' "$OUT" | sed -n 's/^SELECTED_AGENTS=//p' | head -n 1)
|
|
81
|
+
TIER=$(printf '%s\n' "$OUT" | sed -n 's/^TIER=//p' | head -n 1)
|
|
82
|
+
[ -n "$SEL" ] && [ -n "$TIER" ] || emit skip roster-unavailable "" ""
|
|
83
|
+
|
|
84
|
+
# Cost guard: the small tier runs only when a path or contract trigger widened the roster past Security.
|
|
85
|
+
if [ "$TIER" = "small" ] && [ "$SEL" = "security" ]; then emit skip small-security-only "$TIER" "$SEL"; fi
|
|
86
|
+
emit run "" "$TIER" "$SEL"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios
|
|
3
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
#
|
|
5
|
+
# Tests for scripts/selfreview-plan.sh (build-time self-review plan, forge#3971). Run: bash scripts/selfreview-plan.test.sh
|
|
6
|
+
# (bash 3.2 compatible)
|
|
7
|
+
set -u
|
|
8
|
+
DIR=$(cd "$(dirname "$0")" && pwd)
|
|
9
|
+
ROOT=$(cd "$DIR/.." && pwd)
|
|
10
|
+
SCRIPT="$DIR/selfreview-plan.sh"
|
|
11
|
+
pass=0; fail=0
|
|
12
|
+
ok() { pass=$((pass+1)); }
|
|
13
|
+
bad() { fail=$((fail+1)); echo "FAIL: $1"; }
|
|
14
|
+
WORK=$(mktemp -d "${TMPDIR:-/tmp}/selfreview-plan.XXXXXX")
|
|
15
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
16
|
+
export FORGEDOCK_HOME="$ROOT" # the resolver must not pick up an ambient install
|
|
17
|
+
unset FORGE_SELFREVIEW
|
|
18
|
+
|
|
19
|
+
PLAN=""; RC=0
|
|
20
|
+
# run <files, newline separated> <flags...>
|
|
21
|
+
run() {
|
|
22
|
+
printf '%s\n' "$1" > "$WORK/files"; shift
|
|
23
|
+
PLAN=$(bash "$SCRIPT" --files-file "$WORK/files" "$@" 2>/dev/null); RC=$?
|
|
24
|
+
}
|
|
25
|
+
field() { printf '%s\n' "$PLAN" | sed -n "s/^$1=//p"; }
|
|
26
|
+
expect() { # name key want
|
|
27
|
+
local got; got=$(field "$2")
|
|
28
|
+
if [ "$got" = "$3" ]; then ok; else bad "$1: $2='$got', want '$3'"; fi
|
|
29
|
+
}
|
|
30
|
+
has_agent() { case " $(field SELECTED_AGENTS) " in *" $1 "*) return 0 ;; *) return 1 ;; esac; }
|
|
31
|
+
|
|
32
|
+
# e1: docs-only and empty diffs skip with a recorded reason
|
|
33
|
+
run "docs/GUIDE.md
|
|
34
|
+
README.md" --changed-lines 40
|
|
35
|
+
expect "docs-only skips" SELFREVIEW skip; expect "docs-only reason" SKIP_REASON docs-only
|
|
36
|
+
run "" --changed-lines 0
|
|
37
|
+
expect "empty diff skips" SELFREVIEW skip; expect "empty reason" SKIP_REASON empty-diff
|
|
38
|
+
run "commands/work-on/build.md" --changed-lines 40 --changed-files 1
|
|
39
|
+
expect "spec markdown is not docs" SELFREVIEW skip
|
|
40
|
+
if [ "$(field SKIP_REASON)" = "docs-only" ]; then bad "commands/*.md treated as docs"; else ok; fi
|
|
41
|
+
|
|
42
|
+
# e2: small tier, Security-only roster, no trigger: skipped; the same size with an auth path runs
|
|
43
|
+
run "scripts/foo.sh" --changed-lines 30 --changed-files 1
|
|
44
|
+
expect "small security-only skips" SELFREVIEW skip; expect "small reason" SKIP_REASON small-security-only; expect "small tier" TIER small
|
|
45
|
+
run "src/auth/session.py
|
|
46
|
+
src/util.py" --changed-lines 30 --changed-files 2
|
|
47
|
+
expect "small + auth path runs" SELFREVIEW run; expect "small + auth tier" TIER small
|
|
48
|
+
has_agent auth && ok || bad "auth path did not add auth"
|
|
49
|
+
has_agent security && ok || bad "security floor missing"
|
|
50
|
+
run "scripts/foo.sh
|
|
51
|
+
scripts/bar.sh" --changed-lines 30 --changed-files 2 --contract-flags "HIGH_RISK"
|
|
52
|
+
expect "small + HIGH_RISK runs" SELFREVIEW run; expect "HIGH_RISK lifts tier" TIER standard
|
|
53
|
+
|
|
54
|
+
# standard tier runs
|
|
55
|
+
run "scripts/foo.sh
|
|
56
|
+
scripts/bar.sh" --changed-lines 400 --changed-files 2
|
|
57
|
+
expect "standard runs" SELFREVIEW run; expect "standard tier" TIER standard; expect "standard no reason" SKIP_REASON ""
|
|
58
|
+
has_agent security && ok || bad "standard roster lacks security"
|
|
59
|
+
|
|
60
|
+
# EXTENDED depth lifts a small roster
|
|
61
|
+
run "scripts/foo.sh" --changed-lines 20 --changed-files 1 --review-depth EXTENDED
|
|
62
|
+
expect "extended depth runs" SELFREVIEW run; expect "extended tier" TIER standard
|
|
63
|
+
|
|
64
|
+
# e3: off switch, no Agent tool, unresolvable roster degrade to skip and exit 0
|
|
65
|
+
FORGE_SELFREVIEW=off run "scripts/a.sh
|
|
66
|
+
scripts/b.sh" --changed-lines 400
|
|
67
|
+
[ "$RC" = 0 ] && ok || bad "off exit code $RC"
|
|
68
|
+
expect "off skips" SELFREVIEW skip; expect "off reason" SKIP_REASON disabled
|
|
69
|
+
run "scripts/a.sh
|
|
70
|
+
scripts/b.sh" --changed-lines 400 --agent-available false
|
|
71
|
+
[ "$RC" = 0 ] && ok || bad "no-agent exit code $RC"
|
|
72
|
+
expect "no agent skips" SELFREVIEW skip; expect "no agent reason" SKIP_REASON no-agent-tool
|
|
73
|
+
FORGEDOCK_HOME=/nonexistent-forge-home run "scripts/a.sh
|
|
74
|
+
scripts/b.sh" --changed-lines 400
|
|
75
|
+
[ "$RC" = 0 ] && ok || bad "unresolvable exit code $RC"
|
|
76
|
+
expect "unresolvable roster skips" SELFREVIEW skip; expect "unresolvable reason" SKIP_REASON roster-unavailable
|
|
77
|
+
|
|
78
|
+
# e4: a tree that already has a completed self-review is not dispatched again
|
|
79
|
+
run "scripts/a.sh
|
|
80
|
+
scripts/b.sh" --changed-lines 400 --tree aaa --done-trees "bbb aaa"
|
|
81
|
+
expect "same tree skips" SELFREVIEW skip; expect "same tree reason" SKIP_REASON already-done
|
|
82
|
+
run "scripts/a.sh
|
|
83
|
+
scripts/b.sh" --changed-lines 400 --tree ccc --done-trees "bbb aaa"
|
|
84
|
+
expect "new tree runs" SELFREVIEW run
|
|
85
|
+
|
|
86
|
+
# usage: unknown flag exits 2
|
|
87
|
+
bash "$SCRIPT" --nope >/dev/null 2>&1; [ "$?" = 2 ] && ok || bad "unknown flag should exit 2"
|
|
88
|
+
|
|
89
|
+
echo "selfreview-plan: ${pass} passed, ${fail} failed"
|
|
90
|
+
[ "$fail" -eq 0 ]
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# spawn-depth-check.sh — will a /work-on dispatching phase (review, remediate) have the Agent tool?
|
|
2
|
+
# spawn-depth-check.sh — will a /work-on dispatching phase (build self-review, review, remediate) have the Agent tool?
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
#
|
|
6
6
|
# Claude Code grants the Agent tool to sub-agents down to CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH layers
|
|
7
7
|
# below the main conversation (default 3 since 2.1.219; 5 for 2.1.172-2.1.216; 1 for 2.1.217-2.1.218).
|
|
8
|
-
# A sub-agent at layer L can spawn only when L < depth. The router invokes review/remediate at
|
|
8
|
+
# A sub-agent at layer L can spawn only when L < depth. The router invokes build/review/remediate at
|
|
9
9
|
# router layer + 1, so they can spawn reviewers only when router layer + 2 <= depth (forge#3398,
|
|
10
|
-
# docs/WORK-ON-RUNTIME.md).
|
|
10
|
+
# docs/WORK-ON-RUNTIME.md). build (B5.6 self-review, forge#3971) uses the same arithmetic but degrades to a recorded
|
|
11
|
+
# skip on FAIL instead of stopping the run.
|
|
11
12
|
#
|
|
12
13
|
# Usage: spawn-depth-check.sh [--router-layer N] (N = 0 solo, 1 under /orchestrate; default 0)
|
|
13
14
|
# Env: CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH explicit limit (wins over the version default)
|
|
@@ -69,5 +70,5 @@ if [ "$DEPTH" -ge "$REQUIRED" ]; then
|
|
|
69
70
|
echo "SPAWN_DEPTH: OK depth=${DEPTH} required=${REQUIRED} (${SOURCE})"
|
|
70
71
|
exit 0
|
|
71
72
|
fi
|
|
72
|
-
echo "SPAWN_DEPTH: FAIL depth=${DEPTH} required=${REQUIRED} (${SOURCE}) — review/remediate would run without the Agent tool and could not spawn /review-pr reviewers. Set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH>=${REQUIRED}."
|
|
73
|
+
echo "SPAWN_DEPTH: FAIL depth=${DEPTH} required=${REQUIRED} (${SOURCE}) — build/review/remediate would run without the Agent tool and could not spawn self-review or /review-pr reviewers. Set CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH>=${REQUIRED}."
|
|
73
74
|
exit 1
|
|
@@ -43,5 +43,8 @@ t "env depth 09 decimal" 0 "SPAWN_DEPTH: OK" CLAUDE_CODE_MAX_SUBA
|
|
|
43
43
|
# Usage errors.
|
|
44
44
|
t "bad router layer" 2 "spawn-depth-check:" -- --router-layer x
|
|
45
45
|
t "unknown flag" 2 "usage:" -- --nope
|
|
46
|
+
# forge#3971: build is a dispatching phase too, and the FAIL text names it (exit codes unchanged)
|
|
47
|
+
out=$(env -u CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH -u FORGE_RUNTIME FORGE_CLAUDE_VERSION=2.1.217 bash "$S" 2>&1)
|
|
48
|
+
case "$out" in *build/review/remediate*) PASS=$((PASS+1)) ;; *) FAILN=$((FAILN+1)); echo "FAIL: FAIL text does not name build ($out)" ;; esac
|
|
46
49
|
echo "spawn-depth-check: ${PASS} passed, ${FAILN} failed"
|
|
47
50
|
[ "$FAILN" -eq 0 ]
|
|
@@ -61,6 +61,14 @@ check "finding_disposition carries scope" "$(grep '^{' "$TD/posted" | jq -r '.sc
|
|
|
61
61
|
reset; FORGE_PR=9 forge_emit review_panel mode=FULL; grep -q 'issues/9/comments' "$TD/calls" && ok || bad "review_panel targets PR"
|
|
62
62
|
reset; FORGE_PR=9 forge_emit diff_size lines=1; grep -q 'issues/5/comments' "$TD/calls" && ok || bad "diff_size targets issue"
|
|
63
63
|
|
|
64
|
+
# build_selfreview (forge#3971) is a build-side event: posted to the issue even when a PR number is set; ids and counts only
|
|
65
|
+
reset; FORGE_PR=9 forge_emit build_selfreview tier=standard agents=3 findings=4 fixed=2 declined=1 skipped=
|
|
66
|
+
grep -q 'issues/5/comments' "$TD/calls" && ok || bad "build_selfreview targets issue"
|
|
67
|
+
REC=$(grep '^{' "$TD/posted")
|
|
68
|
+
check "build_selfreview event" "$(printf '%s' "$REC" | jq -r '.event')" "build_selfreview"
|
|
69
|
+
check "build_selfreview counts typed" "$(printf '%s' "$REC" | jq -r '.agents + .findings + .fixed + .declined')" "10"
|
|
70
|
+
check "build_selfreview skip reason" "$(reset; forge_emit build_selfreview skipped=small-security-only tier=small; grep '^{' "$TD/posted" | jq -r '.skipped')" "small-security-only"
|
|
71
|
+
|
|
64
72
|
# 2. Sanitising: reserved keys, bad keys, backticks and newlines never reach the record.
|
|
65
73
|
reset
|
|
66
74
|
forge_emit x repo=evil 'a b=1' ok='a`b
|
|
@@ -278,6 +278,32 @@ fi
|
|
|
278
278
|
# ---------------------------------------------------------------------------
|
|
279
279
|
# Add target label
|
|
280
280
|
# ---------------------------------------------------------------------------
|
|
281
|
+
# forge#3567: `gh issue edit --add-label` fails when the label is absent from the repo (a
|
|
282
|
+
# consumer repo not re-synced via `forgedock labels setup`), aborting the transition under
|
|
283
|
+
# `set -e`. Best-effort ensure first: `--force` is a create-or-update, a failure (permissions,
|
|
284
|
+
# rate limit, concurrent create) is ignored so the add below surfaces its own error. Only
|
|
285
|
+
# ForgeDock-managed names are created (fixed table mirroring bin/labels.json, kept in sync by
|
|
286
|
+
# bin/tests/label-bootstrap.test.mjs); a custom FORGE_LABEL_MAP name is never created.
|
|
287
|
+
ensure_label() {
|
|
288
|
+
local name="$1" LBL_COLOR="" LBL_DESC=""
|
|
289
|
+
case "$name" in
|
|
290
|
+
"workflow:investigating") LBL_COLOR="1D76DB"; LBL_DESC="Pipeline: investigation phase in progress. Managed by ForgeDock." ;;
|
|
291
|
+
"workflow:ready-to-build") LBL_COLOR="0075CA"; LBL_DESC="Pipeline: investigation complete, ready for build. Managed by ForgeDock." ;;
|
|
292
|
+
"workflow:building") LBL_COLOR="0052CC"; LBL_DESC="Pipeline: implementation in progress. Managed by ForgeDock." ;;
|
|
293
|
+
"workflow:in-review") LBL_COLOR="5319E7"; LBL_DESC="Pipeline: PR created, under review. Managed by ForgeDock." ;;
|
|
294
|
+
"workflow:remediating") LBL_COLOR="C5DEF5"; LBL_DESC="Pipeline: autonomous remediation pending (no human action needed). Managed by ForgeDock." ;;
|
|
295
|
+
"workflow:awaiting-merge") LBL_COLOR="FF8C00"; LBL_DESC="Pipeline: remediated + re-reviewed, awaiting a human merge decision. Managed by ForgeDock." ;;
|
|
296
|
+
"workflow:merged") LBL_COLOR="0E8A16"; LBL_DESC="Pipeline: PR merged, issue closed. Managed by ForgeDock." ;;
|
|
297
|
+
"workflow:decomposed") LBL_COLOR="BFD4F2"; LBL_DESC="Pipeline: decomposed into sub-issues. Managed by ForgeDock." ;;
|
|
298
|
+
"workflow:invalid") LBL_COLOR="CCCCCC"; LBL_DESC="Pipeline: issue closed as invalid after investigation. Managed by ForgeDock." ;;
|
|
299
|
+
"needs-human") LBL_COLOR="E4E669"; LBL_DESC="Pipeline stalled — requires human intervention. Managed by ForgeDock." ;;
|
|
300
|
+
"workflow:engine-error") LBL_COLOR="B60205"; LBL_DESC="Pipeline stalled — engine/tool failure (not a genuine human-judgment block). Managed by ForgeDock." ;;
|
|
301
|
+
*) return 0 ;;
|
|
302
|
+
esac
|
|
303
|
+
gh label create "$name" --color "$LBL_COLOR" --description "$LBL_DESC" --force "${GH_ARGS[@]}" >/dev/null 2>&1 || true
|
|
304
|
+
}
|
|
305
|
+
ensure_label "$EFFECTIVE_LABEL"
|
|
306
|
+
|
|
281
307
|
echo "Adding $EFFECTIVE_LABEL to issue #$ISSUE_NUMBER..."
|
|
282
308
|
gh issue edit "$ISSUE_NUMBER" "${GH_ARGS[@]}" --add-label "$EFFECTIVE_LABEL"
|
|
283
309
|
|
|
@@ -58,6 +58,7 @@ mk() {
|
|
|
58
58
|
FP_*) items+=("{\"body\":\"<!-- FORGE:FAST_PATH -->\\n**COMPLEXITY_BAND**: ${k#FP_}\"}") ;;
|
|
59
59
|
QUOTED) items+=('{"body":"see `<!-- FORGE:CONTRACT -->` `<!-- FORGE:CONTEXT -->` `<!-- FORGE:ARCHITECT -->` `<!-- FORGE:QUALITY_GATE -->` **Result**: PASS"}') ;;
|
|
60
60
|
INV_INVALID) items+=('{"body":"<!-- FORGE:INVESTIGATOR -->\nInvalid\n<!-- INVESTIGATION:INVALID -->"}') ;;
|
|
61
|
+
SR) items+=('{"body":"<!-- FORGE:SELFREVIEW-AGENT:security -->\nTree: abc\n<!-- REVIEW-FINDINGS-START -->\n<!-- REVIEW-FINDINGS-END -->"}' '{"body":"<!-- FORGE:SELFREVIEW -->\n## Self-review\nTree: abc"}') ;;
|
|
61
62
|
PROSE) items+=('{"body":"I ran the architect and context inline; FORGE:CONTEXT FORGE:ARCHITECT FORGE:QUALITY_GATE done"}') ;;
|
|
62
63
|
esac
|
|
63
64
|
done
|
|
@@ -82,6 +83,11 @@ expect_pass "lowercase band is accepted" "$(mk lower INV CONTRACT FP_trivial QG_
|
|
|
82
83
|
expect_pass "Investigation band passes with only INVESTIGATOR+FAST_PATH" "$(mk invest INV FP_INVESTIGATION)"
|
|
83
84
|
expect_pass "docs-only waives QUALITY_GATE" "$(mk docs INV CONTRACT FP_TRIVIAL)" --docs-only
|
|
84
85
|
|
|
86
|
+
# forge#3971: build-time self-review comments are tolerated but never satisfy a required phase marker
|
|
87
|
+
expect_pass "self-review comments do not disturb a full trail" "$(mk sr1 INV CONTRACT FP_COMPLEX CONTEXT ARCH QG_PASS SR)"
|
|
88
|
+
expect_fail "self-review comments do not stand in for QUALITY_GATE" "$(mk sr2 INV CONTRACT FP_COMPLEX CONTEXT ARCH SR)" QUALITY_GATE
|
|
89
|
+
expect_fail "self-review comments do not stand in for CONTEXT" "$(mk sr3 INV CONTRACT FP_STANDARD ARCH QG_PASS SR)" CONTEXT
|
|
90
|
+
|
|
85
91
|
expect_fail "missing INVESTIGATOR" "$(mk a CONTRACT FP_COMPLEX CONTEXT ARCH QG_PASS)" INVESTIGATOR
|
|
86
92
|
expect_fail "partial investigation (no COMPLETE) fails" "$(mk b INV_PARTIAL CONTRACT FP_COMPLEX CONTEXT ARCH QG_PASS)" INVESTIGATOR
|
|
87
93
|
expect_fail "missing CONTRACT" "$(mk c INV FP_COMPLEX CONTEXT ARCH QG_PASS)" CONTRACT
|