@gtrabanco/pi-agentic-workflow 0.11.2 → 0.13.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/README.md +26 -0
- package/dist/config/defaults.js +2 -0
- package/dist/config/load.d.ts +3 -0
- package/dist/config/load.js +3 -1
- package/dist/config/merge.js +2 -0
- package/dist/config/path-policy.d.ts +97 -0
- package/dist/config/path-policy.js +301 -0
- package/dist/config/schema.js +65 -2
- package/dist/config/types.d.ts +5 -0
- package/dist/extension/index.js +147 -5
- package/package.json +2 -2
- package/skills/audit-docs/SKILL.md +6 -5
- package/skills/audit-pr/SKILL.md +2 -2
- package/skills/design-feature/SKILL.md +2 -2
- package/skills/design-feature/references/REPAIR.md +12 -10
- package/skills/evidence-grounding/SKILL.md +1 -1
- package/skills/execute-phase/SKILL.md +2 -2
- package/skills/execute-phase/references/EXECUTION_CONTRACT.md +19 -0
- package/skills/execute-phase/references/FOLDING.md +9 -2
- package/skills/execute-phase/references/PREFLIGHT.md +28 -0
- package/skills/fold-findings/SKILL.md +6 -4
- package/skills/generate-docs/SKILL.md +1 -1
- package/skills/implementation-discovery/SKILL.md +1 -1
- package/skills/init-workspace/SKILL.md +2 -2
- package/skills/init-workspace/references/BOOTSTRAP_WRITE.md +7 -1
- package/skills/init-workspace/references/UPGRADE.md +7 -2
- package/skills/log-session/SKILL.md +1 -1
- package/skills/orchestration-envelope/SKILL.md +2 -2
- package/skills/orchestration-envelope/references/TURN_CONTRACT.md +52 -0
- package/skills/phase-contract/SKILL.md +1 -1
- package/skills/plan-feature/SKILL.md +5 -4
- package/skills/plan-feature-from-issue/SKILL.md +1 -1
- package/skills/plan-feature-scaffold/SKILL.md +2 -2
- package/skills/plan-feature-scaffold/references/SCAFFOLD_PROCESS.md +8 -0
- package/skills/plan-fix/SKILL.md +1 -1
- package/skills/planning-preflight/SKILL.md +1 -1
- package/skills/pre-execution-review/SKILL.md +2 -2
- package/skills/pre-execution-review/references/LEDGERS.md +43 -6
- package/skills/pre-execution-review/references/POLICY.md +40 -14
- package/skills/product-audit/SKILL.md +4 -4
- package/skills/product-audit/references/AUDIT_DIMENSIONS.md +1 -1
- package/skills/product-audit/references/AUDIT_PROCESS.md +1 -1
- package/skills/replan-findings/SKILL.md +4 -4
- package/skills/review-a11y/SKILL.md +1 -1
- package/skills/review-brand/SKILL.md +1 -1
- package/skills/review-change/SKILL.md +7 -5
- package/skills/review-change/references/OUTPUT_AND_GUARDRAILS.md +2 -1
- package/skills/review-change/references/PERSIST_AND_DECIDE.md +17 -11
- package/skills/review-code/SKILL.md +1 -1
- package/skills/review-debt/SKILL.md +1 -1
- package/skills/review-design/SKILL.md +1 -1
- package/skills/review-implementation/SKILL.md +2 -2
- package/skills/review-implementation/references/CLASSIFY.md +55 -0
- package/skills/review-perf/SKILL.md +1 -1
- package/skills/review-plan/SKILL.md +2 -2
- package/skills/review-plan/references/CHECKS.md +5 -2
- package/skills/review-plan/references/OUTPUT.md +6 -6
- package/skills/review-security/SKILL.md +1 -1
- package/skills/review-seo/SKILL.md +1 -1
- package/skills/review-spec/SKILL.md +2 -2
- package/skills/review-spec/references/CHECKS.md +4 -1
- package/skills/review-spec/references/OUTPUT.md +9 -5
- package/skills/review-verify/SKILL.md +1 -1
- package/skills/triage-issue/SKILL.md +1 -1
- package/skills/verification-contract/SKILL.md +8 -2
- package/skills/workflow-status/SKILL.md +2 -2
- package/skills/workflow-status/references/ENVELOPE_CORE.md +5 -4
- package/skills/workflow-status/references/SENSOR_CORE.md +5 -4
- package/skills/workflow-status/references/SENSOR_SIGNALS.md +3 -2
package/dist/extension/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFileSync, readdirSync, existsSync, lstatSync, readlinkSync, realpathSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { getAgentDir, isToolCallEventType } from "@earendil-works/pi-coding-agent";
|
|
4
5
|
import { loadConfig } from "../config/load.js";
|
|
6
|
+
import { evaluateToolCall, isProtectedPath, normalizeTarget } from "../config/path-policy.js";
|
|
5
7
|
import { createExtension } from "./factory.js";
|
|
6
8
|
import { readGitStatusBounded } from "./receipt-guard.js";
|
|
7
9
|
import { createPickerComponent, PICKER_MAX_VISIBLE, pagedSelect } from "../settings/picker.js";
|
|
@@ -95,9 +97,86 @@ function toRegistrar(pi) {
|
|
|
95
97
|
}),
|
|
96
98
|
};
|
|
97
99
|
}
|
|
100
|
+
/** Every unit decision ledger's `path-protection-records@1` block, concatenated. */
|
|
101
|
+
function collectRecordTexts(root) {
|
|
102
|
+
const texts = [];
|
|
103
|
+
for (const parent of ["docs/features", "docs/fix"]) {
|
|
104
|
+
const base = join(root, parent);
|
|
105
|
+
let entries;
|
|
106
|
+
try {
|
|
107
|
+
entries = readdirSync(base, { withFileTypes: true });
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
if (!entry.isDirectory())
|
|
114
|
+
continue;
|
|
115
|
+
try {
|
|
116
|
+
texts.push(readFileSync(join(base, entry.name, "decisions.md"), "utf8"));
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// A unit without a decisions ledger contributes no records.
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return texts.join("\n");
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Canonicalise an absolute target even when it does not exist yet. `realpathSync`
|
|
127
|
+
* refuses a path whose final component is absent, so the longest existing prefix
|
|
128
|
+
* is canonicalised and the missing tail re-appended; a symlink at the final
|
|
129
|
+
* component is followed explicitly, because a write follows it even when its
|
|
130
|
+
* destination is absent (F28). Resolution errors fail closed.
|
|
131
|
+
*/
|
|
132
|
+
function resolveRealTarget(target) {
|
|
133
|
+
let current = target;
|
|
134
|
+
for (let hops = 0; hops < 40; hops += 1) {
|
|
135
|
+
let link = null;
|
|
136
|
+
try {
|
|
137
|
+
if (lstatSync(current).isSymbolicLink())
|
|
138
|
+
link = readlinkSync(current);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// The path does not exist: canonicalise its longest existing prefix.
|
|
142
|
+
return { ok: true, real: resolveExistingPrefix(current) };
|
|
143
|
+
}
|
|
144
|
+
if (link === null) {
|
|
145
|
+
try {
|
|
146
|
+
return { ok: true, real: realpathSync(current) };
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
current = isAbsolute(link) ? link : resolve(dirname(current), link);
|
|
153
|
+
}
|
|
154
|
+
return { ok: false, reason: "too many symbolic links" };
|
|
155
|
+
}
|
|
156
|
+
/** Canonicalise the longest existing prefix of `target` and re-append the missing tail. */
|
|
157
|
+
function resolveExistingPrefix(target) {
|
|
158
|
+
const tail = [];
|
|
159
|
+
let current = target;
|
|
160
|
+
for (;;) {
|
|
161
|
+
try {
|
|
162
|
+
const real = realpathSync(current);
|
|
163
|
+
return tail.length === 0 ? real : join(real, ...tail.reverse());
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
const parent = dirname(current);
|
|
167
|
+
if (parent === current)
|
|
168
|
+
return target;
|
|
169
|
+
tail.push(basename(current));
|
|
170
|
+
current = parent;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
98
174
|
export default function extension(pi) {
|
|
99
175
|
const agentDir = getAgentDir();
|
|
100
176
|
const hint = createHintStore({ path: stateFilePath(agentDir) });
|
|
177
|
+
// Said once per session: an override that was ignored (or a malformed file)
|
|
178
|
+
// is reported the first time the guard runs, never on every tool call.
|
|
179
|
+
let reportedDegradations = false;
|
|
101
180
|
const { router, guards } = createExtension({
|
|
102
181
|
registrar: toRegistrar(pi),
|
|
103
182
|
// Resolved per call: the router must never hold a session-bound object
|
|
@@ -129,10 +208,73 @@ export default function extension(pi) {
|
|
|
129
208
|
pi.on("thinking_level_select", (event) => router.noteThinkingLevelSelect(event.level));
|
|
130
209
|
// The inline-receipt path is impossible: a `gh pr comment` carrying a
|
|
131
210
|
// REVIEW-PASS / merge-ready marker is blocked before it runs, and the reason
|
|
132
|
-
// names the script that proves the receipt landed (issue #182).
|
|
133
|
-
|
|
211
|
+
// names the script that proves the receipt landed (issue #182). The guard
|
|
212
|
+
// itself filters to `bash`, so every tool call is checked — nesting it under
|
|
213
|
+
// one tool name would make the block unreachable for the calls it exists for.
|
|
214
|
+
pi.on("tool_call", (event, ctx) => {
|
|
134
215
|
const command = "command" in event.input && typeof event.input.command === "string" ? event.input.command : undefined;
|
|
135
|
-
|
|
216
|
+
const receipt = guards.receiptGuard({ toolName: event.toolName, command });
|
|
217
|
+
if (receipt.block)
|
|
218
|
+
return receipt;
|
|
219
|
+
// Tier 2 path prevention (feature 60): block a write/edit to an existing
|
|
220
|
+
// protected path with no matching justification record; reads and new-file
|
|
221
|
+
// creates pass. Reads the same effective policy the Tier 1 gate reads.
|
|
222
|
+
if (!isToolCallEventType("write", event) && !isToolCallEventType("edit", event))
|
|
223
|
+
return undefined;
|
|
224
|
+
const targetPath = event.input.path;
|
|
225
|
+
if (typeof targetPath !== "string" || targetPath === "")
|
|
226
|
+
return undefined;
|
|
227
|
+
const loaded = loadConfig({ agentDir, cwd: ctx.cwd, projectTrusted: ctx.isProjectTrusted() });
|
|
228
|
+
if (!reportedDegradations && loaded.pathProtectionDegradations.length > 0) {
|
|
229
|
+
reportedDegradations = true;
|
|
230
|
+
for (const degradation of loaded.pathProtectionDegradations) {
|
|
231
|
+
ctx.ui.notify(`pi-agentic-workflow: path protection — ${degradation.code}: ${degradation.detail}`, "warning");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const absolute = isAbsolute(targetPath) ? targetPath : resolve(ctx.cwd, targetPath);
|
|
235
|
+
let realRoot = ctx.cwd;
|
|
236
|
+
try {
|
|
237
|
+
realRoot = realpathSync(ctx.cwd);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// ctx.cwd always exists; fall back to the lexical root.
|
|
241
|
+
}
|
|
242
|
+
// Canonicalise the target even when it does not exist yet, so the
|
|
243
|
+
// containment check and the protected-glob match run on the same basis as
|
|
244
|
+
// `realpathSync(ctx.cwd)` (F27) and a dangling symlink cannot route a write
|
|
245
|
+
// outside the project root (F28).
|
|
246
|
+
const resolvedTarget = resolveRealTarget(absolute);
|
|
247
|
+
if (!resolvedTarget.ok) {
|
|
248
|
+
return {
|
|
249
|
+
block: true,
|
|
250
|
+
reason: `"${targetPath}" could not be resolved (${resolvedTarget.reason}); ` +
|
|
251
|
+
`path protection cannot verify it, so the write is blocked.`,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const relativeTarget = normalizeTarget(relative(realRoot, resolvedTarget.real));
|
|
255
|
+
// Fail closed on a target that escapes the project root: the policy is
|
|
256
|
+
// repo-relative, so an out-of-root path cannot be verified (F7).
|
|
257
|
+
if (relativeTarget === "" || relativeTarget === ".." || relativeTarget.startsWith("../") || isAbsolute(relativeTarget)) {
|
|
258
|
+
return {
|
|
259
|
+
block: true,
|
|
260
|
+
reason: `"${targetPath}" resolves outside the project root (${ctx.cwd}); ` +
|
|
261
|
+
`path protection cannot verify it, so the write is blocked.`,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
// Lazy: read the records corpus (every unit's decisions.md) only once the
|
|
265
|
+
// target is a known existing protected path, never on every write/edit (F13).
|
|
266
|
+
if (!existsSync(absolute))
|
|
267
|
+
return undefined;
|
|
268
|
+
if (!isProtectedPath(loaded.config.pathProtection, relativeTarget))
|
|
269
|
+
return undefined;
|
|
270
|
+
const decision = evaluateToolCall({
|
|
271
|
+
toolName: event.toolName,
|
|
272
|
+
targetPath: relativeTarget,
|
|
273
|
+
targetExists: true,
|
|
274
|
+
policy: loaded.config.pathProtection,
|
|
275
|
+
recordsText: collectRecordTexts(ctx.cwd),
|
|
276
|
+
});
|
|
277
|
+
return decision.block ? { block: true, reason: decision.reason } : undefined;
|
|
136
278
|
});
|
|
137
279
|
pi.on("agent_settled", (_event, ctx) => {
|
|
138
280
|
void router.settle(toInvocationContext(ctx));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtrabanco/pi-agentic-workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Pi package: canonical agentic-workflow skills, friendly slash commands, and per-command model routing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"model-routing"
|
|
12
12
|
],
|
|
13
13
|
"license": "MIT",
|
|
14
|
-
"author": "Gabriel Trabanco <gtrabanco@users.noreply.github.com>",
|
|
14
|
+
"author": "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>",
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
17
|
"url": "git+https://github.com/gtrabanco/agentic-workflow.git",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: audit-docs
|
|
3
3
|
user-invocable: true
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
argument-hint: "[--fix]"
|
|
6
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
6
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
7
7
|
license: MIT
|
|
8
8
|
description: >
|
|
9
9
|
Audit cross-document coherence: docs ↔ roadmap ↔ code ↔ fix index ↔ issues.
|
|
@@ -95,7 +95,7 @@ run the command shown, don't infer.
|
|
|
95
95
|
`Docs site` block; otherwise state n/a).** Scan the declared content dir
|
|
96
96
|
for pages carrying `generated-by: agentic-workflow/generate-docs`. For
|
|
97
97
|
each: (a) its `source-unit` exists in the roadmap or fix index — no match
|
|
98
|
-
is an **orphan** (
|
|
98
|
+
is an **orphan** (low: propose deletion or re-attribution); (b) the
|
|
99
99
|
unit's PR merged **after** the page's `updated` date with commits touching
|
|
100
100
|
the page's subject paths — that page is **stale** (LOW: propose
|
|
101
101
|
`/generate-docs <unit>` to refresh). Cite page path + unit per finding.
|
|
@@ -118,16 +118,17 @@ say so.
|
|
|
118
118
|
```
|
|
119
119
|
AUDIT DOCS — scope: <docs tree / roadmap / fix index / issues checked>
|
|
120
120
|
|
|
121
|
-
| # | Check (1-
|
|
121
|
+
| # | Check (1-14) | Finding | Sev | Evidence | Proposed fix |
|
|
122
122
|
|---|-------------|---------|-----|----------|--------------|
|
|
123
123
|
| 1 | <which> | <what> | high|low | <path:line / #issue> | <smallest action> |
|
|
124
124
|
|
|
125
|
-
Checks run: <n>/
|
|
125
|
+
Checks run: <n>/14 (skipped: <which + why — absent structures only>)
|
|
126
126
|
Summary: <1-2 sentences>
|
|
127
127
|
Decision: PASS | FAIL (FAIL if any high-severity finding is open)
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
Sev: **high** = misleading or broken; **low** = cosmetic.
|
|
131
|
+
Only `high` and `low` are defined in this legend
|
|
131
132
|
3. **Fix only on request.** With explicit `--fix` (or user go-ahead), apply the
|
|
132
133
|
low-risk corrections (remove a merged fix-index row, fix a dead link, register
|
|
133
134
|
a missing roadmap entry, add a verified PR link to a bare `done` row). Leave judgment calls to the user.
|
package/skills/audit-pr/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: audit-pr
|
|
3
3
|
user-invocable: true
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.3.0
|
|
5
5
|
argument-hint: <pr-number> (optional — defaults to the current branch's PR)
|
|
6
6
|
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
7
7
|
license: MIT
|
|
@@ -51,7 +51,7 @@ independently evaluates only the delivery gates below.
|
|
|
51
51
|
✓ No review pass was composed or reconstructed: a missing/stale receipt is a
|
|
52
52
|
blocker, never a prompt to re-run review axes from this skill
|
|
53
53
|
✓ Closure integrity was evaluated and its result stated explicitly: pass /
|
|
54
|
-
blocker /
|
|
54
|
+
blocker / n-a (fix-governed PRs are always n-a; never skipped
|
|
55
55
|
silently)
|
|
56
56
|
✓ Scope integrity (descope) was evaluated and its result stated explicitly:
|
|
57
57
|
pass / blocker / n-a (no unit-referencing issues born on the branch → n-a;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: design-feature
|
|
3
3
|
user-invocable: true
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.5.0
|
|
5
5
|
argument-hint: <idea | NN-slug> [<instruction>]
|
|
6
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
6
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
7
7
|
license: MIT
|
|
8
8
|
description: >
|
|
9
9
|
Turn a raw idea or existing feature into a designed product SPEC by completing
|
|
@@ -57,18 +57,20 @@ exists; it never chose how to fill it, and neither does this skill.
|
|
|
57
57
|
### 4. Second cycle = anomaly, not routine
|
|
58
58
|
|
|
59
59
|
Cycle rules have one owner: `pre-execution-review/references/POLICY.md` §4 — a repeat needs a changed
|
|
60
|
-
snapshot or a named falsifiable question plus a new evidence route, and
|
|
61
|
-
|
|
60
|
+
snapshot or a named falsifiable question plus a new evidence route, and a second
|
|
61
|
+
consecutive repair/re-review cycle prints the `CONVERGENCE-ANOMALY` block (repeated
|
|
62
62
|
and new finding ids, the snapshots that moved, the evidence or obligation missed,
|
|
63
63
|
the owning stage, and why the prior readiness/review/repair failed) **before** any
|
|
64
|
-
further edit, then routes to that owner.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
further edit, then routes to that owner. The repair cycles are the correction
|
|
65
|
+
path; they never earn a PASS, and an exhausted cycle budget does not downgrade an
|
|
66
|
+
open finding. A third cycle never starts without explicit user instruction: the
|
|
67
|
+
orchestrator's `stop-review-loop-cap` refusal stops the invocation and names
|
|
68
|
+
`design-feature` as the human route, and a PASS resets the count.
|
|
69
|
+
|
|
70
|
+
The cap counts review invocations, never repairs: a repair responding to a
|
|
71
|
+
persisted verdict produces a new snapshot by design, so the repair turn itself is
|
|
72
|
+
never a loop defect. An open finding is never downgraded or waved through to
|
|
73
|
+
satisfy a count.
|
|
72
74
|
|
|
73
75
|
The spec-stage detail this skill adds: the owning stage of a Product-half miss is
|
|
74
76
|
`product` unless the evidence proves the plan asked for something the SPEC never
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: evidence-grounding
|
|
3
3
|
user-invocable: false
|
|
4
4
|
version: 1.6.0
|
|
5
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
5
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
6
6
|
license: MIT
|
|
7
7
|
description: >
|
|
8
8
|
Internal shared owner of evidence-grounded authoring: the fixed
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: execute-phase
|
|
3
3
|
user-invocable: true
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.7.0
|
|
5
5
|
argument-hint: <NN> [P<k>] | --fix <n> [P<k>] | [--max-attempts N] [--force]
|
|
6
6
|
allowed-tools: [Bash, Read, Edit, Write, MultiEdit]
|
|
7
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
7
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
8
8
|
license: MIT
|
|
9
9
|
description: >
|
|
10
10
|
Implement all remaining phases of a planned feature/fix by default, or one
|
|
@@ -57,6 +57,25 @@ never treat a missing marker as a blocker or crash condition.
|
|
|
57
57
|
Something forbidden looks necessary → stop, record it in `decisions.md` or
|
|
58
58
|
`known-issues.md`, and surface it — never do it silently.
|
|
59
59
|
|
|
60
|
+
## Gate-run mark
|
|
61
|
+
|
|
62
|
+
The phase completion gate records a `GATE-RAN` mark at the head it ran and
|
|
63
|
+
consumes an identical-head green mark instead of re-running. The mark's shape,
|
|
64
|
+
ownership, and reuse rule are declared in `LEDGERS.md` (§gate-ran@1).
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
GATE-RAN | HEAD <40-hex sha> | <cmds> | exit <code>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- **Record**: whoever runs the project gate records a mark at the head the gate
|
|
71
|
+
actually ran. A green run is recorded; a red run is also recorded (exit code
|
|
72
|
+
≠ 0 is evidence, not silence).
|
|
73
|
+
- **Consume**: any skill may consume a green run only at the identical HEAD. A
|
|
74
|
+
changed head ⇒ re-run the gate.
|
|
75
|
+
- **Recorder column-sets**: `execute-phase:gate-ran-marks` (executor phase gates)
|
|
76
|
+
and `review-change:review-gate-ran-marks` (reviewer gate runs) are declared in
|
|
77
|
+
the `review-findings` truth-class row's owner cell.
|
|
78
|
+
|
|
60
79
|
## Phase completion gate — pass only if (every box, every phase)
|
|
61
80
|
|
|
62
81
|
```
|
|
@@ -23,8 +23,8 @@ end up "solved" locally but absent from the merged PR:
|
|
|
23
23
|
(known-issues.md entry resolved? progress.md notes the fold)
|
|
24
24
|
✓ Each folded finding's row in the unit's `review-findings.md` ledger (if one
|
|
25
25
|
exists — the ledger is optional; a unit with no fix-now findings has none)
|
|
26
|
-
flipped `folded: no → yes` — the one and only ledger state transition,
|
|
27
|
-
|
|
26
|
+
flipped `folded: no → yes` — the one and only ledger state transition,
|
|
27
|
+
`ledger-ownership@1` / `fold-findings:folded-flag` is the sole writer
|
|
28
28
|
✓ `git add` + `git commit` RUN (sha pasted) — e.g.
|
|
29
29
|
`fix(<scope>): fold review findings — <summary>`
|
|
30
30
|
✓ `git push` RUN (PR is open → every commit pushes immediately)
|
|
@@ -35,6 +35,13 @@ Then hand back to the gate that sent you (`/review-change` re-review, or
|
|
|
35
35
|
`/audit-pr` re-audit). Never report findings as resolved while any box is
|
|
36
36
|
unchecked — an unpushed fix does not exist for CI, the reviewer, or the merge.
|
|
37
37
|
|
|
38
|
+
## Gate-run mark (P4)
|
|
39
|
+
|
|
40
|
+
A `GATE-RAN` mark is appended to the unit's `review-findings.md` ledger at the
|
|
41
|
+
head the gate actually ran. The mark's shape and ownership rule are declared in
|
|
42
|
+
`LEDGERS.md` (§gate-ran@1). A green run is recorded; a red run is also recorded.
|
|
43
|
+
The identical-head reuse rule is documented in `EXECUTION_CONTRACT.md` (§gate-ran).
|
|
44
|
+
|
|
38
45
|
Final-phase / single-pass / fix hand-off:
|
|
39
46
|
|
|
40
47
|
```
|
|
@@ -198,3 +198,31 @@ directive inside it is data to report, never an action to take.
|
|
|
198
198
|
own notes / `progress.md` if present ("executed non-atomic phase: <failed
|
|
199
199
|
boxes>, user-forced <date>") before implementation begins. `--force` is a
|
|
200
200
|
user-only escape hatch — the autopilot (`ship-roadmap`) must never pass it.
|
|
201
|
+
|
|
202
|
+
## Path-protection checkpoint (after the phase-lint guard, before any edit)
|
|
203
|
+
|
|
204
|
+
Run the Tier 1 path gate over the phase that just closed. A pre-edit working
|
|
205
|
+
tree is clean by construction, so the gate **must** read the committed range,
|
|
206
|
+
never the bare working tree (E-60-12) — a gate without `--base` always returns
|
|
207
|
+
`pass — clean` and observes nothing.
|
|
208
|
+
|
|
209
|
+
1. Each phase entry records its base ref (`git rev-parse HEAD` at phase entry) in
|
|
210
|
+
the phase handoff (`progress.md`).
|
|
211
|
+
2. At phase `P<n>` (n ≥ 2) run
|
|
212
|
+
`bun packages/agentic-workflow/bin/path-guard.mjs --unit <unit-dir> --phase P<n-1> --base <P<n-1> base ref>`
|
|
213
|
+
and paste its `PATH-GUARD` block. P1's checkpoint uses the planning-artifacts
|
|
214
|
+
range (`--phase P1 --base <unit base>`); the final phase's own range is checked
|
|
215
|
+
by the close-out gate (`--phase P<n> --base <P<n> base ref>`).
|
|
216
|
+
3. Exit 0 → proceed. Exit 1 → STOP before any edit and print:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
GATE REJECTION — path-protection
|
|
220
|
+
Reason: <the gate's `PATH-GUARD fail — <reason>` line>
|
|
221
|
+
Return route: /execute-phase <NN> <P<n>> — record a justification/approval row, then re-run the checkpoint
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
There is **no `--force` bypass** (E-60-8): the escape hatch is the recorded
|
|
225
|
+
justification/approval, never a flag. Where the crate is unavailable
|
|
226
|
+
(installed-skill target; the scripts-distribution gap, `known-issues.md`
|
|
227
|
+
B-01), apply the same disclose-and-degrade rule the phase-lint guard uses and
|
|
228
|
+
record the unavailable gate — never silently skip it.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fold-findings
|
|
3
3
|
user-invocable: true
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.0
|
|
5
5
|
argument-hint: [finding-id …]
|
|
6
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
6
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
7
7
|
license: MIT
|
|
8
8
|
description: >
|
|
9
9
|
Repair persisted fix-now findings in compatible atomic batches: root-cause
|
|
@@ -154,8 +154,10 @@ audit-pr ──BLOCKED─────┼──▶ fold-findings ──FOLDED─
|
|
|
154
154
|
│ ──BLOCKED──▶ user supplies missing input
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
`review-change`/`audit-pr` classify and persist;
|
|
158
|
-
`
|
|
157
|
+
`review-change`/`audit-pr` classify and persist;
|
|
158
|
+
`ledger-ownership@1` / `fold-findings:folded-flag` is the sole writer of
|
|
159
|
+
the `folded: no → yes` flip — this skill only flips that flag after a real
|
|
160
|
+
fix. `execute-phase`'s embedded fold checklist
|
|
159
161
|
is the inline fallback; this standalone path keeps frozen classification and its
|
|
160
162
|
forbidden list and never runs above its tier. `DISPUTED` stops for user evidence;
|
|
161
163
|
no issue is created.
|
|
@@ -3,7 +3,7 @@ name: generate-docs
|
|
|
3
3
|
user-invocable: true
|
|
4
4
|
version: 2.0.1
|
|
5
5
|
argument-hint: "[NN-slug | fix-n | path/glob] [--review]"
|
|
6
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
6
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
7
7
|
license: MIT
|
|
8
8
|
description: >
|
|
9
9
|
Generate incremental, diff-driven developer guides through the project's
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: implementation-discovery
|
|
3
3
|
user-invocable: false
|
|
4
4
|
version: 1.1.0
|
|
5
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
5
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
6
6
|
license: MIT
|
|
7
7
|
description: >
|
|
8
8
|
Internal contract: the single owner of the bounded pre-write implementation
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: init-workspace
|
|
3
3
|
user-invocable: true
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.9.0
|
|
5
5
|
argument-hint: <target-dir>
|
|
6
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
6
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
7
7
|
license: MIT
|
|
8
8
|
description: >
|
|
9
9
|
Adapt the workflow scaffold to a new repository or add only missing substrate
|
|
@@ -20,7 +20,13 @@
|
|
|
20
20
|
that the scaffold failed. If retained, add its documentation-map row and
|
|
21
21
|
name the project's explicit architectural-decision authority.
|
|
22
22
|
7. **Install accepted agent safety hooks.** Keep the canonical policy and
|
|
23
|
-
fullauto wrapper at `.agentic-workflow/hooks/`.
|
|
23
|
+
fullauto wrapper at `.agentic-workflow/hooks/`. Seed the shipped
|
|
24
|
+
path-protection policy at `.agentic-workflow/path-policy.json` and its doc
|
|
25
|
+
page at `.agentic-workflow/path-protection.md`, beside the hooks — the
|
|
26
|
+
`path-policy.json` seed is byte-identical to the producer crate's canonical
|
|
27
|
+
default, so a fresh install gets the guard with zero config. Leave an
|
|
28
|
+
existing owner-written `.agentic-workflow/path-policy.json` untouched and
|
|
29
|
+
report it as a residual. For each accepted platform,
|
|
24
30
|
activate only its repository config/example as documented in the hook pack.
|
|
25
31
|
Run `bash .agentic-workflow/hooks/tests/test-command-guard.sh`; missing `jq`,
|
|
26
32
|
an unknown payload, or an existing customized hook file becomes a residual,
|
|
@@ -19,7 +19,9 @@ lacks**. Seven ordered steps:
|
|
|
19
19
|
(`docs/CAPABILITIES.md` + its documentation-map row), the optional
|
|
20
20
|
architectural-invariants document
|
|
21
21
|
(`docs/architecture/ARCHITECTURAL_INVARIANTS.md` + its documentation-map
|
|
22
|
-
row), the portable command-guard pack and detected platform adapter,
|
|
22
|
+
row), the portable command-guard pack and detected platform adapter, the
|
|
23
|
+
shipped path-protection `path-policy.json` seed and its `path-protection.md`
|
|
24
|
+
doc page, or the Normalized
|
|
23
25
|
Repository State ledger (`docs/workflow/REPOSITORY_STATE.md`). This is the
|
|
24
26
|
diff-against-current-template contract; it is the only source of *what's
|
|
25
27
|
new*. (A missing `docs/CAPABILITIES.md` is proposed with the same
|
|
@@ -44,7 +46,10 @@ lacks**. Seven ordered steps:
|
|
|
44
46
|
template also changed is left untouched and listed as a residual, not
|
|
45
47
|
silently updated. For hooks, add the canonical pack when absent and activate
|
|
46
48
|
a platform adapter only after an explicit yes; never replace an existing
|
|
47
|
-
platform hook config.
|
|
49
|
+
platform hook config. A missing `path-policy.json` seed and its
|
|
50
|
+
`path-protection.md` page are proposed from the template; an existing
|
|
51
|
+
owner-written `path-policy.json` is never clobbered and is listed as a
|
|
52
|
+
residual instead. Leave honest placeholders where the user skipped.
|
|
48
53
|
6. **Seed missing urgency labels, additively (feature 15).** Independent of
|
|
49
54
|
the `CLAUDE.md`/`docs/` block diff above (this is forge-repo state, not a
|
|
50
55
|
doc block): check whether the target repo already has the `urgent` and
|
|
@@ -3,7 +3,7 @@ name: log-session
|
|
|
3
3
|
user-invocable: true
|
|
4
4
|
version: 2.2.0
|
|
5
5
|
argument-hint: "[note to prepend to the entry]"
|
|
6
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
6
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
7
7
|
license: MIT
|
|
8
8
|
description: >
|
|
9
9
|
Append a structured entry to the project's session log (`docs/LOGS.md`):
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: orchestration-envelope
|
|
3
3
|
user-invocable: false
|
|
4
|
-
version: 2.
|
|
5
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
4
|
+
version: 2.2.0
|
|
5
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
6
6
|
license: MIT
|
|
7
7
|
description: >
|
|
8
8
|
Internal machine-result contract for headless agentic-workflow drivers. The
|
|
@@ -85,3 +85,55 @@ next | suggested
|
|
|
85
85
|
next | continuation
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
## Path-protection checkpoint (feature 60)
|
|
89
|
+
|
|
90
|
+
The Tier 1 path gate is versioned so the checkpoint invocation, the closed
|
|
91
|
+
reason vocabulary, and the two record blocks cannot drift from the crate module
|
|
92
|
+
that produces them. The preflight runs the checkpoint over the just-closed
|
|
93
|
+
phase's committed range (`execute-phase`'s preflight owns the step text):
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
path-protection@1
|
|
97
|
+
# checkpoint: path-guard --unit <unit-dir> --phase <P<n>> --base <P<n> base ref>
|
|
98
|
+
# reasons: schema-export:PATH_GUARD_REASONS (packages/agentic-workflow/src/path-policy.mjs)
|
|
99
|
+
reason | kind
|
|
100
|
+
clean | pass
|
|
101
|
+
justified | pass
|
|
102
|
+
approved | pass
|
|
103
|
+
protected-modification | fail
|
|
104
|
+
approval-required | fail
|
|
105
|
+
undeclared-test | fail
|
|
106
|
+
unmatched-record | fail
|
|
107
|
+
malformed-declaration | fail
|
|
108
|
+
missing-config | degraded
|
|
109
|
+
malformed-config | degraded
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The gate prints one fixed block (`PATH-GUARD <pass|fail> — <reason>`, then an
|
|
113
|
+
`offenders:` line, then `phase: … freeze-after: … checked:`, then any `DEGRADED`
|
|
114
|
+
line) and exits 0 on pass, 1 on fail, 2 on usage. The plan declares the protected
|
|
115
|
+
set it will author:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
path-protection-plan@1
|
|
119
|
+
freeze-after: <P<n>|none>
|
|
120
|
+
kind | path | justification
|
|
121
|
+
created | <repo-relative path or glob> | <one-line justification>
|
|
122
|
+
not-created | <test name> | <one-line justification>
|
|
123
|
+
ignored | <test name> | <one-line justification>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Every escape is an append-only record row in the unit's `decisions.md`:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
path-protection-records@1
|
|
130
|
+
kind | paths | phase | date | authority | justification
|
|
131
|
+
justification | <path or glob>[,<path or glob>] | <P<n>> | <YYYY-MM-DD> | execute-phase | <one-line justification>
|
|
132
|
+
approval | <path or glob>[,<path or glob>] | <P<n>> | <YYYY-MM-DD> | human-owner | <one-line justification>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
A `justification` row satisfies a justification requirement; an `approval` row
|
|
136
|
+
satisfies an approval requirement and additionally requires a matching
|
|
137
|
+
justification row. The authority column is validated (`execute-phase` for
|
|
138
|
+
justification, `human-owner` for approval), so no auto-approval authority exists.
|
|
139
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: phase-contract
|
|
3
3
|
user-invocable: false
|
|
4
4
|
version: 1.0.5
|
|
5
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
5
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
6
6
|
license: MIT
|
|
7
7
|
description: >
|
|
8
8
|
Internal contract: the single owner of the eight phase-lint rules, the fixed
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plan-feature
|
|
3
3
|
user-invocable: true
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.3.1
|
|
5
5
|
argument-hint: <NN-slug | #N> | --from-issue N | --scaffold <slug> | --next
|
|
6
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
6
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
7
7
|
license: MIT
|
|
8
8
|
description: >
|
|
9
9
|
Route designed features or issues into engineering planning and roadmap
|
|
@@ -91,8 +91,9 @@ one hop from this file, and fail closed when missing.
|
|
|
91
91
|
the internal steps; never re-fetched mid-plan.
|
|
92
92
|
4. **Confirm roadmap.** Verify the feature is registered in
|
|
93
93
|
`docs/features/ROADMAP.md` with the right number, ordering, and dependencies;
|
|
94
|
-
if any of the three is missing or wrong, fix the entry now — never leave
|
|
95
|
-
|
|
94
|
+
if any of the three is missing or wrong, fix the entry now — never leave registration for later.
|
|
95
|
+
`plan-feature` verifies and repairs the roadmap entry; `plan-feature-scaffold`
|
|
96
|
+
is the sole writer of the `defined → planned` write.
|
|
96
97
|
5. **Dependency & blocker check (always, before recommending execution).**
|
|
97
98
|
- Walk the feature's `Depends on:` closure (transitively): every dependency
|
|
98
99
|
must be `done` **and merged**. Any unmet → the closing block recommends
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: plan-feature-from-issue
|
|
3
3
|
user-invocable: false
|
|
4
4
|
version: 2.0.0
|
|
5
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
5
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
6
6
|
license: MIT
|
|
7
7
|
description: >
|
|
8
8
|
Internal step of plan-feature: turn a feature-request issue into a scoped,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plan-feature-scaffold
|
|
3
3
|
user-invocable: false
|
|
4
|
-
version: 2.
|
|
5
|
-
author: "Gabriel Trabanco <gtrabanco@users.noreply.github.com>"
|
|
4
|
+
version: 2.4.0
|
|
5
|
+
author: "Gabriel Trabanco <1969593+gtrabanco@users.noreply.github.com>"
|
|
6
6
|
license: MIT
|
|
7
7
|
description: >
|
|
8
8
|
Internal step of plan-feature: from an already-designed SPEC (product half
|