forgedock 1.7.1 → 1.8.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/bin/engine/admission.mjs +242 -7
- package/bin/engine/admission.test.mjs +183 -2
- package/bin/engine/phases.mjs +31 -22
- package/bin/engine/resolve.mjs +8 -1
- package/bin/engine/resolve.test.mjs +5 -0
- package/bin/engine.mjs +26 -17
- package/bin/forgedock.mjs +15 -2
- package/bin/hooks/pre-tool-use.mjs +573 -2
- package/bin/journey.mjs +11 -7
- package/bin/labels.json +5 -0
- package/bin/opencode-adapter.mjs +47 -13
- package/bin/orchestrate-preflight.mjs +434 -0
- package/bin/runner.mjs +30 -4
- package/commands/audit-agents.md +75 -26
- package/commands/autopilot.md +4 -4
- package/commands/cleanup.md +10 -5
- package/commands/issue.md +95 -35
- package/commands/orchestrate/phase-1-resolve.md +70 -32
- package/commands/orchestrate/phase-3-dependency.md +141 -13
- package/commands/orchestrate/phase-4-execution.md +660 -70
- package/commands/orchestrate/phase-5-cleanup.md +5 -11
- package/commands/orchestrate/phase-6-report.md +27 -1
- package/commands/orchestrate/safety.md +1 -1
- package/commands/orchestrate.md +39 -1
- package/commands/quality-gate.md +30 -10
- package/commands/review-pr-agents/protocols.md +13 -0
- package/commands/review-pr-agents.md +1 -1
- package/commands/review-pr-staging.md +100 -18
- package/commands/review-pr.md +78 -24
- package/commands/work-on/build/validate.md +25 -4
- package/commands/work-on/close.md +40 -10
- package/commands/work-on/decompose.md +33 -1
- package/commands/work-on/investigate.md +33 -0
- package/commands/work-on/remediate.md +40 -5
- package/commands/work-on/review.md +27 -0
- package/commands/work-on.md +48 -5
- package/docs/CONFIG.md +45 -10
- package/docs/OPENCODE.md +21 -6
- package/docs/spec/review-protocol.md +7 -0
- package/package.json +1 -1
- package/scripts/check-admission-parity.mjs +1 -0
- package/scripts/check-command-side-effects.sh +14 -13
- package/scripts/check-shell-portability.sh +36 -0
- package/scripts/check-spec-markers.sh +21 -11
- package/scripts/checkbox-sections.test.sh +67 -0
- package/scripts/extract-affected-files.sh +85 -5
- package/scripts/extract-affected-files.test.sh +154 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# extract-affected-files.sh <issue_number> "-R <owner/repo>" (single pre-joined token also accepted)
|
|
8
8
|
#
|
|
9
9
|
# Output (stdout):
|
|
10
|
-
# Line 1: PROVENANCE=affected-files-section | body-fallback | none | error
|
|
10
|
+
# Line 1: PROVENANCE=contract-deliverables | affected-files-section | body-fallback | none | error
|
|
11
11
|
# Line 2+: one extracted file path per line (zero lines when PROVENANCE=none or error)
|
|
12
12
|
#
|
|
13
13
|
# Exit codes:
|
|
@@ -16,12 +16,39 @@
|
|
|
16
16
|
# that files were found).
|
|
17
17
|
# 2 — Usage error (missing issue number, malformed -R value).
|
|
18
18
|
#
|
|
19
|
-
# Extraction rules (forge#2436):
|
|
19
|
+
# Extraction rules (forge#2436, extended forge#2848):
|
|
20
|
+
# 0. Highest-confidence path — the issue's FORGE:CONTRACT comment (if one exists),
|
|
21
|
+
# scoped to ONLY its own "### Deliverables" section. A contract deliverables table
|
|
22
|
+
# states *intent to change* ("I will edit this file"), whereas an investigation's
|
|
23
|
+
# Affected Files list and especially a raw issue body routinely name files as
|
|
24
|
+
# *context* ("this interacts with X", "similar to the check in Y"). Preferring the
|
|
25
|
+
# contract is what stops a cohort of issues that merely cite the same file from
|
|
26
|
+
# being serialized against each other (forge#2848).
|
|
27
|
+
# -> PROVENANCE=contract-deliverables
|
|
28
|
+
#
|
|
29
|
+
# TEMPORAL CAVEAT — do not over-claim this source: FORGE:CONTRACT is posted at
|
|
30
|
+
# *build* time (work-on/build.md Phase B2), which is AFTER /orchestrate Phase 3
|
|
31
|
+
# builds the DAG. On a cold first-pass plan no contract exists yet, so this path is
|
|
32
|
+
# inert by construction. It pays off only on the paths that re-extract later: wake /
|
|
33
|
+
# re-plan after compaction, mid-batch re-derivation (phase-4-execution.md's DONE-arm
|
|
34
|
+
# DROP handling), and IN_PROGRESS predecessors built in an earlier wave or session.
|
|
35
|
+
#
|
|
36
|
+
# FALL-THROUGH RULE (load-bearing — see forge#2848 risk table): a contract that
|
|
37
|
+
# exists but whose Deliverables section yields ZERO paths MUST fall through to the
|
|
38
|
+
# INVESTIGATOR path below. A contract is an *upgrade* over the investigator source,
|
|
39
|
+
# never a replacement for it — blackholing to `none` here would fire Layer 4's
|
|
40
|
+
# conservative serialization for exactly the mid-batch issues this change exists to
|
|
41
|
+
# un-serialize, i.e. the bug being fixed, inverted. Note this is deliberately NOT
|
|
42
|
+
# the same shape as the INVESTIGATOR->body relationship in rule 2, which does NOT
|
|
43
|
+
# fall through on zero files (see rule 2's own note, forge#2382).
|
|
20
44
|
# 1. Primary path — the issue's FORGE:INVESTIGATOR comment (if one exists), scoped to
|
|
21
45
|
# ONLY its own "### Affected Files" section. Capture stops at the next markdown
|
|
22
46
|
# heading of any level, so paths mentioned in "### Evidence", "### Root Cause",
|
|
23
47
|
# "### Related Issues", etc. are never collected.
|
|
24
48
|
# -> PROVENANCE=affected-files-section
|
|
49
|
+
# NOTE (forge#2382): unlike rule 0, an INVESTIGATOR comment that EXISTS but yields
|
|
50
|
+
# zero paths does NOT fall through to rule 2 — an investigation that scoped its own
|
|
51
|
+
# Affected Files section to nothing is a confirmed-empty result, not a missing one.
|
|
25
52
|
# 2. Fallback path — used ONLY when no FORGE:INVESTIGATOR comment exists at all.
|
|
26
53
|
# Scoped to a deliverables-shaped heading in the raw issue body:
|
|
27
54
|
# "## Affected Files", "## Deliverables", or "### Files to change". Capture stops
|
|
@@ -126,6 +153,20 @@ fi
|
|
|
126
153
|
# deeper sub-heading inside a deliverables section still closes capture
|
|
127
154
|
# rather than leaking into unrelated prose.
|
|
128
155
|
# --------------------------------------------------------------------------- #
|
|
156
|
+
extract_contract_section() {
|
|
157
|
+
# forge#2848 — same sentinel shape as the two helpers below, targeting the
|
|
158
|
+
# FORGE:CONTRACT comment's "### Deliverables" table. The `/^### Deliverables/`
|
|
159
|
+
# heading and the awk sentinel are the ones already proven in-tree at
|
|
160
|
+
# commands/work-on/build.md:218 and :258; only the path-extraction step differs
|
|
161
|
+
# (this script uses grep -oE via extract_paths, never build.md's grep -oP —
|
|
162
|
+
# forge#2436 removed the PCRE dependency on purpose, see extract_paths below).
|
|
163
|
+
awk '
|
|
164
|
+
/^### Deliverables/ { p=1; next }
|
|
165
|
+
/^#/ { p=0 }
|
|
166
|
+
p { print }
|
|
167
|
+
' <<< "$1"
|
|
168
|
+
}
|
|
169
|
+
|
|
129
170
|
extract_investigator_section() {
|
|
130
171
|
awk '
|
|
131
172
|
/^### Affected Files/ { p=1; next }
|
|
@@ -152,13 +193,49 @@ extract_paths() {
|
|
|
152
193
|
grep -oE "$EXT_REGEX" <<< "$1" 2>/dev/null | tr -d '`' | sort -u || true
|
|
153
194
|
}
|
|
154
195
|
|
|
155
|
-
# --------------------------------------------------------------------------- #
|
|
156
|
-
# Primary path: FORGE:INVESTIGATOR comment, scoped to its own Affected Files section
|
|
157
|
-
# --------------------------------------------------------------------------- #
|
|
158
196
|
PROVENANCE="none"
|
|
159
197
|
FILES=""
|
|
160
198
|
GH_CALL_FAILED=0
|
|
161
199
|
|
|
200
|
+
# --------------------------------------------------------------------------- #
|
|
201
|
+
# Highest-confidence path: FORGE:CONTRACT comment, scoped to its own Deliverables
|
|
202
|
+
# section (forge#2848). Runs AHEAD of the INVESTIGATOR path because a deliverables
|
|
203
|
+
# table states intent to change, while an Affected Files list may name files that
|
|
204
|
+
# are merely relevant. See rule 0 in the header for the temporal caveat (a contract
|
|
205
|
+
# only exists post-build, so this is inert on a cold first-pass plan).
|
|
206
|
+
#
|
|
207
|
+
# Uses the same `if ! VAR=$(cmd); then GH_CALL_FAILED=1; fi` idiom as the calls
|
|
208
|
+
# below — never `|| true` — so a failed contract fetch stays distinguishable from
|
|
209
|
+
# "no contract exists" and can still escalate to PROVENANCE=error if nothing else
|
|
210
|
+
# recovers real data (forge#2504).
|
|
211
|
+
# --------------------------------------------------------------------------- #
|
|
212
|
+
if ! CONTRACT_BODY=$(gh api "repos/${REPO}/issues/${NUM}/comments" \
|
|
213
|
+
--jq '[.[] | select(.body | contains("FORGE:CONTRACT"))] | last | .body // ""' 2>/dev/null); then
|
|
214
|
+
GH_CALL_FAILED=1
|
|
215
|
+
echo "WARNING: gh api call failed while fetching comments for issue #$NUM (repo: $REPO) — cannot confirm whether a FORGE:CONTRACT comment exists; treating as inconclusive, not empty" >&2
|
|
216
|
+
CONTRACT_BODY=""
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
if [[ -n "$CONTRACT_BODY" ]]; then
|
|
220
|
+
SCOPED=$(extract_contract_section "$CONTRACT_BODY")
|
|
221
|
+
FILES=$(extract_paths "$SCOPED")
|
|
222
|
+
if [[ -n "$FILES" ]]; then
|
|
223
|
+
PROVENANCE="contract-deliverables"
|
|
224
|
+
fi
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# --------------------------------------------------------------------------- #
|
|
228
|
+
# Primary path: FORGE:INVESTIGATOR comment, scoped to its own Affected Files section
|
|
229
|
+
#
|
|
230
|
+
# Guarded on `-z "$FILES"` so the contract path above FALLS THROUGH when it yielded
|
|
231
|
+
# zero paths (no contract, no Deliverables section, or a deliverables table naming no
|
|
232
|
+
# recognized file extension). The guard wraps the whole INVESTIGATOR/body block from
|
|
233
|
+
# the outside, leaving the INVESTIGATOR->body-fallback relationship inside it
|
|
234
|
+
# byte-identical — that inner relationship deliberately does NOT fall through on zero
|
|
235
|
+
# files (forge#2382), and this change must not alter it.
|
|
236
|
+
# --------------------------------------------------------------------------- #
|
|
237
|
+
if [[ -z "$FILES" ]]; then
|
|
238
|
+
|
|
162
239
|
# NOTE: deliberately no `| tail -1` here — `gh api --jq`'s raw-string output
|
|
163
240
|
# for a multi-line `.body` field embeds literal newlines, so isolating "the
|
|
164
241
|
# last comment" by taking the last output LINE would instead truncate to
|
|
@@ -215,6 +292,9 @@ else
|
|
|
215
292
|
fi
|
|
216
293
|
fi
|
|
217
294
|
fi
|
|
295
|
+
fi # end contract fall-through guard (forge#2848) — the INVESTIGATOR/body block
|
|
296
|
+
# above is intentionally left un-indented so it stays byte-identical to its
|
|
297
|
+
# pre-forge#2848 form; only the surrounding guard is new.
|
|
218
298
|
|
|
219
299
|
# forge#2504: only escalate to "error" when neither path yielded real data AND
|
|
220
300
|
# at least one gh call genuinely failed along the way. A failed primary call
|
|
@@ -28,18 +28,38 @@ trap cleanup EXIT
|
|
|
28
28
|
|
|
29
29
|
# --------------------------------------------------------------------------- #
|
|
30
30
|
# Mock `gh` — intercepts:
|
|
31
|
-
# gh api
|
|
32
|
-
# gh
|
|
31
|
+
# gh api .../comments --jq '...FORGE:CONTRACT...' -> cat $MOCK_GH_CONTRACT (if set+exists, else empty)
|
|
32
|
+
# gh api .../comments --jq '...FORGE:INVESTIGATOR...' -> cat $MOCK_GH_COMMENTS (if set+exists, else empty)
|
|
33
|
+
# gh issue view <num> -R <repo> --json body --jq '...' -> cat $MOCK_GH_BODY (if set+exists, else empty)
|
|
33
34
|
# Any other invocation is a test setup error.
|
|
34
35
|
#
|
|
36
|
+
# forge#2848: the two `gh api` call sites hit the same endpoint and differ only in
|
|
37
|
+
# their --jq selector, so the mock dispatches on which FORGE marker the selector
|
|
38
|
+
# names. This keeps the contract source and the investigator source independently
|
|
39
|
+
# fixturable — required to assert the contract-beats-investigator ordering rule.
|
|
40
|
+
#
|
|
35
41
|
# forge#2504: MOCK_GH_COMMENTS_FAIL=1 / MOCK_GH_BODY_FAIL=1 force the respective
|
|
36
42
|
# call site to simulate a genuine `gh` failure (non-zero exit, nothing on
|
|
37
43
|
# stdout) instead of a "call succeeded, empty/no-match result" — this is the
|
|
38
44
|
# distinction extract-affected-files.sh must now surface as PROVENANCE=error.
|
|
45
|
+
# MOCK_GH_CONTRACT_FAIL=1 does the same for the contract fetch alone; note that
|
|
46
|
+
# MOCK_GH_COMMENTS_FAIL=1 fails BOTH `gh api` call sites, which is the faithful
|
|
47
|
+
# simulation of a real network/auth/rate-limit outage (a real outage does not
|
|
48
|
+
# selectively spare one of two calls to the same endpoint).
|
|
39
49
|
# --------------------------------------------------------------------------- #
|
|
40
50
|
cat > "$TMP_BIN/gh" <<'MOCK'
|
|
41
51
|
#!/usr/bin/env bash
|
|
42
52
|
if [[ "$1" == "api" ]]; then
|
|
53
|
+
if [[ "$*" == *"FORGE:CONTRACT"* ]]; then
|
|
54
|
+
if [[ "${MOCK_GH_CONTRACT_FAIL:-}" == "1" || "${MOCK_GH_COMMENTS_FAIL:-}" == "1" ]]; then
|
|
55
|
+
echo "mock gh api: simulated failure (network error / rate limit)" >&2
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
if [[ -n "${MOCK_GH_CONTRACT:-}" && -f "${MOCK_GH_CONTRACT:-}" ]]; then
|
|
59
|
+
cat "$MOCK_GH_CONTRACT"
|
|
60
|
+
fi
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
43
63
|
if [[ "${MOCK_GH_COMMENTS_FAIL:-}" == "1" ]]; then
|
|
44
64
|
echo "mock gh api: simulated failure (network error / rate limit)" >&2
|
|
45
65
|
exit 1
|
|
@@ -320,6 +340,138 @@ MOCK_GH_COMMENTS_FAIL=1 MOCK_GH_BODY="$BODY_SCOPED" assert_output \
|
|
|
320
340
|
"forge#2504: primary gh api call fails but fallback succeeds with real files -> body-fallback, not error" \
|
|
321
341
|
"body-fallback" "bin/engine.mjs,bin/engine/phases.mjs" 2506 -R test/repo
|
|
322
342
|
|
|
343
|
+
# --------------------------------------------------------------------------- #
|
|
344
|
+
# Scenario 12 (forge#2848): FORGE:CONTRACT comment present with a real
|
|
345
|
+
# "### Deliverables" table -> PROVENANCE=contract-deliverables. Paths named in
|
|
346
|
+
# the contract's OTHER sections ("### Proposed Approach", "### Out of Scope")
|
|
347
|
+
# must be ignored — same heading-scoping guarantee the investigator path has.
|
|
348
|
+
# --------------------------------------------------------------------------- #
|
|
349
|
+
CONTRACT_FULL="$TMP_FIXTURES/contract_full.txt"
|
|
350
|
+
cat > "$CONTRACT_FULL" <<'EOF'
|
|
351
|
+
<!-- FORGE:CONTRACT -->
|
|
352
|
+
## Builder Contract
|
|
353
|
+
|
|
354
|
+
**Task type**: Bug Fix
|
|
355
|
+
|
|
356
|
+
### Proposed Approach
|
|
357
|
+
|
|
358
|
+
Mirrors the approach already taken in `bin/approach-only-context.mjs`.
|
|
359
|
+
|
|
360
|
+
### Deliverables
|
|
361
|
+
|
|
362
|
+
| File | Change | Why |
|
|
363
|
+
|------|--------|-----|
|
|
364
|
+
| `scripts/real-target.sh` | rewrite the parser | the actual defect |
|
|
365
|
+
| `bin/real-target.mjs` | update the caller | keeps the pair in sync |
|
|
366
|
+
|
|
367
|
+
### Out of Scope
|
|
368
|
+
|
|
369
|
+
Anything under `bin/out-of-scope-file.mjs`.
|
|
370
|
+
EOF
|
|
371
|
+
|
|
372
|
+
unset MOCK_GH_COMMENTS MOCK_GH_BODY MOCK_GH_COMMENTS_FAIL MOCK_GH_BODY_FAIL
|
|
373
|
+
MOCK_GH_CONTRACT="$CONTRACT_FULL" assert_output \
|
|
374
|
+
"forge#2848: FORGE:CONTRACT ### Deliverables -> contract-deliverables, ignores Approach/Out-of-Scope paths" \
|
|
375
|
+
"contract-deliverables" "bin/real-target.mjs,scripts/real-target.sh" 2848 -R test/repo
|
|
376
|
+
|
|
377
|
+
# --------------------------------------------------------------------------- #
|
|
378
|
+
# Scenario 13 (forge#2848 ORDERING rule): both a FORGE:CONTRACT and a
|
|
379
|
+
# FORGE:INVESTIGATOR comment exist, and they name DIFFERENT files. The contract
|
|
380
|
+
# must win — a deliverables table states intent to change, while an Affected
|
|
381
|
+
# Files list may name files that are merely relevant. This is the assertion that
|
|
382
|
+
# pins the provenance precedence order; without it the two sources could silently
|
|
383
|
+
# swap with no test failure.
|
|
384
|
+
# --------------------------------------------------------------------------- #
|
|
385
|
+
INV_DIFFERENT="$TMP_FIXTURES/inv_different.txt"
|
|
386
|
+
cat > "$INV_DIFFERENT" <<'EOF'
|
|
387
|
+
<!-- FORGE:INVESTIGATOR -->
|
|
388
|
+
## Investigation Report
|
|
389
|
+
|
|
390
|
+
### Affected Files
|
|
391
|
+
|
|
392
|
+
1. `scripts/investigator-guess.sh` — suspected
|
|
393
|
+
2. `bin/investigator-guess.mjs` — suspected
|
|
394
|
+
EOF
|
|
395
|
+
|
|
396
|
+
unset MOCK_GH_BODY MOCK_GH_COMMENTS_FAIL MOCK_GH_BODY_FAIL
|
|
397
|
+
MOCK_GH_CONTRACT="$CONTRACT_FULL" MOCK_GH_COMMENTS="$INV_DIFFERENT" assert_output \
|
|
398
|
+
"forge#2848 ordering: contract beats investigator when both exist and disagree" \
|
|
399
|
+
"contract-deliverables" "bin/real-target.mjs,scripts/real-target.sh" 2849 -R test/repo
|
|
400
|
+
|
|
401
|
+
# --------------------------------------------------------------------------- #
|
|
402
|
+
# Scenario 14 (forge#2848 FALL-THROUGH rule — load-bearing): a FORGE:CONTRACT
|
|
403
|
+
# exists but yields ZERO paths. It must fall through to the INVESTIGATOR path,
|
|
404
|
+
# NOT blackhole to PROVENANCE=none. Blackholing here would fire Layer 4's
|
|
405
|
+
# conservative serialization for exactly the mid-batch issues this change exists
|
|
406
|
+
# to un-serialize (the bug being fixed, inverted — see the forge#2848 risk table).
|
|
407
|
+
# Two zero-yield shapes are covered: no "### Deliverables" heading at all, and a
|
|
408
|
+
# Deliverables section that names no recognized file path.
|
|
409
|
+
# --------------------------------------------------------------------------- #
|
|
410
|
+
CONTRACT_NO_DELIV="$TMP_FIXTURES/contract_no_deliv.txt"
|
|
411
|
+
cat > "$CONTRACT_NO_DELIV" <<'EOF'
|
|
412
|
+
<!-- FORGE:CONTRACT -->
|
|
413
|
+
## Builder Contract
|
|
414
|
+
|
|
415
|
+
### Proposed Approach
|
|
416
|
+
|
|
417
|
+
Prose only, mentioning `bin/should-not-be-extracted.mjs` as context.
|
|
418
|
+
|
|
419
|
+
### Out of Scope
|
|
420
|
+
|
|
421
|
+
Everything else.
|
|
422
|
+
EOF
|
|
423
|
+
|
|
424
|
+
unset MOCK_GH_BODY MOCK_GH_COMMENTS_FAIL MOCK_GH_BODY_FAIL
|
|
425
|
+
MOCK_GH_CONTRACT="$CONTRACT_NO_DELIV" MOCK_GH_COMMENTS="$INV_DIFFERENT" assert_output \
|
|
426
|
+
"forge#2848 fall-through: contract with no ### Deliverables section -> falls through to affected-files-section" \
|
|
427
|
+
"affected-files-section" "bin/investigator-guess.mjs,scripts/investigator-guess.sh" 2850 -R test/repo
|
|
428
|
+
|
|
429
|
+
CONTRACT_EMPTY_DELIV="$TMP_FIXTURES/contract_empty_deliv.txt"
|
|
430
|
+
cat > "$CONTRACT_EMPTY_DELIV" <<'EOF'
|
|
431
|
+
<!-- FORGE:CONTRACT -->
|
|
432
|
+
## Builder Contract
|
|
433
|
+
|
|
434
|
+
### Deliverables
|
|
435
|
+
|
|
436
|
+
| File | Change | Why |
|
|
437
|
+
|------|--------|-----|
|
|
438
|
+
| (documentation-only, no code paths) | n/a | n/a |
|
|
439
|
+
|
|
440
|
+
### Out of Scope
|
|
441
|
+
|
|
442
|
+
Everything else.
|
|
443
|
+
EOF
|
|
444
|
+
|
|
445
|
+
unset MOCK_GH_BODY MOCK_GH_COMMENTS_FAIL MOCK_GH_BODY_FAIL
|
|
446
|
+
MOCK_GH_CONTRACT="$CONTRACT_EMPTY_DELIV" MOCK_GH_COMMENTS="$INV_DIFFERENT" assert_output \
|
|
447
|
+
"forge#2848 fall-through: contract Deliverables naming no recognized path -> falls through to affected-files-section" \
|
|
448
|
+
"affected-files-section" "bin/investigator-guess.mjs,scripts/investigator-guess.sh" 2851 -R test/repo
|
|
449
|
+
|
|
450
|
+
# --------------------------------------------------------------------------- #
|
|
451
|
+
# Scenario 15 (forge#2848 x forge#2504): the CONTRACT fetch specifically fails
|
|
452
|
+
# while every other source is legitimately empty. Must yield PROVENANCE=error,
|
|
453
|
+
# not none — the new call site doubles the gh failure surface, so its own
|
|
454
|
+
# GH_CALL_FAILED wiring needs its own assertion rather than riding on the
|
|
455
|
+
# investigator call's coverage.
|
|
456
|
+
# --------------------------------------------------------------------------- #
|
|
457
|
+
unset MOCK_GH_CONTRACT MOCK_GH_COMMENTS MOCK_GH_BODY MOCK_GH_COMMENTS_FAIL MOCK_GH_BODY_FAIL
|
|
458
|
+
MOCK_GH_CONTRACT_FAIL=1 assert_output \
|
|
459
|
+
"forge#2848: contract gh api call fails, no other usable source -> PROVENANCE=error, not none" \
|
|
460
|
+
"error" "" 2852 -R test/repo
|
|
461
|
+
|
|
462
|
+
# --------------------------------------------------------------------------- #
|
|
463
|
+
# Scenario 16 (forge#2848 x forge#2504): the CONTRACT fetch fails but the
|
|
464
|
+
# investigator path succeeds with real files. A gh failure must never suppress
|
|
465
|
+
# or overwrite data actually recovered by a subsequent successful call — same
|
|
466
|
+
# invariant Scenario 11 asserts for the primary/fallback pair.
|
|
467
|
+
# --------------------------------------------------------------------------- #
|
|
468
|
+
unset MOCK_GH_CONTRACT MOCK_GH_BODY MOCK_GH_COMMENTS_FAIL MOCK_GH_BODY_FAIL
|
|
469
|
+
MOCK_GH_CONTRACT_FAIL=1 MOCK_GH_COMMENTS="$INV_DIFFERENT" assert_output \
|
|
470
|
+
"forge#2848: contract fetch fails but investigator succeeds with real files -> affected-files-section, not error" \
|
|
471
|
+
"affected-files-section" "bin/investigator-guess.mjs,scripts/investigator-guess.sh" 2853 -R test/repo
|
|
472
|
+
|
|
473
|
+
unset MOCK_GH_CONTRACT_FAIL
|
|
474
|
+
|
|
323
475
|
# --------------------------------------------------------------------------- #
|
|
324
476
|
# Summary
|
|
325
477
|
# --------------------------------------------------------------------------- #
|