sequant 2.11.0 → 2.13.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +47 -3
- package/dist/dashboard/server.js +4 -0
- package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
- package/dist/marketplace/external_plugins/sequant/.mcp.json +1 -1
- package/dist/marketplace/external_plugins/sequant/README.md +9 -0
- package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +331 -12
- package/dist/marketplace/external_plugins/sequant/skills/_shared/references/subagent-types.md +7 -18
- package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +5 -1
- package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +62 -8
- package/dist/marketplace/external_plugins/sequant/skills/fullsolve/SKILL.md +187 -28
- package/dist/marketplace/external_plugins/sequant/skills/loop/SKILL.md +127 -23
- package/dist/marketplace/external_plugins/sequant/skills/merger/SKILL.md +130 -13
- package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +306 -8
- package/dist/marketplace/external_plugins/sequant/skills/release/SKILL.md +79 -0
- package/dist/marketplace/external_plugins/sequant/skills/spec/SKILL.md +42 -20
- package/dist/marketplace/external_plugins/sequant/skills/spec/references/recommended-workflow.md +14 -1
- package/dist/marketplace/external_plugins/sequant/skills/test/SKILL.md +1 -1
- package/dist/marketplace/external_plugins/sequant/skills/testgen/SKILL.md +23 -6
- package/dist/src/commands/doctor.js +20 -18
- package/dist/src/commands/ready.js +7 -1
- package/dist/src/commands/status.js +4 -0
- package/dist/src/lib/ac-linter.js +26 -0
- package/dist/src/lib/ac-parser.d.ts +40 -0
- package/dist/src/lib/ac-parser.js +202 -16
- package/dist/src/lib/markdown-fence.d.ts +24 -0
- package/dist/src/lib/markdown-fence.js +51 -0
- package/dist/src/lib/mcp-config.d.ts +24 -0
- package/dist/src/lib/mcp-config.js +51 -0
- package/dist/src/lib/scope/analyzer.d.ts +4 -0
- package/dist/src/lib/scope/analyzer.js +7 -1
- package/dist/src/lib/settings.d.ts +73 -14
- package/dist/src/lib/settings.js +45 -3
- package/dist/src/lib/system.d.ts +7 -3
- package/dist/src/lib/system.js +7 -3
- package/dist/src/lib/test-tautology-detector.js +50 -3
- package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
- package/dist/src/lib/workflow/batch-executor.js +81 -6
- package/dist/src/lib/workflow/config-resolver.d.ts +30 -2
- package/dist/src/lib/workflow/config-resolver.js +59 -2
- package/dist/src/lib/workflow/drivers/agent-driver.d.ts +14 -0
- package/dist/src/lib/workflow/drivers/claude-code.js +36 -4
- package/dist/src/lib/workflow/metrics-schema.d.ts +10 -1
- package/dist/src/lib/workflow/metrics-schema.js +13 -1
- package/dist/src/lib/workflow/metrics-writer.d.ts +3 -1
- package/dist/src/lib/workflow/mutation-marker.d.ts +86 -0
- package/dist/src/lib/workflow/mutation-marker.js +97 -0
- package/dist/src/lib/workflow/phase-executor.d.ts +17 -0
- package/dist/src/lib/workflow/phase-executor.js +60 -6
- package/dist/src/lib/workflow/qa-gaps-marker.d.ts +38 -0
- package/dist/src/lib/workflow/qa-gaps-marker.js +66 -0
- package/dist/src/lib/workflow/ready-gate.d.ts +25 -1
- package/dist/src/lib/workflow/ready-gate.js +81 -11
- package/dist/src/lib/workflow/reconcile.js +4 -2
- package/dist/src/lib/workflow/run-log-schema.d.ts +120 -0
- package/dist/src/lib/workflow/run-log-schema.js +40 -0
- package/dist/src/lib/workflow/run-orchestrator.d.ts +18 -0
- package/dist/src/lib/workflow/run-orchestrator.js +38 -2
- package/dist/src/lib/workflow/state-cleanup.d.ts +4 -4
- package/dist/src/lib/workflow/state-cleanup.js +9 -5
- package/dist/src/lib/workflow/state-schema.d.ts +10 -1
- package/dist/src/lib/workflow/state-schema.js +13 -1
- package/dist/src/lib/workflow/types.d.ts +20 -0
- package/dist/src/mcp/tools/run.js +10 -1
- package/package.json +13 -12
- package/templates/hooks/pre-tool.sh +108 -17
- package/templates/memory/constitution.md +112 -45
- package/templates/skills/exec/SKILL.md +1 -1
- package/templates/skills/fullsolve/SKILL.md +62 -9
- package/templates/skills/loop/SKILL.md +71 -12
- package/templates/skills/merger/SKILL.md +32 -3
- package/templates/skills/qa/SKILL.md +247 -2
- package/templates/skills/spec/SKILL.md +11 -5
- package/templates/skills/test/SKILL.md +1 -1
|
@@ -39,7 +39,55 @@ else
|
|
|
39
39
|
HOOK_CWD=$(echo "$INPUT_JSON" | grep -oE '"cwd"\s*:\s*"[^"]+"' | head -1 | cut -d'"' -f4)
|
|
40
40
|
# For Bash tool, extract command from tool_input; for others, extract the whole object
|
|
41
41
|
if [[ "$TOOL_NAME" == "Bash" ]]; then
|
|
42
|
-
|
|
42
|
+
# Escape-aware extraction (#963 gap B): the naive `grep -oE '"[^"]+"'`
|
|
43
|
+
# form (still used for the simpler fields above, where an embedded
|
|
44
|
+
# `\"` is implausible) stops at the FIRST escaped quote inside the
|
|
45
|
+
# JSON string, truncating any command containing one — e.g.
|
|
46
|
+
# `git commit -m "msg with \"quotes\""` would be cut down to just
|
|
47
|
+
# `git commit -m ` before it ever reaches the guards below.
|
|
48
|
+
#
|
|
49
|
+
# sed's `(([^"\\]|\\.)*)` captures the full escaped run — any run of
|
|
50
|
+
# non-quote/non-backslash chars, or a backslash paired with whatever
|
|
51
|
+
# follows it — up to the closing unescaped `"`. `JSON.stringify`
|
|
52
|
+
# guarantees the whole payload is one physical line, so a single
|
|
53
|
+
# sed pass is enough (no multi-line `-z` needed, which BSD sed lacks
|
|
54
|
+
# anyway).
|
|
55
|
+
#
|
|
56
|
+
# The captured text still carries JSON string escapes literally
|
|
57
|
+
# (`\"`, `\\`, `\n`, `\t`, ...); the awk pass resolves them in ONE
|
|
58
|
+
# left-to-right scan, consuming two characters per recognized
|
|
59
|
+
# escape. That ordering is what a chain of separate sed/tr
|
|
60
|
+
# substitutions cannot get right without a placeholder: a literal
|
|
61
|
+
# `\\n` in the original command is an escaped backslash (`\\`)
|
|
62
|
+
# immediately followed by a literal `n`, and must stay a backslash
|
|
63
|
+
# plus 'n' — not become an escaped-newline (`\n`) if the two escapes
|
|
64
|
+
# were resolved out of order. Scanning once and advancing past both
|
|
65
|
+
# characters of whichever escape is recognized sidesteps that
|
|
66
|
+
# ambiguity entirely.
|
|
67
|
+
TOOL_INPUT=$(printf '%s' "$INPUT_JSON" \
|
|
68
|
+
| sed -E -n 's/.*"command"[[:space:]]*:[[:space:]]*"(([^"\\]|\\.)*)".*/\1/p' \
|
|
69
|
+
| head -1 \
|
|
70
|
+
| awk '
|
|
71
|
+
{
|
|
72
|
+
s = $0; out = ""; n = length(s)
|
|
73
|
+
for (i = 1; i <= n; i++) {
|
|
74
|
+
c = substr(s, i, 1)
|
|
75
|
+
if (c == "\\" && i < n) {
|
|
76
|
+
nc = substr(s, i + 1, 1)
|
|
77
|
+
if (nc == "\"") { out = out "\""; i++ }
|
|
78
|
+
else if (nc == "\\") { out = out "\\"; i++ }
|
|
79
|
+
else if (nc == "n") { out = out "\n"; i++ }
|
|
80
|
+
else if (nc == "t") { out = out "\t"; i++ }
|
|
81
|
+
else if (nc == "r") { out = out "\r"; i++ }
|
|
82
|
+
else if (nc == "/") { out = out "/"; i++ }
|
|
83
|
+
else { out = out c }
|
|
84
|
+
} else {
|
|
85
|
+
out = out c
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
print out
|
|
89
|
+
}
|
|
90
|
+
')
|
|
43
91
|
else
|
|
44
92
|
TOOL_INPUT=$(echo "$INPUT_JSON" | grep -oE '"tool_input"\s*:\s*\{[^}]+\}' | head -1)
|
|
45
93
|
fi
|
|
@@ -258,6 +306,43 @@ seg_match() {
|
|
|
258
306
|
[[ -n "$SEGMENTS" ]] && grep -qE "$1" <<< "$SEGMENTS"
|
|
259
307
|
}
|
|
260
308
|
|
|
309
|
+
# resolve_cd_target <tool_input> — print the target directory of the LAST
|
|
310
|
+
# `cd <path>` line in a (possibly multi-line) Bash command, if and only if
|
|
311
|
+
# the path is a static literal (quoted or unquoted) that resolves to an
|
|
312
|
+
# existing directory. Scans the raw command, not $SEGMENTS — emit_segments
|
|
313
|
+
# drops double-quoted regions, so `cd "$WT"` would vanish there before this
|
|
314
|
+
# ever saw it. Prints nothing when there is no `cd` line, the target is
|
|
315
|
+
# dynamic (contains `$` or a backtick), or the path doesn't exist — callers
|
|
316
|
+
# must treat empty output as "fail open", never as license to guess a
|
|
317
|
+
# directory (#963).
|
|
318
|
+
resolve_cd_target() {
|
|
319
|
+
local input="$1" line target
|
|
320
|
+
line=$(printf '%s\n' "$input" | grep -E '^[[:space:]]*cd[[:space:]]+' | tail -1)
|
|
321
|
+
[[ -z "$line" ]] && return 0
|
|
322
|
+
|
|
323
|
+
target=$(printf '%s' "$line" | sed -E 's/^[[:space:]]*cd[[:space:]]+//; s/[[:space:]]*[;&|].*$//; s/[[:space:]]+$//')
|
|
324
|
+
|
|
325
|
+
# Strip one layer of surrounding matching quotes.
|
|
326
|
+
case "$target" in
|
|
327
|
+
\"*\") target="${target#\"}"; target="${target%\"}" ;;
|
|
328
|
+
\'*\') target="${target#\'}"; target="${target%\'}" ;;
|
|
329
|
+
esac
|
|
330
|
+
|
|
331
|
+
# Fail open on anything dynamic — resolving shell expansions means
|
|
332
|
+
# reimplementing the shell, which is disproportionate; `git commit`
|
|
333
|
+
# itself already rejects a genuinely empty commit. A backslash is
|
|
334
|
+
# rejected too: it can escape a following `$`/`` ` `` into a form this
|
|
335
|
+
# literal-string check would otherwise miss, and a backslash also carries
|
|
336
|
+
# its own shell meaning (line continuation, escaped chars) that this
|
|
337
|
+
# function does not attempt to resolve — failing open is the safe
|
|
338
|
+
# direction either way (#963).
|
|
339
|
+
case "$target" in
|
|
340
|
+
*'$'*|*'`'*|*'\'*) return 0 ;;
|
|
341
|
+
esac
|
|
342
|
+
|
|
343
|
+
[[ -n "$target" && -d "$target" ]] && printf '%s' "$target"
|
|
344
|
+
}
|
|
345
|
+
|
|
261
346
|
# Path of the session->issue binding the checkout guard maintains (#906).
|
|
262
347
|
# $1 = repo toplevel, $2 = session id. The id is opaque, so squash everything
|
|
263
348
|
# outside a filename-safe set — it must not be able to escape the directory.
|
|
@@ -552,11 +637,10 @@ if [[ -z "${SEQUANT_ORCHESTRATOR:-}" ]] \
|
|
|
552
637
|
# `.cwd` is part of Claude Code's PreToolUse envelope (verified against a
|
|
553
638
|
# live payload alongside `session_id`), with $PWD as the fallback.
|
|
554
639
|
_CO_CWD="${HOOK_CWD:-$PWD}"
|
|
555
|
-
# Honor a
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
fi
|
|
640
|
+
# Honor a `cd <dir>` the same way the commit guard below does — including
|
|
641
|
+
# multi-line commands and quoted/dynamic targets (#963).
|
|
642
|
+
_CO_CD=$(resolve_cd_target "$TOOL_INPUT")
|
|
643
|
+
[[ -n "$_CO_CD" ]] && _CO_CWD="$_CO_CD"
|
|
560
644
|
|
|
561
645
|
# A linked worktree's toplevel has `.git` as a FILE; the main checkout has
|
|
562
646
|
# it as a directory.
|
|
@@ -782,18 +866,25 @@ fi
|
|
|
782
866
|
# Skips for --amend since amending doesn't require new changes
|
|
783
867
|
if [[ "$TOOL_NAME" == "Bash" ]] && seg_match 'git commit'; then
|
|
784
868
|
if ! echo "$TOOL_INPUT" | grep -qE -- '--amend|--allow-empty'; then
|
|
785
|
-
#
|
|
786
|
-
#
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
if [[ -n "$TARGET_DIR"
|
|
794
|
-
CHANGES=$(
|
|
869
|
+
# Resolve where to check for changes: the last resolvable `cd`
|
|
870
|
+
# target if the command has one (multi-line commands included —
|
|
871
|
+
# #963), else the command's own cwd from the hook payload (never
|
|
872
|
+
# this hook process's own cwd, which need not match).
|
|
873
|
+
TARGET_DIR=$(resolve_cd_target "$TOOL_INPUT")
|
|
874
|
+
HAS_CD_LINE=false
|
|
875
|
+
echo "$TOOL_INPUT" | grep -qE '^[[:space:]]*cd[[:space:]]+' && HAS_CD_LINE=true
|
|
876
|
+
|
|
877
|
+
if [[ -n "$TARGET_DIR" ]]; then
|
|
878
|
+
CHANGES=$(git -C "$TARGET_DIR" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
879
|
+
elif [[ "$HAS_CD_LINE" == true ]]; then
|
|
880
|
+
# A `cd` line is present but its target is dynamic (a shell
|
|
881
|
+
# variable/command substitution) or doesn't exist as a
|
|
882
|
+
# directory — fail open rather than check the wrong
|
|
883
|
+
# directory. `git commit` itself already rejects a genuinely
|
|
884
|
+
# empty commit, so this costs one harmless git error (#963).
|
|
885
|
+
CHANGES=1
|
|
795
886
|
else
|
|
796
|
-
CHANGES=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
887
|
+
CHANGES=$(git -C "${HOOK_CWD:-$PWD}" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
797
888
|
fi
|
|
798
889
|
|
|
799
890
|
if [[ "$CHANGES" -eq 0 ]]; then
|
|
@@ -1,64 +1,131 @@
|
|
|
1
|
-
# {{PROJECT_NAME}}
|
|
1
|
+
# {{PROJECT_NAME}} Agent Contract
|
|
2
2
|
|
|
3
|
-
This document
|
|
3
|
+
This document is the enforceable contract surface for AI-assisted development in this project. Every section either machine-checked or referenced by a named skill at a named decision point. Values with no consumer are not present.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
1.
|
|
8
|
-
2. **Test Everything** - All features must have appropriate test coverage
|
|
9
|
-
3. **Document Decisions** - Important decisions should be captured in issue comments
|
|
10
|
-
4. **Incremental Progress** - Break large tasks into small, reviewable chunks
|
|
11
|
-
5. **Respect Existing Patterns** - Follow established project conventions
|
|
7
|
+
## 1. Definition of Done
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
Every PR must pass all gates below before merge. Verified by `/qa` §7 — the table is generated from that section and cannot drift from it (`lint:constitution-dod` fails CI on divergence).
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
- Understand requirements and acceptance criteria
|
|
17
|
-
- Identify potential risks and dependencies
|
|
18
|
-
- Draft implementation plan for approval
|
|
11
|
+
**These are project-wide gates. Do not restate them as issue-level ACs.**
|
|
19
12
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
<!-- BEGIN:DOD-GATES -->
|
|
14
|
+
| Gate | Trigger | Verdict impact |
|
|
15
|
+
|------|---------|----------------|
|
|
16
|
+
| All ACs MET | any `NOT_MET` or `PARTIALLY_MET` | `AC_NOT_MET` — blocks merge |
|
|
17
|
+
| Detection patterns (§6c) | `Failed` | `AC_NOT_MET` — blocks merge |
|
|
18
|
+
| Behavior-rule check (§6e) | `Survivors Found` | `AC_NOT_MET` — blocks merge |
|
|
19
|
+
| Trust boundary (§6f) | `Injection Acted On` | `AC_NOT_MET` — blocks merge |
|
|
20
|
+
| CLI registration (§2h) | `Failed` | `AC_NOT_MET` — blocks merge |
|
|
21
|
+
| Mutation verification (§6i) | `Failed` | `AC_NOT_MET` — blocks merge |
|
|
22
|
+
| Adversarial re-read (§6d) | `Severe Gap` | `AC_NOT_MET` — blocks merge |
|
|
23
|
+
| Skill verification (§6a) | `Failed` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
24
|
+
| Script execution evidence | `Incomplete` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
25
|
+
| Declared evidence (§6h) | `Incomplete` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
26
|
+
| Mutation verification (§6i) | `Missing` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
27
|
+
| Script verification (§11) | `Not Verified` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
28
|
+
| CHANGELOG entry (§10a) | both conditions true | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
29
|
+
| Quality plan (Phase 0b) | both conditions true | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
30
|
+
| Browser test | condition true | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
31
|
+
| Pending verifications | count `> 0` | `NEEDS_VERIFICATION` — holds for external verification |
|
|
32
|
+
| Quality plan (Phase 0b) | `Partial` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
33
|
+
| Smoke tests (§6b) | `Partial` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
34
|
+
| Detection patterns (§6c) | `Insufficient Samples` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
35
|
+
| Detection patterns (§6c) | `Skipped` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
36
|
+
| Adversarial re-read (§6d) | `Gaps Found` | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
37
|
+
| Improvement suggestions | list non-empty | `AC_MET_BUT_NOT_A_PLUS` — cannot be A+ |
|
|
38
|
+
<!-- END:DOD-GATES -->
|
|
24
39
|
|
|
25
|
-
|
|
26
|
-
- Review against acceptance criteria
|
|
27
|
-
- Run all quality checks
|
|
28
|
-
- Address feedback before merge
|
|
40
|
+
---
|
|
29
41
|
|
|
30
|
-
##
|
|
42
|
+
## 2. AC Authoring Standard
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
- Use descriptive variable and function names
|
|
34
|
-
- Follow language-specific conventions (camelCase, snake_case, etc.)
|
|
44
|
+
Referenced by `/spec`'s AC Quality Check step when flagging lint warnings.
|
|
35
45
|
|
|
36
|
-
###
|
|
37
|
-
- Handle errors gracefully
|
|
38
|
-
- Log meaningful error messages
|
|
39
|
-
- Don't swallow exceptions silently
|
|
46
|
+
### Format rules
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
- Write tests for new features
|
|
43
|
-
- Update tests when modifying existing code
|
|
44
|
-
- Test edge cases and error paths
|
|
48
|
+
**Write each AC on a single line.** The parser is line-anchored; an AC that wraps to a second line is silently truncated at the first newline, producing a partial description with no `Evidence:` or `Risk:` clause. This is the most common AC-hygiene defect in this repo.
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
**Required fields for testable ACs:**
|
|
47
51
|
|
|
48
|
-
|
|
|
49
|
-
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
| `/qa` | Quality review before merge |
|
|
54
|
-
| `/loop` | Fix iteration when tests fail |
|
|
55
|
-
| `/docs` | Generate feature documentation |
|
|
52
|
+
| Field | Purpose | Required when |
|
|
53
|
+
|-------|---------|---------------|
|
|
54
|
+
| `Evidence:` | Names the artifact that proves the AC was met | AC is verifiable by code review or test |
|
|
55
|
+
| `Risk:` | Names the failure mode if this AC is wrong | AC has a non-obvious failure mode |
|
|
56
|
+
| `Human decision` | Flags the AC as requiring human judgment | AC cannot be verified mechanically |
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
**Non-Goals section:** Every issue must have a `## Non-Goals` section. Scope without a boundary is unbounded scope. The Non-Goals section is where you declare what the issue explicitly does not do.
|
|
59
|
+
|
|
60
|
+
### Examples
|
|
61
|
+
|
|
62
|
+
**Bad** (three violations on one AC):
|
|
63
|
+
```
|
|
64
|
+
- [ ] **AC-3:** The feature should work correctly and handle errors
|
|
65
|
+
gracefully with good test coverage.
|
|
66
|
+
```
|
|
67
|
+
Problems: wraps to second line (parser truncates), "work correctly" is not measurable, no `Evidence:` clause.
|
|
68
|
+
|
|
69
|
+
**Good** (single line, measurable, evidence declared):
|
|
70
|
+
```
|
|
71
|
+
- [ ] **AC-3:** `/spec`'s AC Quality Check output references the constitution AC standard. Evidence: scoped gate test on the spec skill's reference string, mutation-verified.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 3. Boundaries
|
|
77
|
+
|
|
78
|
+
Every rule below names its enforcing mechanism. Rules without a named enforcer are not in this section.
|
|
79
|
+
|
|
80
|
+
| Rule | Enforcing mechanism |
|
|
81
|
+
|------|---------------------|
|
|
82
|
+
| No force-push or amend on pushed branches | `templates/hooks/pre-tool.sh` (pre-tool hook, `HOOK_BLOCKED: Force push`) |
|
|
83
|
+
| No edits outside the issue worktree | `templates/hooks/pre-tool.sh` (worktree-only editing guard) |
|
|
84
|
+
| Gate tests must be mutation-verified | `/qa` §6i + `SEQUANT_MUTATION` marker in PR body (#939); `Missing` caps at `AC_MET_BUT_NOT_A_PLUS`, `Failed` floors at `AC_NOT_MET` |
|
|
85
|
+
| All §1 Definition of Done gates | `/qa` §7 verdict algorithm (see §1 above) |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 4. Budgets & Stop Conditions
|
|
90
|
+
|
|
91
|
+
### Iteration and token caps
|
|
92
|
+
|
|
93
|
+
| Cap | Setting key | Default |
|
|
94
|
+
|-----|-------------|---------|
|
|
95
|
+
| Quality-loop max iterations | `run.maxIterations` | 3 |
|
|
96
|
+
| Auto-wait budget (rate-limit windows) | `run.autoWaitMinutes` | 0 (off) |
|
|
97
|
+
|
|
98
|
+
When a cap is reached, the run stops at the human merge gate rather than continuing indefinitely.
|
|
99
|
+
|
|
100
|
+
### Stop and hold states
|
|
101
|
+
|
|
102
|
+
The workflow stops or holds at these states — do not attempt to continue past them:
|
|
103
|
+
|
|
104
|
+
| State | Meaning | Action |
|
|
105
|
+
|-------|---------|--------|
|
|
106
|
+
| `waiting_for_human_merge` | All gates passed; PR is open | Human reviews and merges |
|
|
107
|
+
| `awaiting_verification` | At least one AC is `PENDING` external verification | Wait for the external signal; see [`docs/features/qa-verdict-workflow-states.md`](../../docs/features/qa-verdict-workflow-states.md) |
|
|
108
|
+
| `blocked` | A guard halted the run | Investigate the block; do not bypass |
|
|
109
|
+
|
|
110
|
+
### Gap-prompt discipline
|
|
111
|
+
|
|
112
|
+
**Diagnostic prompts are cheap and high-yield. Imperative prompts require triage first.**
|
|
113
|
+
|
|
114
|
+
- **Diagnostic** ("what are the gaps?"): run freely. Surfaces unknowns at low cost.
|
|
115
|
+
- **Imperative** ("fix all gaps"): requires triage first. An unfocused imperative prompt against a list of gaps produces shallow patches for every item rather than deep fixes for the real ones. The 2026-08 incident (#930) demonstrated this directly: an imperative "fix all gaps" run against a QA verdict produced 12 surface-level changes that passed re-QA but left the root-cause gap intact, requiring a third QA cycle.
|
|
116
|
+
|
|
117
|
+
When QA returns gaps: run a diagnostic first ("which gap is the most blocking?"), then issue a targeted imperative for that gap specifically.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 5. Stack-Specific Notes
|
|
58
122
|
|
|
59
123
|
{{STACK_NOTES}}
|
|
60
124
|
|
|
61
|
-
|
|
125
|
+
---
|
|
62
126
|
|
|
63
|
-
|
|
127
|
+
## Project-Specific Notes
|
|
64
128
|
|
|
129
|
+
<!-- Add your project-specific guidelines below this line.
|
|
130
|
+
This section is preserved across `sequant update` and `sync` runs
|
|
131
|
+
(it is in CUSTOMIZABLE_FILES). Everything above is updated automatically. -->
|
|
@@ -1955,7 +1955,7 @@ The goal is to satisfy AC with the smallest, safest change possible.
|
|
|
1955
1955
|
### 6. Progress Summary and Draft Issue Update
|
|
1956
1956
|
|
|
1957
1957
|
**If orchestrated (SEQUANT_ORCHESTRATOR is set):**
|
|
1958
|
-
- Skip posting progress comments to GitHub
|
|
1958
|
+
- Skip posting progress comments to GitHub — no per-phase comment is posted under `sequant run`; progress surfaces through the run summary and the PR body (#964)
|
|
1959
1959
|
- Still provide AC coverage summary in output for orchestrator to capture
|
|
1960
1960
|
- Let orchestrator handle final GitHub update
|
|
1961
1961
|
|
|
@@ -23,7 +23,6 @@ allowed-tools:
|
|
|
23
23
|
- Bash(gh issue edit:*)
|
|
24
24
|
- Bash(gh pr create:*)
|
|
25
25
|
- Bash(gh pr list:*)
|
|
26
|
-
- Bash(gh pr merge:*)
|
|
27
26
|
- Bash(npm test:*)
|
|
28
27
|
- Bash(npm run build:*)
|
|
29
28
|
- Bash(git diff:*)
|
|
@@ -52,22 +51,28 @@ When invoked as `/fullsolve <issue-number>`, execute the complete issue resoluti
|
|
|
52
51
|
|
|
53
52
|
## CRITICAL: Auto-Progression Between Phases
|
|
54
53
|
|
|
55
|
-
**DO NOT wait for user confirmation between phases.** This is an autonomous workflow.
|
|
54
|
+
**DO NOT wait for user confirmation between phases.** This is an autonomous workflow — through PR creation.
|
|
56
55
|
|
|
57
56
|
After each phase completes successfully, **immediately proceed** to the next phase:
|
|
58
57
|
1. `/spec` completes → **immediately** invoke `/exec`
|
|
59
58
|
2. `/exec` completes → **immediately** invoke `/test` (if UI) or `/qa`
|
|
60
59
|
3. `/test` completes → **immediately** invoke `/qa`
|
|
61
|
-
4. `/qa` completes → **immediately** create PR
|
|
60
|
+
4. `/qa` completes → **immediately** create the PR and post the final summary
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
<!-- BEGIN: merge-gate (#958) -->
|
|
63
|
+
**The workflow's terminal state is PR created + final summary posted — not merged.** Merging (§5.3), post-merge verification (§5.4), and the auto-merge-path lock release (§5.5) run **only** when `--auto-merge` is passed, `run.autoMerge` is `true` in `.sequant/settings.json`, or the user has explicitly instructed a merge in this conversation (invoking `/fullsolve` alone does not count). Without one of those, `/fullsolve` stops after the final summary — the PR is left open for human review. See "Merge Gate" below for how this is resolved, and §5.3 for the gate itself.
|
|
64
|
+
|
|
65
|
+
**The user invoked `/fullsolve` expecting end-to-end automation up to a mergeable PR.** Only stop for:
|
|
64
66
|
- Unrecoverable errors (after retry attempts exhausted)
|
|
65
|
-
- Final summary after PR creation
|
|
67
|
+
- Final summary after PR creation — **this is the workflow's terminal state**, not a pause
|
|
66
68
|
- Explicit user interruption
|
|
69
|
+
<!-- END: merge-gate (#958) -->
|
|
67
70
|
|
|
68
71
|
```
|
|
69
72
|
WRONG: "Spec complete. Ready for exec phase." [waits]
|
|
70
73
|
RIGHT: "Spec complete. Proceeding to exec..." [invokes /exec immediately]
|
|
74
|
+
WRONG (no --auto-merge): [creates PR, immediately runs `gh pr merge`]
|
|
75
|
+
RIGHT (no --auto-merge): [creates PR, posts final summary, stops]
|
|
71
76
|
```
|
|
72
77
|
|
|
73
78
|
## Workflow Overview
|
|
@@ -125,6 +130,7 @@ RIGHT: "Spec complete. Proceeding to exec..." [invokes /exec immediately]
|
|
|
125
130
|
/fullsolve 218 --max-iterations 5 # Override max fix iterations
|
|
126
131
|
/fullsolve 218 --parallel # Force parallel agent execution (faster, higher token usage)
|
|
127
132
|
/fullsolve 218 --sequential # Force sequential agent execution (slower, lower token usage)
|
|
133
|
+
/fullsolve 218 --auto-merge # Merge the PR automatically once QA passes (default: off)
|
|
128
134
|
```
|
|
129
135
|
|
|
130
136
|
## Agent Execution Mode
|
|
@@ -151,6 +157,30 @@ When spawning sub-agents for quality checks, determine the execution mode:
|
|
|
151
157
|
|
|
152
158
|
**Pass execution mode to child skills:** When invoking `/qa` or other skills that spawn agents, pass the `--parallel` or `--sequential` flag to maintain consistency.
|
|
153
159
|
|
|
160
|
+
## Merge Gate (#958)
|
|
161
|
+
|
|
162
|
+
Determine whether Phase 5.3–5.5's merge workflow runs at all. This mirrors the Agent Execution Mode resolution above — flag first, then settings, defaulting closed.
|
|
163
|
+
|
|
164
|
+
1. **Check for CLI flag override:**
|
|
165
|
+
- `--auto-merge` → run the merge workflow (§5.3) after the final summary
|
|
166
|
+
- No flag → do not merge automatically; fall through to step 2
|
|
167
|
+
|
|
168
|
+
2. **If no flag, read project settings:**
|
|
169
|
+
Use the Read tool to check project settings:
|
|
170
|
+
```
|
|
171
|
+
Read(file_path=".sequant/settings.json")
|
|
172
|
+
# Parse JSON and extract run.autoMerge (default: false)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
3. **Default:** off. `/fullsolve` ends at PR creation + final summary — this
|
|
176
|
+
preserves the human merge gate recorded in #817–#819 (`sequant ready`
|
|
177
|
+
drives an issue to merge-*readiness*; a human runs `sequant merge` to
|
|
178
|
+
actually merge it).
|
|
179
|
+
|
|
180
|
+
**Explicit user instruction overrides the gate independent of the flag or setting.** If the user has told you in this conversation to merge once ready (not merely "run `/fullsolve`"), treat that as satisfying the gate for this run.
|
|
181
|
+
|
|
182
|
+
**If the gate does not fire:** skip §5.3 and §5.4 entirely. Release the concurrency locks immediately after §5.2 (see §5.5) and stop — do not attempt `gh pr merge` under any circumstance without one of the three conditions above.
|
|
183
|
+
|
|
154
184
|
## Orchestration Context
|
|
155
185
|
|
|
156
186
|
This skill acts as an **orchestrator** and sets environment variables for child skills to optimize their behavior:
|
|
@@ -306,7 +336,7 @@ npx sequant locks checkout acquire \
|
|
|
306
336
|
|
|
307
337
|
Release it alongside the per-issue lock: `npx sequant locks checkout release --issue=<issue-number> || true`. **`--issue` is mandatory** (#906) — it is what proves you are the holder. `--skip-pid-check` means the acquiring shell's PID is already dead, so PID identity is unavailable and a release without `--issue` is refused, not merely ineffective. Stale recovery is therefore age-based only for this lock: the 6h `SEQUANT_SKILL_LOCK_TTL_MS` and the 24h `SEQUANT_MAX_LOCK_AGE_MS` ceiling, *not* same-host dead-PID recovery, which `--skip-pid-check` disables by definition. An abandoned holder still cannot wedge the checkout permanently.
|
|
308
338
|
|
|
309
|
-
**Release contract:**
|
|
339
|
+
**Release contract (#958):** the happy path releases both locks **right after §5.2's final summary** — that is the workflow's default terminal state, since §5.3–5.4 do not run without the Merge Gate firing. Only when the Merge Gate *does* fire does release move to §5.5, after merge (§5.3) and post-merge verification (§5.4) complete. On ANY branch that **exits the workflow without reaching Phase 5** — spec failure, exec iterations exhausted, unrecoverable error — you MUST run `npx sequant locks release <issue-number> || true` and `npx sequant locks checkout release --issue=<issue-number> || true` **before** printing the halt message. The explicit release calls below cover the known branches; if you add a new early-exit path, add a release call there too.
|
|
310
340
|
|
|
311
341
|
**Do NOT release at a branch that continues to Phase 5.** QA-loop exhaustion and the stagnation halt both fall through to PR creation, which still runs git in this tree — releasing there would leave Phase 5 unprotected.
|
|
312
342
|
|
|
@@ -763,9 +793,17 @@ Post completion comment to issue with:
|
|
|
763
793
|
- PR link
|
|
764
794
|
- Quality metrics
|
|
765
795
|
|
|
766
|
-
### 5.3 Merge Workflow (
|
|
796
|
+
### 5.3 Merge Workflow (Opt-In Only) (#958)
|
|
767
797
|
|
|
768
|
-
**
|
|
798
|
+
**STOP — do not run this section unless the Merge Gate above fired.** That
|
|
799
|
+
means one of: `--auto-merge` was passed on this `/fullsolve` invocation,
|
|
800
|
+
`run.autoMerge` is `true` in `.sequant/settings.json`, or the user
|
|
801
|
+
explicitly instructed a merge in this conversation. If none of those hold,
|
|
802
|
+
**do not run `gh pr merge`.** Stop after §5.2's final summary instead — the
|
|
803
|
+
PR stays open, awaiting human review. That is the default terminal state,
|
|
804
|
+
not a fallback.
|
|
805
|
+
|
|
806
|
+
**IMPORTANT (once the gate above has fired):** Merge the PR first, then clean up the worktree.
|
|
769
807
|
|
|
770
808
|
```bash
|
|
771
809
|
# 1. Merge PR (without --delete-branch; cleanup happens after success)
|
|
@@ -783,6 +821,8 @@ gh pr merge <N> --squash
|
|
|
783
821
|
|
|
784
822
|
### 5.4 Post-Merge Verification
|
|
785
823
|
|
|
824
|
+
**Skip this section if §5.3 did not run.** Nothing to verify post-merge when there was no merge.
|
|
825
|
+
|
|
786
826
|
**Recommended:** After merge, verify the build and CLI still work:
|
|
787
827
|
|
|
788
828
|
```bash
|
|
@@ -800,7 +840,14 @@ If any command fails, fix immediately on main before continuing. This catches is
|
|
|
800
840
|
|
|
801
841
|
### 5.5 Release Concurrency Locks (#625, #901)
|
|
802
842
|
|
|
803
|
-
|
|
843
|
+
**Default path (Merge Gate did not fire):** release runs immediately after
|
|
844
|
+
§5.2's final summary — that is the happy path, since §5.3–5.4 never execute.
|
|
845
|
+
Run the release calls below there, not here.
|
|
846
|
+
|
|
847
|
+
**Auto-merge path (Merge Gate fired):** release runs here, after §5.3
|
|
848
|
+
(merge) and §5.4 (post-merge verification) complete.
|
|
849
|
+
|
|
850
|
+
Either way, release both locks so other sessions can claim them:
|
|
804
851
|
|
|
805
852
|
```bash
|
|
806
853
|
npx sequant locks release <issue-number> || true
|
|
@@ -949,6 +996,7 @@ Do **not** run it on the two branches below that continue to Phase 5 — "test l
|
|
|
949
996
|
| MAX_QA_ITERATIONS | 2 | Max fix loops for QA phase |
|
|
950
997
|
| SKIP_TEST | false | Skip testing phase |
|
|
951
998
|
| AUTO_PR | true | Create PR automatically |
|
|
999
|
+
| AUTO_MERGE | false | Merge the PR automatically once QA passes (#958) |
|
|
952
1000
|
|
|
953
1001
|
## Smart Tests Integration
|
|
954
1002
|
|
|
@@ -993,6 +1041,11 @@ npx tsx scripts/dev/analyze-hook-logs.ts --tests
|
|
|
993
1041
|
/fullsolve 218 --max-iterations 5
|
|
994
1042
|
```
|
|
995
1043
|
|
|
1044
|
+
**End-to-end including merge:**
|
|
1045
|
+
```
|
|
1046
|
+
/fullsolve 218 --auto-merge
|
|
1047
|
+
```
|
|
1048
|
+
|
|
996
1049
|
## Batch Processing
|
|
997
1050
|
|
|
998
1051
|
For multiple issues, run `/fullsolve` on each sequentially:
|
|
@@ -59,7 +59,7 @@ When running as part of an orchestrated workflow (e.g., `sequant run` or `/fulls
|
|
|
59
59
|
1. **Use provided worktree** - Work in `SEQUANT_WORKTREE` path directly
|
|
60
60
|
2. **Use `SEQUANT_ISSUE`** - Skip issue number parsing from invocation
|
|
61
61
|
3. **Reduce GitHub comment frequency** - Defer updates to orchestrator
|
|
62
|
-
4. **Trust
|
|
62
|
+
4. **Trust embedded context** - when the orchestrator injected a `<!-- SEQUANT_PROMPT_CONTEXT -->` block into this invocation, it is the authoritative QA-findings source; do not re-fetch from GitHub (see Step 1A below)
|
|
63
63
|
|
|
64
64
|
**Behavior when standalone (SEQUANT_ORCHESTRATOR is NOT set):**
|
|
65
65
|
|
|
@@ -81,10 +81,20 @@ When running as part of an orchestrated workflow (e.g., `sequant run` or `/fulls
|
|
|
81
81
|
|
|
82
82
|
#### Step 1A: Orchestrated Mode (SEQUANT_ORCHESTRATOR is set)
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
<!-- BEGIN: step-1a-context-source (#960) -->
|
|
85
|
+
|
|
86
|
+
**Check your own invocation first — before fetching anything.** The orchestrator (`ready-gate.ts` or `batch-executor.ts`, via `buildLoopContext`) may already have embedded the QA findings directly into the prompt that invoked this `/loop` run, wrapped in a `<!-- SEQUANT_PROMPT_CONTEXT -->` / `<!-- /SEQUANT_PROMPT_CONTEXT -->` sentinel pair (`getPhasePrompt`, `src/lib/workflow/phase-executor.ts`). When that sentinel is present in your own invocation text:
|
|
87
|
+
|
|
88
|
+
- Treat the text between the markers as the authoritative QA findings (`qa_comment` below).
|
|
89
|
+
- **Do not** fetch `gh issue view` for QA comments — skip straight to "Parsing QA comment" below, using the embedded text in place of the fetched comment.
|
|
90
|
+
- **The embedded block's gap list IS your `recommendations`.** The block is not QA-comment-shaped — the parsing snippets below (verdict grep aside) won't extract anything from it. Read the list under `Gaps to address:` (ready-gate) or `QA Gaps:` (batch-executor) directly as the findings to fix; the `QA Verdict:` line is the verdict.
|
|
91
|
+
- That gap list is already `fixableGaps`-filtered by the orchestrator (`selectFixableGaps` in `batch-executor.ts`, or ready-gate's own filter), so the `document`/`pause_for_human` exclusion in "Excluded Finding Classes" below is redundant for it — it exists for the fetched-comment fallback. But this applies **only to the gap list**: any `Suggestions:` or `Last output:` sections in the block (batch-executor only) are raw, unfiltered context — use them for understanding, never as additional findings to fix.
|
|
92
|
+
|
|
93
|
+
**Only when the sentinel is absent** from your invocation — a standalone-style dispatch, or an orchestrator that doesn't inject `promptContext` — fall back to reading QA findings from the GitHub issue comments instead of a log file:
|
|
85
94
|
|
|
86
95
|
```bash
|
|
87
|
-
#
|
|
96
|
+
# Fallback: no embedded SEQUANT_PROMPT_CONTEXT sentinel in the invocation.
|
|
97
|
+
# Fetch QA findings from GitHub comments instead.
|
|
88
98
|
if [[ -n "$SEQUANT_ORCHESTRATOR" ]]; then
|
|
89
99
|
echo "Orchestrated mode detected (orchestrator: $SEQUANT_ORCHESTRATOR)"
|
|
90
100
|
|
|
@@ -96,6 +106,8 @@ if [[ -n "$SEQUANT_ORCHESTRATOR" ]]; then
|
|
|
96
106
|
fi
|
|
97
107
|
```
|
|
98
108
|
|
|
109
|
+
<!-- END: step-1a-context-source (#960) -->
|
|
110
|
+
|
|
99
111
|
**How to identify QA comments:**
|
|
100
112
|
|
|
101
113
|
| Pattern | Meaning |
|
|
@@ -103,7 +115,7 @@ fi
|
|
|
103
115
|
| `## QA Review for Issue #N` | QA phase comment header |
|
|
104
116
|
| `### Verdict:` | Contains AC_NOT_MET, AC_MET_BUT_NOT_A_PLUS, etc. |
|
|
105
117
|
| `### AC Coverage` | Table with MET/NOT_MET/PARTIALLY_MET statuses |
|
|
106
|
-
|
|
|
118
|
+
| `<!-- SEQUANT_QA_GAPS: {...} -->` | Structured findings — the primary source for `recommendations` (#937; see below) |
|
|
107
119
|
|
|
108
120
|
**Parsing QA comment:**
|
|
109
121
|
|
|
@@ -116,14 +128,58 @@ verdict=$(echo "$qa_comment" | grep -oE "Verdict:\s*\w+" | head -1 | awk '{print
|
|
|
116
128
|
# Extract NOT_MET AC items
|
|
117
129
|
not_met_acs=$(echo "$qa_comment" | grep -E "NOT_MET|PARTIALLY_MET" || true)
|
|
118
130
|
|
|
119
|
-
#
|
|
120
|
-
|
|
131
|
+
# #937: prefer the structured SEQUANT_QA_GAPS marker over prose scraping.
|
|
132
|
+
# `### Required Fixes` was removed — no QA output template ever emitted that
|
|
133
|
+
# heading, so the old `sed -n '/### Required Fixes/,/###/p'` extraction was
|
|
134
|
+
# dead code that always produced an empty `recommendations`. The marker's
|
|
135
|
+
# payload is an array of objects, so a single node -e does the stripping,
|
|
136
|
+
# matching, AND JSON.parse/filter in one script — instead of hand-rolled
|
|
137
|
+
# jq/awk — mirroring the "do real parsing in TS/JS, keep shell to presence
|
|
138
|
+
# checks" split from the #871 drift-guard lesson (the same taxonomy filter
|
|
139
|
+
# also lives in `selectFixableGaps`, `src/lib/workflow/phase-executor.ts` —
|
|
140
|
+
# this is the shell-side mirror for standalone/orchestrated-comment-scrape
|
|
141
|
+
# mode, not a duplicate contract).
|
|
142
|
+
#
|
|
143
|
+
# Stripping fenced/inline code before matching mirrors `stripMarkdownCode`
|
|
144
|
+
# (src/lib/workflow/phase-detection.ts) — a bare grep/sed would mistake a
|
|
145
|
+
# marker quoted inside a code fence (e.g. this skill's own "QA Log Example"
|
|
146
|
+
# below) for a real one. Latest-wins if more than one marker is present,
|
|
147
|
+
# matching `parseQaGapsMarker`'s semantics.
|
|
148
|
+
recommendations=$(printf '%s' "$qa_comment" | node -e '
|
|
149
|
+
let input = "";
|
|
150
|
+
process.stdin.on("data", (d) => (input += d));
|
|
151
|
+
process.stdin.on("end", () => {
|
|
152
|
+
const stripped = input
|
|
153
|
+
.replace(/`{3,}[\s\S]*?`{3,}|~{3,}[\s\S]*?~{3,}/g, "")
|
|
154
|
+
.replace(/`[^`\n]+`/g, "");
|
|
155
|
+
const matches = [...stripped.matchAll(/<!-- SEQUANT_QA_GAPS: (\{[\s\S]*?\}) -->/g)];
|
|
156
|
+
if (matches.length === 0) return;
|
|
157
|
+
try {
|
|
158
|
+
const payload = JSON.parse(matches[matches.length - 1][1]);
|
|
159
|
+
const findings = Array.isArray(payload.findings) ? payload.findings : [];
|
|
160
|
+
for (const f of findings) {
|
|
161
|
+
if (f.recommendedAction === "document" || f.recommendedAction === "pause_for_human") continue;
|
|
162
|
+
console.log(`- ${f.description}`);
|
|
163
|
+
}
|
|
164
|
+
} catch {
|
|
165
|
+
// Malformed marker JSON — leave recommendations empty, not a crash.
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
' || true)
|
|
169
|
+
|
|
170
|
+
# No marker (QA output predates #937, or emitted an empty findings array
|
|
171
|
+
# with everything filtered) — fall back to the AC-table NOT_MET/PARTIALLY_MET
|
|
172
|
+
# rows already captured above; there is no prose "Required Fixes" section to
|
|
173
|
+
# scrape.
|
|
174
|
+
if [[ -z "$recommendations" ]]; then
|
|
175
|
+
recommendations="$not_met_acs"
|
|
176
|
+
fi
|
|
121
177
|
```
|
|
122
178
|
|
|
123
|
-
**If
|
|
124
|
-
1. Log a clear error: `"Warning: No QA comment found
|
|
179
|
+
**If neither an embedded `SEQUANT_PROMPT_CONTEXT` block nor a matching GitHub QA comment is found in orchestrated mode:**
|
|
180
|
+
1. Log a clear error: `"Warning: No embedded context or QA comment found for issue #N"`
|
|
125
181
|
2. Fall back to Step 1B (log file) as a recovery mechanism
|
|
126
|
-
3. If log file also doesn't exist, exit with error
|
|
182
|
+
3. If log file also doesn't exist, exit with error — do not silently report "no actionable issues"; a silent miss here is the exact failure mode this section exists to prevent (#960)
|
|
127
183
|
|
|
128
184
|
#### Step 1B: Standalone Mode (no SEQUANT_ORCHESTRATOR)
|
|
129
185
|
|
|
@@ -178,13 +234,14 @@ Some QA findings are real but **not fixable by a code change**. Feeding them to
|
|
|
178
234
|
| Class | Marker in the QA comment | Why it is not actionable |
|
|
179
235
|
|-------|--------------------------|--------------------------|
|
|
180
236
|
| Infra-blocked CI | `<!-- qa:ci-infra-blocked -->` | Every check failed without a runner ever starting (e.g. an Actions spending-limit lockout). The cause is account/infrastructure state; no diff can turn the checks green. See `qa/SKILL.md` § "Infra-Blocked CI Detection". |
|
|
237
|
+
| `document`/`pause_for_human` findings | `<!-- SEQUANT_QA_GAPS: {...} -->`, per-finding `recommendedAction` | Quality/polish gaps deliberately deferred (`document`), or findings needing a human decision the loop can't make on its own (`pause_for_human`) — see #937. Filtered directly out of the `recommendations` extraction above (Step 1A), not by rebinding `qa_comment` — the marker's structure makes a per-finding filter more precise than a text-range delete. |
|
|
181
238
|
|
|
182
239
|
```bash
|
|
183
240
|
# Drop the marked findings when QA flagged CI as infra-blocked, so its
|
|
184
241
|
# NEEDS_VERIFICATION AC items are never mistaken for actionable findings.
|
|
185
242
|
# Range is EXCLUSIVE of the next `### ` header — a `sed '/marker/,/^### /d'`
|
|
186
243
|
# range would delete that header too and orphan the following section's
|
|
187
|
-
# content (verified
|
|
244
|
+
# content (verified against this file's own `### AC Coverage` header).
|
|
188
245
|
qa_comment_raw="$qa_comment" # keep the original so the cause can be reported verbatim
|
|
189
246
|
|
|
190
247
|
if echo "$qa_comment" | grep -q '<!-- qa:ci-infra-blocked -->'; then
|
|
@@ -513,13 +570,15 @@ For each iteration, output:
|
|
|
513
570
|
|
|
514
571
|
### Verdict: AC_NOT_MET
|
|
515
572
|
|
|
516
|
-
###
|
|
573
|
+
### Next Steps
|
|
517
574
|
|
|
518
575
|
1. Complete URL validation in ExternalUrlTab
|
|
519
576
|
2. Add focal point persistence in updateArticleImage action
|
|
577
|
+
|
|
578
|
+
<!-- SEQUANT_QA_GAPS: {"findings":[{"category":"requirement_gap","evidence":"AC-3 row: PARTIALLY_MET — External URL validation incomplete","description":"Complete URL validation in ExternalUrlTab","recommendedAction":"fix_now","affectedAcs":["AC-3"]},{"category":"requirement_gap","evidence":"AC-4 row: NOT_MET — Focal point not persisted to database","description":"Add focal point persistence in updateArticleImage action","recommendedAction":"fix_now","affectedAcs":["AC-4"]}]} -->
|
|
520
579
|
```
|
|
521
580
|
|
|
522
|
-
**Parsed Output
|
|
581
|
+
**Parsed Output** (marker-derived — this is the real emission shape, see §"How to build the marker" in `qa/SKILL.md`):
|
|
523
582
|
- Last phase: `/qa`
|
|
524
583
|
- Verdict: `AC_NOT_MET`
|
|
525
584
|
- Issues to fix:
|