forgedock 1.16.0 → 1.16.2

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.
Files changed (39) hide show
  1. package/bin/engine/phases.mjs +69 -15
  2. package/bin/engine/runlog.mjs +21 -3
  3. package/bin/engine.mjs +43 -7
  4. package/bin/runner.mjs +21 -2
  5. package/commands/forge-stats.md +2 -2
  6. package/commands/orchestrate/phase-1-resolve.md +6 -40
  7. package/commands/orchestrate/phase-4-execution.md +26 -162
  8. package/commands/quality-gate.md +12 -80
  9. package/commands/review-pr-staging.md +67 -301
  10. package/commands/review-pr.md +150 -752
  11. package/commands/work-on/build/validate.md +6 -40
  12. package/commands/work-on/build.md +82 -40
  13. package/commands/work-on/close.md +7 -22
  14. package/commands/work-on/decompose.md +8 -24
  15. package/commands/work-on/investigate.md +18 -29
  16. package/commands/work-on/remediate.md +38 -147
  17. package/commands/work-on/review.md +25 -42
  18. package/commands/work-on.md +13 -63
  19. package/docs/CONFIG.md +10 -7
  20. package/docs/RELEASE-NOTES.md +6 -0
  21. package/docs/WORK-ON-RUNTIME.md +1 -1
  22. package/docs/spec/forge-protocol-v1.md +1 -1
  23. package/package.json +1 -1
  24. package/scripts/check-spec-markers.sh +2 -0
  25. package/scripts/check-spec-size.sh +47 -27
  26. package/scripts/check-spec-size.test.sh +46 -3
  27. package/scripts/diff-size.sh +36 -3
  28. package/scripts/diff-size.test.sh +47 -0
  29. package/scripts/forge-root.test.sh +218 -91
  30. package/scripts/lib/fence-bootstrap.sh +16 -0
  31. package/scripts/lib/forge-resolve.sh +96 -0
  32. package/scripts/lib/review-delta-mode.sh +41 -0
  33. package/scripts/lint-dispatch-prompt.test.sh +3 -3
  34. package/scripts/remediate-liveness.sh +96 -0
  35. package/scripts/review-acceptance-gate.sh +132 -0
  36. package/scripts/review-acceptance-gate.test.sh +90 -0
  37. package/scripts/review-pr-delta-wiring.test.sh +24 -7
  38. package/scripts/review-pr-staging-scope.test.sh +14 -7
  39. package/scripts/spec-no-worktree-script.test.sh +1 -1
@@ -19,8 +19,14 @@
19
19
  # lockfiles (package-lock.json yarn.lock pnpm-lock.yaml Cargo.lock poetry.lock uv.lock go.sum Gemfile.lock
20
20
  # composer.lock), *.min.*, *.snap, root-anchored dist/ build/ generated/ fixtures/ vendor/, any-depth
21
21
  # __generated__/ __snapshots__/
22
- # Output (stdout, key=value lines): diff_lines=N excluded_lines=M threshold=T over=true|false, then up to 10
22
+ # Output (stdout, key=value lines): diff_lines=N excluded_lines=M threshold=T over=true|false, then the cohesion
23
+ # measure new_lines=N test_lines=N cohesive_lines=N cohesive=true|false, then up to 10
23
24
  # "top=<lines> <path>" lines, largest first. threshold 0 disables the gate (over=false always).
25
+ # Cohesion (forge#3790) counts only non-excluded files. new_lines = lines in files ADDED by the diff;
26
+ # test_lines = lines in test files (a test/ tests/ __tests__/ directory segment, *.test.* *.spec.* test_* *_test.*
27
+ # by basename); cohesive_lines = the union (a new test file counts once). cohesive=true when diff_lines>0 and
28
+ # cohesive_lines*100 >= 70*diff_lines and diff_lines <= threshold*3/2 (integer math; threshold 0 -> false).
29
+ # Test lines are classified, never discounted from diff_lines.
24
30
  # Exit: 0 measured (even when over); 2 usage or git failure with EMPTY stdout (fail closed: unknown is not zero).
25
31
 
26
32
  set -euo pipefail
