@miller-tech/uap 1.175.11 → 1.175.13
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/dist/.tsbuildinfo +1 -1
- package/dist/cli/plan.d.ts +33 -0
- package/dist/cli/plan.d.ts.map +1 -1
- package/dist/cli/plan.js +88 -14
- package/dist/cli/plan.js.map +1 -1
- package/package.json +2 -2
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/validate_plan_on_change.py +144 -49
- package/src/policies/schemas/policies/validate-plan-on-change.md +58 -20
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/tools/agents/tests/run_acceptance.py +83 -0
- package/tools/agents/tests/test_validate_plan_gate.py +308 -0
package/dist/cli/plan.d.ts
CHANGED
|
@@ -21,6 +21,39 @@ export interface PlanReviewOutcome {
|
|
|
21
21
|
}
|
|
22
22
|
declare function statePath(cwd: string): string;
|
|
23
23
|
declare function windowSec(): number;
|
|
24
|
+
/**
|
|
25
|
+
* Shared state with the enforcer (validate_plan_on_change.py). The contract:
|
|
26
|
+
*
|
|
27
|
+
* pending { <repo-relative plan path>: <epoch seen> } written by the
|
|
28
|
+
* enforcer when a plan artifact is created or modified; cleared
|
|
29
|
+
* here once that plan has actually been validated.
|
|
30
|
+
* validated { <repo-relative plan path>: <sha256 of the reviewed bytes> }
|
|
31
|
+
*
|
|
32
|
+
* Keying on CONTENT is the point. The old gate keyed on a 300s timestamp and
|
|
33
|
+
* fired on the plan WRITE, which meant the agent was told to validate a plan
|
|
34
|
+
* before it existed: `uap plan validate` found no artifact (or an older one),
|
|
35
|
+
* stamped anyway, and every write for the next five minutes sailed through
|
|
36
|
+
* unread — with nothing gating the build at all. A hash says "these exact bytes
|
|
37
|
+
* were reviewed", so editing the plan afterwards re-arms the gate.
|
|
38
|
+
*/
|
|
39
|
+
export interface PlanState {
|
|
40
|
+
validated_at?: number;
|
|
41
|
+
review?: PlanReviewOutcome;
|
|
42
|
+
pending?: Record<string, number>;
|
|
43
|
+
validated?: Record<string, string>;
|
|
44
|
+
}
|
|
45
|
+
/** Path key shared with the enforcer: repo-relative, forward slashes. */
|
|
46
|
+
export declare function planKey(cwd: string, file: string): string;
|
|
47
|
+
export declare function planHash(text: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Plans the enforcer recorded as touched but which have not been validated
|
|
50
|
+
* since, plus plans that were validated and have since DRIFTED on disk.
|
|
51
|
+
* Anything listed here is what the build gate is waiting on.
|
|
52
|
+
*/
|
|
53
|
+
export declare function outstandingPlans(cwd: string): {
|
|
54
|
+
pending: string[];
|
|
55
|
+
drifted: string[];
|
|
56
|
+
};
|
|
24
57
|
/** Most recently modified plan-like artifact: plans/ dirs first, then cwd. */
|
|
25
58
|
export declare function findPlanArtifact(cwd: string): string | null;
|
|
26
59
|
export declare function planCommand(action: string | undefined, options?: PlanOptions, cwd?: string, deps?: PlanDeps): Promise<void>;
|
package/dist/cli/plan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/cli/plan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/cli/plan.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAGpE,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,2EAA2E;AAC3E,MAAM,WAAW,QAAQ;IACvB,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,iBAAS,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtC;AACD,iBAAS,SAAS,IAAI,MAAM,CAG3B;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,SAAS;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAWD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CActF;AASD,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4B3D;AA0GD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,GAAE,WAAgB,EACzB,GAAG,GAAE,MAAsB,EAC3B,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CA8Gf;AAED,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,SAAS,IAAI,aAAa,EAAE,CAAC"}
|
package/dist/cli/plan.js
CHANGED
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
* endpoint stamps with a note — the plan gate must never deadlock offline.
|
|
25
25
|
* A completed review that returns "fail" is the only thing that blocks.
|
|
26
26
|
*/
|
|
27
|
+
import { createHash } from 'crypto';
|
|
27
28
|
import { mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'fs';
|
|
28
|
-
import { join, resolve, sep } from 'path';
|
|
29
|
+
import { join, relative, resolve, sep } from 'path';
|
|
29
30
|
import { reviewPlanText } from '../delivery/plan-check.js';
|
|
30
31
|
function stateDir(cwd) {
|
|
31
32
|
return join(cwd, process.env.UAP_STATE_DIR || '.uap');
|
|
@@ -37,14 +38,44 @@ function windowSec() {
|
|
|
37
38
|
const w = parseInt(process.env.UAP_PLAN_VALIDATE_WINDOW || '300', 10);
|
|
38
39
|
return Number.isFinite(w) ? w : 300;
|
|
39
40
|
}
|
|
41
|
+
/** Path key shared with the enforcer: repo-relative, forward slashes. */
|
|
42
|
+
export function planKey(cwd, file) {
|
|
43
|
+
return relative(resolve(cwd), resolve(cwd, file)).split(sep).join('/');
|
|
44
|
+
}
|
|
45
|
+
export function planHash(text) {
|
|
46
|
+
return createHash('sha256').update(text, 'utf-8').digest('hex');
|
|
47
|
+
}
|
|
40
48
|
function readState(cwd) {
|
|
41
49
|
try {
|
|
42
|
-
|
|
50
|
+
const parsed = JSON.parse(readFileSync(statePath(cwd), 'utf-8'));
|
|
51
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
43
52
|
}
|
|
44
53
|
catch {
|
|
45
54
|
return {};
|
|
46
55
|
}
|
|
47
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Plans the enforcer recorded as touched but which have not been validated
|
|
59
|
+
* since, plus plans that were validated and have since DRIFTED on disk.
|
|
60
|
+
* Anything listed here is what the build gate is waiting on.
|
|
61
|
+
*/
|
|
62
|
+
export function outstandingPlans(cwd) {
|
|
63
|
+
const st = readState(cwd);
|
|
64
|
+
const pending = Object.keys(st.pending ?? {}).sort();
|
|
65
|
+
const drifted = [];
|
|
66
|
+
for (const [key, hash] of Object.entries(st.validated ?? {})) {
|
|
67
|
+
let text;
|
|
68
|
+
try {
|
|
69
|
+
text = readFileSync(join(cwd, key), 'utf-8');
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
continue; // deleted or unreadable — nothing left to gate on
|
|
73
|
+
}
|
|
74
|
+
if (planHash(text) !== hash)
|
|
75
|
+
drifted.push(key);
|
|
76
|
+
}
|
|
77
|
+
return { pending, drifted: drifted.sort() };
|
|
78
|
+
}
|
|
48
79
|
/** Mirror of the enforcer's plan-artifact test (validate_plan_on_change.py). */
|
|
49
80
|
const PLAN_STEM_RE = /(^|[-_. ])plans?([-_. ]|$)/i;
|
|
50
81
|
function isPlanFile(name) {
|
|
@@ -213,7 +244,31 @@ export async function planCommand(action, options = {}, cwd = process.cwd(), dep
|
|
|
213
244
|
mkdirSync(dir, { recursive: true });
|
|
214
245
|
const prev = readState(cwd);
|
|
215
246
|
const now = Math.floor(Date.now() / 1000);
|
|
216
|
-
|
|
247
|
+
const pending = { ...(prev.pending ?? {}) };
|
|
248
|
+
const validated = { ...(prev.validated ?? {}) };
|
|
249
|
+
// Record the hash of what was ACTUALLY reviewed, and clear that plan from
|
|
250
|
+
// the pending set. Only the reviewed plan is cleared: validating one plan
|
|
251
|
+
// must not silently vouch for another the agent also touched.
|
|
252
|
+
// Which plan this validation vouches for. `review.file` is absent whenever
|
|
253
|
+
// the review did not resolve one — most importantly when the review was
|
|
254
|
+
// DISABLED (UAP_PLAN_REVIEW=0 / --no-review), which returns a bare
|
|
255
|
+
// {status:'skipped'}. Keying only off review.file meant `uap plan validate
|
|
256
|
+
// PLAN.md` reported success, recorded nothing, and left the build blocked
|
|
257
|
+
// on the very file the operator had just named. Fall back to the explicit
|
|
258
|
+
// argument, then to the artifact the review would have picked.
|
|
259
|
+
const stamped = review.file ?? explicitFile ?? findPlanArtifact(cwd) ?? undefined;
|
|
260
|
+
if (stamped) {
|
|
261
|
+
const key = planKey(cwd, stamped);
|
|
262
|
+
try {
|
|
263
|
+
validated[key] = planHash(readFileSync(resolve(cwd, stamped), 'utf-8'));
|
|
264
|
+
delete pending[key];
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// Unreadable at stamp time — leave it pending rather than record a
|
|
268
|
+
// hash we cannot stand behind.
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
writeFileSync(statePath(cwd), JSON.stringify({ ...prev, validated_at: now, review, pending, validated }, null, 2));
|
|
217
272
|
if (options.json) {
|
|
218
273
|
console.log(JSON.stringify({ ok: true, validated_at: now, review }));
|
|
219
274
|
return;
|
|
@@ -228,28 +283,47 @@ export async function planCommand(action, options = {}, cwd = process.cwd(), dep
|
|
|
228
283
|
else {
|
|
229
284
|
console.log(`✓ Plan validation recorded (review skipped: ${review.reason}).`);
|
|
230
285
|
}
|
|
231
|
-
|
|
286
|
+
const left = outstandingPlans(cwd);
|
|
287
|
+
const remaining = [...left.pending, ...left.drifted];
|
|
288
|
+
if (remaining.length) {
|
|
289
|
+
console.log(` Still awaiting validation before a build can run: ${remaining.join(', ')}`);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
console.log(' All touched plans are validated — builds are unblocked until a plan changes.');
|
|
293
|
+
}
|
|
232
294
|
return;
|
|
233
295
|
}
|
|
234
296
|
// status (default)
|
|
235
297
|
const st = readState(cwd);
|
|
236
298
|
const validatedAt = Number(st.validated_at) || 0;
|
|
237
299
|
const ageSec = validatedAt ? Math.floor(Date.now() / 1000) - validatedAt : null;
|
|
238
|
-
const
|
|
300
|
+
const { pending, drifted } = outstandingPlans(cwd);
|
|
301
|
+
// What the gate actually keys on now — not the age of the last stamp.
|
|
302
|
+
const blocked = pending.length > 0 || drifted.length > 0;
|
|
239
303
|
if (options.json) {
|
|
240
|
-
console.log(JSON.stringify({
|
|
304
|
+
console.log(JSON.stringify({
|
|
305
|
+
validated_at: validatedAt || null,
|
|
306
|
+
ageSec,
|
|
307
|
+
blocked,
|
|
308
|
+
pending,
|
|
309
|
+
drifted,
|
|
310
|
+
review: st.review ?? null,
|
|
311
|
+
}));
|
|
241
312
|
return;
|
|
242
313
|
}
|
|
243
|
-
if (!
|
|
244
|
-
console.log(
|
|
314
|
+
if (!blocked) {
|
|
315
|
+
console.log(validatedAt
|
|
316
|
+
? `Plan validation: OK — no plan is awaiting validation (last validated ${ageSec}s ago).`
|
|
317
|
+
: 'Plan validation: nothing pending. Creating or editing a plan will require `validate the plan` before a build.');
|
|
318
|
+
if (st.review?.status) {
|
|
319
|
+
console.log(` Last review: ${st.review.status}${st.review.file ? ` (${st.review.file})` : ''}`);
|
|
320
|
+
}
|
|
245
321
|
return;
|
|
246
322
|
}
|
|
247
|
-
console.log(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (!fresh)
|
|
252
|
-
console.log(' Re-run the `validate the plan` prompt, then `uap plan validate`, before editing a plan.');
|
|
323
|
+
console.log('Plan validation: BLOCKING — a build cannot run until these are validated:');
|
|
324
|
+
pending.forEach((p) => console.log(` • ${p} (created/modified, never validated)`));
|
|
325
|
+
drifted.forEach((p) => console.log(` • ${p} (changed since it was validated)`));
|
|
326
|
+
console.log(' Run the `validate the plan` prompt, then `uap plan validate <file>`.');
|
|
253
327
|
}
|
|
254
328
|
export { statePath as planStatePath, windowSec as planWindowSec };
|
|
255
329
|
//# sourceMappingURL=plan.js.map
|
package/dist/cli/plan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/cli/plan.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/cli/plan.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miller-tech/uap",
|
|
3
|
-
"version": "1.175.
|
|
3
|
+
"version": "1.175.13",
|
|
4
4
|
"description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"start": "node dist/bin/cli.js",
|
|
22
22
|
"test": "vitest",
|
|
23
23
|
"test:ci": "vitest run",
|
|
24
|
-
"test:enforcers": "python3 -m unittest tools.agents.tests.test_enforcement_self_protect tools.agents.tests.test_schema_diff_gate tools.agents.tests.test_stream_telemetry tools.agents.tests.test_project_telemetry_events tools.agents.tests.test_workdir_scope_enforcer tools.agents.tests.test_path_containment tools.agents.tests.test_path_normalizer_hardened tools.agents.tests.test_sandbox_tool_strip tools.agents.tests.test_proxy_env_loader tools.agents.tests.test_stream_required_tool tools.agents.tests.test_tool_call_wrapper_profiles tools.agents.tests.test_tool_convert_cache tools.agents.tests.test_doubling_break tools.agents.tests.test_error_loop_ignores_correctives tools.agents.tests.test_attractor_detection tools.agents.tests.test_client_disconnect tools.agents.tests.test_confidence_escalation tools.agents.tests.test_coordination_ban tools.agents.tests.test_coordination_early_ban tools.agents.tests.test_cycle_break_exploration tools.agents.tests.test_deferral_break tools.agents.tests.test_deliver_autoroute tools.agents.tests.test_delivery_enforcement_all_langs tools.agents.tests.test_delivery_enforcement_exemptions tools.agents.tests.test_delivery_enforcement_filepath tools.agents.tests.test_delivery_enforcement_web_and_bash tools.agents.tests.test_disconnect_watcher tools.agents.tests.test_empty_maxtokens_recovery tools.agents.tests.test_empty_tool_loop_break tools.agents.tests.test_enforcer_escape_hatches tools.agents.tests.test_error_loop_break tools.agents.tests.test_finalize_suppression tools.agents.tests.test_malformed_unclosed_think tools.agents.tests.test_mandate_beats_recon tools.agents.tests.test_mandate_deliver tools.agents.tests.test_overflow_truncate_count_tokens tools.agents.tests.test_passthrough_oauth tools.agents.tests.test_project_telemetry tools.agents.tests.test_proxy_auth_headers tools.agents.tests.test_prune_preserve_force_write tools.agents.tests.test_recon_deliver_gate tools.agents.tests.test_session_admission tools.agents.tests.test_stream_heartbeat tools.agents.tests.test_stuck_break_reattach tools.agents.tests.test_turn_count_breaker_periodic tools.agents.tests.test_upstream_chokepoint tools.agents.tests.test_vision_passthrough tools.agents.tests.test_worktree_required tools.agents.tests.test_enforcer_suite_coverage",
|
|
24
|
+
"test:enforcers": "python3 -m unittest tools.agents.tests.test_enforcement_self_protect tools.agents.tests.test_schema_diff_gate tools.agents.tests.test_stream_telemetry tools.agents.tests.test_project_telemetry_events tools.agents.tests.test_workdir_scope_enforcer tools.agents.tests.test_path_containment tools.agents.tests.test_path_normalizer_hardened tools.agents.tests.test_sandbox_tool_strip tools.agents.tests.test_proxy_env_loader tools.agents.tests.test_stream_required_tool tools.agents.tests.test_tool_call_wrapper_profiles tools.agents.tests.test_tool_convert_cache tools.agents.tests.test_doubling_break tools.agents.tests.test_error_loop_ignores_correctives tools.agents.tests.test_attractor_detection tools.agents.tests.test_client_disconnect tools.agents.tests.test_confidence_escalation tools.agents.tests.test_coordination_ban tools.agents.tests.test_coordination_early_ban tools.agents.tests.test_cycle_break_exploration tools.agents.tests.test_deferral_break tools.agents.tests.test_deliver_autoroute tools.agents.tests.test_delivery_enforcement_all_langs tools.agents.tests.test_delivery_enforcement_exemptions tools.agents.tests.test_delivery_enforcement_filepath tools.agents.tests.test_delivery_enforcement_web_and_bash tools.agents.tests.test_disconnect_watcher tools.agents.tests.test_empty_maxtokens_recovery tools.agents.tests.test_empty_tool_loop_break tools.agents.tests.test_enforcer_escape_hatches tools.agents.tests.test_error_loop_break tools.agents.tests.test_finalize_suppression tools.agents.tests.test_malformed_unclosed_think tools.agents.tests.test_mandate_beats_recon tools.agents.tests.test_mandate_deliver tools.agents.tests.test_overflow_truncate_count_tokens tools.agents.tests.test_passthrough_oauth tools.agents.tests.test_project_telemetry tools.agents.tests.test_proxy_auth_headers tools.agents.tests.test_prune_preserve_force_write tools.agents.tests.test_recon_deliver_gate tools.agents.tests.test_session_admission tools.agents.tests.test_stream_heartbeat tools.agents.tests.test_stuck_break_reattach tools.agents.tests.test_turn_count_breaker_periodic tools.agents.tests.test_upstream_chokepoint tools.agents.tests.test_vision_passthrough tools.agents.tests.test_worktree_required tools.agents.tests.test_enforcer_suite_coverage tools.agents.tests.test_validate_plan_gate",
|
|
25
25
|
"test:coverage": "vitest --coverage",
|
|
26
26
|
"bench": "vitest --config vitest.bench.config.ts",
|
|
27
27
|
"lint": "eslint src --ext .ts",
|
|
Binary file
|
|
@@ -1,41 +1,104 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""validate-plan-on-change
|
|
3
|
-
modifying it.
|
|
2
|
+
"""validate-plan-on-change: the plan gate fires BEFORE a build, not on the write.
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
The old rule blocked a Write/Edit to a plan artifact unless `uap plan validate`
|
|
5
|
+
had run in the last 300 seconds. That asked the agent to validate a plan that did
|
|
6
|
+
not exist yet: the review found no artifact (or an older one), recorded itself as
|
|
7
|
+
"skipped", stamped anyway, and for the next five minutes any plan content went in
|
|
8
|
+
unread — while nothing gated the build at all. The plan that actually got
|
|
9
|
+
implemented was never reviewed.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
`uap plan validate`, so a burst of edits in one planning session shares a single
|
|
13
|
-
validation, but a plan touched after a gap re-validates.
|
|
11
|
+
So the gate moved to where it belongs:
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
- creating or editing a plan is ALLOWED, and records the plan as pending
|
|
14
|
+
- a BUILD / EXECUTE / DEPLOY command is BLOCKED while any plan is pending, or
|
|
15
|
+
while a plan that WAS validated has since drifted on disk
|
|
16
|
+
- the refusal carries the `validate the plan` self-prompt
|
|
17
|
+
|
|
18
|
+
State lives in `.uap/plan_state.json` (honouring UAP_STATE_DIR) and is shared
|
|
19
|
+
with `uap plan validate` in src/cli/plan.ts:
|
|
20
|
+
|
|
21
|
+
pending { "<repo-relative path>": <epoch seen> }
|
|
22
|
+
validated { "<repo-relative path>": "<sha256 of the reviewed bytes>" }
|
|
23
|
+
|
|
24
|
+
Keying on CONTENT rather than a clock is the point: "these exact bytes were
|
|
25
|
+
reviewed" cannot be satisfied by validating an empty file and then writing the
|
|
26
|
+
real plan, which is precisely how the old window was defeated.
|
|
27
|
+
|
|
28
|
+
Escape hatch (justify in the plan/PR): UAP_PLAN_VALIDATE_OFF=1.
|
|
17
29
|
"""
|
|
18
30
|
from __future__ import annotations
|
|
19
31
|
|
|
32
|
+
import hashlib
|
|
20
33
|
import json
|
|
21
34
|
import os
|
|
22
35
|
import re
|
|
36
|
+
import sys
|
|
23
37
|
import time
|
|
24
38
|
from pathlib import Path
|
|
25
|
-
import sys
|
|
26
39
|
|
|
27
40
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
28
|
-
from _common import emit, parse_cli # noqa: E402
|
|
41
|
+
from _common import emit, parse_cli, scannable_command # noqa: E402
|
|
29
42
|
|
|
30
43
|
EDIT_OPS = {"Write", "Edit", "MultiEdit", "write", "edit", "multiedit"}
|
|
31
|
-
|
|
32
|
-
DEFAULT_WINDOW = 300
|
|
44
|
+
BASH_OPS = {"Bash", "bash", "run_bash", "shell"}
|
|
33
45
|
|
|
34
46
|
# A plan-like filename STEM (the part before `.md`): `plan`, `foo-plan`, `plan-v2`,
|
|
35
|
-
# `implementation_plan`, `foo.plan`. Deliberately does NOT match `planning`,
|
|
36
|
-
# (plural handled by the plans/ dir rule), or `explanation`.
|
|
47
|
+
# `implementation_plan`, `foo.plan`. Deliberately does NOT match `planning`,
|
|
48
|
+
# `plans` (plural handled by the plans/ dir rule), or `explanation`.
|
|
37
49
|
PLAN_STEM_RE = re.compile(r"(^|[-_. ])plans?([-_. ]|$)", re.IGNORECASE)
|
|
38
50
|
|
|
51
|
+
# Commands that IMPLEMENT the plan. Matched anywhere in the command, not just at
|
|
52
|
+
# the start: `cd sub && npm run build` is a build, and a gate that only checks
|
|
53
|
+
# the prefix is avoidable by prepending anything at all.
|
|
54
|
+
#
|
|
55
|
+
# Word boundaries keep `make` from matching `cmake` or `makefile`. Everything
|
|
56
|
+
# NOT listed here is allowed — there is no second allowlist to keep in sync, and
|
|
57
|
+
# tests/linters/reads therefore stay free by construction. That matters: you
|
|
58
|
+
# cannot review a plan if you cannot inspect the tree or run its tests.
|
|
59
|
+
BUILD_RE = re.compile(
|
|
60
|
+
r"\b("
|
|
61
|
+
r"uap\s+deliver"
|
|
62
|
+
r"|npm\s+run\s+build|npm\s+start"
|
|
63
|
+
r"|(?:yarn|pnpm)\s+(?:run\s+)?build"
|
|
64
|
+
r"|make"
|
|
65
|
+
r"|cargo\s+(?:build|run)"
|
|
66
|
+
r"|go\s+(?:build|run)"
|
|
67
|
+
r"|mvn\s+(?:package|install)"
|
|
68
|
+
r"|gradle\s+build"
|
|
69
|
+
r"|docker\s+build"
|
|
70
|
+
r"|docker[\s-]compose\s+up"
|
|
71
|
+
r"|terraform\s+apply"
|
|
72
|
+
r"|kubectl\s+apply"
|
|
73
|
+
r"|helm\s+(?:install|upgrade)"
|
|
74
|
+
r")\b",
|
|
75
|
+
re.IGNORECASE,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _state_path() -> Path:
|
|
80
|
+
"""`.uap/plan_state.json`, honouring UAP_STATE_DIR (absolute or relative)."""
|
|
81
|
+
return Path(os.environ.get("UAP_STATE_DIR", ".uap")) / "plan_state.json"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _load_state() -> dict:
|
|
85
|
+
try:
|
|
86
|
+
data = json.loads(_state_path().read_text())
|
|
87
|
+
return data if isinstance(data, dict) else {}
|
|
88
|
+
except Exception: # noqa: BLE001 - unreadable state must not break the tool call
|
|
89
|
+
return {}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _save_state(state: dict) -> None:
|
|
93
|
+
"""Best-effort persist. A gate that crashes on an unwritable dir is worse
|
|
94
|
+
than one that forgets — the write it was recording still happened."""
|
|
95
|
+
try:
|
|
96
|
+
path = _state_path()
|
|
97
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
path.write_text(json.dumps(state, indent=2))
|
|
99
|
+
except Exception: # noqa: BLE001
|
|
100
|
+
pass
|
|
101
|
+
|
|
39
102
|
|
|
40
103
|
def _target(args: dict) -> str:
|
|
41
104
|
for k in ("file_path", "path", "notebook_path", "filePath", "target"):
|
|
@@ -48,57 +111,89 @@ def _is_plan_file(target: str) -> bool:
|
|
|
48
111
|
if not target:
|
|
49
112
|
return False
|
|
50
113
|
posix = target.replace(os.sep, "/")
|
|
51
|
-
#
|
|
52
|
-
if re.search(r"(^|/)plans?/", posix, re.IGNORECASE):
|
|
114
|
+
if re.search(r"(^|/)plans?/", posix, re.IGNORECASE): # any file under plans/
|
|
53
115
|
return True
|
|
54
116
|
name = posix.rsplit("/", 1)[-1]
|
|
55
117
|
if not name.lower().endswith(".md"):
|
|
56
118
|
return False
|
|
57
|
-
|
|
58
|
-
return bool(PLAN_STEM_RE.search(stem))
|
|
119
|
+
return bool(PLAN_STEM_RE.search(name[:-3]))
|
|
59
120
|
|
|
60
121
|
|
|
61
|
-
def
|
|
122
|
+
def _key(target: str) -> str:
|
|
123
|
+
"""Repo-relative, forward-slashed — the shape `uap plan validate` records."""
|
|
124
|
+
posix = target.replace(os.sep, "/")
|
|
62
125
|
try:
|
|
63
|
-
|
|
126
|
+
rel = os.path.relpath(posix, os.getcwd())
|
|
127
|
+
if not rel.startswith(".."):
|
|
128
|
+
posix = rel.replace(os.sep, "/")
|
|
64
129
|
except Exception: # noqa: BLE001
|
|
65
|
-
|
|
130
|
+
pass
|
|
131
|
+
return posix.lstrip("./") if posix.startswith("./") else posix
|
|
66
132
|
|
|
67
133
|
|
|
68
|
-
def
|
|
69
|
-
op, args = parse_cli()
|
|
70
|
-
if os.environ.get("UAP_PLAN_VALIDATE_OFF") == "1":
|
|
71
|
-
emit(True, "UAP_PLAN_VALIDATE_OFF override set")
|
|
72
|
-
if op not in EDIT_OPS:
|
|
73
|
-
emit(True, "not a file-write operation")
|
|
74
|
-
|
|
75
|
-
target = _target(args)
|
|
76
|
-
if not _is_plan_file(target):
|
|
77
|
-
emit(True, "not a plan artifact")
|
|
78
|
-
|
|
134
|
+
def _sha(path: str) -> str | None:
|
|
79
135
|
try:
|
|
80
|
-
|
|
81
|
-
except
|
|
82
|
-
|
|
136
|
+
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
|
|
137
|
+
except Exception: # noqa: BLE001
|
|
138
|
+
return None
|
|
83
139
|
|
|
84
|
-
age = time.time() - _validated_at()
|
|
85
|
-
if age <= window:
|
|
86
|
-
emit(True, f"plan validated {int(age)}s ago (within {window}s)")
|
|
87
140
|
|
|
141
|
+
def _refuse(paths: list[str], why: str) -> None:
|
|
142
|
+
listed = ", ".join(sorted(paths))
|
|
88
143
|
emit(
|
|
89
144
|
False,
|
|
90
|
-
"validate-plan-on-change:
|
|
91
|
-
|
|
92
|
-
"creating or modifying it.\n"
|
|
145
|
+
f"validate-plan-on-change: {why} ({listed}). A plan must be validated "
|
|
146
|
+
"before the work it describes is built.\n"
|
|
93
147
|
" 1. Run the prompt `validate the plan` — review assumptions, gaps, "
|
|
94
148
|
"risks, and whether it still matches the request.\n"
|
|
95
|
-
" 2. Record it: `uap plan validate`.\n"
|
|
96
|
-
" 3. Retry this
|
|
97
|
-
"(
|
|
98
|
-
f"{window}s; override with UAP_PLAN_VALIDATE_OFF=1.)",
|
|
149
|
+
f" 2. Record it: `uap plan validate {sorted(paths)[0]}`.\n"
|
|
150
|
+
" 3. Retry this command.\n"
|
|
151
|
+
"(Escape hatch, justify in the plan/PR: UAP_PLAN_VALIDATE_OFF=1.)",
|
|
99
152
|
inject_prompt="validate the plan",
|
|
100
153
|
)
|
|
101
154
|
|
|
102
155
|
|
|
156
|
+
def main() -> None:
|
|
157
|
+
op, args = parse_cli()
|
|
158
|
+
if os.environ.get("UAP_PLAN_VALIDATE_OFF") == "1":
|
|
159
|
+
emit(True, "UAP_PLAN_VALIDATE_OFF override set")
|
|
160
|
+
|
|
161
|
+
# A plan write is never blocked — it is RECORDED. Blocking here is what made
|
|
162
|
+
# the old gate ask for validation of a file that did not exist.
|
|
163
|
+
if op in EDIT_OPS:
|
|
164
|
+
target = _target(args)
|
|
165
|
+
if not _is_plan_file(target):
|
|
166
|
+
emit(True, "not a plan artifact")
|
|
167
|
+
state = _load_state()
|
|
168
|
+
pending = state.get("pending") or {}
|
|
169
|
+
pending[_key(target)] = int(time.time())
|
|
170
|
+
state["pending"] = pending
|
|
171
|
+
_save_state(state)
|
|
172
|
+
emit(True, f"plan write recorded — validation required before a build ({_key(target)})")
|
|
173
|
+
|
|
174
|
+
if op not in BASH_OPS:
|
|
175
|
+
emit(True, "not a gated operation")
|
|
176
|
+
|
|
177
|
+
command = str(args.get("command") or args.get("cmd") or "")
|
|
178
|
+
# scannable_command strips heredoc bodies and quoted payloads, so a build
|
|
179
|
+
# phrase inside DATA (`echo 'npm run build'`) is not a build.
|
|
180
|
+
if not BUILD_RE.search(scannable_command(command)):
|
|
181
|
+
emit(True, "not a build/execute/deploy command")
|
|
182
|
+
|
|
183
|
+
state = _load_state()
|
|
184
|
+
pending = list((state.get("pending") or {}).keys())
|
|
185
|
+
if pending:
|
|
186
|
+
_refuse(pending, "these plans were created or modified and never validated")
|
|
187
|
+
|
|
188
|
+
drifted = [
|
|
189
|
+
key for key, recorded in (state.get("validated") or {}).items()
|
|
190
|
+
if (_sha(key) is not None and _sha(key) != recorded)
|
|
191
|
+
]
|
|
192
|
+
if drifted:
|
|
193
|
+
_refuse(drifted, "these plans changed after they were validated")
|
|
194
|
+
|
|
195
|
+
emit(True, "no plan is awaiting validation")
|
|
196
|
+
|
|
197
|
+
|
|
103
198
|
if __name__ == "__main__":
|
|
104
199
|
main()
|
|
@@ -7,34 +7,72 @@
|
|
|
7
7
|
|
|
8
8
|
## Rule
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
`implementation-plan.md`, `*.plan.md`). `planning.md`, `explanation.md`, and
|
|
14
|
-
plural-but-unrelated names are NOT plan artifacts.
|
|
10
|
+
Creating or modifying a **plan artifact** is ALLOWED, and records that plan as
|
|
11
|
+
awaiting validation. A **build, execute or deploy** command is then BLOCKED
|
|
12
|
+
until the plan has been validated.
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
A plan artifact is any file under a `plans/` directory, or a file with a
|
|
15
|
+
plan-like name (`PLAN.md`, `*-plan.md`, `plan-*.md`, `implementation-plan.md`,
|
|
16
|
+
`*.plan.md`). `planning.md`, `explanation.md`, and plural-but-unrelated names
|
|
17
|
+
are NOT plan artifacts.
|
|
18
|
+
|
|
19
|
+
On a blocked build the agent MUST:
|
|
17
20
|
|
|
18
21
|
1. Run the prompt `validate the plan` — review assumptions, gaps, risks, and
|
|
19
22
|
whether the plan still matches the request.
|
|
20
|
-
2. Record the validation: `uap plan validate
|
|
21
|
-
3. Retry the
|
|
23
|
+
2. Record the validation: `uap plan validate <file>`.
|
|
24
|
+
3. Retry the command.
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
a plan
|
|
26
|
+
Validation is recorded against the **content hash** of the plan that was
|
|
27
|
+
reviewed. Editing that plan afterwards re-arms the gate. Reads, tests, linters
|
|
28
|
+
and type-checks are never gated — you cannot review a plan if you cannot inspect
|
|
29
|
+
the tree or run its tests.
|
|
26
30
|
|
|
27
31
|
## Why
|
|
28
32
|
|
|
29
|
-
User directive: "
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
User directive: "once a plan is created the LLM is prompted to `validate the
|
|
34
|
+
plan` before execution/build."
|
|
35
|
+
|
|
36
|
+
The gate used to fire on the plan WRITE, keyed to a 300-second window. That
|
|
37
|
+
asked the agent to validate a plan before it existed: `uap plan validate` found
|
|
38
|
+
no artifact (or an older one), recorded the review as "skipped", stamped anyway,
|
|
39
|
+
and for the next five minutes any plan content could be written unread — while
|
|
40
|
+
nothing gated the build at all. The plan that actually got implemented was never
|
|
41
|
+
reviewed.
|
|
42
|
+
|
|
43
|
+
Moving the gate to the build fixes both halves. There is now something real to
|
|
44
|
+
review when the prompt fires, and the thing being gated is the work itself.
|
|
45
|
+
Keying on content rather than a clock closes the remaining hole: "these exact
|
|
46
|
+
bytes were reviewed" cannot be satisfied by validating an empty file first.
|
|
47
|
+
|
|
48
|
+
(Supersedes the older `validate-plan-before-build`, which never fired because
|
|
49
|
+
nothing set its `plan_ready` marker.)
|
|
35
50
|
|
|
36
51
|
## Enforcement
|
|
37
52
|
|
|
38
|
-
Python enforcer `validate_plan_on_change.py
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
Python enforcer `validate_plan_on_change.py`, exiting 2 on a refusal with
|
|
54
|
+
`inject_prompt: "validate the plan"`.
|
|
55
|
+
|
|
56
|
+
State in `.uap/plan_state.json` (honours `UAP_STATE_DIR`), shared with
|
|
57
|
+
`uap plan validate`:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"pending": { "<repo-relative path>": "<epoch seen>" },
|
|
62
|
+
"validated": { "<repo-relative path>": "<sha256 of the reviewed bytes>" }
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Gated commands: `uap deliver`, `npm run build`, `npm start`, `yarn`/`pnpm build`,
|
|
67
|
+
`make`, `cargo build|run`, `go build|run`, `mvn package|install`,
|
|
68
|
+
`gradle build`, `docker build`, `docker compose up`, `terraform apply`,
|
|
69
|
+
`kubectl apply`, `helm install|upgrade` — matched anywhere in the command, so
|
|
70
|
+
`cd sub && npm run build` is gated, and matched against the command with quoted
|
|
71
|
+
data and heredoc bodies stripped, so `echo 'npm run build'` is not.
|
|
72
|
+
|
|
73
|
+
Everything not listed is allowed; there is no second allowlist to keep in sync.
|
|
74
|
+
|
|
75
|
+
Escape hatch, justify in the plan/PR: `UAP_PLAN_VALIDATE_OFF=1`.
|
|
76
|
+
|
|
77
|
+
`uap plan status` reports exactly what the gate is waiting on (pending plans and
|
|
78
|
+
plans that have drifted since validation).
|
|
Binary file
|