From b2205dbb5c673d7a360da759db6fc1b8457e8ff9 Mon Sep 17 00:00:00 2001 From: Conal <33135619+Conalh@users.noreply.github.com> Date: Fri, 22 May 2026 09:32:06 -0700 Subject: [PATCH] Namespace finding kinds: prefix with 'task_bound.' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopts agent-gov-core v0.2.0 and prefixes every Finding.kind with the 'task_bound.' namespace per the suite-wide v1.0 wire-format wave (agent-gov-core#1). Kinds renamed (9): dependency_added, dependency_changed, env_file_changed, external_fetch_added, lifecycle_script_changed, out_of_scope_file, script_pipe_to_shell, sensitive_surface_touched, subprocess_spawn_added Also updated .taskbound.yml fixtures so the per-rule severity-override config keys use the new prefixed form (a downstream consumer of the config will need the same update; documented in this PR). Pure rename — no detector semantics, severities, or messages changed. 27/27 tests passing on the new prefixed assertions. --- package-lock.json | 2 +- package.json | 2 +- src/detectors/capability-signals.ts | 8 +++---- src/detectors/dependency-drift.ts | 4 ++-- src/detectors/env-drift.ts | 2 +- src/detectors/file-scope.ts | 4 ++-- test/cli-output.test.mjs | 22 +++++++++---------- .../configured-severity/new/.taskbound.yml | 2 +- .../configured-severity/old/.taskbound.yml | 2 +- test/git-review.test.mjs | 4 ++-- test/scope-infer.test.mjs | 4 ++-- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index c68bf42..cb77b8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.2.3", "license": "MIT", "dependencies": { - "agent-gov-core": "github:Conalh/agent-gov-core#v0.1.2" + "agent-gov-core": "github:Conalh/agent-gov-core#v0.2.0" }, "bin": { "taskbound": "dist/index.js" diff --git a/package.json b/package.json index 8710a43..7db6a39 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "test": "node --test test/*.test.mjs" }, "dependencies": { - "agent-gov-core": "github:Conalh/agent-gov-core#v0.1.2" + "agent-gov-core": "github:Conalh/agent-gov-core#v0.2.0" }, "devDependencies": { "@types/node": "^24.0.0", diff --git a/src/detectors/capability-signals.ts b/src/detectors/capability-signals.ts index 229b8af..8d6243c 100644 --- a/src/detectors/capability-signals.ts +++ b/src/detectors/capability-signals.ts @@ -58,7 +58,7 @@ function detectFetch(added: AddedLine): Finding[] { return [ { - kind: 'external_fetch_added', + kind: 'task_bound.external_fetch_added', category: 'capability', severity: 'medium', file: added.file, @@ -77,7 +77,7 @@ function detectSubprocess(added: AddedLine): Finding[] { return [ { - kind: 'subprocess_spawn_added', + kind: 'task_bound.subprocess_spawn_added', category: 'capability', severity: 'high', file: added.file, @@ -102,7 +102,7 @@ function compareLifecycleScripts(file: string, oldText: string, newText: string) const line = lineOfJsonKey(newText, key) ?? lineOfJsonStringValue(newText, newValue); findings.push({ - kind: 'lifecycle_script_changed', + kind: 'task_bound.lifecycle_script_changed', category: 'lifecycle', severity: 'high', file, @@ -114,7 +114,7 @@ function compareLifecycleScripts(file: string, oldText: string, newText: string) if (/(?:curl[^\n|]*\|\s*(?:ba)?sh|wget[^\n|]*\|\s*sh|Invoke-Expression|iex\s*\()/i.test(newValue)) { findings.push({ - kind: 'script_pipe_to_shell', + kind: 'task_bound.script_pipe_to_shell', category: 'lifecycle', severity: 'critical', file, diff --git a/src/detectors/dependency-drift.ts b/src/detectors/dependency-drift.ts index bc78d9b..0845d20 100644 --- a/src/detectors/dependency-drift.ts +++ b/src/detectors/dependency-drift.ts @@ -34,7 +34,7 @@ function compareDependencies(file: string, oldText: string, newText: string): Fi for (const [name, version] of Object.entries(newDeps)) { if (!(name in oldDeps)) { findings.push({ - kind: 'dependency_added', + kind: 'task_bound.dependency_added', category: 'dependency', severity: 'medium', file, @@ -48,7 +48,7 @@ function compareDependencies(file: string, oldText: string, newText: string): Fi if (oldDeps[name] !== version) { findings.push({ - kind: 'dependency_changed', + kind: 'task_bound.dependency_changed', category: 'dependency', severity: 'low', file, diff --git a/src/detectors/env-drift.ts b/src/detectors/env-drift.ts index 7a4bd44..93d7609 100644 --- a/src/detectors/env-drift.ts +++ b/src/detectors/env-drift.ts @@ -10,7 +10,7 @@ export function detectEnvDrift(changedFiles: ChangedFile[]): Finding[] { } findings.push({ - kind: 'env_file_changed', + kind: 'task_bound.env_file_changed', category: 'env', severity: 'high', file: changed.file, diff --git a/src/detectors/file-scope.ts b/src/detectors/file-scope.ts index e660977..4c9b337 100644 --- a/src/detectors/file-scope.ts +++ b/src/detectors/file-scope.ts @@ -14,7 +14,7 @@ export function detectFileScope(context: DiffContext, resolvedScope?: InferredSc const sensitiveLabel = getSensitiveSurfaceLabel(changed.file); if (sensitiveLabel && !scope.mentionsSensitiveSurfaces) { findings.push({ - kind: 'sensitive_surface_touched', + kind: 'task_bound.sensitive_surface_touched', category: 'sensitive_surface', severity: 'high', file: changed.file, @@ -34,7 +34,7 @@ export function detectFileScope(context: DiffContext, resolvedScope?: InferredSc } findings.push({ - kind: 'out_of_scope_file', + kind: 'task_bound.out_of_scope_file', category: 'scope', severity: isSensitiveSurface(changed.file) ? 'high' : 'medium', file: changed.file, diff --git a/test/cli-output.test.mjs b/test/cli-output.test.mjs index 23ab2a9..33ed9b5 100644 --- a/test/cli-output.test.mjs +++ b/test/cli-output.test.mjs @@ -41,9 +41,9 @@ test('CLI flags scope creep for CSS task with CI, MCP, and package changes', asy assert.equal(report.rating, 'critical'); assert.ok(report.findingCount >= 5); assert.ok(report.taskScopeSummary.some((entry) => entry.includes('css'))); - assert.ok(report.findings.some((finding) => finding.kind === 'sensitive_surface_touched')); - assert.ok(report.findings.some((finding) => finding.kind === 'dependency_added')); - assert.ok(report.findings.some((finding) => finding.kind === 'script_pipe_to_shell')); + assert.ok(report.findings.some((finding) => finding.kind === 'task_bound.sensitive_surface_touched')); + assert.ok(report.findings.some((finding) => finding.kind === 'task_bound.dependency_added')); + assert.ok(report.findings.some((finding) => finding.kind === 'task_bound.script_pipe_to_shell')); }); test('CLI emits Markdown task scope summary', async () => { @@ -128,7 +128,7 @@ test('CLI writes supplemental report files from one review', async () => { assert.match(stdout, /::warning file=\.mcp\.json/); assert.match(markdown, /# TaskBound scope review: CRITICAL/); assert.equal(json.rating, 'critical'); - assert.ok(json.findings.some((finding) => finding.kind === 'script_pipe_to_shell')); + assert.ok(json.findings.some((finding) => finding.kind === 'task_bound.script_pipe_to_shell')); } finally { await rm(outputDir, { recursive: true, force: true }); } @@ -186,7 +186,7 @@ test('additional scope context affects out-of-scope file findings', async () => ); const report = JSON.parse(stdout); const apiFileScopeFinding = report.findings.find( - (finding) => finding.kind === 'out_of_scope_file' && finding.file === 'src/api/client.ts' + (finding) => finding.kind === 'task_bound.out_of_scope_file' && finding.file === 'src/api/client.ts' ); assert.equal(report.scopeMatchCount, 2); @@ -255,7 +255,7 @@ test('CLI applies .taskbound.yml per-rule severity overrides', async () => { const report = JSON.parse(stdout); assert.equal(report.rating, 'high'); - assert.equal(report.findings.find((finding) => finding.kind === 'script_pipe_to_shell')?.severity, 'high'); + assert.equal(report.findings.find((finding) => finding.kind === 'task_bound.script_pipe_to_shell')?.severity, 'high'); }); test('CLI does not treat repository test fixture package files as install surfaces', async () => { @@ -269,9 +269,9 @@ test('CLI does not treat repository test fixture package files as install surfac ); const report = JSON.parse(stdout); - assert.equal(report.findings.some((finding) => finding.kind === 'script_pipe_to_shell'), false); - assert.equal(report.findings.some((finding) => finding.kind === 'lifecycle_script_changed'), false); - assert.equal(report.findings.some((finding) => finding.kind === 'dependency_added'), false); + assert.equal(report.findings.some((finding) => finding.kind === 'task_bound.script_pipe_to_shell'), false); + assert.equal(report.findings.some((finding) => finding.kind === 'task_bound.lifecycle_script_changed'), false); + assert.equal(report.findings.some((finding) => finding.kind === 'task_bound.dependency_added'), false); }); @@ -285,8 +285,8 @@ test('capability signal findings expose stable kind and category fields', async { cwd: packageRoot } ); const report = JSON.parse(stdout); - const capabilityFinding = report.findings.find((finding) => finding.kind === 'external_fetch_added'); + const capabilityFinding = report.findings.find((finding) => finding.kind === 'task_bound.external_fetch_added'); - assert.equal(capabilityFinding?.kind, 'external_fetch_added'); + assert.equal(capabilityFinding?.kind, 'task_bound.external_fetch_added'); assert.equal(capabilityFinding?.category, 'capability'); }); diff --git a/test/fixtures/configured-severity/new/.taskbound.yml b/test/fixtures/configured-severity/new/.taskbound.yml index 8e5c636..d64802c 100644 --- a/test/fixtures/configured-severity/new/.taskbound.yml +++ b/test/fixtures/configured-severity/new/.taskbound.yml @@ -1,2 +1,2 @@ severity: - script_pipe_to_shell: high + task_bound.script_pipe_to_shell: high diff --git a/test/fixtures/configured-severity/old/.taskbound.yml b/test/fixtures/configured-severity/old/.taskbound.yml index 8e5c636..d64802c 100644 --- a/test/fixtures/configured-severity/old/.taskbound.yml +++ b/test/fixtures/configured-severity/old/.taskbound.yml @@ -1,2 +1,2 @@ severity: - script_pipe_to_shell: high + task_bound.script_pipe_to_shell: high diff --git a/test/git-review.test.mjs b/test/git-review.test.mjs index f3f1b16..e82bdd1 100644 --- a/test/git-review.test.mjs +++ b/test/git-review.test.mjs @@ -64,8 +64,8 @@ test('CLI reviews scope creep between git refs', async () => { const report = JSON.parse(stdout); assert.equal(report.rating, 'critical'); - assert.ok(report.findings.some((finding) => finding.kind === 'sensitive_surface_touched')); - assert.ok(report.findings.some((finding) => finding.kind === 'dependency_added')); + assert.ok(report.findings.some((finding) => finding.kind === 'task_bound.sensitive_surface_touched')); + assert.ok(report.findings.some((finding) => finding.kind === 'task_bound.dependency_added')); } finally { await rm(repo, { recursive: true, force: true }); } diff --git a/test/scope-infer.test.mjs b/test/scope-infer.test.mjs index 65ade32..0bc3fd3 100644 --- a/test/scope-infer.test.mjs +++ b/test/scope-infer.test.mjs @@ -48,7 +48,7 @@ test('file scope detector flags sensitive surfaces for CSS task', () => { addedLines: [] }); - assert.ok(findings.some((finding) => finding.kind === 'sensitive_surface_touched' && finding.file === '.mcp.json')); - assert.ok(findings.some((finding) => finding.kind === 'sensitive_surface_touched' && finding.file === 'package.json')); + assert.ok(findings.some((finding) => finding.kind === 'task_bound.sensitive_surface_touched' && finding.file === '.mcp.json')); + assert.ok(findings.some((finding) => finding.kind === 'task_bound.sensitive_surface_touched' && finding.file === 'package.json')); assert.equal(findings.some((finding) => finding.file === 'styles/header.css'), false); });