@@ -62,7 +68,21 @@ MB="$(git -C "$REPO_PATH" merge-base HEAD "origin/$BASE" 2>/dev/null)" && [ -n "
62
68
  RAW="$(git -C "$REPO_PATH" diff --cached --numstat --no-renames -z "$MB" -- | tr '\0' '\001')" \
63
69
  || die "git diff against merge base $MB failed"
64
70
 
65
- TOTAL=0; EXCL=0; LIST=""
71
+ ADDED="$(git -C "$REPO_PATH" diff --cached --diff-filter=A --no-renames --name-only -z "$MB" -- | tr '\0' '\001')" \
72
+ || die "git diff --diff-filter=A against merge base $MB failed"
73
+ is_added() { # path -> 0 when the diff adds the file
74
+ case "$ADDED_SET" in *$'\001'"$1"$'\001'*) return 0 ;; esac
75
+ return 1
76
+ }
77
+ is_test() { # path -> 0 when it is a test file (directory segments exact, name patterns on the basename)
78
+ local p="$1" b="${1##*/}"
79
+ case "/$p" in */test/*|*/tests/*|*/__tests__/*) return 0 ;; esac
80
+ case "$b" in *.test.*|*.spec.*|test_*|*_test.*) return 0 ;; esac
81
+ return 1
82
+ }
83
+ ADDED_SET=$'\001'"$ADDED"
84
+
85
+ TOTAL=0; EXCL=0; LIST=""; NEWL=0; TESTL=0; COHL=0
66
86
  # -z numstat records are "added<TAB>deleted<TAB>path" separated by NUL (translated to \001 above).
67
87
  while IFS= read -r -d $'\001' rec; do
68
88
  [ -n "$rec" ] || continue
@@ -70,7 +90,13 @@ while IFS= read -r -d $'\001' rec; do
70
90
  case "$a" in ''|*[!0-9]*) a=0 ;; esac
71
91
  case "$d" in ''|*[!0-9]*) d=0 ;; esac
72
92
  n=$((a + d))
73
- if excluded "$path"; then EXCL=$((EXCL + n)); else TOTAL=$((TOTAL + n)); LIST="${LIST}${n} ${path}"$'\n'; fi
93
+ if excluded "$path"; then EXCL=$((EXCL + n)); else
94
+ TOTAL=$((TOTAL + n)); LIST="${LIST}${n} ${path}"$'\n'
95
+ isn=0; ist=0
96
+ if is_added "$path"; then isn=1; NEWL=$((NEWL + n)); fi
97
+ if is_test "$path"; then ist=1; TESTL=$((TESTL + n)); fi
98
+ if [ "$isn" = 1 ] || [ "$ist" = 1 ]; then COHL=$((COHL + n)); fi
99
+ fi
74
100
  done <<< "$RAW"
75
101
 
76
102
  OVER=false
@@ -79,6 +105,13 @@ echo "diff_lines=$TOTAL"
79
105
  echo "excluded_lines=$EXCL"
80
106
  echo "threshold=$THRESHOLD"
81
107
  echo "over=$OVER"
108
+ COHESIVE=false
109
+ if [ "$THRESHOLD" -gt 0 ] && [ "$TOTAL" -gt 0 ] && [ $((COHL * 100)) -ge $((70 * TOTAL)) ] \
110
+ && [ $((TOTAL * 2)) -le $((THRESHOLD * 3)) ]; then COHESIVE=true; fi
111
+ echo "new_lines=$NEWL"
112
+ echo "test_lines=$TESTL"
113
+ echo "cohesive_lines=$COHL"
114
+ echo "cohesive=$COHESIVE"
82
115
  if [ -n "$LIST" ]; then
83
116
  printf '%s' "$LIST" | sort -t' ' -k1,1nr | head -n 10 | sed 's/^/top=/' || true
84
117
  fi
@@ -95,6 +95,53 @@ reset; gen 3 > s.txt; gen 9 > l.txt; git add -A
95
95
  OUT="$(run)"; FIRST="$(printf '%s\n' "$OUT" | sed -n 's/^top=//p' | head -n1)"
96
96
  [ "$FIRST" = "9 l.txt" ] && ok || bad "top ordering (got '$FIRST')"
97
97
 
98
+ # cohesion (forge#3790): new files + test files >= 70% of diff_lines and diff_lines <= threshold*3/2
99
+ shape() { # all-new fixture: $1=new module lines, $2=new test file lines
100
+ reset; mkdir -p src tests; gen "$1" > src/newmod.py; gen "$2" > tests/test_newmod.py; git add -A
101
+ }
102
+ shape 685 458; OUT="$(run --threshold 1000)"
103
+ check "34844 shape cohesive" "$OUT" cohesive true; check "34844 shape new (test file is also new)" "$OUT" new_lines 1143
104
+ check "34844 shape test" "$OUT" test_lines 458; check "34844 shape cohesive_lines" "$OUT" cohesive_lines 1143
105
+ shape 471 593; OUT="$(run --threshold 1000)"; check "35124 shape cohesive" "$OUT" cohesive true
106
+ shape 516 697; OUT="$(run --threshold 1000)"; check "35143 shape cohesive" "$OUT" cohesive true
107
+ shape 1478 0; OUT="$(run --threshold 1000)"; check "35100 all-new at 1.5x cohesive" "$OUT" cohesive true
108
+ shape 1500 1; OUT="$(run --threshold 1000)"; check "over 1.5x not cohesive" "$OUT" cohesive false
109
+ shape 1000 0; OUT="$(run --threshold 0)"; check "threshold 0 not cohesive" "$OUT" cohesive false
110
+
111
+ # new test file counts once (union), under the threshold still reports cohesive
112
+ reset; mkdir -p tests; gen 50 > tests/test_x.py; git add -A
113
+ OUT="$(run --threshold 1000)"; check "new test file new" "$OUT" new_lines 50; check "new test file test" "$OUT" test_lines 50
114
+ check "new test file union once" "$OUT" cohesive_lines 50
115
+
116
+ # a modified (not added) test file counts as test, not new
117
+ reset; mkdir -p tests; gen 40 > tests/test_old.py
118
+ git add -A; git commit -qm t; git push -q origin feat:staging 2>/dev/null
119
+ gen 10 | sed 's/line/chg/' > tests/test_old.py; gen 30 > src_new.py; git add -A
120
+ OUT="$(run)"; check "modified test new_lines" "$OUT" new_lines 30; check "modified test test_lines" "$OUT" test_lines 50
121
+ check "modified test union" "$OUT" cohesive_lines 80
122
+ git reset -q --hard origin/staging
123
+
124
+ # sprawl: 1300 lines across 15 modified files is not cohesive
125
+ reset; for i in $(seq 1 15); do gen 50 > "m$i.txt"; done; git add -A; git commit -qm m; git push -q origin feat:staging 2>/dev/null
126
+ for i in $(seq 1 15); do gen 43 | sed 's/line/edit/' > "m$i.txt"; done; git add -A
127
+ OUT="$(run --threshold 1000)"
128
+ check "sprawl lines" "$OUT" diff_lines 1395; check "sprawl cohesive_lines" "$OUT" cohesive_lines 0; check "sprawl not cohesive" "$OUT" cohesive false
129
+ git reset -q --hard origin/staging
130
+
131
+ # modified (not added) test file is test-classified; modified non-test stays out; basename patterns, no substring match
132
+ reset; mkdir -p t; gen 10 > latest.sh; gen 10 > contest.txt; gen 10 > a.spec.ts; gen 10 > b_test.go; gen 10 > test_c.py; git add -A
133
+ OUT="$(run)"; check "latest.sh and contest.txt are new, all counted" "$OUT" new_lines 50
134
+ check "test name patterns" "$OUT" test_lines 30
135
+
136
+ # excluded files are not counted by cohesion
137
+ reset; gen 20 > keep.py; gen 900 > package-lock.json; git add -A
138
+ OUT="$(run --threshold 1000)"; check "excluded not in new_lines" "$OUT" new_lines 20
139
+
140
+ # existing key order is unchanged: cohesion keys sit between over= and top=
141
+ reset; gen 3 > s.txt; git add -A
142
+ KEYS="$(run | sed -n 's/^\([a-z_]*\)=.*/\1/p' | tr '\n' ' ')"
143
+ [ "$KEYS" = "diff_lines excluded_lines threshold over new_lines test_lines cohesive_lines cohesive top " ] && ok || bad "key order ($KEYS)"
144
+
98
145
  # fail closed: bad repo path, bad base, bad threshold, unknown arg, missing base
99
146
  OUT="$(bash "$S" --repo-path "$TMP/nope" --base staging 2>/dev/null)"; rc=$?
100
147
  { [ "$rc" = 2 ] && [ -z "$OUT" ]; } && ok || bad "bad repo path (rc=$rc out='$OUT')"