@hivehub/rulebook 5.8.1 → 5.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hivehub/rulebook",
3
- "version": "5.8.1",
3
+ "version": "5.8.2",
4
4
  "description": "Tool-agnostic AI development framework. Standardize projects across Claude Code, Cursor, Gemini, Codex, Windsurf, Copilot with automated templates, quality gates, persistent memory, and framework detection for 28 languages, 17 frameworks, 13 MCP modules, and 20 services",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -2,7 +2,7 @@ export const meta = {
2
2
  name: 'review-fanout',
3
3
  description:
4
4
  'Adversarial multi-dimension review of the current git diff (correctness, security, performance, tests). Each finding is independently verified before it survives, then synthesized into a prioritized report.',
5
- phases: [{ title: 'Review' }, { title: 'Verify' }, { title: 'Synthesize', model: 'opus' }],
5
+ phases: [{ title: 'Review' }, { title: 'Verify' }, { title: 'Synthesize', model: 'sonnet' }],
6
6
  }
7
7
 
8
8
  const FINDINGS_SCHEMA = {
@@ -119,7 +119,7 @@ phase('Synthesize')
119
119
  const report = await agent(
120
120
  `Synthesize a prioritized code-review report from these confirmed findings (already verified as real). Group by severity, give each a one-line fix recommendation, and lead with blockers.
121
121
  ${JSON.stringify(confirmed, null, 2)}`,
122
- { label: 'synthesize', phase: 'Synthesize', model: 'opus' }
122
+ { label: 'synthesize', phase: 'Synthesize', model: 'sonnet' }
123
123
  )
124
124
 
125
125
  return { confirmedCount: confirmed.length, confirmed, blocking, report }
@@ -8,25 +8,31 @@ export const meta = {
8
8
  { title: 'Review', detail: 'independent full SDD+TDD review', model: 'opus' },
9
9
  { title: 'Document', detail: 'docs-writer updates README/CHANGELOG', model: 'haiku' },
10
10
  { title: 'Commit', detail: 'commit the approved item (conventional, hooks must pass)', model: 'sonnet' },
11
- { title: 'Fanout', detail: 'review-fanout adversarial review of the task changeset', model: 'sonnet' },
11
+ { title: 'Fanout', detail: 'OPT-IN ({ fanout: true }) review-fanout adversarial review of the task changeset', model: 'sonnet' },
12
12
  { title: 'Gate', detail: 'release-gate go/no-go once the backlog is drained', model: 'sonnet' },
13
13
  ],
14
14
  }
15
15
 
16
16
  // ---- Tunables (override via args) ------------------------------------------
17
- // args: { once?: boolean, maxItems?: number, minBudget?: number, fanoutRounds?: number }
17
+ // args: { once?, maxItems?, minBudget?, fanout?, fanoutRounds? }
18
18
  // once — process a single item then stop (legacy one-shot behavior)
19
19
  // maxItems — hard cap on items processed in one run (default 25 safety stop)
20
20
  // minBudget — stop before the next item if remaining tokens fall below this
21
- // fanoutRounds max review-fanout remediation rounds per completed task (default 2)
21
+ // fanout run the per-task review-fanout adversarial gate. DEFAULT false
22
+ // (it is the most token-expensive phase). Pass { fanout: true } to
23
+ // enable. The per-item SDD+TDD opus review + the commit hooks still
24
+ // run regardless; fanout is the extra multi-dimension pass.
25
+ // fanoutRounds — max review-fanout remediation rounds per completed task (default 1)
22
26
  const opts = args && typeof args === 'object' ? args : {}
23
27
  const ONCE = opts.once === true
24
28
  const MAX_ITEMS = typeof opts.maxItems === 'number' ? opts.maxItems : 25
25
29
  const MIN_BUDGET = typeof opts.minBudget === 'number' ? opts.minBudget : 60_000
26
30
  const MAX_REVIEW_ROUNDS = 3
31
+ // Fanout is OFF by default — opt in with { fanout: true }.
32
+ const FANOUT_ENABLED = opts.fanout === true
27
33
  // Per-completed-task adversarial gate. Counted SEPARATELY from MAX_REVIEW_ROUNDS so a
28
34
  // fanout finding never competes with the per-item SDD/TDD round budget.
29
- const MAX_FANOUT_ROUNDS = typeof opts.fanoutRounds === 'number' ? opts.fanoutRounds : 2
35
+ const MAX_FANOUT_ROUNDS = typeof opts.fanoutRounds === 'number' ? opts.fanoutRounds : 1
30
36
 
31
37
  // ---- Structured-output schemas --------------------------------------------
32
38
 
@@ -288,7 +294,13 @@ let currentTaskBaseRef = null
288
294
  let halted = false
289
295
 
290
296
  // Run the per-task review-fanout gate once, scoped to the task's committed changeset (baseRef).
297
+ // No-op (auto-pass) when fanout is disabled — the per-item SDD+TDD review + commit hooks
298
+ // already gated every item; fanout is the opt-in extra adversarial pass.
291
299
  async function gateCompletedTask(taskId, specPaths, baseRef) {
300
+ if (!FANOUT_ENABLED) {
301
+ taskGates.push({ taskId, passed: true, rounds: 0, blockingCount: 0, baseRef, skipped: true })
302
+ return { passed: true, rounds: 0, blocking: [] }
303
+ }
292
304
  const gate = await reviewFanoutGate(taskId, specPaths, baseRef)
293
305
  taskGates.push({ taskId, passed: gate.passed, rounds: gate.rounds, blockingCount: gate.blocking.length, baseRef })
294
306
  return gate