baldart 4.52.4 → 4.53.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/CHANGELOG.md +26 -0
- package/VERSION +1 -1
- package/framework/.claude/agents/api-perf-cost-auditor.md +4 -0
- package/framework/.claude/agents/code-reviewer.md +11 -0
- package/framework/.claude/agents/doc-reviewer.md +1 -0
- package/framework/.claude/agents/security-reviewer.md +7 -0
- package/framework/.claude/skills/new/SKILL.md +1 -1
- package/framework/.claude/skills/new/references/final-review.md +12 -3
- package/framework/.claude/skills/new/references/review-cycle.md +14 -1
- package/framework/.claude/skills/new/references/setup.md +24 -32
- package/framework/.claude/skills/worktree-manager/SKILL.md +55 -188
- package/framework/.claude/skills/worktree-manager/scripts/setup-worktree.sh +457 -0
- package/framework/.claude/workflows/new-card-review.js +35 -10
- package/framework/.claude/workflows/new-final-review.js +29 -8
- package/framework/.claude/workflows/new2.js +1 -1
- package/package.json +1 -1
|
@@ -54,6 +54,7 @@ const FINDING = {
|
|
|
54
54
|
evidence: { type: 'string', description: 'exact file:line + code quote' },
|
|
55
55
|
minimal_fix_direction: { type: 'string' },
|
|
56
56
|
domain: { enum: ['doc', 'security', 'migration', 'code', 'perf', 'test'], description: 'Domain-Override routing bucket' },
|
|
57
|
+
requires_action: { type: 'boolean', description: 'false = a VERIFIED observation that needs NO change anywhere (concern cleared / safe-as-is / advisory) — recorded for audit, NEVER routed to a writer. Omit (⇒ actionable) when a concrete edit is needed. If a change is needed but not by you (out of scope), keep true and say so in minimal_fix_direction (it surfaces as residual).' },
|
|
57
58
|
},
|
|
58
59
|
}
|
|
59
60
|
const FINDINGS_SCHEMA = {
|
|
@@ -157,16 +158,19 @@ const codexPrompt =
|
|
|
157
158
|
`Return codexAvailable:false ONLY if $REVIEW_FILE ends up containing "CODEX_NOT_FOUND" or stays empty after the FULL 10-minute window — NEVER because a single Bash call returned slowly. The script's existence is already verified, so a premature false here is a bug, not a capability gap.\n\n` +
|
|
158
159
|
`${scopeBrief}\n\n${baselineBrief}\n\n` +
|
|
159
160
|
`For each finding return: finding_id, title, severity (BLOCKER|HIGH|MEDIUM|LOW), confidence (0-100), evidence (exact file:line + code quote), minimal_fix_direction, and domain (doc|security|migration|code|perf|test). ` +
|
|
160
|
-
`Run the mandatory false-positive check on every finding and suppress the unconvincing ones (your findings are treated as already FP-validated).
|
|
161
|
+
`Run the mandatory false-positive check on every finding and suppress the unconvincing ones (your findings are treated as already FP-validated). ` +
|
|
162
|
+
`Then the actionability check: an observation you have VERIFIED needs NO change anywhere (the fix direction would be "no fix required" / "acceptable as-is" / "verified non-issue") is not work — set requires_action:false on it (it is recorded but never sent to a fixer), or simply do not emit it. Emit requires_action true/omitted ONLY when a concrete edit is needed. Set codexAvailable:true when the review ran.`
|
|
161
163
|
|
|
162
164
|
const docPrompt =
|
|
163
165
|
`Cross-card documentation + SSOT-registry review over the batch diff, per ${protocolRef} Step F.3 (doc-reviewer row). Check doc consistency, ssot-registry completeness, and invariants across the changed files.\n\n${scopeBrief}\n\n${baselineBrief}\n\n` +
|
|
164
|
-
`You OWN the doc domain end-to-end: run the mandatory false-positive check on every finding yourself and SUPPRESS the unconvincing ones — your surviving findings are treated as already validated and are NOT re-judged by another agent (a generic code-reviewer judging prose would be cross-domain).
|
|
166
|
+
`You OWN the doc domain end-to-end: run the mandatory false-positive check on every finding yourself and SUPPRESS the unconvincing ones — your surviving findings are treated as already validated and are NOT re-judged by another agent (a generic code-reviewer judging prose would be cross-domain). ` +
|
|
167
|
+
`Then the actionability check: an observation you VERIFIED needs NO change (the fix direction would be "no fix required" / "already accurate") is not work — set requires_action:false (recorded, never sent to a fixer), or do not emit it. Flag only a finding you genuinely cannot resolve as confidence < 80.\n\n` +
|
|
165
168
|
`Return findings (domain almost always "doc"). Use the finding schema fields.`
|
|
166
169
|
|
|
167
170
|
const apiPrompt =
|
|
168
171
|
`API / data-model / performance / cost defect review over the batch diff, per ${protocolRef} Step F.3 (api-perf-cost-auditor row). Look for unbounded reads, N+1, missing pagination, contract drift, and cost regressions.\n\n${scopeBrief}\n\n${baselineBrief}\n\n` +
|
|
169
|
-
`You OWN the api/perf/data domain end-to-end: run the mandatory false-positive check on every finding yourself and SUPPRESS the unconvincing ones — your surviving findings are treated as already validated and are NOT re-judged by another agent.
|
|
172
|
+
`You OWN the api/perf/data domain end-to-end: run the mandatory false-positive check on every finding yourself and SUPPRESS the unconvincing ones — your surviving findings are treated as already validated and are NOT re-judged by another agent. ` +
|
|
173
|
+
`Then the actionability check: an observation you VERIFIED needs NO change (the fix direction would be "no fix required" / "acceptable as-is" / "optional") is not work — set requires_action:false (recorded, never sent to a fixer), or do not emit it. Flag only a finding you genuinely cannot resolve as confidence < 80.\n\n` +
|
|
170
174
|
`Return findings with domain in {code, perf, migration, security}. Use the finding schema fields.`
|
|
171
175
|
|
|
172
176
|
const qaPrompt =
|
|
@@ -238,7 +242,7 @@ for (const item of reviewResults) {
|
|
|
238
242
|
if (!codexRan) {
|
|
239
243
|
codexEngine = 'code-reviewer (fallback)'
|
|
240
244
|
const fb = await agent(
|
|
241
|
-
`Codex was unavailable for the batch final review. Run the FULL code review yourself over the batch diff, per ${protocolRef} Step F.3.\n\n${scopeBrief}\n\n${baselineBrief}\n\nReturn findings using the schema fields, with a self false-positive check applied.`,
|
|
245
|
+
`Codex was unavailable for the batch final review. Run the FULL code review yourself over the batch diff, per ${protocolRef} Step F.3.\n\n${scopeBrief}\n\n${baselineBrief}\n\nReturn findings using the schema fields, with a self false-positive check applied. An observation you VERIFIED needs NO change (fix direction "no fix required" / "acceptable as-is") is not work — set requires_action:false (recorded, never sent to a fixer), or do not emit it.`,
|
|
242
246
|
{ label: 'code-reviewer (fallback)', phase: 'Review', agentType: 'code-reviewer', schema: FINDINGS_SCHEMA }
|
|
243
247
|
)
|
|
244
248
|
// the fallback code-reviewer IS the primary code-review engine here and applied its own FP
|
|
@@ -247,6 +251,12 @@ if (!codexRan) {
|
|
|
247
251
|
if (fb && Array.isArray(fb.findings)) raw.push(...fb.findings.map((f) => ({ ...f, source: 'code-reviewer', preValidated: true })))
|
|
248
252
|
}
|
|
249
253
|
|
|
254
|
+
// Globally-unique finding_id at the fan-in (parity with new-card-review.js). Finders number F###
|
|
255
|
+
// INDEPENDENTLY → a Codex F003 and a doc F003 collide; downstream telemetry/routing (new2 ledger,
|
|
256
|
+
// the skill's F.5 partition) keys on finding_id, so a collision conflates them. Prefix source +
|
|
257
|
+
// running index → uniqueness without losing the human-readable id.
|
|
258
|
+
raw.forEach((f, i) => { f.finding_id = `${f.source || 'src'}#${i}:${f.finding_id || ('F' + i)}` })
|
|
259
|
+
|
|
250
260
|
// ───────────────────────────────────────────────────────────────────────────
|
|
251
261
|
// Phase Verify (F.4) — specialist-owned validation (NOT a generic code-reviewer re-judge).
|
|
252
262
|
// Each domain specialist owns its lane end-to-end: it FP-checks its OWN findings in the
|
|
@@ -292,20 +302,31 @@ async function verifyFinding(f) {
|
|
|
292
302
|
return { ...f, classification: (v && v.classification) || 'NEEDS_MANUAL_CONFIRMATION' }
|
|
293
303
|
}
|
|
294
304
|
|
|
295
|
-
// ---- Result: drop FALSE_POSITIVE, keep VERIFIED + NEEDS_MANUAL
|
|
296
|
-
|
|
305
|
+
// ---- Result: drop FALSE_POSITIVE, segregate no-action, keep actionable VERIFIED + NEEDS_MANUAL --
|
|
306
|
+
// Actionability gate (parity with new-card-review.js): a VERIFIED finding needing NO change must NOT
|
|
307
|
+
// reach the skill's F.5 writer partition. Honoured ONLY for MED/LOW — BLOCKER/HIGH always actionable.
|
|
308
|
+
// No silent drop: no-action findings are returned separately (noActionFindings) + counted, so the
|
|
309
|
+
// skill can log them; only the actionable set flows into `findings` (what F.5 routes to writers).
|
|
310
|
+
const NO_ACTION_RE = /(^|[.\s(])(no\s+(fix|change|action)\s+(is\s+)?(required|needed)|none\s+(needed|required)|not\s+a\s+(defect|bug|correctness\s+bug)|acceptable\s+as[-\s]is|verified\s+(safe|non[-\s]issue)|no\s+action\s+(needed|required))([.\s,;)]|$)/i
|
|
311
|
+
const isNoAction = (f) => f.classification === 'VERIFIED' && (f.severity !== 'BLOCKER' && f.severity !== 'HIGH') &&
|
|
312
|
+
(f.requires_action === false || NO_ACTION_RE.test(String(f.minimal_fix_direction || '')))
|
|
313
|
+
const noActionFindings = classified.filter(isNoAction)
|
|
314
|
+
const noActionSet = new Set(noActionFindings)
|
|
315
|
+
const findings = classified.filter((f) => f.classification !== 'FALSE_POSITIVE' && !noActionSet.has(f))
|
|
316
|
+
for (const f of noActionFindings) log(`Final review: no-action finding recorded (not routed to a writer): [${f.finding_id}] ${f.severity} ${f.domain} — ${f.title} (${f.requires_action === false ? 'requires_action:false' : 'no-action-inferred'})`)
|
|
297
317
|
const summary = {
|
|
298
318
|
total: raw.length,
|
|
299
319
|
verified: classified.filter((f) => f.classification === 'VERIFIED').length,
|
|
320
|
+
noAction: noActionFindings.length,
|
|
300
321
|
falsePositive: classified.filter((f) => f.classification === 'FALSE_POSITIVE').length,
|
|
301
322
|
needsManual: classified.filter((f) => f.classification === 'NEEDS_MANUAL_CONFIRMATION').length,
|
|
302
323
|
blockers: classified.filter((f) => f.classification === 'VERIFIED' && f.severity === 'BLOCKER').length,
|
|
303
324
|
highs: classified.filter((f) => f.classification === 'VERIFIED' && f.severity === 'HIGH').length,
|
|
304
325
|
failingGates: gateTable.filter((g) => g.status === 'FAIL').map((g) => g.gate),
|
|
305
326
|
}
|
|
306
|
-
log(`Final review done: ${summary.verified} verified (${summary.blockers} BLOCKER / ${summary.highs} HIGH), ${summary.needsManual} needs-manual, ${summary.failingGates.length} failing gate(s). Engine: ${codexEngine}.`)
|
|
327
|
+
log(`Final review done: ${summary.verified} verified (${summary.blockers} BLOCKER / ${summary.highs} HIGH), ${summary.noAction} no-action (recorded), ${summary.needsManual} needs-manual, ${summary.failingGates.length} failing gate(s). Engine: ${codexEngine}.`)
|
|
307
328
|
|
|
308
|
-
return { codexEngine, findings, gateTable, summary }
|
|
329
|
+
return { codexEngine, findings, noActionFindings, gateTable, summary }
|
|
309
330
|
|
|
310
331
|
function emptySummary() {
|
|
311
332
|
return { total: 0, verified: 0, falsePositive: 0, needsManual: 0, blockers: 0, highs: 0, failingGates: [] }
|
|
@@ -268,7 +268,7 @@ try {
|
|
|
268
268
|
`ROLE BOUNDARY (specialization integrity): you are the OPS/GIT agent. You NEVER edit source or doc files — any needed content change belongs to the coder specialist; report it instead.\n\n` +
|
|
269
269
|
`DETERMINISTIC GATE POLICIES (NO user prompts):\n` +
|
|
270
270
|
`• G1 dirty-tree (main repo ${MAIN}): partition framework-managed noise exactly as setup.md step 3 ($METRICS=${METRICS}, .baldart/generated|state.json|skill-conflicts.json — NOT overlays/). Genuine user work → auto-stash 'baldart-new2-${firstCard}' (main checkout) and record the label. Never commit/abort/prompt.\n` +
|
|
271
|
-
`• Worktree (setup.md step 4):
|
|
271
|
+
`• Worktree (setup.md step 4): the ENTIRE build sequence (worktree add → install → env copy → port → registry → baseline) is the SSOT script \`scripts/setup-worktree.sh\` — the SAME script /nw and classic /new run. Do NOT hand-roll the bash (a re-authored copy is the duplication CLAUDE.md forbids, and the script cannot fabricate a baseline or stall). Resolve the branch from the lead/parent card's git_strategy.branch (fallback feat/<PARENT-ID|lead>-<slug>) + a kebab slug, then derive the git-authoritative idempotency pre-check (existing worktree for the branch → reset the half-built orphan before running, never re-create into a fail-loud collision). Resolve the script: \`SETUP_SH="$(ls .framework/framework/.claude/skills/worktree-manager/scripts/setup-worktree.sh .claude/skills/worktree-manager/scripts/setup-worktree.sh 2>/dev/null | head -1)"\`. Run it (foreground — you ARE the background context here): \`bash "$SETUP_SH" --main ${MAIN} --trunk ${TRUNK} --branch <branch> --slug <slug> --cards "${cardIds.join(',')}" --group-parent "<PARENT|>" --env-files "${ENV_FILES.join(',')}" --manifest /tmp/new2-wt-${firstCard}.txt\`. It installs non-interactively, copies stack.env_files (FILES plain cp / DIRS cp -R / missing FILE → WARN, never abort; never .env.example, never bulk-copy untracked), allocates a locked port, writes the registry, and runs the baseline under timeout 600 (tsc/lint report-but-continue, build STOP-on-fail). Read the manifest block (status/baseline/worktree_path/port/created_at/baseline_log): map baseline → your baseline field (pass|fail|timeout) and baseline_log → baselineLog. E2: a \`baseline:fail\`/\`status:error\` build break is NOT yours to fix (role boundary — the coder repairs it); just return it precisely. Then, INDEPENDENTLY of the manifest, VERIFY the worktree on disk and return EVIDENCE (the workflow E2.5 gate string-matches it, never the script's word): set worktreeVerified:true ONLY after running \`git -C ${MAIN} worktree list --porcelain\` (the worktree path MUST appear) AND \`test -d <wt>/node_modules\` AND confirming the branch; put the LITERAL stdout into worktreeEvidence{ worktreeListPorcelain, artifactsLs:\`ls -la <wt>/node_modules <wt>/.next 2>/dev/null | head\`, baselineLogTail }. If the script is ABSENT (older subtree), fall back to running the sequence inline per setup.md step 4 prose. NEVER report worktreeVerified:true without actually running the verify commands.\n` +
|
|
272
272
|
codexResolveBullet +
|
|
273
273
|
g3Bullet +
|
|
274
274
|
`• G4 card-field validation (setup.md 1b/1c): card missing requirements/acceptance_criteria/files_likely_touched → EXCLUDE (excluded[] + reason). Never HALT for one bad card.\n` +
|