workflow-toolkit 1.0.1
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/.agents/skills/ponytail/SKILL.md +111 -0
- package/.agents/skills/ponytail-audit/SKILL.md +37 -0
- package/.agents/skills/ponytail-debt/SKILL.md +41 -0
- package/.agents/skills/ponytail-gain/SKILL.md +47 -0
- package/.agents/skills/ponytail-help/SKILL.md +70 -0
- package/.agents/skills/ponytail-review/SKILL.md +52 -0
- package/.agents/skills/prompt-review/SKILL.md +60 -0
- package/.agents/skills/wtk/SKILL.md +64 -0
- package/.agents/skills/wtk/references/artifacts.md +82 -0
- package/.agents/skills/wtk/references/evidence.md +68 -0
- package/.agents/skills/wtk/references/git.md +75 -0
- package/.agents/skills/wtk/references/test-contract.md +76 -0
- package/.agents/skills/wtk/references/validation.md +127 -0
- package/.agents/skills/wtk-config/SKILL.md +102 -0
- package/.agents/skills/wtk-config/assets/agents/claude/deep-reviewer.md +40 -0
- package/.agents/skills/wtk-config/assets/agents/claude/designer.md +57 -0
- package/.agents/skills/wtk-config/assets/agents/claude/explorer.md +41 -0
- package/.agents/skills/wtk-config/assets/agents/claude/implementer.md +57 -0
- package/.agents/skills/wtk-config/assets/agents/claude/planner.md +68 -0
- package/.agents/skills/wtk-config/assets/agents/claude/verifier.md +80 -0
- package/.agents/skills/wtk-config/assets/agents/codex/deep-reviewer.toml +41 -0
- package/.agents/skills/wtk-config/assets/agents/codex/designer.toml +55 -0
- package/.agents/skills/wtk-config/assets/agents/codex/explorer.toml +35 -0
- package/.agents/skills/wtk-config/assets/agents/codex/implementer.toml +52 -0
- package/.agents/skills/wtk-config/assets/agents/codex/planner.toml +66 -0
- package/.agents/skills/wtk-config/assets/agents/codex/verifier.toml +78 -0
- package/.agents/skills/wtk-config/assets/agents/cursor/deep-reviewer.md +38 -0
- package/.agents/skills/wtk-config/assets/agents/cursor/designer.md +55 -0
- package/.agents/skills/wtk-config/assets/agents/cursor/explorer.md +39 -0
- package/.agents/skills/wtk-config/assets/agents/cursor/implementer.md +55 -0
- package/.agents/skills/wtk-config/assets/agents/cursor/planner.md +66 -0
- package/.agents/skills/wtk-config/assets/agents/cursor/verifier.md +79 -0
- package/.agents/skills/wtk-config/scripts/ad-index.py +123 -0
- package/.agents/skills/wtk-config/scripts/repository_intelligence.py +671 -0
- package/.agents/skills/wtk-config/scripts/workflow_config.py +972 -0
- package/.agents/skills/wtk-deep-review/SKILL.md +164 -0
- package/.agents/skills/wtk-deep-review/assets/PROMPT.md +56 -0
- package/.agents/skills/wtk-deep-review/assets/REVIEW_UI.html +1340 -0
- package/.agents/skills/wtk-deep-review/assets/findings.schema.json +113 -0
- package/.agents/skills/wtk-deep-review/references/context-pack.md +88 -0
- package/.agents/skills/wtk-deep-review/references/orchestration.md +164 -0
- package/.agents/skills/wtk-deep-review/references/output-contracts.md +149 -0
- package/.agents/skills/wtk-deep-review/references/publish-github.md +83 -0
- package/.agents/skills/wtk-deep-review/references/state-and-learnings.md +64 -0
- package/.agents/skills/wtk-deep-review/references/subagent-runtimes.md +33 -0
- package/.agents/skills/wtk-deep-review/references/taxonomy.md +70 -0
- package/.agents/skills/wtk-deep-review/scripts/_common.py +371 -0
- package/.agents/skills/wtk-deep-review/scripts/build_jobs.py +561 -0
- package/.agents/skills/wtk-deep-review/scripts/build_knowledge.py +349 -0
- package/.agents/skills/wtk-deep-review/scripts/build_manifest.py +479 -0
- package/.agents/skills/wtk-deep-review/scripts/graft_context.py +160 -0
- package/.agents/skills/wtk-deep-review/scripts/graphify_context.py +75 -0
- package/.agents/skills/wtk-deep-review/scripts/merge_findings.py +313 -0
- package/.agents/skills/wtk-deep-review/scripts/render_html.py +240 -0
- package/.agents/skills/wtk-deep-review/scripts/render_review.py +282 -0
- package/.agents/skills/wtk-deep-review/scripts/run_jobs.py +436 -0
- package/.agents/skills/wtk-deep-review/scripts/token_metrics.py +369 -0
- package/.agents/skills/wtk-discover/SKILL.md +270 -0
- package/.agents/skills/wtk-discover/references/document-format.md +149 -0
- package/.agents/skills/wtk-implement/SKILL.md +95 -0
- package/.agents/skills/wtk-implement/references/checklist-format.md +116 -0
- package/.agents/skills/wtk-implement/references/screens.md +129 -0
- package/.agents/skills/wtk-implement/references/test-policy.md +152 -0
- package/.agents/skills/wtk-implement/references/verify.md +297 -0
- package/.agents/skills/wtk-knowledge-check/SKILL.md +16 -0
- package/.agents/skills/wtk-knowledge-check/scripts/check.ts +502 -0
- package/.agents/skills/wtk-knowledge-check/scripts/cli.ts +32 -0
- package/.agents/skills/wtk-knowledge-check/scripts/frontmatter.ts +44 -0
- package/.agents/skills/wtk-lean/.skill-meta.json +6 -0
- package/.agents/skills/wtk-lean/NOTICE.md +18 -0
- package/.agents/skills/wtk-lean/SKILL.md +137 -0
- package/.agents/skills/wtk-lean/references/build.md +168 -0
- package/.agents/skills/wtk-lean/references/checks.md +253 -0
- package/.agents/skills/wtk-lean/references/memory.md +156 -0
- package/.agents/skills/wtk-lean/references/plan.md +514 -0
- package/.agents/skills/wtk-lean/references/verify.md +336 -0
- package/.agents/skills/wtk-lean/scripts/check_commit.py +121 -0
- package/.agents/skills/wtk-lean/scripts/fixtures/checks.md +98 -0
- package/.agents/skills/wtk-lean/scripts/fixtures/plan.md +119 -0
- package/.agents/skills/wtk-lean/scripts/fixtures/verification.md +41 -0
- package/.agents/skills/wtk-lean/scripts/lessons.py +412 -0
- package/.agents/skills/wtk-lean/scripts/selftest.py +401 -0
- package/.agents/skills/wtk-lean/scripts/validate_checks.py +417 -0
- package/.agents/skills/wtk-lean/scripts/validate_plan.py +580 -0
- package/.agents/skills/wtk-lean/scripts/validate_verification.py +357 -0
- package/.agents/skills/wtk-plan/SKILL.md +102 -0
- package/.agents/skills/wtk-plan/references/document-format.md +222 -0
- package/.agents/skills/wtk-qa/SKILL.md +14 -0
- package/.agents/skills/wtk-qa-execute/SKILL.md +115 -0
- package/.agents/skills/wtk-qa-execute/references/fix-loop.md +23 -0
- package/.agents/skills/wtk-qa-execute/references/session-protocol.md +25 -0
- package/.agents/skills/wtk-qa-plan/SKILL.md +111 -0
- package/.agents/skills/wtk-qa-plan/references/profile.md +35 -0
- package/.agents/skills/wtk-ship/SKILL.md +49 -0
- package/.agents/skills/wtk-ship/remediation.py +170 -0
- package/.agents/skills/wtk-ship/scripts/close_feature.py +83 -0
- package/.agents/skills/wtk-ship/scripts/review_convergence.py +373 -0
- package/.wtk.toml.example +93 -0
- package/AGENTS.md +129 -0
- package/NOTICE.md +12 -0
- package/README.md +440 -0
- package/bin/wtk.js +25 -0
- package/docs/toolkit/README.md +56 -0
- package/docs/toolkit/decisions.md +61 -0
- package/docs/toolkit/guidelines/CONTEXT-BUDGET.md +64 -0
- package/docs/toolkit/guidelines/DX.md +67 -0
- package/docs/toolkit/guidelines/FRONTEND.md +73 -0
- package/docs/toolkit/guidelines/KNOWLEDGE-WIKI.md +128 -0
- package/docs/toolkit/guidelines/MODELING.md +134 -0
- package/docs/toolkit/guidelines/QA-EXECUTION.md +46 -0
- package/docs/toolkit/guidelines/QA-SCENARIOS.md +165 -0
- package/docs/toolkit/guidelines/REVIEW-ROUNDS.md +160 -0
- package/docs/toolkit/guidelines/SECURITY.md +160 -0
- package/docs/toolkit/guidelines/UI-UX.md +117 -0
- package/docs/toolkit/guidelines/WORKFLOW-MEMORY.md +73 -0
- package/docs/toolkit/guidelines.md +50 -0
- package/docs/toolkit/loop.md +77 -0
- package/docs/toolkit/purpose.md +51 -0
- package/docs/toolkit/repository-intelligence.md +53 -0
- package/docs/toolkit/reviews.md +77 -0
- package/knowledge/AGENTS.md +316 -0
- package/knowledge/raw/README.md +17 -0
- package/package.json +74 -0
- package/scripts/install_security_skills.py +816 -0
- package/scripts/installer/engine.js +254 -0
- package/scripts/installer/knowledge.js +28 -0
- package/scripts/installer/packets.js +77 -0
- package/scripts/installer/terminal.js +98 -0
- package/scripts/installer/transaction.js +75 -0
- package/skills-lock.json +92 -0
- package/templates/adoption/agents/core.md +23 -0
- package/templates/adoption/agents/quality.md +3 -0
- package/templates/adoption/knowledge/wiki/architecture/index.md +3 -0
- package/templates/adoption/knowledge/wiki/decisions/index.md +3 -0
- package/templates/adoption/knowledge/wiki/design/index.md +3 -0
- package/templates/adoption/knowledge/wiki/domain/index.md +3 -0
- package/templates/adoption/knowledge/wiki/index.md +3 -0
- package/templates/adoption/knowledge/wiki/log.md +3 -0
- package/templates/adoption/knowledge/wiki/open-questions/index.md +3 -0
- package/templates/adoption/knowledge/wiki/product/index.md +3 -0
- package/templates/adoption/knowledge/wiki/research/index.md +3 -0
- package/templates/adoption/product/AGENT-CONTEXT.md +25 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"required": ["defects", "advisories", "suppressions", "coverage"],
|
|
4
|
+
"properties": {
|
|
5
|
+
"defects": {
|
|
6
|
+
"type": "array",
|
|
7
|
+
"items": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"required": ["file", "line", "in_diff", "hunk", "category", "severity", "quick_win", "title", "body", "rule_ids", "evidence"],
|
|
10
|
+
"properties": {
|
|
11
|
+
"file": { "type": "string" },
|
|
12
|
+
"line": { "type": "integer" },
|
|
13
|
+
"end_line": { "type": ["integer", "null"] },
|
|
14
|
+
"in_diff": { "type": "boolean" },
|
|
15
|
+
"hunk": { "type": ["string", "null"] },
|
|
16
|
+
"rule_ids": { "type": "array", "items": { "type": "string" } },
|
|
17
|
+
"category": { "enum": ["potential-issue"] },
|
|
18
|
+
"severity": { "enum": ["critical", "major", "minor"] },
|
|
19
|
+
"quick_win": { "type": "boolean" },
|
|
20
|
+
"title": { "type": "string", "maxLength": 100 },
|
|
21
|
+
"body": { "type": "string" },
|
|
22
|
+
"also_applies": { "type": "array", "items": { "type": "string" } },
|
|
23
|
+
"guideline": { "type": ["string", "null"] },
|
|
24
|
+
"suggestion": { "type": ["string", "null"] },
|
|
25
|
+
"evidence": { "type": "array", "minItems": 1, "items": { "type": "string" } }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"advisories": {
|
|
30
|
+
"type": "array",
|
|
31
|
+
"items": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"required": ["file", "line", "in_diff", "hunk", "category", "severity", "quick_win", "title", "body", "rule_ids", "evidence"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"file": { "type": "string" },
|
|
36
|
+
"line": { "type": "integer" },
|
|
37
|
+
"end_line": { "type": ["integer", "null"] },
|
|
38
|
+
"in_diff": { "type": "boolean" },
|
|
39
|
+
"hunk": { "type": ["string", "null"] },
|
|
40
|
+
"rule_ids": { "type": "array", "items": { "type": "string" } },
|
|
41
|
+
"category": { "enum": ["refactor", "nitpick"] },
|
|
42
|
+
"severity": { "enum": ["minor", "trivial"] },
|
|
43
|
+
"quick_win": { "type": "boolean" },
|
|
44
|
+
"title": { "type": "string", "maxLength": 100 },
|
|
45
|
+
"body": { "type": "string" },
|
|
46
|
+
"also_applies": { "type": "array", "items": { "type": "string" } },
|
|
47
|
+
"guideline": { "type": ["string", "null"] },
|
|
48
|
+
"suggestion": { "type": ["string", "null"] },
|
|
49
|
+
"evidence": { "type": "array", "minItems": 1, "items": { "type": "string" } }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"prior_findings": {
|
|
54
|
+
"type": "array",
|
|
55
|
+
"items": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"required": ["fingerprint", "status", "evidence"],
|
|
58
|
+
"properties": {
|
|
59
|
+
"fingerprint": { "type": "string" },
|
|
60
|
+
"status": { "enum": ["resolved", "open"] },
|
|
61
|
+
"evidence": { "type": "string" }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"suppressions": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"items": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"required": ["file", "line", "hunk", "candidate", "reason", "rule_ids", "note"],
|
|
70
|
+
"properties": {
|
|
71
|
+
"file": { "type": "string" },
|
|
72
|
+
"line": { "type": ["integer", "null"] },
|
|
73
|
+
"hunk": { "type": ["string", "null"] },
|
|
74
|
+
"candidate": { "type": "string", "maxLength": 140 },
|
|
75
|
+
"reason": { "enum": ["linter-overlap", "intentional", "generated-vendored", "formatting", "speculative", "pre-existing", "phantom-knowledge", "duplicate-within-job"] },
|
|
76
|
+
"rule_ids": { "type": "array", "items": { "type": "string" } },
|
|
77
|
+
"note": { "type": "string" }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"coverage": {
|
|
82
|
+
"type": "object",
|
|
83
|
+
"required": ["hunks", "rules"],
|
|
84
|
+
"properties": {
|
|
85
|
+
"hunks": {
|
|
86
|
+
"type": "array",
|
|
87
|
+
"items": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"required": ["file", "hunk", "checks", "outcome"],
|
|
90
|
+
"properties": {
|
|
91
|
+
"file": { "type": "string" },
|
|
92
|
+
"hunk": { "type": "string" },
|
|
93
|
+
"checks": { "type": "array", "minItems": 1, "items": { "type": "string" } },
|
|
94
|
+
"outcome": { "enum": ["clear", "reported"] }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"rules": {
|
|
99
|
+
"type": "array",
|
|
100
|
+
"items": {
|
|
101
|
+
"type": "object",
|
|
102
|
+
"required": ["rule_id", "status", "note"],
|
|
103
|
+
"properties": {
|
|
104
|
+
"rule_id": { "type": "string" },
|
|
105
|
+
"status": { "enum": ["compliant", "violated", "not-applicable"] },
|
|
106
|
+
"note": { "type": "string" }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Context Pack
|
|
2
|
+
|
|
3
|
+
How to assemble `<out>/context-pack.md` — the shared context every reviewer and sweep receives. **Keep it lean: target ≤ ~10 KB.** Every agent in the fan-out reads it in full, so each extra kilobyte is paid once per agent; reviewers dig into the code themselves (rg, git, file reads), so the pack carries only what they cannot cheaply rediscover — intent, review law, and what the linters already caught.
|
|
4
|
+
|
|
5
|
+
## 1. Repository knowledge — discover before extracting
|
|
6
|
+
|
|
7
|
+
Run the read-only discovery/bootstrap helper after the manifest:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
python3 <skill-dir>/scripts/build_knowledge.py --out <out>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
It discovers every repository-local root/nested `AGENTS.md` and `CLAUDE.md`, repo review config/learnings, project `SKILL.md` under conventional local skill roots, and direct markdown references of candidate skills. Nested instructions apply to selected paths in their directory subtree; all ancestors remain applicable and deeper sources have higher precedence.
|
|
14
|
+
|
|
15
|
+
`knowledge.json` records why every source is or is not a candidate. `rules.template.json` starts every candidate as `pending`. Read each pending source **in full**; for a selected skill, read each pending direct reference in full too. Copy the template to `rules.json` and change every pending row to:
|
|
16
|
+
|
|
17
|
+
- `applied` — the source was read and governs at least one selected path; or
|
|
18
|
+
- `not-applicable` — include a concrete reason why it does not govern this change.
|
|
19
|
+
|
|
20
|
+
`build_jobs.py` rejects missing sources, pending statuses, empty reasons, rule sources not marked applied, and rule scopes that match no selected path.
|
|
21
|
+
|
|
22
|
+
## 2. Rubric — extract the review law
|
|
23
|
+
|
|
24
|
+
Extract verdict-bearing rules in precedence order (higher wins on conflict):
|
|
25
|
+
|
|
26
|
+
1. Path instructions from repo review config.
|
|
27
|
+
2. Nested `AGENTS.md` / `CLAUDE.md`, deepest applicable directory first.
|
|
28
|
+
3. Root `AGENTS.md` / `CLAUDE.md`.
|
|
29
|
+
4. Explicitly dispatched or change-relevant project skills and their required references.
|
|
30
|
+
5. `.wtk-deep-review/learnings.md` entries whose scope matches selected files.
|
|
31
|
+
|
|
32
|
+
Extract only rules that can bind a review result (error handling, testing shape, layering, security, naming, documentation, design tokens, framework patterns). Operational commands can leave an applied source with zero rules when the accounting reason says it was read but contains no review law. Register each rule once and keep its text verbatim:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{ "sources": [
|
|
36
|
+
{ "source": "AGENTS.md", "kind": "instruction", "status": "applied",
|
|
37
|
+
"reason": "root rules govern every selected path" }
|
|
38
|
+
],
|
|
39
|
+
"rules": [
|
|
40
|
+
{ "id": "R07", "scope": ["**/*_test.go"], "source": "AGENTS.md",
|
|
41
|
+
"guideline": "MUST use t.Run(\"Should...\") pattern for ALL test cases" }
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`scope` is the path-instruction glob, the instruction file's directory subtree, the selected skill's routed paths, or the learning's scope. To preserve the fan-out budget, the pack lists applied sources/rule counts plus one aggregate not-applicable count; complete per-source decisions stay in rules.json. `build_jobs.py` injects bound rules into defect cohorts and sweeps, and each output accounts for every assigned rule.
|
|
47
|
+
|
|
48
|
+
## 3. Linter lanes — run first, suppress overlaps
|
|
49
|
+
|
|
50
|
+
Detect what the repo already enforces and run it scoped to selected files; findings a lane reports are suppressed from the review (taxonomy rule 1).
|
|
51
|
+
|
|
52
|
+
| Signal in repo | Lane command (scope to changed files where supported) |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `Makefile` with `lint`/`check` target | `make lint` (authoritative when present — prefer it over raw tools) |
|
|
55
|
+
| `golangci-lint` config / Go modules | `golangci-lint run <changed dirs>` |
|
|
56
|
+
| `package.json` scripts `lint`/`typecheck` | the repo's own script via its package manager |
|
|
57
|
+
| eslint/biome/oxlint config | corresponding tool on changed files |
|
|
58
|
+
| `tsconfig.json` | `tsc --noEmit` (project-wide; cheap signal) |
|
|
59
|
+
| `ruff.toml` / pyproject | `ruff check <files>` |
|
|
60
|
+
| `Cargo.toml` | `cargo clippy` |
|
|
61
|
+
|
|
62
|
+
Record per lane: `ran` (attach findings on selected files, trimmed) or `unavailable` (tool missing/failed — overlap suppression is off for that lane and review.md must say so). Never install tools to fill a lane.
|
|
63
|
+
|
|
64
|
+
## 4. PR intent
|
|
65
|
+
|
|
66
|
+
With `--pr`: title, description, linked issues (`gh pr view N --json title,body,closingIssuesReferences`), and base/head. Locally: `git log --oneline <base>..<head>` plus the user's stated intent. Reviewers judge the diff against *stated intent* — a change that does more than its description says is itself a finding.
|
|
67
|
+
|
|
68
|
+
## 5. Spec contract (`--spec`)
|
|
69
|
+
|
|
70
|
+
Resolve the conformance baseline: a file path is itself the artifact; a directory contributes its contract-bearing documents — `_prd.md`, `_techspec.md`, `_tests.md`, `_examples.md`, `_qa.md`, `_user_stories.md`, parity maps, requirement/UX docs, plus any document the spec's own files name as canonical. List every resolved artifact as `path → one-line role` for Technical Verifier context. Deep Review does not dispatch a separate spec-parity proof job; do NOT extract rubric rules from these artifacts: §1 sources are review law, the spec is the contract under test.
|
|
71
|
+
|
|
72
|
+
## 6. context-pack.md layout
|
|
73
|
+
|
|
74
|
+
```markdown
|
|
75
|
+
# Context Pack — <target>
|
|
76
|
+
|
|
77
|
+
## Intent
|
|
78
|
+
<title/description/commits digest>
|
|
79
|
+
|
|
80
|
+
## Rubric
|
|
81
|
+
<applied source: path → rule count; N other sources classified not-applicable in rules.json; canonical forms: knowledge.json + rules.json>
|
|
82
|
+
|
|
83
|
+
## Linters
|
|
84
|
+
<lane → ran(findings digest) | unavailable(reason)>
|
|
85
|
+
|
|
86
|
+
## Spec contract
|
|
87
|
+
<only with --spec: one `- `path`` line per artifact — render_review.py parses these lines for the conformance table>
|
|
88
|
+
```
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Orchestration
|
|
2
|
+
|
|
3
|
+
The pipeline stage map, cohort planning rules, sweep triggers, and the execution engines. Prompt wording is single-sourced in `assets/PROMPT.md` (rendered by `build_jobs.py`); output shape in `assets/findings.schema.json` — this file explains how the stages compose and how jobs get executed.
|
|
4
|
+
|
|
5
|
+
## Pipeline — stages, gates, artifacts
|
|
6
|
+
|
|
7
|
+
Every stage materializes jobs with lane ownership (`{label, kind, lane, prompt, output, required_hunks, rule_ids}`), executes them on any engine, and passes a script gate. Valid outputs are preserved, so re-running touches only missing or invalid work.
|
|
8
|
+
|
|
9
|
+
| Stage | Produce | Execute | Gate (exit 0) |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| Knowledge | `build_knowledge.py` → knowledge.json + rules.template.json | — | source discovery |
|
|
12
|
+
| Plan | `build_jobs.py` → prompts + jobs.json | — | source accounting + ownership |
|
|
13
|
+
| Review | — | jobs.json (defect cohorts + sweeps) | `run_jobs.py --validate-only` |
|
|
14
|
+
| Merge | `merge_findings.py` → findings.json + review-stats.json | — | complete defect-lane coverage |
|
|
15
|
+
| Report | `render_review.py` → review.md + state.json; `render_html.py` → review.html | — | `render_review.py` |
|
|
16
|
+
|
|
17
|
+
Both job kinds (`cohort`, `sweep`) return the same schema: defects, advisories, objective suppressions, hunk coverage, and explicit rule accounting. `hunk` is the assigned canonical range (`<side>:<start>-<end>`), null outside the diff. Defects use the causal certificate; advisories use the improvement certificate.
|
|
18
|
+
|
|
19
|
+
## Cohort rules (Step 2)
|
|
20
|
+
|
|
21
|
+
1. Group selected files by package/directory and domain: a source file, its tests, and its types travel together; a file pulled apart from its test loses its reviewer the cheapest evidence.
|
|
22
|
+
2. Size: target ~400 changed lines per cohort, so at most `min(concurrency, ceil(changed_lines / 400))` cohorts (fewer is allowed), each ≤ `--max-cohort-files` files (default `100`) **and** ≤ ~6,000 changed lines. Pass the same value to `build_jobs.py`; a single oversized file becomes its own cohort.
|
|
23
|
+
3. **Oversized-file split** — when one file alone exceeds ~6,000 changed lines, divide the search across sibling reviewers: same file, disjoint slices of its manifest hunks (`hunk_scope`), one cohort per slice. Every slice reviewer reads the whole file for context but judges only its slice; build_jobs.py proves the merged slices cover every hunk line exactly once.
|
|
24
|
+
4. Tag each cohort `risk: high|normal|low` — high when it touches storage/migrations, security/auth, public contracts, or concurrency; low for docs/config-only. Risk feeds reviewer emphasis, not selection.
|
|
25
|
+
5. Every selected file in exactly one cohort (or, when sliced, every hunk line in exactly one slice) — build_jobs.py rejects any other shape. `plan.json`:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{ "cohorts": [
|
|
29
|
+
{ "id": "c01", "name": "store: task queue", "risk": "high",
|
|
30
|
+
"files": ["internal/store/queue.go", "internal/store/queue_test.go"] },
|
|
31
|
+
{ "id": "c02a", "name": "loop/action.go — hunks 1-14", "risk": "high",
|
|
32
|
+
"files": ["internal/loop/action.go"],
|
|
33
|
+
"hunk_scope": { "internal/loop/action.go": [{"start": 12, "lines": 40, "side": "new"}] } }
|
|
34
|
+
],
|
|
35
|
+
"sweeps": ["contracts", {"key": "layering", "lens": "custom lens text"}] }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Sweeps are bare keys from the table below (built-in lens text) or `{key, lens}` objects for a custom lens.
|
|
39
|
+
|
|
40
|
+
When `manifest.mode` is `incremental` (a remediation check), `build_jobs.py` ignores `cohorts` and `sweeps` (printing `sweeps skipped in incremental mode` when any were planned) and emits one defect-lane job `cohort-rc` over every selected path, carrying `prior_fingerprints` and `prior_anchors` for every `open` ledger entry in `state.json`; the gate demands one `prior_findings` row per fingerprint and rejects a defect at a prior anchor. Write `plan.json` as usual.
|
|
41
|
+
|
|
42
|
+
`build_jobs.py` rejects a plan with more cohorts than the rule-2 target and prints `cohort target: E for L changed lines at concurrency C`: merge the cohorts.
|
|
43
|
+
|
|
44
|
+
## Sweep triggers
|
|
45
|
+
|
|
46
|
+
Sweeps are **opt-in and rare** — default to none. Each sweep is one extra agent that sees the manifest, not one cohort; include it only when its trigger clearly fires and the plan has three or more cohorts (`build_jobs.py` rejects sweeps on smaller plans), and prefer at most one or two per round:
|
|
47
|
+
|
|
48
|
+
| Key | Trigger | Looks for |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `contracts` | exported/wire/API symbol changed contract | breaking changes, drift between spec/impl/clients, missing codegen co-ship |
|
|
51
|
+
| `security` | new endpoint/input path/authz surface/secret handling | injection, missing authn/authz, secret leakage, cross-tenant access |
|
|
52
|
+
| `migrations` | schema/migration files in diff | destructive ops, missing migration for model change, ordering/identity hazards |
|
|
53
|
+
| `consistency` | renames or repeated patterns in diff | incomplete renames, sibling paths not mirroring a fix, duplicated logic |
|
|
54
|
+
| `config` | config keys/flags/env vars changed | unwired or undocumented keys, dead flags, default mismatches |
|
|
55
|
+
|
|
56
|
+
## Engines
|
|
57
|
+
|
|
58
|
+
The jobs contract makes engines interchangeable — pick one per run, record it in context-pack.md (`Mode: workflow | agent-fallback | subagent:<runtime>`), and always close the loop with `run_jobs.py --validate-only`. Validation rejects missing coverage rows, in-diff anchors outside job ownership, and unassigned rule ids.
|
|
59
|
+
|
|
60
|
+
**Named native dispatch (default when host supports it).** Dispatch up to the manifest concurrency
|
|
61
|
+
bound to the custom `deep-reviewer` agent, refill slots as jobs complete, and keep retries inside
|
|
62
|
+
the owning worker slot. After a provider block, let active attempts finish and do not refill. Use
|
|
63
|
+
the host's real selector:
|
|
64
|
+
|
|
65
|
+
- Claude Code Task: `subagent_type: "deep-reviewer"`.
|
|
66
|
+
- Cursor `cursor/task`: `subagentType: { custom: "deep-reviewer" }`.
|
|
67
|
+
- Native Agent/spawn: custom agent name/type `deep-reviewer`, resolved from the host's local agent
|
|
68
|
+
configuration.
|
|
69
|
+
|
|
70
|
+
Metrics are optional provider-neutral hooks. An adapter may call `start_metrics`,
|
|
71
|
+
`checkpoint_metrics`, and `finalize_metrics` around the bounded dispatch; the main thread records
|
|
72
|
+
serialized cumulative snapshots only and never assigns overlapping deltas to jobs or changes exits.
|
|
73
|
+
Record `Mode: native` in context-pack.md, then run the validate-only gate. Provider-specific
|
|
74
|
+
telemetry setup belongs in the runtime adapter guidance, not in this orchestration contract.
|
|
75
|
+
|
|
76
|
+
Before prompts are materialized, `build_jobs.py` always prepares the pinned Graft context:
|
|
77
|
+
`graft build`, repository-map lookup, blast-radius tracing, and symbol lookup are written to the
|
|
78
|
+
prompt's context artifact. Graft is a non-blocking inspection aid: a missing binary, stale map, or failed
|
|
79
|
+
command falls back to plain repository inspection and does not block review. Graft does not index
|
|
80
|
+
dot-directories, so selected `.agents` paths always carry an explicit plain-inspection fallback.
|
|
81
|
+
|
|
82
|
+
**Workflow fallback (when named native dispatch is unavailable).** One generic script executes any
|
|
83
|
+
stage's pending jobs — pass the pending list from the validate-only status file as `args.jobs` and
|
|
84
|
+
launch at most the manifest concurrency. Refill completed slots, stop refilling after a provider
|
|
85
|
+
block, and preserve jobs-file order when the stage returns. This path intentionally stays role-free;
|
|
86
|
+
it does not assume a named-agent parameter.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
export const meta = {
|
|
90
|
+
name: 'wtk-deep-review-jobs',
|
|
91
|
+
description: 'Execute pending wtk-deep-review jobs; each agent reads a prompt file and writes one output file',
|
|
92
|
+
phases: [{ title: 'Execute' }],
|
|
93
|
+
}
|
|
94
|
+
// args: { jobs: [{label, prompt, output}], concurrency?: integer } — PENDING jobs only
|
|
95
|
+
phase('Execute')
|
|
96
|
+
let returned = 0
|
|
97
|
+
const inputJobs = [...(args.jobs ?? [])]
|
|
98
|
+
const pending = [...inputJobs]
|
|
99
|
+
const requestedConcurrency = args?.concurrency
|
|
100
|
+
if (requestedConcurrency !== undefined &&
|
|
101
|
+
(!Number.isInteger(requestedConcurrency) || requestedConcurrency < 1 || requestedConcurrency > 6)) {
|
|
102
|
+
throw new Error('concurrency must be an integer from 1 through 6')
|
|
103
|
+
}
|
|
104
|
+
const resolvedConcurrency = requestedConcurrency === undefined ? 3 : requestedConcurrency
|
|
105
|
+
const workerLimit = Math.min(resolvedConcurrency, pending.length)
|
|
106
|
+
const active = []
|
|
107
|
+
const resultsByLabel = new Map()
|
|
108
|
+
let providerBlock = null
|
|
109
|
+
while (pending.length || active.length) {
|
|
110
|
+
while (!providerBlock && pending.length && active.length < workerLimit) {
|
|
111
|
+
const j = pending.shift()
|
|
112
|
+
const promise = agent(`Read ${j.prompt} and follow it exactly. It defines the review task, the JSON ` +
|
|
113
|
+
`schema, and the single file you write (${j.output}). Repo files are read-only. ` +
|
|
114
|
+
`Reply with one sentence once the artifact is written.`,
|
|
115
|
+
{ label: j.label, phase: 'Execute' }).then(
|
|
116
|
+
() => ({ label: j.label, status: 'pass' }),
|
|
117
|
+
(error) => {
|
|
118
|
+
const message = String(error?.message ?? error)
|
|
119
|
+
return { label: j.label, status: message.includes('usageLimitExceeded') ? 'blocked' : 'fail', error: message }
|
|
120
|
+
},
|
|
121
|
+
)
|
|
122
|
+
active.push({ label: j.label, promise })
|
|
123
|
+
}
|
|
124
|
+
if (!active.length) break
|
|
125
|
+
const finished = await Promise.race(active.map(({ promise }) => promise))
|
|
126
|
+
const index = active.findIndex(({ label }) => label === finished.label)
|
|
127
|
+
active.splice(index, 1)
|
|
128
|
+
resultsByLabel.set(finished.label, finished)
|
|
129
|
+
if (finished.status === 'blocked' && providerBlock === null) providerBlock = finished
|
|
130
|
+
if (finished.status === 'pass') returned += 1
|
|
131
|
+
}
|
|
132
|
+
const orderedJobs = inputJobs.map(({ label }) => resultsByLabel.get(label) ?? ({ label, status: 'pending' }))
|
|
133
|
+
const unfinished = orderedJobs.filter(({ status }) => status !== 'pass')
|
|
134
|
+
return {
|
|
135
|
+
dispatched: inputJobs.length,
|
|
136
|
+
returned,
|
|
137
|
+
jobs: orderedJobs,
|
|
138
|
+
blocker: providerBlock,
|
|
139
|
+
pending: unfinished,
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
After the workflow returns, run the validate-only gate; re-invoke with the still-pending jobs (interrupted runs can also resume via `resumeFromRunId`). Two re-dispatches without progress → inspect a failing output by hand before continuing.
|
|
144
|
+
|
|
145
|
+
**Agent fallback (`--no-workflow` or no Workflow tool).** Same contract through the Agent tool: use
|
|
146
|
+
the named native selectors above when available. If the host has no named-agent path, use the
|
|
147
|
+
generic prompt-only subagent dispatch ("Read `<prompt>` and follow it exactly…") with the manifest
|
|
148
|
+
concurrency bound; do not add an unsupported role argument. Then run the validate-only gate.
|
|
149
|
+
|
|
150
|
+
**External runtimes (`--subagent` ≠ `native`).** `run_jobs.py --command` drives `compozy exec` per
|
|
151
|
+
subagent-runtimes.md — the runner owns bounded execution, retries, output validation,
|
|
152
|
+
provider-block detection, and the freeze check.
|
|
153
|
+
|
|
154
|
+
The orchestrator never reviews inline, regardless of PR size: reviewers spend their own context on their cohort; the orchestrator plans, dispatches, gates, and reports.
|
|
155
|
+
|
|
156
|
+
### Bounded dispatch
|
|
157
|
+
|
|
158
|
+
The manifest builder resolves reviewer concurrency once, with precedence `--concurrency N` over
|
|
159
|
+
`.wtk-deep-review.yaml` over the default `3`, validates `1` through `6`, and pins the result in
|
|
160
|
+
`manifest.json`. Every execution engine consumes that pinned value. It launches up to
|
|
161
|
+
`min(concurrency, pending jobs)`, refills a worker slot after completion, and never schedules a
|
|
162
|
+
new job after the first provider block. Active attempts finish; pending and blocked jobs remain in
|
|
163
|
+
the blocker ledger. Results are stored by label and emitted in jobs-file order, regardless of
|
|
164
|
+
completion order. The removed legacy `--workers` option is rejected.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Output Contracts
|
|
2
|
+
|
|
3
|
+
Exact templates for every artifact. Placeholders in `<angle brackets>`; keep section order and marker strings byte-stable — fingerprints and upserts depend on them. walkthrough.md is orchestrator-authored; review.md and state.json are rendered from findings.json by `scripts/render_review.py`, which implements these templates and the verdict rule — this file is the contract it must keep.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- walkthrough.md
|
|
8
|
+
- Finding block
|
|
9
|
+
- review.md
|
|
10
|
+
- review.html
|
|
11
|
+
- ReportFindings mapping
|
|
12
|
+
- Verdict rule
|
|
13
|
+
|
|
14
|
+
## walkthrough.md
|
|
15
|
+
|
|
16
|
+
```markdown
|
|
17
|
+
<!-- wtk-deep-review:walkthrough -->
|
|
18
|
+
## Walkthrough
|
|
19
|
+
|
|
20
|
+
<one dense paragraph: what the change does across the stack, in prose>
|
|
21
|
+
|
|
22
|
+
## Changes
|
|
23
|
+
|
|
24
|
+
| Cohort / File(s) | Summary |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| **<cohort name>** <br> `<path>`, `<path>`, `<dir>/{a,b}.go` | <what changed there, 1–2 sentences> |
|
|
27
|
+
|
|
28
|
+
## Sequence Diagram(s)
|
|
29
|
+
|
|
30
|
+
<only when the change alters a multi-actor flow (request path, event flow, lifecycle);
|
|
31
|
+
one mermaid sequenceDiagram per flow, actors = real components>
|
|
32
|
+
|
|
33
|
+
## Estimated code review effort
|
|
34
|
+
|
|
35
|
+
🎯 <1-5> (<label>) | ⏱️ ~<minutes> minutes
|
|
36
|
+
|
|
37
|
+
## Review details
|
|
38
|
+
|
|
39
|
+
- **Scope**: <base sha short> → <head sha short> (<incremental round N | full review>)
|
|
40
|
+
- **Files**: <n> selected · <n> ignored by filters · <n> skipped (trivial/similar)
|
|
41
|
+
- **Posture**: assertive · **Mode**: <workflow|agent-fallback|subagent:runtime>
|
|
42
|
+
- **Rubric**: <sources consulted, comma-separated paths>
|
|
43
|
+
- **Linters**: <lane: ran/unavailable, ...>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Effort scale (calibrate on *reviewable surface* — selected source, not raw file count):
|
|
47
|
+
|
|
48
|
+
| 🎯 | Label | ⏱️ | When |
|
|
49
|
+
| --- | --- | --- | --- |
|
|
50
|
+
| 1 | Trivial | ~5 min | mechanical or config-only |
|
|
51
|
+
| 2 | Simple | ~12 min | small localized change |
|
|
52
|
+
| 3 | Moderate | ~25 min | one subsystem, some cross-file reasoning |
|
|
53
|
+
| 4 | Complex | ~60 min | multiple subsystems or a contract change |
|
|
54
|
+
| 5 | Critical | ~120 min | core invariants, storage, security, or wide blast radius |
|
|
55
|
+
|
|
56
|
+
## Finding block (used in review.md and PR comments)
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
_<category badge>_ | _<severity badge>_[ | _<effort badge>_]
|
|
60
|
+
|
|
61
|
+
**<Imperative one-line claim ending in a period.>**
|
|
62
|
+
|
|
63
|
+
<Evidence paragraph: the concrete failure mode or improvement, referencing real
|
|
64
|
+
symbols and line numbers. State what happens, under which input/state, and why.>
|
|
65
|
+
|
|
66
|
+
[Also applies to: <path>:<lines>, <path>:<lines>]
|
|
67
|
+
[As per coding guidelines [R<NN>] (`<source path>`): "<verbatim rule>"]
|
|
68
|
+
Certificate: <defect: Premise → Path → Verdict | advisory: Premise → Improvement → Fix>
|
|
69
|
+
|
|
70
|
+
<details>
|
|
71
|
+
<summary>📝 Committable suggestion</summary>
|
|
72
|
+
|
|
73
|
+
> ‼️ **IMPORTANT**: review before committing — generated against lines <X>–<Y>.
|
|
74
|
+
|
|
75
|
+
```suggestion
|
|
76
|
+
<exact replacement for lines X–Y, only when the fix is mechanical and complete>
|
|
77
|
+
```
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
<details>
|
|
81
|
+
<summary>🛠️ Repair plan</summary>
|
|
82
|
+
|
|
83
|
+
1. Root cause: <Premise clause of the certificate> → <Path clause of the certificate>
|
|
84
|
+
2. Fix every site: <path:line>, <also_applies anchors...>
|
|
85
|
+
3. Before editing, grep every caller of the symbol at <path:line>; fix at the owning layer.
|
|
86
|
+
4. Extend the nearest test so it fails on the Premise, then fix until it passes.
|
|
87
|
+
5. Suggested change: <suggestion | none>
|
|
88
|
+
</details>
|
|
89
|
+
<!-- wtk-deep-review:fp:<fingerprint> -->
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Bracketed lines appear only when they apply. Every result has the certificate for its class. The committable `suggestion` block appears only when the replacement is exact and self-contained; the Repair plan appears on **Critical, Major, and Minor defects**.
|
|
93
|
+
|
|
94
|
+
## review.md
|
|
95
|
+
|
|
96
|
+
```markdown
|
|
97
|
+
# Deep Review — <target> (round <N>)
|
|
98
|
+
|
|
99
|
+
**Verdict: <SHIP | FIX_BEFORE_SHIP | REWORK>** — <one-line rationale>
|
|
100
|
+
**Defects: <n>** (🔴 <n> · 🟠 <n> · 🟡 <n>) · advisories: <n> · duplicates: <n> · resolved since last round: <n> · merged duplicate reports: <n>
|
|
101
|
+
|
|
102
|
+
<walkthrough.md content, inlined>
|
|
103
|
+
|
|
104
|
+
## Findings
|
|
105
|
+
|
|
106
|
+
### <path>
|
|
107
|
+
|
|
108
|
+
<finding blocks for this file, severity-descending>
|
|
109
|
+
|
|
110
|
+
## Outside diff range
|
|
111
|
+
|
|
112
|
+
<finding blocks with in_diff: false, grouped per file; "None.">
|
|
113
|
+
|
|
114
|
+
## Spec context
|
|
115
|
+
|
|
116
|
+
<spec artifacts are provided to Technical Verifier; Deep Review does not render a separate spec-parity proof section>
|
|
117
|
+
|
|
118
|
+
## Duplicates (unresolved from round <N-1>)
|
|
119
|
+
|
|
120
|
+
<one-line entries: badge · claim · original round; "None.">
|
|
121
|
+
|
|
122
|
+
## Advisories
|
|
123
|
+
|
|
124
|
+
<full advisory blocks grouped per file; "None.">
|
|
125
|
+
|
|
126
|
+
## Review observability
|
|
127
|
+
|
|
128
|
+
<candidate, suppression, and complete defect hunk coverage counts>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`review.md` orders files by max severity, then path.
|
|
132
|
+
|
|
133
|
+
## review.html
|
|
134
|
+
|
|
135
|
+
The human-facing dashboard, emitted by `scripts/render_html.py`, hydrates `assets/REVIEW_UI.html` with defects and advisories in separate sections plus suppression and coverage observability. The fixed template is self-contained (inline CSS/JS, no network) and `review.html` is never hand-edited. Before render_review.py writes the state entry, the verdict remains a neutral "round in progress" state.
|
|
136
|
+
|
|
137
|
+
## ReportFindings mapping
|
|
138
|
+
|
|
139
|
+
When the harness exposes the ReportFindings tool, call it once after review.md is written: one entry per defect and advisory, defects first by severity and then advisories by file. Use `file`/`line` from the anchor, `summary` from the claim, and the matching evidence certificate. Omit `verdict`; the certificate and refutation checks are the confidence signal.
|
|
140
|
+
|
|
141
|
+
## Verdict rule
|
|
142
|
+
|
|
143
|
+
Derive after Step 4's merge from open **defects only**; advisories never change the verdict:
|
|
144
|
+
|
|
145
|
+
- **SHIP** — no Critical or Major defect is open; Minor defects enter the mandatory current-feature closeout batch without a remediation check; Trivials and advisories become follow-ups.
|
|
146
|
+
- **FIX_BEFORE_SHIP** — at least one Critical/Major defect is open, and remediation is local: the change's shape is right and each defect names a bounded fix.
|
|
147
|
+
- **REWORK** — defects show structural failure needing redesign: one root cause across ≥3 cohorts or a Critical whose fix rewrites the change's core. REWORK always carries a named rationale; otherwise FIX_BEFORE_SHIP is the ceiling.
|
|
148
|
+
|
|
149
|
+
The verdict lands in review.md, state.json, and the final message. render_review.py derives SHIP / FIX_BEFORE_SHIP from defects with round status new or duplicate plus prior `open` ledger entries without a `prior_findings` disposition, and accepts REWORK only through `--rework "<rationale>"` backed by structural defects.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Publish to GitHub
|
|
2
|
+
|
|
3
|
+
Recipes for `--publish`. Everything goes through `gh api`; `R` is `owner/repo`, `N` is the PR number. Bodies come from files (`-F body=@file`) rather than inline shell strings.
|
|
4
|
+
|
|
5
|
+
## Reviewer identity
|
|
6
|
+
|
|
7
|
+
GitHub rejects `APPROVE`/`REQUEST_CHANGES` on a PR authored by the authenticated user. Detect identity first:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
AUTHOR=$(gh api repos/$R/pulls/$N --jq .user.login); ME=$(gh api user --jq .login)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Same login means `event=COMMENT`. For a bot/machine user, `request_changes_workflow: true` permits `REQUEST_CHANGES` only when Critical/Major **defects** are open. Advisories never change the event.
|
|
14
|
+
|
|
15
|
+
## 1. Upsert the walkthrough comment
|
|
16
|
+
|
|
17
|
+
One comment per PR, edited in place through its marker:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
CID=$(gh api repos/$R/issues/$N/comments --paginate \
|
|
21
|
+
--jq '[.[] | select(.body | contains("<!-- wtk-deep-review:walkthrough -->"))][0].id // empty')
|
|
22
|
+
if [ -n "$CID" ]; then
|
|
23
|
+
gh api repos/$R/issues/comments/$CID -X PATCH -F body=@"$OUT/walkthrough.md"
|
|
24
|
+
else
|
|
25
|
+
gh api repos/$R/issues/$N/comments -F body=@"$OUT/walkthrough.md"
|
|
26
|
+
fi
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 2. Anchor defects and advisories
|
|
30
|
+
|
|
31
|
+
Inline comments must land on changed lines. The valid ranges are in manifest.json. Every in-diff defect **and every in-diff advisory** becomes an inline comment; low severity is not a collapse reason. Outside-diff or drifted anchors move to the matching review-body section. On a GitHub 422 despite the precheck, move that result to the body and continue.
|
|
32
|
+
|
|
33
|
+
## 3. Post the review submission
|
|
34
|
+
|
|
35
|
+
`comments.json` has one entry per anchorable defect/advisory. Render `body` from the result block template and preserve its fingerprint marker:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
[{ "path": "internal/store/queue.go", "line": 42, "side": "RIGHT",
|
|
39
|
+
"start_line": 38, "start_side": "RIGHT", "body": "<rendered result block>" }]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use `start_line`/`start_side` only for multi-line ranges. The review body starts with `**Defects posted: <n> · Advisories posted: <n>**`, includes Outside diff, Duplicates, and results whose anchors were unavailable, then ends with `Reviewing files that changed between <base> and <head>.`:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
jq -n --rawfile body "$OUT/review-body.md" --slurpfile c "$OUT/comments.json" \
|
|
46
|
+
--arg ev "$EVENT" '{event:$ev, body:$body, comments:$c[0]}' > "$OUT/review-payload.json"
|
|
47
|
+
gh api repos/$R/pulls/$N/reviews --input "$OUT/review-payload.json"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
More than 75 inline comments means multiple submissions of at most 75. The first carries the full body; continuations state separate defect/advisory counts.
|
|
51
|
+
|
|
52
|
+
## 4. Resolve prior-round comments
|
|
53
|
+
|
|
54
|
+
For each prior defect/advisory marked `resolved`, prepend the resolution while preserving the original body:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
gh api repos/$R/pulls/comments/$COMMENT_ID -X PATCH \
|
|
58
|
+
-F body=@<(printf '✅ Addressed in commit %s\n\n%s' "$SHORT_SHA" "$ORIGINAL_BODY")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Unresolved prior results are not re-posted inline; they appear once under Duplicates.
|
|
62
|
+
|
|
63
|
+
## 5. Recover state from the PR
|
|
64
|
+
|
|
65
|
+
For CI or another machine without local state:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
gh api repos/$R/pulls/$N/comments --paginate --jq '.[].body' | grep -o 'wtk-deep-review:fp:[a-f0-9]*'
|
|
69
|
+
gh api repos/$R/pulls/$N/reviews --paginate --jq '.[].body' | grep -o 'wtk-deep-review:fp:[a-f0-9]*'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Recover the latest `Reviewing files that changed between <base> and <head>.` line as the prior head. A fingerprint absent from the current defects/advisories remains open unless the incremental reviewer returns a `prior_findings` row with `status: resolved` and evidence; otherwise it remains under Duplicates.
|
|
73
|
+
|
|
74
|
+
## Order and idempotency
|
|
75
|
+
|
|
76
|
+
1. Verify `gh auth status` and access; detect identity.
|
|
77
|
+
2. Upsert walkthrough.
|
|
78
|
+
3. Anchor-check every defect/advisory and render fingerprints.
|
|
79
|
+
4. Post submission batches.
|
|
80
|
+
5. Apply resolution edits.
|
|
81
|
+
6. Cite walkthrough and review URLs.
|
|
82
|
+
|
|
83
|
+
Before posting, check reviews for the same base/head scope line. One review series per round and head SHA is allowed; a match means the publish step already ran.
|