harness-everything 0.31.3 → 0.33.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.
Files changed (52) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -1
  3. package/CHANGELOG.md +21 -0
  4. package/README.md +3 -2
  5. package/ci/mechanism-2az-step-type-registry.test.js +923 -0
  6. package/ci/mechanism-2ba-step-type-docs.test.js +166 -0
  7. package/ci/openai-plugin-package.test.js +1 -1
  8. package/ci/release-consistency-check.js +26 -9
  9. package/ci/release-consistency-check.test.js +30 -0
  10. package/ci/router-workflow-plan.test.js +36 -0
  11. package/code-review/SKILL.md +41 -0
  12. package/code-review/references/review-playbook.md +40 -0
  13. package/code-review/templates/finding.template.md +33 -0
  14. package/docs/openai-plugin.md +1 -1
  15. package/docs/workflows/code-review.md +58 -0
  16. package/evals/code-review/eval.yaml +26 -0
  17. package/evals/code-review/tasks/negative-grill-me.yaml +16 -0
  18. package/evals/code-review/tasks/negative-security-review.yaml +16 -0
  19. package/evals/code-review/tasks/negative-tdd.yaml +16 -0
  20. package/evals/code-review/tasks/negative-verification-loop.yaml +16 -0
  21. package/evals/code-review/tasks/positive-pr-review.yaml +16 -0
  22. package/evals/code-review/tasks/positive-revised-head-rereview.yaml +16 -0
  23. package/harness-everything/SKILL.md +1 -1
  24. package/harness-everything/references/router-workflow-plan.md +18 -0
  25. package/harness-everything/references/skill-registry.md +1 -0
  26. package/harness-everything/scripts/kernel-router.js +37 -5
  27. package/harness-everything/scripts/routing-keywords.json +7 -0
  28. package/hooks/scripts/codex-user-prompt.js +5 -2
  29. package/hooks/scripts/lib/binding-resolver.js +1 -0
  30. package/hooks/scripts/lib/step-types.json +37 -0
  31. package/hooks/scripts/lib/workflow-obligations.js +117 -14
  32. package/hooks/scripts/workflow-disposition.js +16 -9
  33. package/hooks/scripts/workflow-stop-gate.js +31 -8
  34. package/opencode-plugin/plugin.json +1 -1
  35. package/package.json +2 -2
  36. package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
  37. package/plugins/harness-everything/hooks/scripts/codex-user-prompt.js +5 -2
  38. package/plugins/harness-everything/hooks/scripts/lib/binding-resolver.js +1 -0
  39. package/plugins/harness-everything/hooks/scripts/lib/step-types.json +37 -0
  40. package/plugins/harness-everything/hooks/scripts/lib/workflow-obligations.js +117 -14
  41. package/plugins/harness-everything/hooks/scripts/workflow-disposition.js +16 -9
  42. package/plugins/harness-everything/hooks/scripts/workflow-stop-gate.js +31 -8
  43. package/plugins/harness-everything/plugin.json +1 -1
  44. package/plugins/harness-everything/skills/code-review/SKILL.md +41 -0
  45. package/plugins/harness-everything/skills/code-review/references/review-playbook.md +40 -0
  46. package/plugins/harness-everything/skills/code-review/templates/finding.template.md +33 -0
  47. package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
  48. package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +18 -0
  49. package/plugins/harness-everything/skills/harness-everything/references/skill-registry.md +1 -0
  50. package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +37 -5
  51. package/plugins/harness-everything/skills/harness-everything/scripts/routing-keywords.json +7 -0
  52. package/sbom.cdx.json +7 -7
