@gobing-ai/spur 0.4.7 → 0.4.9
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/.claude-plugin/marketplace.json +1 -1
- package/config/pipeline-budgets.json +2 -2
- package/config/rules/boundary/config-loading-ownership.yaml +1 -0
- package/config/rules/boundary/sp-plugin-standalone.yaml +1 -1
- package/config/rules/boundary/sp-script-placement.yaml +1 -1
- package/config/rules/docs/sourced-api-claims.yaml +45 -7
- package/config/rules/strict/runtime-boundaries.yaml +40 -1
- package/config/rules/structure/protected-files.yaml +1 -1
- package/config/rules/surface/check-cli-surface.yaml +33 -0
- package/config/rules/typescript/no-debugger.yaml +3 -0
- package/config/workflow-candidates.json +2 -2
- package/config/workflows/feature-verification.yaml +6 -11
- package/config/workflows/history-anatomy.yaml +14 -28
- package/config/workflows/idea-pipeline.yaml +6 -19
- package/config/workflows/pr-review.yaml +9 -16
- package/config/workflows/task-pipeline.yaml +16 -23
- package/config/workflows/wrapup-pipeline.yaml +21 -63
- package/package.json +3 -3
- package/plugins/sp/README.md +70 -37
- package/plugins/sp/agents/super-planner.md +5 -5
- package/plugins/sp/agents/super-reviewer.md +2 -2
- package/plugins/sp/commands/dev-changelog.md +1 -1
- package/plugins/sp/commands/dev-daily.md +1 -1
- package/plugins/sp/commands/dev-pr-review.md +1 -1
- package/plugins/sp/commands/dev-review-session.md +1 -1
- package/plugins/sp/commands/dev-runall.md +4 -4
- package/plugins/sp/commands/dev-verify.md +4 -6
- package/plugins/sp/commands/dev-verifyall.md +4 -5
- package/plugins/sp/hooks/hooks.json +11 -1
- package/plugins/sp/lib/context-post-tool.ts +1 -1
- package/plugins/sp/lib/context-session-start.ts +1 -1
- package/plugins/sp/lib/context-session-stop.ts +1 -1
- package/plugins/sp/lib/destructive-policy.ts +65 -1
- package/plugins/sp/plugin.json +2 -5
- package/plugins/sp/{hooks → scripts/hooks}/agent-lifecycle.ts +1 -1
- package/plugins/sp/scripts/hooks/careful-guard.ts +94 -0
- package/plugins/sp/{hooks → scripts/hooks}/context-post-tool.ts +2 -2
- package/plugins/sp/{hooks → scripts/hooks}/context-session-start.ts +1 -1
- package/plugins/sp/{hooks → scripts/hooks}/context-session-stop.ts +1 -1
- package/plugins/sp/{hooks → scripts/hooks}/fleet-guest-stop.ts +6 -4
- package/plugins/sp/{hooks → scripts/hooks}/task-write-guard.ts +38 -21
- package/plugins/sp/skills/code-implementation/SKILL.md +1 -1
- package/plugins/sp/skills/code-verification/SKILL.md +8 -8
- package/plugins/sp/skills/code-verification/references/secu-review.md +4 -3
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +9 -1
- package/plugins/sp/skills/daily-summary/SKILL.md +4 -5
- package/plugins/sp/skills/dogfood-testing/SKILL.md +9 -9
- package/plugins/sp/skills/dogfood-testing/references/report-template.md +1 -1
- package/plugins/sp/skills/history-anatomy/references/modes.md +2 -2
- package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
- package/plugins/sp/skills/parallel-execution/SKILL.md +1 -1
- package/plugins/sp/skills/pr-reviewing/SKILL.md +14 -15
- package/plugins/sp/skills/session-review/SKILL.md +3 -3
- package/plugins/sp/skills/source-driven-development/SKILL.md +7 -4
- package/plugins/sp/skills/spur-check/SKILL.md +14 -13
- package/plugins/sp/skills/spur-cli/SKILL.md +1 -1
- package/plugins/sp/skills/spur-cli/references/agent.md +12 -0
- package/plugins/sp/skills/spur-cli/references/builder.md +27 -6
- package/plugins/sp/skills/spur-cli/references/features.md +6 -1
- package/plugins/sp/skills/spur-cli/references/history.md +3 -0
- package/plugins/sp/skills/spur-cli/references/self.md +5 -3
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +3 -0
- package/plugins/sp/skills/spur-cli/references/tasks.md +13 -3
- package/plugins/sp/skills/spur-cli/references/workflows.md +36 -1
- package/plugins/sp/skills/spur-dev/SKILL.md +1 -1
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +1 -1
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +12 -12
- package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +10 -11
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +16 -17
- package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +1 -1
- package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +8 -11
- package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +6 -8
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +33 -40
- package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +24 -24
- package/plugins/sp/skills/spur-doctor/SKILL.md +5 -4
- package/spur.js +41901 -30598
- package/config/plugin-scripts.json +0 -116
- package/config/script-placement-baseline.json +0 -33
- package/plugins/sp/hooks/careful-guard.ts +0 -74
- package/plugins/sp/hooks/pi/guard-extension.ts +0 -304
- package/plugins/sp/lib/dogfood-pipeline.ts +0 -265
- package/plugins/sp/lib/dogfood-report.ts +0 -278
- package/plugins/sp/lib/history-anatomy.generated.d.mts +0 -112
- package/plugins/sp/lib/history-anatomy.generated.mjs +0 -691
- package/plugins/sp/lib/idea-handoff.generated.d.mts +0 -17
- package/plugins/sp/lib/idea-handoff.generated.mjs +0 -1446
- package/plugins/sp/lib/inline-run-app.ts +0 -68
- package/plugins/sp/lib/inline-run.generated.d.mts +0 -37
- package/plugins/sp/lib/inline-run.generated.mjs +0 -3103
- package/plugins/sp/lib/plan-projection.generated.d.mts +0 -197
- package/plugins/sp/lib/plan-projection.generated.mjs +0 -982
- package/plugins/sp/lib/quality-gate.generated.d.mts +0 -139
- package/plugins/sp/lib/quality-gate.generated.mjs +0 -30510
- package/plugins/sp/lib/residual-scan.generated.d.mts +0 -93
- package/plugins/sp/lib/residual-scan.generated.mjs +0 -383
- package/plugins/sp/lib/run-summary-core.ts +0 -225
- package/plugins/sp/lib/spur-bin.ts +0 -36
- package/plugins/sp/lib/step-profile.generated.d.mts +0 -71
- package/plugins/sp/lib/step-profile.generated.mjs +0 -174
- package/plugins/sp/lib/transcript.ts +0 -112
- package/plugins/sp/scripts/batch-plan.mjs +0 -1096
- package/plugins/sp/scripts/batch-plan.ts +0 -145
- package/plugins/sp/scripts/batch-preflight.mjs +0 -423
- package/plugins/sp/scripts/batch-preflight.ts +0 -270
- package/plugins/sp/scripts/commit-guard.mjs +0 -226
- package/plugins/sp/scripts/commit-guard.ts +0 -248
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +0 -626
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +0 -855
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +0 -211
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +0 -110
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +0 -282
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +0 -98
- package/plugins/sp/scripts/feature-verification-steps.mjs +0 -82
- package/plugins/sp/scripts/feature-verification-steps.ts +0 -164
- package/plugins/sp/scripts/history-anatomy-cache.mjs +0 -931
- package/plugins/sp/scripts/history-anatomy-cache.ts +0 -247
- package/plugins/sp/scripts/idea-handoff.mjs +0 -32
- package/plugins/sp/scripts/idea-handoff.ts +0 -47
- package/plugins/sp/scripts/inline-run-dispatch.mjs +0 -131
- package/plugins/sp/scripts/inline-run-dispatch.ts +0 -115
- package/plugins/sp/scripts/inline-run-setup.mjs +0 -746
- package/plugins/sp/scripts/inline-run-setup.ts +0 -198
- package/plugins/sp/scripts/persist-out-check.mjs +0 -217
- package/plugins/sp/scripts/persist-out-check.ts +0 -249
- package/plugins/sp/scripts/pr-reviewing.mjs +0 -712
- package/plugins/sp/scripts/pr-reviewing.ts +0 -952
- package/plugins/sp/scripts/quality-gate.mjs +0 -30491
- package/plugins/sp/scripts/quality-gate.ts +0 -80
- package/plugins/sp/scripts/residual-scan.mjs +0 -634
- package/plugins/sp/scripts/residual-scan.ts +0 -248
- package/plugins/sp/scripts/run-summary.mjs +0 -758
- package/plugins/sp/scripts/run-summary.ts +0 -107
- package/plugins/sp/scripts/script-root.mjs +0 -129
- package/plugins/sp/scripts/script-root.ts +0 -199
- package/plugins/sp/scripts/session-timeline.mjs +0 -359
- package/plugins/sp/scripts/session-timeline.ts +0 -190
- package/plugins/sp/scripts/task-diffstat.mjs +0 -181
- package/plugins/sp/scripts/task-diffstat.ts +0 -219
- package/plugins/sp/scripts/workflow-step-profile.mjs +0 -338
- package/plugins/sp/scripts/workflow-step-profile.ts +0 -165
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +0 -190
- package/plugins/sp/scripts/wrapup-drift-probe.ts +0 -261
- package/plugins/sp/scripts/wrapup-steps.mjs +0 -627
- package/plugins/sp/scripts/wrapup-steps.ts +0 -891
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* careful-guard — PreToolUse guard for destructive shell commands (task 0215, R3).
|
|
5
|
+
*
|
|
6
|
+
* Warn (permission `ask`) before a `Bash` tool call runs a destructive command — `rm -rf`
|
|
7
|
+
* (any flag spelling, including the POSIX uppercase `-R`), `DROP TABLE`/`DROP DATABASE`/
|
|
8
|
+
* `TRUNCATE`, `git push --force`/`-f`/`+refspec`, `git reset --hard`, `git checkout .`/
|
|
9
|
+
* `git restore .`, `kubectl delete`, `docker system prune`. The operator can confirm to
|
|
10
|
+
* proceed. Pure pattern-match + decision, no domain logic (mirrors `task-write-guard`).
|
|
11
|
+
*
|
|
12
|
+
* Git global options between the executable and the subcommand are recognized — any run of them,
|
|
13
|
+
* not a fixed list: value-less flags (`--no-pager`, `--bare`, `-p`, …), glued long values
|
|
14
|
+
* (`--git-dir=<path>`), and value-taking options in separated form (`-C <path>`,
|
|
15
|
+
* `-c <name>=<value>`, `--git-dir|--work-tree|--namespace|--config-env|--attr-source <value>`).
|
|
16
|
+
* So `git -C . push --force` and `git --no-pager push --force` classify exactly like
|
|
17
|
+
* `git push --force`; the lexical pass only removes that option span and never executes git or
|
|
18
|
+
* expands a substitution. The run cannot cross a command boundary (`;`, `&`, `|`, newline).
|
|
19
|
+
*
|
|
20
|
+
* **Safe exceptions:** `rm -rf` of well-known build/dependency caches (`node_modules`, `dist`,
|
|
21
|
+
* `.next`, `coverage`, `build`, `.turbo`, `.cache`) passes without a warning — deleting a rebuildable
|
|
22
|
+
* cache is routine, not dangerous.
|
|
23
|
+
*
|
|
24
|
+
* **Output contract** (superskill ADR-039 `hook run`): allow prints **nothing** (exit 0). Ask prints
|
|
25
|
+
* Claude-native PreToolUse JSON with the reason in `permissionDecisionReason` (the confirm prompt) and
|
|
26
|
+
* `systemMessage` (Claude Code's user-facing warning, which the host-neutral `{decision,reason}` form
|
|
27
|
+
* cannot carry). Hosts that cannot confirm (Codex, omp, generic) receive a deny with the reason:
|
|
28
|
+
* superskill fails an unconfirmable ask closed. Pi confirms through its native host adapter.
|
|
29
|
+
*
|
|
30
|
+
* **Fail-open contract:** every error path — unparseable payload, non-Bash tool, empty command —
|
|
31
|
+
* allows (prints nothing). A broken guard must never wedge an agent tool call.
|
|
32
|
+
*
|
|
33
|
+
* **Escape hatch:** `SPUR_CAREFUL=off` short-circuits to allow.
|
|
34
|
+
*
|
|
35
|
+
* Classification itself lives in `lib/destructive-policy.ts` — one policy, every platform
|
|
36
|
+
* adapter runs this hook through superskill). This file owns the hook payload/decision shape only.
|
|
37
|
+
* Registered in `hooks/hooks.json` as `PreToolUse` / matcher `Bash` (task 0215 R3).
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
import { classifyCommand } from '../../lib/destructive-policy';
|
|
41
|
+
import { getEnvVar } from '../../lib/env';
|
|
42
|
+
|
|
43
|
+
interface ToolPayload {
|
|
44
|
+
tool_name?: string;
|
|
45
|
+
tool_input?: { command?: string };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Allow: print nothing and exit 0 (no objection; the host's own permission rules still apply). */
|
|
49
|
+
function allow(): never {
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Ask the operator to confirm, with the reason on the prompt and as a user-facing warning. */
|
|
54
|
+
function ask(reason: string): never {
|
|
55
|
+
process.stdout.write(
|
|
56
|
+
JSON.stringify({
|
|
57
|
+
hookSpecificOutput: {
|
|
58
|
+
hookEventName: 'PreToolUse',
|
|
59
|
+
permissionDecision: 'ask',
|
|
60
|
+
permissionDecisionReason: reason,
|
|
61
|
+
},
|
|
62
|
+
systemMessage: reason,
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function main(): Promise<void> {
|
|
69
|
+
if (getEnvVar('SPUR_CAREFUL') === 'off') allow();
|
|
70
|
+
|
|
71
|
+
const stdinText = await Bun.stdin.text();
|
|
72
|
+
let payload: ToolPayload;
|
|
73
|
+
try {
|
|
74
|
+
payload = JSON.parse(stdinText) as ToolPayload;
|
|
75
|
+
} catch {
|
|
76
|
+
allow(); // unparseable payload — fail open
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (payload.tool_name !== 'Bash') allow();
|
|
80
|
+
|
|
81
|
+
const command = payload.tool_input?.command ?? '';
|
|
82
|
+
if (command.trim() === '') allow();
|
|
83
|
+
|
|
84
|
+
const hit = classifyCommand(command);
|
|
85
|
+
if (hit !== null) {
|
|
86
|
+
ask(
|
|
87
|
+
`This command looks like ${hit} — a destructive operation. Confirm you intend to run it. ` +
|
|
88
|
+
'Set SPUR_CAREFUL=off to disable this guard.',
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
allow();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (import.meta.main) void main();
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { join } from 'node:path';
|
|
13
|
-
import { recordToolUseEvent, type ToolPayload } from '
|
|
14
|
-
import { getEnvVar } from '
|
|
13
|
+
import { recordToolUseEvent, type ToolPayload } from '../../lib/context-post-tool';
|
|
14
|
+
import { getEnvVar } from '../../lib/env';
|
|
15
15
|
|
|
16
16
|
if (import.meta.main) {
|
|
17
17
|
void (async () => {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* (legacy policy) and every error path exits 0 with no output.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { recordSessionStartFromPayloadText } from '
|
|
10
|
+
import { recordSessionStartFromPayloadText } from '../../lib/context-session-start';
|
|
11
11
|
|
|
12
12
|
if (import.meta.main) {
|
|
13
13
|
try {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* `agent.run`'s shutdown stays a no-op because the owner gate lives in the core, not here.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { recordSessionEndFromPayloadText } from '
|
|
10
|
+
import { recordSessionEndFromPayloadText } from '../../lib/context-session-stop';
|
|
11
11
|
|
|
12
12
|
if (import.meta.main) {
|
|
13
13
|
try {
|
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
* - **Bounded.** The pending check is `spur agent wait --inbox <id> --timeout 2000`, which also
|
|
16
16
|
* heartbeats the guest lease (R5), and the reason names at most the first few messages.
|
|
17
17
|
*
|
|
18
|
-
* Block contract
|
|
19
|
-
* `{"decision":"block","reason":"<non-empty>"}`.
|
|
20
|
-
* Codex
|
|
18
|
+
* Block contract: exit 0 with the host-neutral superskill result on stdout (ADR-039) —
|
|
19
|
+
* `{"decision":"block","reason":"<non-empty>"}`. `superskill hook run` renders it per host: Claude
|
|
20
|
+
* Code and Codex receive that same Stop JSON (Claude uses the reason as the stop reason; Codex turns
|
|
21
|
+
* it into the next user prompt), omp/Pi get exit 2 + the reason on stderr. No pending work prints
|
|
22
|
+
* nothing. Hosts that drop the Stop event (`codex exec` on
|
|
21
23
|
* 0.160.0 — see `docs/plans/2026-10-05-codex-guest-spike.md`) simply never call it.
|
|
22
24
|
*
|
|
23
25
|
* Self-contained by design: hooks are bundled standalone at install time, so this file imports
|
|
@@ -27,7 +29,7 @@
|
|
|
27
29
|
import { spawnSync } from 'node:child_process';
|
|
28
30
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
29
31
|
import { join } from 'node:path';
|
|
30
|
-
import { getEnvVar } from '
|
|
32
|
+
import { getEnvVar } from '../../lib/env';
|
|
31
33
|
|
|
32
34
|
/** Budget for the pending-work probe; the hook must never noticeably slow a turn. */
|
|
33
35
|
export const GUEST_STOP_PROBE_MS = 2000;
|
|
@@ -7,21 +7,28 @@
|
|
|
7
7
|
* hand. Pure delegation: ownership is decided by `spur task resolve --strict --json`'s exit code
|
|
8
8
|
* alone (exit 0 → owned, non-zero → unowned).
|
|
9
9
|
*
|
|
10
|
+
* **Output contract** (superskill ADR-039 `hook run`): allow prints **nothing** (exit 0) — a printed
|
|
11
|
+
* Claude `permissionDecision:"allow"` would auto-approve the call and bypass the user's permission
|
|
12
|
+
* rules. Deny prints Claude-native PreToolUse JSON carrying the reason twice: `permissionDecisionReason`
|
|
13
|
+
* (what Claude Code feeds back to the model, and what `hook run` turns into exit 2 + stderr on
|
|
14
|
+
* Codex/omp/generic hosts) and `systemMessage` (Claude Code's user-facing warning — the one field the
|
|
15
|
+
* host-neutral `{decision,reason}` form cannot carry, which is why this guard stays Claude-native).
|
|
16
|
+
*
|
|
10
17
|
* **Fail-open contract** (inherited from the pre-N3 shim and from superskill's runner): every error
|
|
11
18
|
* path — unparseable payload, non-Write/Edit tool, empty path, missing `spur` binary, spawn
|
|
12
|
-
* failure, timeout, `spur task resolve` non-zero exit, non-JSON stdout —
|
|
13
|
-
*
|
|
19
|
+
* failure, timeout, `spur task resolve` non-zero exit, non-JSON stdout — allows (prints nothing).
|
|
20
|
+
* A broken guard must never wedge an agent tool call.
|
|
14
21
|
*
|
|
15
22
|
* **Escape hatch:** `SPUR_WRITE_GUARD=off` short-circuits to allow.
|
|
16
23
|
*
|
|
17
|
-
* Self-contained by design (Wave E, task 0181, R3)
|
|
18
|
-
* `superskill hook run sp task-write-guard
|
|
19
|
-
*
|
|
24
|
+
* Self-contained by design (Wave E, task 0181, R3): `node:*` builtins and relative imports only.
|
|
25
|
+
* Installed hook configs invoke `superskill hook run sp task-write-guard`, which resolves this file
|
|
26
|
+
* as `scripts/hooks/task-write-guard.ts` under the native plugin root or the staged scripts root.
|
|
20
27
|
*/
|
|
21
28
|
|
|
22
29
|
import { spawnSync } from 'node:child_process';
|
|
23
|
-
import { getEnvVar } from '
|
|
24
|
-
import { couldBeTaskFile } from '
|
|
30
|
+
import { getEnvVar } from '../../lib/env';
|
|
31
|
+
import { couldBeTaskFile } from '../../lib/task-file-policy';
|
|
25
32
|
|
|
26
33
|
interface ToolPayload {
|
|
27
34
|
tool_name?: string;
|
|
@@ -30,12 +37,23 @@ interface ToolPayload {
|
|
|
30
37
|
|
|
31
38
|
type TaskOwnership = 'owned' | 'unowned' | 'unknown';
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
/** Allow: print nothing and exit 0 (no objection; the host's own permission rules still apply). */
|
|
41
|
+
function allow(): never {
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Deny with a reason the model (`permissionDecisionReason`) and the user (`systemMessage`) both see. */
|
|
46
|
+
function deny(reason: string): never {
|
|
47
|
+
process.stdout.write(
|
|
48
|
+
JSON.stringify({
|
|
49
|
+
hookSpecificOutput: {
|
|
50
|
+
hookEventName: 'PreToolUse',
|
|
51
|
+
permissionDecision: 'deny',
|
|
52
|
+
permissionDecisionReason: reason,
|
|
53
|
+
},
|
|
54
|
+
systemMessage: reason,
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
39
57
|
process.exit(0);
|
|
40
58
|
}
|
|
41
59
|
|
|
@@ -55,35 +73,34 @@ function resolveSpurTaskOwnership(filePath: string, cwd: string): TaskOwnership
|
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
async function main(): Promise<void> {
|
|
58
|
-
if (getEnvVar('SPUR_WRITE_GUARD') === 'off')
|
|
76
|
+
if (getEnvVar('SPUR_WRITE_GUARD') === 'off') allow();
|
|
59
77
|
|
|
60
78
|
const stdinText = await Bun.stdin.text();
|
|
61
79
|
let payload: ToolPayload;
|
|
62
80
|
try {
|
|
63
81
|
payload = JSON.parse(stdinText) as ToolPayload;
|
|
64
82
|
} catch {
|
|
65
|
-
|
|
83
|
+
allow(); // unparseable payload — fail open
|
|
66
84
|
}
|
|
67
85
|
|
|
68
86
|
const toolName = payload.tool_name ?? '';
|
|
69
|
-
if (toolName !== 'Write' && toolName !== 'Edit')
|
|
87
|
+
if (toolName !== 'Write' && toolName !== 'Edit') allow();
|
|
70
88
|
|
|
71
89
|
const filePath = payload.tool_input?.file_path ?? '';
|
|
72
|
-
if (filePath === '')
|
|
90
|
+
if (filePath === '') allow();
|
|
73
91
|
// Skip the `spur task resolve` subprocess (~120ms) for paths whose basename
|
|
74
92
|
// cannot name a task file — that is every ordinary source edit.
|
|
75
|
-
if (!couldBeTaskFile(filePath))
|
|
93
|
+
if (!couldBeTaskFile(filePath)) allow();
|
|
76
94
|
|
|
77
95
|
const ownership = resolveSpurTaskOwnership(filePath, getEnvVar('CLAUDE_PROJECT_DIR') ?? process.cwd());
|
|
78
96
|
if (ownership === 'owned') {
|
|
79
|
-
|
|
80
|
-
'deny',
|
|
97
|
+
deny(
|
|
81
98
|
`${filePath} is a task file owned by the spur corpus. Edit it through the spur CLI ` +
|
|
82
99
|
'(e.g. `spur task update <wbs> --section <name> --from-file <file>`), not a raw ' +
|
|
83
100
|
'Write/Edit. Set SPUR_WRITE_GUARD=off to bypass.',
|
|
84
101
|
);
|
|
85
102
|
}
|
|
86
|
-
|
|
103
|
+
allow();
|
|
87
104
|
}
|
|
88
105
|
|
|
89
106
|
void main();
|
|
@@ -169,7 +169,7 @@ that single full gate.
|
|
|
169
169
|
|
|
170
170
|
**Worker iteration check order (task 1142 R3):**
|
|
171
171
|
1. The **changed-path matrix** below (narrow behavior tests + affected consumers);
|
|
172
|
-
2.
|
|
172
|
+
2. `spur task gate <wbs> light` (biome on changed files, per-workspace typecheck, rule presets `rules:pre`/`rules:post`, related tests).
|
|
173
173
|
|
|
174
174
|
Neither step takes the full project gate. The full gate is named only for the pipeline's `test` and `test-recheck` hops.
|
|
175
175
|
|
|
@@ -284,9 +284,8 @@ the deterministic Testing writer `spur task record` (section authorship never ha
|
|
|
284
284
|
# write .spur/run/<wbs>-verdict.json (shape in references/verdict-schema.md), then:
|
|
285
285
|
spur task record <wbs> --verdict-file .spur/run/<wbs>-verdict.json # renders ## Testing, flips proven boxes
|
|
286
286
|
# F96 residual sweep (observe-only): scan + fold AFTER record, under every --fix mode (0987).
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
node "$RESIDUAL" fold <wbs>
|
|
287
|
+
spur task residual <wbs> scan
|
|
288
|
+
spur task residual <wbs> fold
|
|
290
289
|
# Downgrade only: re-record so Testing carries the final (folded) verdict.
|
|
291
290
|
[ "$(jq -r .verdict .spur/run/<wbs>-verdict.json)" = PASS ] \
|
|
292
291
|
|| spur task record <wbs> --verdict-file .spur/run/<wbs>-verdict.json
|
|
@@ -297,10 +296,9 @@ node "$RESIDUAL" fold <wbs>
|
|
|
297
296
|
> `residual-sweep` check in place (PASS → PARTIAL when a blocking residual exists), and the
|
|
298
297
|
> downgrade-only re-record transcribes it — a manual verify cannot certify what the pipeline would
|
|
299
298
|
> reject. The sweep runs after `record` (same order as the pipeline, 0983/0987): before it, a
|
|
300
|
-
> verdict-proven box is still unticked and a clean PASS would fold to PARTIAL.
|
|
301
|
-
>
|
|
302
|
-
> `
|
|
303
|
-
> through `--next`, run `residual-scan settle` (links follow-up tasks; best-effort).
|
|
299
|
+
> verdict-proven box is still unticked and a clean PASS would fold to PARTIAL. The sweep is the
|
|
300
|
+
> `spur task residual` verb (no plugin script to resolve). When the task reaches `done` through
|
|
301
|
+
> `--next`, run `spur task residual <wbs> settle` (files the follow-up task; best-effort).
|
|
304
302
|
|
|
305
303
|
> **Corrections: the answer file is the source of truth.** `spur task record` re-transcribes
|
|
306
304
|
> `## Testing` from the verdict artifact — direct `--section Testing` writes are futile. Fix
|
|
@@ -447,11 +445,13 @@ gate is **active**, evaluate feature AC satisfaction via the existing CLI.
|
|
|
447
445
|
|
|
448
446
|
```bash
|
|
449
447
|
SPUR_BIN="${SPUR_BIN:-$([ -f apps/cli/src/index.ts ] && echo 'bun apps/cli/src/index.ts' || echo spur)}"
|
|
450
|
-
$SPUR_BIN feature check <featureId> --json
|
|
448
|
+
$SPUR_BIN feature check <featureId> --as done --strict --json
|
|
451
449
|
$SPUR_BIN task list --feature <featureId> --json
|
|
452
450
|
```
|
|
453
451
|
|
|
454
452
|
3. Classify **Shippable: PASS** only if **all** of:
|
|
453
|
+
- Strict completion exits 0: PASS feature-verification receipts and required dogfood evidence.
|
|
454
|
+
Projection changes no status; active-state checks are insufficient.
|
|
455
455
|
- No finding whose code/message indicates **linked but unverified** scenarios
|
|
456
456
|
(`L4_SCENARIO_UNVERIFIED`).
|
|
457
457
|
- No **orphan / uncovered** feature scenarios (`L4_ORPHAN_SCENARIOS`,
|
|
@@ -83,7 +83,7 @@ verdict artifact so quality failures are not lost behind a requirements-only PAS
|
|
|
83
83
|
Before declaring a task `done`, run this lightweight checklist. It catches the most common oversights that survive the formal pipeline gates:
|
|
84
84
|
|
|
85
85
|
- [ ] Check receipt `.spur/run/<wbs>-check-receipt.json` reports `reuse: true` for the current
|
|
86
|
-
digest via `
|
|
86
|
+
digest via `spur task gate <wbs> status`; run `bun run spur-check` only when it reports stale or
|
|
87
87
|
missing (0940).
|
|
88
88
|
- [ ] No `TODO` or `FIXME` without a linked task WBS.
|
|
89
89
|
- [ ] `git status` shows only intentional changes (no debug artifacts, no temp files).
|
|
@@ -91,8 +91,9 @@ Before declaring a task `done`, run this lightweight checklist. It catches the m
|
|
|
91
91
|
- [ ] No `--no-verify`, `--force`, or new suppression comments added to bypass gates.
|
|
92
92
|
- [ ] Solution section contains `file:line` citations for every changed file.
|
|
93
93
|
- [ ] API/library claims in changed docs carry a source citation (URL or `path:line`) and an honest
|
|
94
|
-
confidence level (HIGH/MEDIUM/LOW) per source-driven-development
|
|
95
|
-
the
|
|
94
|
+
confidence level (HIGH/MEDIUM/LOW) per source-driven-development — a HIGH claim must show the
|
|
95
|
+
source it was verified against on the same line (MEDIUM/LOW need no anchor); the deterministic advisory backstop is
|
|
96
|
+
the `cited-version-strings` / `cited-api-claims` / `cited-api-claims-confidence` / `cited-high-confidence` rules
|
|
96
97
|
(`.spur/rules/docs/sourced-api-claims.yaml`, run ad hoc — not wired into a preset).
|
|
97
98
|
- [ ] Review section has P1–P4 findings table (even if all rows are empty — the table itself proves review happened).
|
|
98
99
|
|
|
@@ -170,6 +170,14 @@ before the proof capture (task 1109), but it qualifies **unique** basenames only
|
|
|
170
170
|
basename (two tracked files share it) is reported and left untouched, and line drift and
|
|
171
171
|
`L4.anchor-subject-mismatch` are never repaired by that pass — those remain the author's rows.
|
|
172
172
|
|
|
173
|
+
A **workspace-relative** path fails the same way, and is the easier mistake to make because the
|
|
174
|
+
command it came from is real. `(cd apps/cli && bun test tests/commands/builder/pr.test.ts)` is the
|
|
175
|
+
right way to run the suite, but `tests/commands/builder/pr.test.ts` does not resolve from the repo
|
|
176
|
+
root, so the AC-coverage guard reports `missing: <AC> — <path>` and refuses `done` (observed
|
|
177
|
+
2026-10-16, task 1215 — the repair was a fresh verify pass over the whole answer). Cite both halves:
|
|
178
|
+
the workspace-rooted command you ran, then the repo-root-relative anchor of the file it names
|
|
179
|
+
(`apps/cli/tests/commands/builder/pr.test.ts`). One anchor per cited file per cell is enough.
|
|
180
|
+
|
|
173
181
|
## Source citations for external claims (task 1070)
|
|
174
182
|
|
|
175
183
|
A Requirement/AC evidence cell that asserts an external API/library claim must carry a verifiable
|
|
@@ -185,7 +193,7 @@ citation in the SAME cell, or lint rejects the row with `evidence-citation` (blo
|
|
|
185
193
|
presence-only — which citation proves which claim is not deterministically decidable.
|
|
186
194
|
- The same two predicates (`hasClaimMarker` / `hasCitationForm` in
|
|
187
195
|
`packages/app/src/services/verify-answer-lint.ts`) gate the review report's findings table through
|
|
188
|
-
`residual
|
|
196
|
+
`spur task residual <wbs> review-gate` as the blocking `review-contract` category — one definition of
|
|
189
197
|
"external claim" and one set of accepted citation forms for both paths.
|
|
190
198
|
|
|
191
199
|
## Hedged evidence is rejected on MET rows
|
|
@@ -52,13 +52,13 @@ The daily-summary skill:
|
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
# Generate summary for today
|
|
55
|
-
|
|
55
|
+
spur history summary
|
|
56
56
|
|
|
57
57
|
# Generate summary for a specific date
|
|
58
|
-
|
|
58
|
+
spur history summary --date 2026-04-17
|
|
59
59
|
|
|
60
60
|
# Show summary without writing file
|
|
61
|
-
|
|
61
|
+
spur history summary --dry-run
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
## Workflows
|
|
@@ -165,7 +165,6 @@ Read the skill file and follow the workflow manually.
|
|
|
165
165
|
|
|
166
166
|
## Additional Resources
|
|
167
167
|
|
|
168
|
-
- **
|
|
169
|
-
- **Tests:** [tests/daily-summary/daily-summary.test.ts](../../tests/daily-summary/daily-summary.test.ts) — unit coverage for parsing, date ranges, markdown output
|
|
168
|
+
- **CLI:** `spur history summary [--date d] [--dry-run] [--output p] [--no-git] [--no-ccusage]` — see `sp:spur-cli` (history reference)
|
|
170
169
|
- **Related skills:** `sp:dev-handover` (blocker handoff), `sp:dev-changelog` (commit-based changelog), `sp:spur-cli` (task management)
|
|
171
170
|
- **Upstream CLI:** [ccusage](https://github.com/ryoppippi/ccusage) — AI agent token usage reporter
|
|
@@ -82,11 +82,11 @@ The command forwards these via `$ARGUMENTS`:
|
|
|
82
82
|
> <!-- pipeline-tokens:end -->
|
|
83
83
|
> matched as a **distinct hyphen-word**
|
|
84
84
|
> (machine-checked by
|
|
85
|
-
>
|
|
85
|
+
> `detectPipelineDriving` (`spur agent dogfood gate`);
|
|
86
86
|
> see [§Pipeline-driving word-boundary contract](#pipeline-driving-word-boundary-contract))
|
|
87
87
|
> → `⚠ pipeline-driving testee detected; pass --max-retry 0 (observe-only) or --max-retry N (fix mode, tree mutation acknowledged)`.
|
|
88
88
|
> - **Mutating `--fix` modes** — `--fix all` / `--fix blockers-first`, boundary-guarded via
|
|
89
|
-
>
|
|
89
|
+
> `hasMutatingFixMode` (`spur agent dogfood gate`) (never matches
|
|
90
90
|
> `--fix none` / `--focus all` / `--prefix all`). No pipeline token required: a verify/review leg
|
|
91
91
|
> with `--fix all` mutates the tree on its own (0280 dogfood P2, task 0293). Honesty note:
|
|
92
92
|
> `--max-retry 0` here bounds **the driver only** — the testee still mutates the tree — so the
|
|
@@ -100,7 +100,7 @@ The command forwards these via `$ARGUMENTS`:
|
|
|
100
100
|
in-agent):
|
|
101
101
|
|
|
102
102
|
```bash
|
|
103
|
-
|
|
103
|
+
spur agent dogfood gate \
|
|
104
104
|
--testee "<raw testee string>" \
|
|
105
105
|
[--max-retry-present]
|
|
106
106
|
```
|
|
@@ -109,7 +109,7 @@ The command forwards these via `$ARGUMENTS`:
|
|
|
109
109
|
of two independent mutation sources (task 0293); its two refuse lines are the ones quoted
|
|
110
110
|
verbatim in the repo-mutation warning above.
|
|
111
111
|
- Exit **0** → proceed. Do not auto-substitute `--max-retry 0`.
|
|
112
|
-
- The matcher contract is unit-checked by `tests/dogfood
|
|
112
|
+
- The matcher contract is unit-checked by `packages/app/tests/services/dogfood/pipeline-detect.test.ts`.
|
|
113
113
|
See [§Pipeline-driving word-boundary contract](#pipeline-driving-word-boundary-contract) and
|
|
114
114
|
[§Mutating `--fix` mode contract](#mutating---fix-mode-contract).
|
|
115
115
|
1. **Resolve + classify** the testee: slash command (`/sp:...`), agent skill (`Skill(...)`), or shell
|
|
@@ -121,7 +121,7 @@ The command forwards these via `$ARGUMENTS`:
|
|
|
121
121
|
re-run the gate with the derived step labels:
|
|
122
122
|
|
|
123
123
|
```bash
|
|
124
|
-
|
|
124
|
+
spur agent dogfood gate \
|
|
125
125
|
--testee "<raw testee string>" \
|
|
126
126
|
--max-retry-present \
|
|
127
127
|
--steps "step1 label||step2 label||..."
|
|
@@ -232,7 +232,7 @@ contract violation**.
|
|
|
232
232
|
**before** claiming `status: complete`:
|
|
233
233
|
|
|
234
234
|
```bash
|
|
235
|
-
|
|
235
|
+
spur agent dogfood validate-report --file <report-path>
|
|
236
236
|
```
|
|
237
237
|
|
|
238
238
|
Exit **0** → proceed. Exit **2** → set `status: aborted`, list every error code under §5
|
|
@@ -338,7 +338,7 @@ Do **not** use this skill for:
|
|
|
338
338
|
Pipeline-driving detection is **word-boundary**, not leading-space substring. The live gate is:
|
|
339
339
|
|
|
340
340
|
```bash
|
|
341
|
-
|
|
341
|
+
spur agent dogfood gate --testee "<testee>" [--max-retry-present] [--steps "…"] [--json]
|
|
342
342
|
```
|
|
343
343
|
|
|
344
344
|
| Token shape | Examples | Matches | Rejects |
|
|
@@ -347,9 +347,9 @@ node "$(superskill script path sp dogfood-testing/detect-pipeline-driving.mjs)"
|
|
|
347
347
|
| Bare noun | <!-- pipeline-tokens:start -->`run`, `runall`, `wrap`, `wrapall`, `idea`, `refineall`, `verifyall`<!-- pipeline-tokens:end --> | `task run 0042` | `runaway`, `wrapper`, `idealist` |
|
|
348
348
|
|
|
349
349
|
`-` is a **word character** for boundaries: a token must be a distinct hyphen-word. Contract tests:
|
|
350
|
-
`
|
|
350
|
+
`packages/app/tests/services/dogfood/pipeline-detect.test.ts`. Helpers:
|
|
351
351
|
`detectPipelineDriving`, `isImplementHeavyStep`, `detectImplementHeavy`, `evaluateDogfoodGate` in
|
|
352
|
-
|
|
352
|
+
`spur agent dogfood gate` (absorbed into the CLI; was `plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts`).
|
|
353
353
|
|
|
354
354
|
## Mutating `--fix` mode contract
|
|
355
355
|
|
|
@@ -336,7 +336,7 @@ Before the skill may stop (success, partial, fail, observe-only end, or abort),
|
|
|
336
336
|
and mirror the footer block at the **end of the report file**. A report whose body lacks the
|
|
337
337
|
footer cannot set `status: complete`.
|
|
338
338
|
8. **Self-validate (task 0278 R6):** run
|
|
339
|
-
`
|
|
339
|
+
`spur agent dogfood validate-report --file <report-path>` before
|
|
340
340
|
claiming `status: complete`. Exit 2 → `status: aborted` + list error codes under
|
|
341
341
|
`#### Unresolved` (never force complete on a non-@1.2 shape).
|
|
342
342
|
9. **Refusal rule (@1.2):** when any check above fails, set `status: aborted` and list every
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The skill resolves exactly two modes. Everything else fails loud. This matrix is the enforcement
|
|
4
4
|
surface the workflow (0660) and the skill share; keep the vocabulary frozen. Execution note
|
|
5
|
-
(0920): argument validation runs deterministically in
|
|
6
|
-
|
|
5
|
+
(0920): argument validation runs deterministically in `spur history anatomy paths`
|
|
6
|
+
(formerly the `history-anatomy-cache` helper) (logic core: `packages/app/src/services/history-anatomy.ts`, task 1005) before the
|
|
7
7
|
workflow starts; the model hop no longer performs it.
|
|
8
8
|
|
|
9
9
|
## Mode vocabulary (frozen)
|
|
@@ -15,7 +15,7 @@ dispatcher: resolve target → load corpus → apply primary table → optional
|
|
|
15
15
|
|
|
16
16
|
`sp:super-planner` (via `/sp:dev-runall`) **reads** TABLE A STOP preconditions for:
|
|
17
17
|
|
|
18
|
-
1. **Preflight** — skip pipeline launch when A2/A7/A8/A9 would stop `dev-next` (`
|
|
18
|
+
1. **Preflight** — skip pipeline launch when A2/A7/A8/A9 would stop `dev-next` (`spur task preflight`).
|
|
19
19
|
2. **One-shot recovery** — after a failed pipeline, map status → primary hop (A1/A3/A5/A6/A7) at most once.
|
|
20
20
|
|
|
21
21
|
It does **not** reimplement TABLES or replace `task-pipeline.yaml` with a `dev-next` loop. Keep this
|
|
@@ -104,7 +104,7 @@ was meant to avoid. Let the reviewer reach its own conclusion.
|
|
|
104
104
|
|
|
105
105
|
- **`sp:spur-dev`** owns task selection and lifecycle. When a batch contains independent tasks, the spine consults this skill for the fan-out pattern.
|
|
106
106
|
- **`sp:super-planner`** is the orchestrator that executes the fan-out. Its parallel mode (documented in its agent definition) applies the patterns from this skill.
|
|
107
|
-
- **`/sp:dev-runall --mode parallel|auto`** is the task-batch entry point; its `batch-plan
|
|
107
|
+
- **`/sp:dev-runall --mode parallel|auto`** is the task-batch entry point; its `spur task batch-plan order` schedule applies this skill's dependency and file-overlap rows deterministically.
|
|
108
108
|
|
|
109
109
|
## When to use
|
|
110
110
|
|
|
@@ -40,9 +40,9 @@ sp:pr-reviewing (this skill — mode routing, triage, fix, rules)
|
|
|
40
40
|
│ deterministic spine, state order + guards:
|
|
41
41
|
▼
|
|
42
42
|
pr-review.yaml ← workflow SSOT (seeded by spur init; project-tunable)
|
|
43
|
-
│ every
|
|
43
|
+
│ every deterministic action shells out to:
|
|
44
44
|
▼
|
|
45
|
-
|
|
45
|
+
`spur builder pr` ← Bun entrypoint for the tested git/gh core
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
- **State order and guards** are defined once, in the workflow YAML. Do not re-derive them in
|
|
@@ -128,44 +128,43 @@ root causes rather than wording, prefer the smallest coherent patch, avoid drive
|
|
|
128
128
|
## Workflow-backed spine (`full`, `submit`, `rerun`)
|
|
129
129
|
|
|
130
130
|
Run the workflow YAML's declared states in order. Every deterministic state invokes the
|
|
131
|
-
|
|
131
|
+
`spur builder pr` operation below, supports `--json`, and must be parsed. Stop at the first red gate and
|
|
132
132
|
report its artifact. The canonical installed invocation is:
|
|
133
133
|
|
|
134
134
|
```sh
|
|
135
|
-
|
|
135
|
+
spur builder pr <subcommand> [flags]
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
superskill script contract.
|
|
138
|
+
The installed Spur CLI owns these operations; no staged script, Node twin or plugin resolver is used.
|
|
140
139
|
|
|
141
|
-
1. **Preflight** —
|
|
140
|
+
1. **Preflight** — `spur builder pr preflight --base "$base" --json`. Hard-fails on a
|
|
142
141
|
detached HEAD, missing `gh` auth, no GitHub remote, a dirty tree, or the current branch
|
|
143
142
|
being the base branch (a PR reviews a feature branch against the base; nothing on the
|
|
144
143
|
base branch is reviewable, and the guard runs before any push can publish it). On a
|
|
145
144
|
dirty tree, triage with the user (commit/stash/exclude) before continuing — the
|
|
146
145
|
workflow refuses to guess.
|
|
147
|
-
2. **Hygiene** —
|
|
146
|
+
2. **Hygiene** — `spur builder pr hygiene --base "$base" --json`. `BLOCK` (secrets, `.env`, conflict markers,
|
|
148
147
|
private keys) stops the run — never submit a tainted diff. `WARN` (debug residue) rides along
|
|
149
148
|
into the report. This is a submission sanity check, not a second local review.
|
|
150
149
|
3. **Precheck** — if the workflow YAML's `preReviewCmd` var is set, run it; a red check stops the
|
|
151
150
|
run (do not spend a review request on code that fails its own gate). When unset, report that
|
|
152
151
|
pre-review verification was not configured rather than inventing project commands.
|
|
153
|
-
4. **Push** —
|
|
154
|
-
5. **Ensure PR** —
|
|
152
|
+
4. **Push** — `spur builder pr push --json`. Normal push only; sets upstream when missing.
|
|
153
|
+
5. **Ensure PR** — `spur builder pr ensure-pr --base "$base" --json`. Reuses the branch's PR; creates with
|
|
155
154
|
`gh pr create --fill` only when absent. Never a duplicate PR.
|
|
156
|
-
6. **Request** —
|
|
155
|
+
6. **Request** — `spur builder pr request --focus "<focus>" --json` (`--force` in `rerun` mode). Dedupes when
|
|
157
156
|
Codex already reviewed the exact pushed HEAD (`ALREADY_REVIEWED` → skip to collect) or a marked
|
|
158
157
|
request by the current GitHub user is still in flight (`ALREADY_REQUESTED` → pending). The
|
|
159
158
|
request body is concise when the repo has `## Code Review Rules`, else carries the default
|
|
160
159
|
actionable-issues focus. Records PR, URL, HEAD, and request time.
|
|
161
160
|
7. **Wait** (full/rerun unless `--no-wait`; submit stops before it) —
|
|
162
|
-
|
|
161
|
+
`spur builder pr wait --since "$requestedAt" --head "$requestHead" --json`, using the request result so
|
|
163
162
|
a fast response is not missed, `rerun` cannot reuse the prior review, and a moved HEAD fails loud.
|
|
164
163
|
Polls every ~30s for up to
|
|
165
164
|
~10 minutes across the current HEAD's PR review and inline comments. Uncorrelated conversation
|
|
166
165
|
comments are ignored. A current-HEAD clean review is a completed `CLEAN` outcome; findings are
|
|
167
166
|
`FOUND`; timeout or no current-HEAD result is **pending, not failed** — collect later.
|
|
168
|
-
8. **Collect** —
|
|
167
|
+
8. **Collect** — `spur builder pr collect --since "$requestedAt" --head "$requestHead" --json`. Normalize
|
|
169
168
|
only the requested HEAD and request window; then invoke `status` with the same bounds for
|
|
170
169
|
PR/base/CI/local state. Never turn an absent, stale, or moved-HEAD result into `clean`.
|
|
171
170
|
`--head` is mandatory on wait/collect/status (0771): an empty or missing pin fails loud
|
|
@@ -288,7 +287,7 @@ or review requests.
|
|
|
288
287
|
|
|
289
288
|
- **Workflow SSOT:** `pr-review.yaml` (seeded by `spur init`; tune per project —
|
|
290
289
|
wait budget, `preReviewCmd`, dedupe policy)
|
|
291
|
-
- **Script source:**
|
|
292
|
-
- **Tests:**
|
|
290
|
+
- **Script source:** `spur builder pr` (absorbed; was `plugins/sp/scripts/pr-reviewing.ts`) — subcommand CLI
|
|
291
|
+
- **Tests:** `packages/app/tests/services/pr-review/pr-review.test.ts` — stubbed git/gh suites
|
|
293
292
|
- **Related skills:** `sp:code-verification` (local SECUA review), `sp:functional-review`
|
|
294
293
|
(requirements traceability) — complements, never substitutes, the independent Codex review
|
|
@@ -90,15 +90,15 @@ issues with its evidence. Notes stay report-only.
|
|
|
90
90
|
|
|
91
91
|
1. **Resolve scope.** Review the active session from the operator's initiating request through the
|
|
92
92
|
latest result. Use `[focus]` only to rank relevant material. Measure it with
|
|
93
|
-
`
|
|
93
|
+
`spur history timeline --group "<ranges>"`: one segment per
|
|
94
94
|
operator prompt, read-only from the host transcript. Run it once without `--group` to list the
|
|
95
95
|
segments, then map them to stages (`"1-3,4,5-6"`). It splits each segment into `work` and
|
|
96
96
|
operator `wait` (idle before the next prompt plus AskUserQuestion answer time) and counts tokens
|
|
97
97
|
once per message id. On pi the transcript is `$PI_SESSION_FILE` (pass it as `--transcript` when
|
|
98
98
|
the run reports no host session id). **A measurement that returns `segments: []` with zero totals
|
|
99
99
|
while the session had operator prompts is an unreadable or stale adapter, not an empty session:**
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
check `spur --version` against this tree's release and upgrade the CLI before reporting
|
|
101
|
+
numbers; report `n/a` until then.
|
|
102
102
|
The transcript resolves from `--transcript`, else `CLAUDE_CODE_SESSION_ID`, else `PI_SESSION_FILE`
|
|
103
103
|
(the pi host sets it and no Claude session id); with none of them the measurement reports
|
|
104
104
|
`available:false` with a reason and the table renders `n/a` instead of guessing. A pi
|
|
@@ -101,10 +101,13 @@ line: `Verification: HIGH|MEDIUM|LOW — <first failing check and deviation, or
|
|
|
101
101
|
- **Honest confidence** — the stated HIGH/MEDIUM/LOW matches the evidence: HIGH requires a check against the pinned source this session; MEDIUM/LOW items are labeled, and LOW is never presented as fact.
|
|
102
102
|
- **HIGH** — all three checks pass. **MEDIUM** — coverage intact but some citations are off-version (latest docs for a pinned dependency) or secondary-source only. **LOW** — an API/library claim lacks any citation, or a LOW-confidence claim was asserted as fact.
|
|
103
103
|
|
|
104
|
-
Deterministic backstop: the `cited-version-strings`, `cited-api-claims
|
|
105
|
-
`cited-api-claims-confidence`
|
|
106
|
-
that assert a version string or a
|
|
107
|
-
|
|
104
|
+
Deterministic backstop: the `cited-version-strings`, `cited-api-claims`,
|
|
105
|
+
`cited-api-claims-confidence` and `cited-high-confidence` rules
|
|
106
|
+
(`.spur/rules/docs/sourced-api-claims.yaml`) flag markdown lines that assert a version string or a
|
|
107
|
+
time-anchored API claim with no citation anchor on the same line, claim lines that carry no
|
|
108
|
+
HIGH/MEDIUM/LOW level, and claim lines that claim HIGH with no anchor — the one level that asserts
|
|
109
|
+
"verified this session", so its source must be on the line; MEDIUM (recalled) and LOW (memory only)
|
|
110
|
+
need no anchor by contract and are not flagged. They are an info-severity advisory backstop for
|
|
108
111
|
this contract and are deliberately NOT wired into `recommended-pre-check` — run them ad hoc with
|
|
109
112
|
`spur rule run --file .spur/rules/docs/sourced-api-claims.yaml`. The checks above and the SECUA
|
|
110
113
|
checklist remain the enforcement points.
|