@@ -0,0 +1,166 @@
1
+ const fs = require('fs');
2
+ const os = require('os');
3
+ const path = require('path');
4
+ const { spawnSync } = require('child_process');
5
+
6
+ const ROOT = path.resolve(__dirname, '..');
7
+ const registryFile = path.join(ROOT, 'hooks', 'scripts', 'lib', 'step-types.json');
8
+ const routerFile = path.join(ROOT, 'harness-everything', 'scripts', 'kernel-router.js');
9
+ const AUTHORITATIVE_DOC = 'harness-everything/references/router-workflow-plan.md';
10
+ const ALLOWED_LIST_DOCS = [
11
+ 'docs/routing.md',
12
+ 'harness-everything/references/router-workflow-plan.md',
13
+ 'harness-everything/references/triage-and-tiers.md',
14
+ 'docs/workflows/harness-everything.md',
15
+ ];
16
+ const START = '<!-- step-types:start -->';
17
+ const END = '<!-- step-types:end -->';
18
+ const FIX_PROMPT = 'Fix this checkout bug and add a regression test.';
19
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-step-type-docs-'));
20
+ let failed = 0;
21
+
22
+ process.on('exit', () => fs.rmSync(tempRoot, { recursive: true, force: true }));
23
+
24
+ console.log('\n[2ba] step-type registry documentation and router drift...');
25
+
26
+ function check(name, ok, detail) {
27
+ if (ok) console.log(`✅ ${name}`);
28
+ else {
29
+ failed++;
30
+ console.log(`❌ ${name}`);
31
+ if (detail) console.log(` ${detail}`);
32
+ }
33
+ }
34
+
35
+ function checkCase(name, run) {
36
+ try {
37
+ run();
38
+ check(name, true);
39
+ } catch (error) {
40
+ check(name, false, error && error.message ? error.message : String(error));
41
+ }
42
+ }
43
+
44
+ // Independent oracle: renders the registry directly from the JSON file, not through the runtime loader.
45
+ function renderRegistry(entries) {
46
+ const byId = (left, right) => (left.id < right.id ? -1 : left.id > right.id ? 1 : 0);
47
+ const list = bindings => bindings.map(binding => `\`${binding}\``).join(', ') || 'none';
48
+ return entries.slice().sort(byId).map(entry =>
49
+ `- \`${entry.id}\` — required bindings: ${list(entry.requiredBindings)} — forbidden bindings: ${list(entry.forbiddenBindings)}`,
50
+ );
51
+ }
52
+
53
+ function markerBlocks(text, label) {
54
+ const lines = text.split('\n');
55
+ const blocks = [];
56
+ let openAt = null;
57
+ lines.forEach((line, index) => {
58
+ const marker = line.trim();
59
+ if (marker === START) {
60
+ if (openAt !== null) throw new Error(`${label}: nested step-types:start at line ${index + 1}`);
61
+ openAt = index;
62
+ } else if (marker === END) {
63
+ if (openAt === null) throw new Error(`${label}: step-types:end without start at line ${index + 1}`);
64
+ blocks.push(lines.slice(openAt + 1, index).map(item => item.trim()).filter(Boolean));
65
+ openAt = null;
66
+ }
67
+ });
68
+ if (openAt !== null) throw new Error(`${label}: step-types:start is never closed`);
69
+ return blocks;
70
+ }
71
+
72
+ function routeFixPrompt(runtimeRoot, workspace) {
73
+ const home = path.join(tempRoot, `home-${Math.random().toString(36).slice(2)}`);
74
+ fs.mkdirSync(home, { recursive: true });
75
+ const payload = { session_id: `2ba-${Math.random().toString(36).slice(2)}`, cwd: workspace, prompt: FIX_PROMPT };
76
+ return spawnSync(process.execPath, [path.join(runtimeRoot, 'harness-everything', 'scripts', 'kernel-router.js')], {
77
+ cwd: workspace,
78
+ encoding: 'utf8',
79
+ input: JSON.stringify(payload),
80
+ env: {
81
+ ...process.env,
82
+ HARNESS_STATE_HOME: path.join(tempRoot, 'state'),
83
+ HARNESS_WORKSPACE_ROOT: workspace,
84
+ HOME: home,
85
+ USERPROFILE: home,
86
+ },
87
+ });
88
+ }
89
+
90
+ const registry = JSON.parse(fs.readFileSync(registryFile, 'utf8'));
91
+ const registryIds = registry.map(entry => entry.id).sort();
92
+ const expectedLines = renderRegistry(registry);
93
+
94
+ checkCase('2ba. every step-types marker block in the allowed-list docs equals the registry rendering', () => {
95
+ let total = 0;
96
+ for (const doc of ALLOWED_LIST_DOCS) {
97
+ const blocks = markerBlocks(fs.readFileSync(path.join(ROOT, doc), 'utf8'), doc);
98
+ for (const block of blocks) {
99
+ total++;
100
+ if (JSON.stringify(block) !== JSON.stringify(expectedLines)) {
101
+ throw new Error(`${doc} marker block drifted from the registry:\n${block.join('\n')}\nexpected:\n${expectedLines.join('\n')}`);
102
+ }
103
+ }
104
+ }
105
+ if (total === 0) throw new Error('no step-types marker block found in any allowed-list doc');
106
+ const authoritative = markerBlocks(fs.readFileSync(path.join(ROOT, AUTHORITATIVE_DOC), 'utf8'), AUTHORITATIVE_DOC);
107
+ if (authoritative.length !== 1) throw new Error(`${AUTHORITATIVE_DOC} must carry exactly one step-types marker block; found ${authoritative.length}`);
108
+ });
109
+
110
+ checkCase('2ba. router lists exactly the registry step-type ids', () => {
111
+ const routed = routeFixPrompt(ROOT, ROOT);
112
+ if (routed.status !== 0) throw new Error(`router exited ${routed.status}: ${routed.stderr}`);
113
+ const match = routed.stdout.match(/Record ordered step types \(([^)]*)\) and their bindings/);
114
+ if (!match) throw new Error('router did not print the ordered step-type list');
115
+ const listed = match[1].split(',').map(item => item.trim());
116
+ if (JSON.stringify(listed) !== JSON.stringify(registryIds)) {
117
+ throw new Error(`router listed [${listed.join(', ')}]; registry ids are [${registryIds.join(', ')}]`);
118
+ }
119
+ });
120
+
121
+ checkCase('2ba. router example plan does not steer step authoring toward behavior-change', () => {
122
+ const routed = routeFixPrompt(ROOT, ROOT);
123
+ const recordPlan = routed.stdout.split('\n').find(line => line.includes('Record plan:')) || '';
124
+ if (!recordPlan) throw new Error('router did not print a Record plan example');
125
+ if (recordPlan.includes('behavior-change')) throw new Error(`example still hard-codes behavior-change: ${recordPlan}`);
126
+ });
127
+
128
+ checkCase('2ba. router prints the explicit-choice guidance line exactly once in fresh tier2 output', () => {
129
+ const guidance = '- Replace <step-type-id> with a registered type you choose explicitly; mixed docs+code work uses separate doc-change and behavior-change steps; keep the verification step.';
130
+ const routed = routeFixPrompt(ROOT, ROOT);
131
+ if (routed.status !== 0) throw new Error(`router exited ${routed.status}: ${routed.stderr}`);
132
+ const matches = routed.stdout.split('\n').filter(line => line.trim() === guidance);
133
+ if (matches.length !== 1) throw new Error(`expected the guidance line exactly once; found ${matches.length}`);
134
+ });
135
+
136
+ checkCase('2ba. router record-plan guidance keeps the space after "node" in fresh tier2 output', () => {
137
+ const routed = routeFixPrompt(ROOT, ROOT);
138
+ if (routed.status !== 0) throw new Error(`router exited ${routed.status}: ${routed.stderr}`);
139
+ if (!routed.stdout.includes(' - Record plan: node "')) {
140
+ throw new Error(`router record-plan line lacks "Record plan: node"; got: ${routed.stdout.split('\n').find(line => line.includes('Record plan')) || '(none)'}`);
141
+ }
142
+ });
143
+
144
+ checkCase('2ba. router never crashes or prints a stale step-type list when the registry is missing', () => {
145
+ const copy = path.join(tempRoot, 'runtime-without-registry');
146
+ fs.cpSync(ROOT, copy, {
147
+ recursive: true,
148
+ filter: source => !/[\\/](node_modules|\.git|benchmarks|plugins)([\\/]|$)/.test(source),
149
+ });
150
+ fs.rmSync(path.join(copy, 'hooks', 'scripts', 'lib', 'step-types.json'));
151
+ const routed = routeFixPrompt(copy, copy);
152
+ if (routed.status !== 0) throw new Error(`router exited ${routed.status} without the registry: ${routed.stderr}`);
153
+ if (/Record ordered step types \(/.test(routed.stdout)) throw new Error('router printed a step-type list without a registry');
154
+ if (!routed.stderr.includes('cannot load step-type registry')) {
155
+ throw new Error(`router did not surface the missing registry visibly; stderr: ${routed.stderr}`);
156
+ }
157
+ });
158
+
159
+ checkCase('2ba. router-workflow-plan documents old-runtime rejection of persisted doc-change plans', () => {
160
+ const text = fs.readFileSync(path.join(ROOT, AUTHORITATIVE_DOC), 'utf8');
161
+ for (const required of ['doc-change', 'declared-only', 'planning:steps-invalid']) {
162
+ if (!text.includes(required)) throw new Error(`${AUTHORITATIVE_DOC} must mention ${required}`);
163
+ }
164
+ });
165
+
166
+ process.exitCode = failed ? 1 : 0;
@@ -104,7 +104,7 @@ const packagedSkillNames = fs.readdirSync(path.join(PLUGIN, 'skills'), { withFil
104
104
  .filter(entry => entry.isDirectory())
105
105
  .map(entry => entry.name)
106
106
  .sort();
107
- assert.strictEqual(skillNames.length, 26, 'canonical suite should contain 26 skills');
107
+ assert.strictEqual(skillNames.length, 27, 'canonical suite should contain 27 skills');
108
108
  assert.deepStrictEqual(packagedSkillNames, skillNames, 'OpenAI package must contain exactly the canonical skill set');
109
109
  for (const entry of SOURCE_MANIFEST.skills) {
110
110
  const source = path.resolve(ROOT, entry);
@@ -43,6 +43,22 @@ const releaseRenames = new Map([
43
43
  ['create-agent-launcher', 'multi-agent-workspace']
44
44
  ]);
45
45
 
46
+ function logicalSkillName(skill) {
47
+ return releaseRenames.get(skill) || skill;
48
+ }
49
+
50
+ function compareSkillCatalogs(tagSkills, currentSkills) {
51
+ const releaseLogical = new Set(tagSkills.map(logicalSkillName));
52
+ const currentLogical = new Set(currentSkills.map(logicalSkillName));
53
+ const missing = [...releaseLogical].filter(skill => !currentLogical.has(skill)).sort();
54
+ const additions = [...new Set(currentSkills.filter(skill => !releaseLogical.has(logicalSkillName(skill))))].sort();
55
+ return { missing, additions, exitCode: missing.length ? 1 : 0 };
56
+ }
57
+
58
+ function formatAdditions(additions) {
59
+ return additions.length ? `Additions since release tag: ${additions.join(', ')}` : '';
60
+ }
61
+
46
62
  function git(args) {
47
63
  return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim();
48
64
  }
@@ -90,15 +106,13 @@ function main() {
90
106
  process.exit(2);
91
107
  }
92
108
  const current = new Set(discoverSkills(root));
93
- const currentLogical = new Set([...current].map(skill => releaseRenames.get(skill) || skill));
94
- const releaseLogical = new Set(tagRoot.map(skill => releaseRenames.get(skill) || skill));
95
- const missing = [...releaseLogical].filter(skill => !currentLogical.has(skill));
96
- const extra = [...currentLogical].filter(skill => !releaseLogical.has(skill));
109
+ const comparison = compareSkillCatalogs(tagRoot, [...current]);
97
110
  console.log(`Release ${tag}: ${tagRoot.length} skill(s); current tree: ${current.size} skill(s).`);
98
- if (missing.length || extra.length) {
99
- if (missing.length) console.error(`Missing from current tree: ${missing.join(', ')}`);
100
- if (extra.length) console.error(`Not present in release tag: ${extra.join(', ')}`);
101
- process.exit(1);
111
+ const additionsLine = formatAdditions(comparison.additions);
112
+ if (additionsLine) console.log(additionsLine);
113
+ if (comparison.exitCode !== 0) {
114
+ console.error(`Missing from current tree: ${comparison.missing.join(', ')}`);
115
+ process.exit(comparison.exitCode);
102
116
  }
103
117
 
104
118
  let references = 0;
@@ -140,7 +154,10 @@ function main() {
140
154
  console.error(`CURRENT RELEASE CHECK FAILED: ${currentReferences.failures.length} dangling reference(s).`);
141
155
  process.exit(1);
142
156
  }
143
- console.log(`RELEASE SKILL CATALOG PASSED for ${tag}; current source has the same logical skill catalog (${tagRoot.length} release entries, ${current.size} current directories after merges).`);
157
+ const additionLabel = comparison.additions.length === 1 ? 'addition' : 'additions';
158
+ console.log(`RELEASE SKILL BASELINE PASSED for ${tag}: all ${tagRoot.length} release-tag skills remain present; current source has ${current.size} skill(s), including ${comparison.additions.length} ${additionLabel} not yet in the tag.`);
144
159
  }
145
160
 
146
161
  if (require.main === module) main();
162
+
163
+ module.exports = { compareSkillCatalogs, formatAdditions };
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+ const { compareSkillCatalogs, formatAdditions } = require('./release-consistency-check');
5
+
6
+ const addedSkill = compareSkillCatalogs(
7
+ ['existing-skill'],
8
+ ['code-review', 'existing-skill']
9
+ );
10
+ assert.deepStrictEqual(addedSkill.missing, [], 'a release-tag skill must remain present');
11
+ assert.deepStrictEqual(addedSkill.additions, ['code-review']);
12
+ assert.strictEqual(addedSkill.exitCode, 0, 'an extra current skill is informational');
13
+ assert.strictEqual(formatAdditions(addedSkill.additions), 'Additions since release tag: code-review');
14
+
15
+ const missingSkill = compareSkillCatalogs(
16
+ ['existing-skill', 'removed-skill'],
17
+ ['existing-skill']
18
+ );
19
+ assert.deepStrictEqual(missingSkill.missing, ['removed-skill']);
20
+ assert.strictEqual(missingSkill.exitCode, 1, 'a released skill missing from current source must fail');
21
+
22
+ const renamedSkill = compareSkillCatalogs(
23
+ ['build-multi-agent-system'],
24
+ ['multi-agent-workspace']
25
+ );
26
+ assert.deepStrictEqual(renamedSkill.missing, [], 'the established rename must satisfy the released entry');
27
+ assert.deepStrictEqual(renamedSkill.additions, [], 'a rename must not be reported as a new addition');
28
+ assert.strictEqual(renamedSkill.exitCode, 0);
29
+
30
+ console.log('Release consistency catalog additions, missing-skill failures, and rename mapping verified.');
@@ -27,6 +27,12 @@ function check(condition, message) {
27
27
  }
28
28
  }
29
29
 
30
+ function reviewBindingIds(run) {
31
+ const text = `${run.result.stdout || ''}\n${run.result.stderr || ''}`;
32
+ const line = text.match(/Candidate step binding ids: ([^\r\n]+)/);
33
+ return line ? line[1].split(',').map(id => id.trim()).filter(Boolean) : [];
34
+ }
35
+
30
36
  function runTier(prompt, options = {}) {
31
37
  const contractPath = path.join(os.tmpdir(), `harness-router-test-${process.pid}-${Math.random().toString(16).slice(2)}.json`);
32
38
  const context = options.context || null;
@@ -91,6 +97,36 @@ if (validContract(iterative, 'iterative-single')) {
91
97
  check(!plan.requiredInvariants.includes('tdd'), 'binding ids remain step-local rather than workflow invariants');
92
98
  }
93
99
 
100
+ const reviewPositives = [
101
+ 'Review PR #412 before we merge it',
102
+ 'Review pull request #412',
103
+ 'Review this PR before merge',
104
+ 'Review the diff',
105
+ 'Review the implementation',
106
+ 'Re-review the fix at the new HEAD',
107
+ ];
108
+ const reviewNegatives = [
109
+ 'review project plan',
110
+ 'review proposal',
111
+ 'review process',
112
+ 'preview pr environment',
113
+ 'Review this proposal',
114
+ 'Review the project plan',
115
+ 'Review my process',
116
+ 'Re-review the problem statement',
117
+ 'Review my implementation plan, ask one question at a time',
118
+ 'Preview the diff rendering',
119
+ 'Preview PR #412 environment',
120
+ ];
121
+ for (const prompt of reviewPositives) {
122
+ const run = runTier(prompt);
123
+ check(reviewBindingIds(run).includes('code-review'), `review signal: ${JSON.stringify(prompt)} yields the code-review candidate`);
124
+ }
125
+ for (const prompt of reviewNegatives) {
126
+ const run = runTier(prompt);
127
+ check(!reviewBindingIds(run).includes('code-review'), `review signal: ${JSON.stringify(prompt)} stays code-review-free`);
128
+ }
129
+
94
130
  const memoryPersist = runTier('Persist this lesson as memory after resolving the checkout regression.');
95
131
  if (validContract(memoryPersist, 'self-evolve persistence')) {
96
132
  const plan = memoryPersist.contract.workflowPlan;
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: code-review
3
+ description: "Independently review a PR, diff or finished implementation for correctness, contract and negative-path defects, with source-anchored findings labelled executed, source-traced or inconclusive; read-only by default. USE FOR: \"review this PR before merge\", \"re-review the fix at the new HEAD\". DO NOT USE FOR: \"security threat modeling\", \"implementing or fixing the code\"."
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: Miya Daniel
7
+ version: 0.33.0
8
+ ---
9
+
10
+ # Code Review
11
+
12
+ Independently review completed changes for correctness, contract violations, and negative-path defects. Default to read-only.
13
+
14
+ ## 📋 Skill Contract
15
+
16
+ | Component | Specification |
17
+ | :--- | :--- |
18
+ | **Trigger / Input** | Requested review of a PR, diff, implementation, or revised HEAD. |
19
+ | **Expected Output** | Source-anchored findings and an evidence-qualified summary. |
20
+ | **State Mutations** | None unless the user explicitly authorizes an action. |
21
+ | **Enforcement Gate** | Apply the checklist in `<this-skill-dir>/references/review-playbook.md`. |
22
+
23
+ ## USE FOR:
24
+ - Review a PR / diff / finished implementation before merge
25
+ - Re-review a revised HEAD: prior-finding disposition + new risks
26
+
27
+ ## DO NOT USE FOR:
28
+ - Security-only threat modeling / secrets / OWASP (use `security-review`)
29
+ - Design or plan stress-testing (use `grill-me`); running gates (use `verification-loop`); writing the fix (use `tdd`)
30
+
31
+ ## Workflow
32
+
33
+ 1. Pin repository, contract, base/head, changed scope, and CI state; inspect relevant callers and consumers.
34
+ 2. Independently trace behavior and test applicable counterexamples. Separate severity from safety conditions.
35
+ 3. Report only supported findings with evidence tier, smallest correction, regression, and positive control. Use `<this-skill-dir>/templates/finding.template.md`.
36
+ 4. On re-review, disposition every prior finding at the new HEAD, then inspect for regressions.
37
+ 5. Keep review read-only unless explicitly authorized. Do not claim “bug-free.”
38
+
39
+ In the interim, bind explicitly on an existing review step: `{"stepType":"review","optionalBindings":["code-review"]}`.
40
+
41
+ Deep dive: <this-skill-dir>/references/review-playbook.md
@@ -0,0 +1,40 @@
1
+ # Review Playbook
2
+
3
+ Use this checklist for the applicable risks; do not force irrelevant categories.
4
+
5
+ ## Establish scope and evidence
6
+
7
+ - [ ] Pin repository, PR, base/head SHA, user requirement or PRD/ADR, changed files, relevant callers/callees, and current CI state. Avoid unrelated checkout areas.
8
+ - [ ] Make an independent pass. Treat author explanations and tests as leads, not proof; derive expected behavior from contracts and source.
9
+ - [ ] Label evidence honestly: **executed/reproduced** (command, result, environment, SHA); **source-traced** (concrete path and preconditions); **inconclusive** (missing facts or ambiguous semantics; do not present as a proven blocker).
10
+ - [ ] Inventory user-facing entry points and configuration handoffs (CLI flags, cwd, path spellings, config loading). Exercise them end-to-end, not only the recently edited internals.
11
+ - [ ] Reproduce a candidate finding against the PR base before classifying it as new. Pre-existing defects are follow-ups, not new blockers.
12
+
13
+ ## Try applicable counterexamples
14
+
15
+ - [ ] Missing, null, malformed input; old persisted state; base-to-candidate transitions; tenant/scope boundaries.
16
+ - [ ] Missing or broken dependencies: enumerate every entry point, including help, recovery, and stop paths; inspect fallback behavior.
17
+ - [ ] OS/shell differences; concurrency, crash, retry; user paths and symlinks; API/migration compatibility; downstream or generated views.
18
+ - [ ] Follow each important diagnostic/fact through every consumer and ancestor. Check whether required facts are computed before derived authority, indexes, or output.
19
+ - [ ] Compare new rules with previously accepted rules and controls. Separate display severity from safety prerequisites.
20
+
21
+ ## Check tests and output
22
+
23
+ - [ ] Ask whether each test still passes if the behavior is disabled, bypassed, or broken (mutation thought experiment). Confirm the test is included in CI.
24
+ - [ ] When output text changes, compare the intended changed lines with literal templates; do not exclude changed lines from assertions.
25
+ - [ ] Dedupe findings. Use P1 for severe merge blockers, P2 for meaningful correctness/contract defects, P3 for low-risk issues; avoid speculation.
26
+ - [ ] For each finding, include exact path:line or diff anchor at HEAD SHA, trigger, observed behavior, violated contract and impact, evidence tier, smallest fix, negative regression, positive control, and disposition.
27
+
28
+ ## Re-review and conclude
29
+
30
+ - [ ] Pin the new HEAD. Disposition every prior finding separately: resolved, still open, superseded, or inconclusive. Then inspect fix-induced side effects and new changes.
31
+ - [ ] Stay read-only unless the user/workflow explicitly authorizes action. Do not edit, comment, label, or merge on review authority alone.
32
+ - [ ] Summarize scope/SHA, CI, covered and unexamined risks, fixed/open/new counts, and evidence-grounded merge recommendation. “No actionable findings in examined scope” does not mean “bug-free.” Distinguish repository tests from live-host evidence.
33
+
34
+ ## Per-finding format
35
+
36
+ `[P1/P2/P3] Title` — `path:line @ <HEAD SHA>`
37
+
38
+ **Trigger** → **behavior** → **contract violation / impact**. **Evidence:** executed / source-traced / inconclusive. **Minimal correction:** … **Regression:** negative case …; positive control … **Disposition:** blocker / follow-up / owner decision.
39
+
40
+ Use `<this-skill-dir>/templates/finding.template.md` for the complete findings and summary form.
@@ -0,0 +1,33 @@
1
+ # Code Review — <PR or change>
2
+
3
+ ## Scope and evidence
4
+
5
+ - Repository / PR:
6
+ - Base SHA → reviewed HEAD SHA:
7
+ - Requirement / PRD / ADR:
8
+ - Changed files and relevant callers/consumers:
9
+ - CI state and commands observed:
10
+ - Counterexample categories covered:
11
+ - Risks not examined / evidence limits:
12
+
13
+ ## Findings
14
+
15
+ ### [P1/P2/P3] <Short, specific title>
16
+
17
+ - **Location:** `<path>:<line or diff anchor> @ <HEAD SHA>`
18
+ - **Trigger:** <minimal input, state transition, or interleaving>
19
+ - **Behavior → impact:** <observed or source-traced behavior and violated contract>
20
+ - **Evidence tier:** <executed/reproduced | source-traced | inconclusive; include exact command/result or preconditions>
21
+ - **Minimal correction:** <smallest feasible fix>
22
+ - **Regression:** Negative case: <case that fails before fix>; positive control: <valid behavior that remains valid>
23
+ - **Disposition:** <blocker | follow-up | owner decision; for re-review, resolved | still open | superseded | inconclusive>
24
+
25
+ <!-- Duplicate this finding section as needed. Remove headings for which there are no findings. -->
26
+
27
+ ## Summary
28
+
29
+ - **Scope / reviewed SHA:**
30
+ - **CI evidence:**
31
+ - **Covered / unexamined risks:**
32
+ - **Findings:** <fixed / open / new counts on re-review>
33
+ - **Conclusion:** <merge recommendation grounded in evidence; “no actionable findings in examined scope” is not a claim of bug-free code>
@@ -74,7 +74,7 @@ The local package path is distinct from the general `--codex` installer. The gen
74
74
  The package tests prove the following repository-side contract:
75
75
 
76
76
  - the portable root manifest and `.codex-plugin` compatibility manifest agree on identity, version, interface, and hook entry point;
77
- - the root `skills/` tree contains exactly the 26 canonical skills;
77
+ - the root `skills/` tree contains exactly the 27 canonical skills;
78
78
  - Windows and POSIX hook commands resolve through `PLUGIN_ROOT`;
79
79
  - session start emits the compact policy and prompt submission invokes invariant-first routing;
80
80
  - supported local `Bash` and `apply_patch` calls receive the packaged guards and state tracking;
@@ -0,0 +1,58 @@
1
+ # Workflow: Code Review
2
+
3
+ > Independently review a PR, diff, or finished implementation for correctness, contract, and negative-path defects — read-only by default, with evidence-tiered, source-anchored findings.
4
+
5
+ Source of truth: `code-review/SKILL.md`.
6
+
7
+ Contract summary from SKILL.md — Trigger: requested review of a PR, diff, implementation, or revised HEAD. Output: source-anchored findings and an evidence-qualified summary. USE FOR: review a PR/diff/finished implementation before merge, re-review a revised HEAD (prior-finding disposition + new risks). DO NOT USE FOR: security-only threat modeling/secrets/OWASP (use `security-review`); design or plan stress-testing (use `grill-me`); running gates (use `verification-loop`); writing the fix (use `tdd`).
8
+
9
+ ## 1. Skill Behavior Workflow
10
+
11
+ ```mermaid
12
+ graph TD
13
+ A[Pinned Repo Principle BB And CI State] --> B[Read Diff And Relevant Callers Callees]
14
+ B --> C[Map State Trust Fallback Consumers Tests]
15
+ C --> D[Construct Counterexamples And Negative Paths]
16
+ D --> E[Verify Findings Against Source And CI]
17
+ E --> F{Actionable Supported Finding}
18
+ F -->|yes| G[P1 P2 P3 Severity Plus Evidence Tier Plus Minimal Fix Plus Regression]
19
+ F -->|no| H[Discard Qualify Or Mark Inconclusive]
20
+ G --> I[Report Read Only Only Authorized Actions Post]
21
+ H --> I
22
+ ```
23
+
24
+ ## 2. Triggering and Routing Path
25
+
26
+ ```mermaid
27
+ graph TD
28
+ ReviewReq[Review This PR Or Diff Request] --> Skill[code-review SKILL]
29
+ ReReviewReq[Re-Review Fix At New HEAD] --> Skill
30
+ SecurityReq[Threat Model Secrets OWASP] --> NotCodeReview[security-review SKILL]
31
+ DesignReq[Stress Test Plan Or Design] --> Grm[grill-me SKILL]
32
+ GateReq[Run Build Test Lint Gates] --> VL[verification-loop SKILL]
33
+ FixReq[Implement Or Fix] --> Tdd[tdd SKILL]
34
+ ```
35
+
36
+ ## 3. Re-Review Cycle
37
+
38
+ ```mermaid
39
+ graph TD
40
+ New[Fix Pushed New HEAD] --> Pin[Pin New SHA And Diff]
41
+ Pin --> Prior[Disposition Every Prior Finding Resolved Open Superseded Inconclusive]
42
+ Prior --> Regress[Inspect Fix For Induced Side Effects And New Changes]
43
+ Regress --> Sum[Summary Scope SHA CI Fixed Open New Counts Evidence-Grounded Recommendation]
44
+ Sum -->|fix needed| Fix[Fix New Defects]
45
+ Fix --> Pin
46
+ ```
47
+
48
+ Template: `code-review/templates/finding.template.md`. Deep dive: `code-review/references/review-playbook.md`.
49
+
50
+ ## 4. Verification Check
51
+
52
+ - [ ] Repository, contract, base/head SHA, changed scope, and CI state pinned before reviewing
53
+ - [ ] Independent pass completed; author explanations and tests treated as leads, not proof
54
+ - [ ] Applicable counterexamples constructed (missing/malformed input, persisted state, transitions, boundaries, degraded dependencies, OS/shell, concurrency); irrelevant categories not forced
55
+ - [ ] Every reported finding carries exact path:line/diff anchor at HEAD, trigger, observed behavior, violated contract, impact, evidence tier (executed / source-traced / inconclusive), smallest fix, negative regression, and positive control
56
+ - [ ] Prior findings dispositioned at the new HEAD on re-review, plus fix-induced regressions inspected
57
+ - [ ] Review stayed read-only unless explicitly authorized; no edits, comments, labels, or merges on review authority
58
+ - [ ] Summary distinguished "no actionable findings in examined scope" from "bug-free," with test/CI/live-host evidence boundaries stated
@@ -0,0 +1,26 @@
1
+ name: code-review-routing-eval
2
+ description: Trigger precision eval for the code-review skill.
3
+ skill: code-review
4
+ version: "1.0"
5
+ config:
6
+ trials_per_task: 1
7
+ timeout_seconds: 300
8
+ parallel: false
9
+ executor: copilot-sdk
10
+ model: claude-sonnet-4.6
11
+ metrics:
12
+ - name: task_completion
13
+ weight: 0.7
14
+ threshold: 0.8
15
+ description: Did code-review trigger exactly when it should, and stay dormant for neighboring skills' requests?
16
+ - name: efficiency
17
+ weight: 0.3
18
+ threshold: 0.7
19
+ description: Did the skill stay within behavior limits?
20
+ graders:
21
+ - type: behavior
22
+ name: token-budget
23
+ config:
24
+ max_tokens: 1200
25
+ tasks:
26
+ - "tasks/*.yaml"
@@ -0,0 +1,16 @@
1
+ id: negative-code-review-002
2
+ name: Plan stress-testing must route to grill-me, not code-review
3
+ description: Stress-testing a design or plan one question at a time is in code-review's DO NOT USE FOR scope and belongs to grill-me; code-review must stay dormant.
4
+ tags:
5
+ - negative-trigger
6
+ inputs:
7
+ prompt: "Re-review my plan, asking one question at a time: stress-test the new billing service plan until we agree on where retries live."
8
+ expected:
9
+ should_trigger: false
10
+ graders:
11
+ - type: text
12
+ name: not-contains-keywords
13
+ config:
14
+ contains:
15
+ - "source-anchored"
16
+ - "source-traced"
@@ -0,0 +1,16 @@
1
+ id: negative-code-review-001
2
+ name: Security threat modeling must route to security-review, not code-review
3
+ description: A security-only threat modeling request is in code-review's DO NOT USE FOR scope and belongs to security-review; code-review must stay dormant.
4
+ tags:
5
+ - negative-trigger
6
+ inputs:
7
+ prompt: "Re-review the STRIDE threat model for security only: do a full threat model of the new payments endpoint against the OWASP Top 10, including secrets exposure."
8
+ expected:
9
+ should_trigger: false
10
+ graders:
11
+ - type: text
12
+ name: not-contains-keywords
13
+ config:
14
+ contains:
15
+ - "source-anchored"
16
+ - "source-traced"
@@ -0,0 +1,16 @@
1
+ id: negative-code-review-004
2
+ name: Implementing the fix must route to tdd, not code-review
3
+ description: Writing the fix test-first is implementation work that belongs to tdd; code-review is read-only and must stay dormant.
4
+ tags:
5
+ - negative-trigger
6
+ inputs:
7
+ prompt: "Fix the off-by-one error in the pagination helper. Write a regression test first, then make it pass."
8
+ expected:
9
+ should_trigger: false
10
+ graders:
11
+ - type: text
12
+ name: not-contains-keywords
13
+ config:
14
+ contains:
15
+ - "source-anchored"
16
+ - "source-traced"
@@ -0,0 +1,16 @@
1
+ id: negative-code-review-003
2
+ name: Running the gates must route to verification-loop, not code-review
3
+ description: Running the build, types, lint and test gates is an objective check that belongs to verification-loop; code-review must stay dormant.
4
+ tags:
5
+ - negative-trigger
6
+ inputs:
7
+ prompt: "Run the build, type check, lint and the full test suite on this branch and tell me which gates pass."
8
+ expected:
9
+ should_trigger: false
10
+ graders:
11
+ - type: text
12
+ name: not-contains-keywords
13
+ config:
14
+ contains:
15
+ - "source-anchored"
16
+ - "source-traced"
@@ -0,0 +1,16 @@
1
+ id: positive-code-review-001
2
+ name: Pre-merge PR review request triggers code-review
3
+ description: "Independently review a PR, diff or finished implementation for correctness, contract and negative-path defects, with source-anchored findings labelled executed, source-traced or inconclusive; read-only by default. USE FOR: \"review this PR before merge\", \"re-review the fix at the new HEAD\". DO NOT USE FOR: \"security threat modeling\", \"implementing or fixing the code\"."
4
+ tags:
5
+ - positive-trigger
6
+ inputs:
7
+ prompt: "Review PR #412 before we merge it. Check the diff for correctness and negative-path defects against the contract in the PRD, and label each finding as executed, source-traced or inconclusive."
8
+ expected:
9
+ should_trigger: true
10
+ graders:
11
+ - type: text
12
+ name: contains-keywords
13
+ config:
14
+ contains:
15
+ - "source-traced"
16
+ - "inconclusive"
@@ -0,0 +1,16 @@
1
+ id: positive-code-review-002
2
+ name: Re-review of a revised HEAD triggers code-review
3
+ description: "Independently review a PR, diff or finished implementation for correctness, contract and negative-path defects, with source-anchored findings labelled executed, source-traced or inconclusive; read-only by default. USE FOR: \"review this PR before merge\", \"re-review the fix at the new HEAD\". DO NOT USE FOR: \"security threat modeling\", \"implementing or fixing the code\"."
4
+ tags:
5
+ - positive-trigger
6
+ inputs:
7
+ prompt: "The author pushed a new commit to address last round's findings. Re-review the new HEAD: check each prior finding on its own as resolved, still open or superseded, and look for regressions the fix introduced."
8
+ expected:
9
+ should_trigger: true
10
+ graders:
11
+ - type: text
12
+ name: contains-keywords
13
+ config:
14
+ contains:
15
+ - "prior finding"
16
+ - "HEAD"
@@ -4,7 +4,7 @@ description: "Route software/project work through Harness: classify tier/topolog
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.31.0
7
+ version: 0.33.0
8
8
  ---
9
9
 
10
10
  # Harness Everything