@miller-tech/uap 1.170.1 → 1.172.0
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/bin/cli.js +26 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/browser/web-browser.d.ts +17 -0
- package/dist/browser/web-browser.d.ts.map +1 -1
- package/dist/browser/web-browser.js +36 -0
- package/dist/browser/web-browser.js.map +1 -1
- package/dist/cli/interaction.d.ts +29 -0
- package/dist/cli/interaction.d.ts.map +1 -0
- package/dist/cli/interaction.js +217 -0
- package/dist/cli/interaction.js.map +1 -0
- package/dist/cli/verify.d.ts +6 -0
- package/dist/cli/verify.d.ts.map +1 -1
- package/dist/cli/verify.js +112 -7
- package/dist/cli/verify.js.map +1 -1
- package/dist/delivery/fidelity.d.ts +16 -0
- package/dist/delivery/fidelity.d.ts.map +1 -1
- package/dist/delivery/fidelity.js +7 -0
- package/dist/delivery/fidelity.js.map +1 -1
- package/dist/delivery/interaction/driver.d.ts +60 -0
- package/dist/delivery/interaction/driver.d.ts.map +1 -0
- package/dist/delivery/interaction/driver.js +18 -0
- package/dist/delivery/interaction/driver.js.map +1 -0
- package/dist/delivery/interaction/manifest.d.ts +84 -0
- package/dist/delivery/interaction/manifest.d.ts.map +1 -0
- package/dist/delivery/interaction/manifest.js +241 -0
- package/dist/delivery/interaction/manifest.js.map +1 -0
- package/dist/delivery/interaction/mine.d.ts +54 -0
- package/dist/delivery/interaction/mine.d.ts.map +1 -0
- package/dist/delivery/interaction/mine.js +218 -0
- package/dist/delivery/interaction/mine.js.map +1 -0
- package/dist/delivery/interaction/runner.d.ts +51 -0
- package/dist/delivery/interaction/runner.d.ts.map +1 -0
- package/dist/delivery/interaction/runner.js +277 -0
- package/dist/delivery/interaction/runner.js.map +1 -0
- package/dist/delivery/interaction/types.d.ts +223 -0
- package/dist/delivery/interaction/types.d.ts.map +1 -0
- package/dist/delivery/interaction/types.js +19 -0
- package/dist/delivery/interaction/types.js.map +1 -0
- package/dist/delivery/interaction/verdict.d.ts +26 -0
- package/dist/delivery/interaction/verdict.d.ts.map +1 -0
- package/dist/delivery/interaction/verdict.js +139 -0
- package/dist/delivery/interaction/verdict.js.map +1 -0
- package/dist/delivery/interaction/watchdog.d.ts +82 -0
- package/dist/delivery/interaction/watchdog.d.ts.map +1 -0
- package/dist/delivery/interaction/watchdog.js +210 -0
- package/dist/delivery/interaction/watchdog.js.map +1 -0
- package/dist/delivery/interaction/web-driver.d.ts +102 -0
- package/dist/delivery/interaction/web-driver.d.ts.map +1 -0
- package/dist/delivery/interaction/web-driver.js +306 -0
- package/dist/delivery/interaction/web-driver.js.map +1 -0
- package/dist/delivery/interaction-gate.d.ts +45 -0
- package/dist/delivery/interaction-gate.d.ts.map +1 -0
- package/dist/delivery/interaction-gate.js +248 -0
- package/dist/delivery/interaction-gate.js.map +1 -0
- package/dist/delivery/mission-acceptance.d.ts +2 -0
- package/dist/delivery/mission-acceptance.d.ts.map +1 -1
- package/dist/delivery/mission-acceptance.js +23 -0
- package/dist/delivery/mission-acceptance.js.map +1 -1
- package/dist/delivery/vision-judge.d.ts +21 -0
- package/dist/delivery/vision-judge.d.ts.map +1 -1
- package/dist/delivery/vision-judge.js +96 -0
- package/dist/delivery/vision-judge.js.map +1 -1
- package/dist/types/config.d.ts +20 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +7 -0
- package/dist/types/config.js.map +1 -1
- package/package.json +1 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Driver abstraction — the seam that keeps the interaction gate universal.
|
|
3
|
+
*
|
|
4
|
+
* A probe says "drive this input, then assert this observable". That sentence is
|
|
5
|
+
* identical for a canvas game, a CLI and an HTTP API; only the verbs differ. So
|
|
6
|
+
* the manifest format is shared and each artifact kind supplies a driver:
|
|
7
|
+
*
|
|
8
|
+
* web → pointer/keys into a real headless browser, `read` evaluates in-page
|
|
9
|
+
* cli → keystrokes into a pty, `read` inspects the transcript/exit state
|
|
10
|
+
* http → requests, `read` inspects the last response
|
|
11
|
+
*
|
|
12
|
+
* Keeping `read(expr)` opaque is what makes assertions read the artifact's OWN
|
|
13
|
+
* runtime state instead of guessing from pixels or stdout scraping.
|
|
14
|
+
*/
|
|
15
|
+
import type { Step } from './types.js';
|
|
16
|
+
/** Outcome of one observation: did the expression resolve, and to what. */
|
|
17
|
+
export interface ReadResult {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
value?: unknown;
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface InteractionDriver {
|
|
23
|
+
/** Launch and reach the artifact's initial state. */
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Return the artifact to its initial state before the next probe.
|
|
27
|
+
*
|
|
28
|
+
* Without this every probe inherits the previous probe's state, so results
|
|
29
|
+
* are order-dependent and a later probe reports failures caused by an
|
|
30
|
+
* earlier one — e.g. 'colliding costs health' failing because a previous
|
|
31
|
+
* probe already ended the game. Optional: a driver that cannot reset simply
|
|
32
|
+
* runs probes in sequence, which is the old behaviour.
|
|
33
|
+
*/
|
|
34
|
+
reset?(): Promise<void>;
|
|
35
|
+
/** Execute one input step. Unknown step kinds must be ignored, not thrown. */
|
|
36
|
+
runStep(step: Step): Promise<void>;
|
|
37
|
+
/** Evaluate an observation expression in the artifact's own context. */
|
|
38
|
+
read(expr: string): Promise<unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* Evaluate an observation and say whether it RESOLVED. A probe naming
|
|
41
|
+
* something the artifact does not expose is a broken probe, and reporting it
|
|
42
|
+
* as a failing behaviour makes the agent "fix" working code.
|
|
43
|
+
*/
|
|
44
|
+
readDetailed?(expr: string): Promise<ReadResult>;
|
|
45
|
+
/** Mutate artifact state (accelerated probes only — the runner enforces this). */
|
|
46
|
+
inject(expr: string): Promise<void>;
|
|
47
|
+
/** Runtime errors observed so far (uncaught throws, console errors, 404s). */
|
|
48
|
+
errors(): string[];
|
|
49
|
+
/**
|
|
50
|
+
* Read one watchdog sample. Owned by the DRIVER because the instrumentation
|
|
51
|
+
* global is named per-run — the caller cannot know the name, which is the
|
|
52
|
+
* point: a page that can guess it can forge its own liveness counters.
|
|
53
|
+
*/
|
|
54
|
+
watchdogSample?(watchExprs: string[]): Promise<unknown>;
|
|
55
|
+
/** Best-effort screenshot/transcript capture for the evidence trail. */
|
|
56
|
+
capture?(path: string): Promise<void>;
|
|
57
|
+
stop(): Promise<void>;
|
|
58
|
+
}
|
|
59
|
+
export declare function delay(ms: number): Promise<void>;
|
|
60
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../../src/delivery/interaction/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,2EAA2E;AAC3E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,8EAA8E;IAC9E,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,wEAAwE;IACxE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC;;;;OAIG;IACH,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACjD,kFAAkF;IAClF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,8EAA8E;IAC9E,MAAM,IAAI,MAAM,EAAE,CAAC;IACnB;;;;OAIG;IACH,cAAc,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,wEAAwE;IACxE,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Driver abstraction — the seam that keeps the interaction gate universal.
|
|
3
|
+
*
|
|
4
|
+
* A probe says "drive this input, then assert this observable". That sentence is
|
|
5
|
+
* identical for a canvas game, a CLI and an HTTP API; only the verbs differ. So
|
|
6
|
+
* the manifest format is shared and each artifact kind supplies a driver:
|
|
7
|
+
*
|
|
8
|
+
* web → pointer/keys into a real headless browser, `read` evaluates in-page
|
|
9
|
+
* cli → keystrokes into a pty, `read` inspects the transcript/exit state
|
|
10
|
+
* http → requests, `read` inspects the last response
|
|
11
|
+
*
|
|
12
|
+
* Keeping `read(expr)` opaque is what makes assertions read the artifact's OWN
|
|
13
|
+
* runtime state instead of guessing from pixels or stdout scraping.
|
|
14
|
+
*/
|
|
15
|
+
export function delay(ms) {
|
|
16
|
+
return new Promise((r) => setTimeout(r, Math.max(0, ms)));
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/delivery/interaction/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAiDH,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction manifest — persistence, validation and the coverage ledger.
|
|
3
|
+
*
|
|
4
|
+
* The manifest lives OUTSIDE the deliverable (`.uap/interaction/manifest.json`)
|
|
5
|
+
* for the same reason a test suite is not shipped inside the thing it tests: an
|
|
6
|
+
* agent that can edit its own acceptance criteria will eventually edit them
|
|
7
|
+
* instead of fixing the defect. `.uap/interaction/` is added to the self-protect
|
|
8
|
+
* enforcer's deny list so a delivering agent cannot rewrite its own probes.
|
|
9
|
+
*/
|
|
10
|
+
import type { CoverageLedger, InteractionManifest, Probe, Step } from './types.js';
|
|
11
|
+
export declare const MANIFEST_DIR: string;
|
|
12
|
+
export declare const MANIFEST_FILE = "manifest.json";
|
|
13
|
+
/** Probe ids become evidence filenames — no separators, no traversal. */
|
|
14
|
+
export declare const PROBE_ID_RE: RegExp;
|
|
15
|
+
/** Hard ceiling on nested `repeat` so validation cannot be blown up by depth. */
|
|
16
|
+
export declare const MAX_STEP_DEPTH = 6;
|
|
17
|
+
/**
|
|
18
|
+
* Reject observation expressions that can MUTATE the artifact.
|
|
19
|
+
*
|
|
20
|
+
* The `inject`-only-in-accelerated rule is worthless on its own, because a JS
|
|
21
|
+
* *expression* can assign: `{expect:'gte', expr:'(kills = 5)', value:5}` writes
|
|
22
|
+
* the state it then grades, passes validation as a `core` probe, and proves
|
|
23
|
+
* exactly nothing. The rule has to cover every string that reaches an
|
|
24
|
+
* evaluation slot — assertions, `eval` steps and watch expressions alike.
|
|
25
|
+
*
|
|
26
|
+
* Honest about its limits: this is syntactic, and no string inspection can
|
|
27
|
+
* *prove* a JS expression is side-effect-free (a getter or a called function can
|
|
28
|
+
* mutate). It raises the cost of the obvious bypass; the observation-level
|
|
29
|
+
* invariant (watched values must not change across a read) is what catches the
|
|
30
|
+
* rest, and the manifest's write-protection is what makes both meaningful.
|
|
31
|
+
*/
|
|
32
|
+
export declare function expressionMutates(expr: string): string | null;
|
|
33
|
+
/** True when `text` has a comma outside every (), [] and {} and outside strings. */
|
|
34
|
+
export declare function hasTopLevelComma(text: string): boolean;
|
|
35
|
+
export declare function manifestPath(projectRoot: string): string;
|
|
36
|
+
/** Stable short hash of the requirements text a manifest was mined from. */
|
|
37
|
+
export declare function hashSpec(text: string): string;
|
|
38
|
+
/** Walk nested `repeat` blocks so validation cannot be bypassed by nesting. */
|
|
39
|
+
export declare function flattenSteps(steps: Step[], depth?: number): Step[];
|
|
40
|
+
/**
|
|
41
|
+
* Structural validation + the anti-cheat invariants. Returns the problems found;
|
|
42
|
+
* empty means valid.
|
|
43
|
+
*
|
|
44
|
+
* The load-bearing rule is the `inject` restriction: a probe that writes
|
|
45
|
+
* `score = 100` and then asserts `score >= 100` proves nothing at all. State
|
|
46
|
+
* injection is therefore legal ONLY in `accelerated` probes, whose results are
|
|
47
|
+
* reported separately and never counted as evidence of natural progression.
|
|
48
|
+
*/
|
|
49
|
+
export declare function validateManifest(m: unknown): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Load result that distinguishes ABSENT from INVALID.
|
|
52
|
+
*
|
|
53
|
+
* Collapsing the two is how a tampered manifest reads as a fresh project: the
|
|
54
|
+
* gate says "no manifest — run `uap interaction mine`", the operator re-mines,
|
|
55
|
+
* and the tamper is laundered into a clean skip.
|
|
56
|
+
*/
|
|
57
|
+
export type ManifestLoad = {
|
|
58
|
+
status: 'ok';
|
|
59
|
+
manifest: InteractionManifest;
|
|
60
|
+
} | {
|
|
61
|
+
status: 'absent';
|
|
62
|
+
} | {
|
|
63
|
+
status: 'invalid';
|
|
64
|
+
problems: string[];
|
|
65
|
+
};
|
|
66
|
+
export declare function loadManifestDetailed(projectRoot: string): ManifestLoad;
|
|
67
|
+
export declare function loadManifest(projectRoot: string): InteractionManifest | null;
|
|
68
|
+
export declare function saveManifest(projectRoot: string, manifest: InteractionManifest): string;
|
|
69
|
+
/**
|
|
70
|
+
* Which requirements have at least one probe. This is what turns "all
|
|
71
|
+
* requirements are present and active" from a claim into a check: an unmapped
|
|
72
|
+
* requirement is a coverage gap, and under max fidelity a gap blocks DONE.
|
|
73
|
+
*/
|
|
74
|
+
export declare function coverageOf(manifest: InteractionManifest,
|
|
75
|
+
/**
|
|
76
|
+
* The probes that will ACTUALLY run this invocation. Counting the whole
|
|
77
|
+
* manifest reports a requirement as covered when its only probe belongs to a
|
|
78
|
+
* mode that was not run — "covered" would mean "has a probe somewhere",
|
|
79
|
+
* not "was verified".
|
|
80
|
+
*/
|
|
81
|
+
ranProbes?: Probe[]): CoverageLedger;
|
|
82
|
+
/** True when the manifest was mined from different requirements than the current text. */
|
|
83
|
+
export declare function manifestIsStale(manifest: InteractionManifest, specText: string): boolean;
|
|
84
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/delivery/interaction/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EACV,cAAc,EACd,mBAAmB,EACnB,KAAK,EAEL,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,YAAY,QAA8B,CAAC;AACxD,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,yEAAyE;AACzE,eAAO,MAAM,WAAW,QAA4B,CAAC;AAErD,iFAAiF;AACjF,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc7D;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAgBtD;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,SAAI,GAAG,IAAI,EAAE,CAU7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAsErD;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,mBAAmB,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE9C,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAWtE;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAG5E;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CAKvF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,mBAAmB;AAC7B;;;;;GAKG;AACH,SAAS,CAAC,EAAE,KAAK,EAAE,GAClB,cAAc,CAgBhB;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,QAAQ,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExF"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interaction manifest — persistence, validation and the coverage ledger.
|
|
3
|
+
*
|
|
4
|
+
* The manifest lives OUTSIDE the deliverable (`.uap/interaction/manifest.json`)
|
|
5
|
+
* for the same reason a test suite is not shipped inside the thing it tests: an
|
|
6
|
+
* agent that can edit its own acceptance criteria will eventually edit them
|
|
7
|
+
* instead of fixing the defect. `.uap/interaction/` is added to the self-protect
|
|
8
|
+
* enforcer's deny list so a delivering agent cannot rewrite its own probes.
|
|
9
|
+
*/
|
|
10
|
+
import { createHash } from 'node:crypto';
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { dirname, join } from 'node:path';
|
|
13
|
+
export const MANIFEST_DIR = join('.uap', 'interaction');
|
|
14
|
+
export const MANIFEST_FILE = 'manifest.json';
|
|
15
|
+
/** Probe ids become evidence filenames — no separators, no traversal. */
|
|
16
|
+
export const PROBE_ID_RE = /^[A-Za-z0-9._-]{1,120}$/;
|
|
17
|
+
/** Hard ceiling on nested `repeat` so validation cannot be blown up by depth. */
|
|
18
|
+
export const MAX_STEP_DEPTH = 6;
|
|
19
|
+
/**
|
|
20
|
+
* Reject observation expressions that can MUTATE the artifact.
|
|
21
|
+
*
|
|
22
|
+
* The `inject`-only-in-accelerated rule is worthless on its own, because a JS
|
|
23
|
+
* *expression* can assign: `{expect:'gte', expr:'(kills = 5)', value:5}` writes
|
|
24
|
+
* the state it then grades, passes validation as a `core` probe, and proves
|
|
25
|
+
* exactly nothing. The rule has to cover every string that reaches an
|
|
26
|
+
* evaluation slot — assertions, `eval` steps and watch expressions alike.
|
|
27
|
+
*
|
|
28
|
+
* Honest about its limits: this is syntactic, and no string inspection can
|
|
29
|
+
* *prove* a JS expression is side-effect-free (a getter or a called function can
|
|
30
|
+
* mutate). It raises the cost of the obvious bypass; the observation-level
|
|
31
|
+
* invariant (watched values must not change across a read) is what catches the
|
|
32
|
+
* rest, and the manifest's write-protection is what makes both meaningful.
|
|
33
|
+
*/
|
|
34
|
+
export function expressionMutates(expr) {
|
|
35
|
+
const text = String(expr);
|
|
36
|
+
// Assignment that is not a comparison: `=` not preceded by = ! < > and not
|
|
37
|
+
// followed by =. Covers `x = 1`, `x += 1`, `x ||= 1`.
|
|
38
|
+
if (/(?<![=!<>+\-*/%&|^])(?:[+\-*/%&|^]|\*\*|<<|>>>?|\|\||&&|\?\?)?=(?!=)/.test(text)) {
|
|
39
|
+
return 'contains an assignment';
|
|
40
|
+
}
|
|
41
|
+
if (/\+\+|--/.test(text))
|
|
42
|
+
return 'contains an increment/decrement';
|
|
43
|
+
// `delete x.y`, and the comma operator used to sequence a side effect.
|
|
44
|
+
if (/\bdelete\s/.test(text))
|
|
45
|
+
return 'contains a delete';
|
|
46
|
+
// A TOP-LEVEL comma is the sequence operator (`hp = 1, true`). Commas nested
|
|
47
|
+
// inside a call or literal — `Math.min(a, b)`, `[1, 2].length` — are ordinary.
|
|
48
|
+
if (hasTopLevelComma(text))
|
|
49
|
+
return 'contains a comma sequence';
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/** True when `text` has a comma outside every (), [] and {} and outside strings. */
|
|
53
|
+
export function hasTopLevelComma(text) {
|
|
54
|
+
let depth = 0;
|
|
55
|
+
let quote = null;
|
|
56
|
+
for (let i = 0; i < text.length; i++) {
|
|
57
|
+
const c = text[i];
|
|
58
|
+
if (quote) {
|
|
59
|
+
if (c === '\\')
|
|
60
|
+
i++;
|
|
61
|
+
else if (c === quote)
|
|
62
|
+
quote = null;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (c === '"' || c === "'" || c === '`')
|
|
66
|
+
quote = c;
|
|
67
|
+
else if (c === '(' || c === '[' || c === '{')
|
|
68
|
+
depth++;
|
|
69
|
+
else if (c === ')' || c === ']' || c === '}')
|
|
70
|
+
depth--;
|
|
71
|
+
else if (c === ',' && depth <= 0)
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
export function manifestPath(projectRoot) {
|
|
77
|
+
return join(projectRoot, MANIFEST_DIR, MANIFEST_FILE);
|
|
78
|
+
}
|
|
79
|
+
/** Stable short hash of the requirements text a manifest was mined from. */
|
|
80
|
+
export function hashSpec(text) {
|
|
81
|
+
return createHash('sha256').update(text.trim()).digest('hex').slice(0, 16);
|
|
82
|
+
}
|
|
83
|
+
/** Walk nested `repeat` blocks so validation cannot be bypassed by nesting. */
|
|
84
|
+
export function flattenSteps(steps, depth = 0) {
|
|
85
|
+
const out = [];
|
|
86
|
+
// Depth-capped: a deeply nested manifest would otherwise blow the stack
|
|
87
|
+
// inside validation, turning a malformed input into a crash.
|
|
88
|
+
if (depth > MAX_STEP_DEPTH || !Array.isArray(steps))
|
|
89
|
+
return out;
|
|
90
|
+
for (const s of steps) {
|
|
91
|
+
out.push(s);
|
|
92
|
+
if (s.do === 'repeat')
|
|
93
|
+
out.push(...flattenSteps(s.steps, depth + 1));
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Structural validation + the anti-cheat invariants. Returns the problems found;
|
|
99
|
+
* empty means valid.
|
|
100
|
+
*
|
|
101
|
+
* The load-bearing rule is the `inject` restriction: a probe that writes
|
|
102
|
+
* `score = 100` and then asserts `score >= 100` proves nothing at all. State
|
|
103
|
+
* injection is therefore legal ONLY in `accelerated` probes, whose results are
|
|
104
|
+
* reported separately and never counted as evidence of natural progression.
|
|
105
|
+
*/
|
|
106
|
+
export function validateManifest(m) {
|
|
107
|
+
const problems = [];
|
|
108
|
+
const man = m;
|
|
109
|
+
if (!man || typeof man !== 'object')
|
|
110
|
+
return ['manifest is not an object'];
|
|
111
|
+
if (man.version !== 1)
|
|
112
|
+
problems.push(`unsupported manifest version: ${String(man.version)}`);
|
|
113
|
+
if (!man.kind || !['web', 'cli', 'http'].includes(man.kind)) {
|
|
114
|
+
problems.push(`unknown artifact kind: ${String(man.kind)}`);
|
|
115
|
+
}
|
|
116
|
+
if (!Array.isArray(man.requirements))
|
|
117
|
+
problems.push('requirements must be an array');
|
|
118
|
+
if (!Array.isArray(man.probes))
|
|
119
|
+
problems.push('probes must be an array');
|
|
120
|
+
if (problems.length > 0)
|
|
121
|
+
return problems;
|
|
122
|
+
const reqIds = new Set(man.requirements.map((r) => r.id));
|
|
123
|
+
const seenProbeIds = new Set();
|
|
124
|
+
for (const p of man.probes) {
|
|
125
|
+
if (!p.id)
|
|
126
|
+
problems.push('probe with no id');
|
|
127
|
+
// The probe id becomes a FILENAME (the evidence screenshot), and the
|
|
128
|
+
// manifest is untrusted by construction — it is kept behind the
|
|
129
|
+
// self-protect deny list precisely because an agent would otherwise edit
|
|
130
|
+
// it. An id of `../../../etc/x` would write outside the evidence dir.
|
|
131
|
+
else if (!PROBE_ID_RE.test(p.id)) {
|
|
132
|
+
problems.push(`probe ${p.id}: id must be filename-safe (letters, digits, dot, dash, underscore)`);
|
|
133
|
+
}
|
|
134
|
+
if (seenProbeIds.has(p.id))
|
|
135
|
+
problems.push(`duplicate probe id: ${p.id}`);
|
|
136
|
+
seenProbeIds.add(p.id);
|
|
137
|
+
if (!Array.isArray(p.steps) || p.steps.length === 0) {
|
|
138
|
+
problems.push(`probe ${p.id}: no steps`);
|
|
139
|
+
}
|
|
140
|
+
if (!Array.isArray(p.asserts) || p.asserts.length === 0) {
|
|
141
|
+
// A probe with no assertions is theatre: it drives input and claims a pass
|
|
142
|
+
// no matter what the artifact did.
|
|
143
|
+
problems.push(`probe ${p.id}: no assertions — a probe that asserts nothing cannot fail`);
|
|
144
|
+
}
|
|
145
|
+
for (const rid of p.requirementIds ?? []) {
|
|
146
|
+
if (!reqIds.has(rid))
|
|
147
|
+
problems.push(`probe ${p.id}: unknown requirement id ${rid}`);
|
|
148
|
+
}
|
|
149
|
+
const steps = flattenSteps(p.steps ?? []);
|
|
150
|
+
if (p.mode !== 'accelerated') {
|
|
151
|
+
const injects = steps.filter((s) => s.do === 'inject');
|
|
152
|
+
if (injects.length > 0) {
|
|
153
|
+
problems.push(`probe ${p.id}: state injection is only allowed in 'accelerated' probes ` +
|
|
154
|
+
`(a probe that injects the state it then asserts proves nothing)`);
|
|
155
|
+
}
|
|
156
|
+
// Every OTHER evaluation slot has to obey the same rule, or the rule is
|
|
157
|
+
// theatre: an assertion of `(kills = 5)` mutates and then grades itself.
|
|
158
|
+
for (const s of steps) {
|
|
159
|
+
if (s.do !== 'eval')
|
|
160
|
+
continue;
|
|
161
|
+
const why = expressionMutates(s.expr);
|
|
162
|
+
if (why)
|
|
163
|
+
problems.push(`probe ${p.id}: eval expression ${why} — observations must not mutate`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const a of p.asserts ?? []) {
|
|
167
|
+
if (!('expr' in a) || typeof a.expr !== 'string')
|
|
168
|
+
continue;
|
|
169
|
+
const why = expressionMutates(a.expr);
|
|
170
|
+
if (why) {
|
|
171
|
+
problems.push(`probe ${p.id}: assertion expression ${why} — an assertion that mutates grades its own write`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
for (const w of man.watch ?? []) {
|
|
176
|
+
const why = typeof w === 'string' ? expressionMutates(w) : 'is not a string';
|
|
177
|
+
if (why)
|
|
178
|
+
problems.push(`watch expression ${why} — the watchdog must only observe`);
|
|
179
|
+
}
|
|
180
|
+
return problems;
|
|
181
|
+
}
|
|
182
|
+
export function loadManifestDetailed(projectRoot) {
|
|
183
|
+
const path = manifestPath(projectRoot);
|
|
184
|
+
if (!existsSync(path))
|
|
185
|
+
return { status: 'absent' };
|
|
186
|
+
let parsed;
|
|
187
|
+
try {
|
|
188
|
+
parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
return { status: 'invalid', problems: [`manifest is not valid JSON: ${String(e).slice(0, 160)}`] };
|
|
192
|
+
}
|
|
193
|
+
const problems = validateManifest(parsed);
|
|
194
|
+
return problems.length === 0 ? { status: 'ok', manifest: parsed } : { status: 'invalid', problems };
|
|
195
|
+
}
|
|
196
|
+
export function loadManifest(projectRoot) {
|
|
197
|
+
const r = loadManifestDetailed(projectRoot);
|
|
198
|
+
return r.status === 'ok' ? r.manifest : null;
|
|
199
|
+
}
|
|
200
|
+
export function saveManifest(projectRoot, manifest) {
|
|
201
|
+
const path = manifestPath(projectRoot);
|
|
202
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
203
|
+
writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
|
|
204
|
+
return path;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Which requirements have at least one probe. This is what turns "all
|
|
208
|
+
* requirements are present and active" from a claim into a check: an unmapped
|
|
209
|
+
* requirement is a coverage gap, and under max fidelity a gap blocks DONE.
|
|
210
|
+
*/
|
|
211
|
+
export function coverageOf(manifest,
|
|
212
|
+
/**
|
|
213
|
+
* The probes that will ACTUALLY run this invocation. Counting the whole
|
|
214
|
+
* manifest reports a requirement as covered when its only probe belongs to a
|
|
215
|
+
* mode that was not run — "covered" would mean "has a probe somewhere",
|
|
216
|
+
* not "was verified".
|
|
217
|
+
*/
|
|
218
|
+
ranProbes) {
|
|
219
|
+
const covered = new Set();
|
|
220
|
+
for (const p of ranProbes ?? manifest.probes) {
|
|
221
|
+
// Accelerated probes reach their path by INJECTING state, so they are not
|
|
222
|
+
// evidence that a user can get there. Counting them as coverage would let
|
|
223
|
+
// "every requirement is covered" mean "every requirement has a probe that
|
|
224
|
+
// wrote its own preconditions".
|
|
225
|
+
if (p.mode === 'accelerated')
|
|
226
|
+
continue;
|
|
227
|
+
for (const rid of p.requirementIds ?? [])
|
|
228
|
+
covered.add(rid);
|
|
229
|
+
}
|
|
230
|
+
const uncovered = manifest.requirements.filter((r) => !covered.has(r.id));
|
|
231
|
+
return {
|
|
232
|
+
total: manifest.requirements.length,
|
|
233
|
+
covered: manifest.requirements.length - uncovered.length,
|
|
234
|
+
uncovered,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/** True when the manifest was mined from different requirements than the current text. */
|
|
238
|
+
export function manifestIsStale(manifest, specText) {
|
|
239
|
+
return manifest.specHash !== hashSpec(specText);
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/delivery/interaction/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest mining — turn a requirements document into probes.
|
|
3
|
+
*
|
|
4
|
+
* Two halves, deliberately:
|
|
5
|
+
*
|
|
6
|
+
* - a DETERMINISTIC baseline that needs no model and always produces something
|
|
7
|
+
* real (it loads the artifact, drives its start interaction, and asserts the
|
|
8
|
+
* loop is alive and error-free). Tonight's fatal defect would have been
|
|
9
|
+
* caught by the baseline alone.
|
|
10
|
+
* - a MODEL pass that reads the requirements and proposes artifact-specific
|
|
11
|
+
* probes. Its output is validated and any probe naming an observable the
|
|
12
|
+
* artifact does not expose is dropped rather than shipped, because a probe
|
|
13
|
+
* that cannot observe anything reports failures the agent then "fixes" in
|
|
14
|
+
* working code.
|
|
15
|
+
*
|
|
16
|
+
* The model is an accelerator, never a dependency: with no model configured the
|
|
17
|
+
* gate still runs, still gates, and still says plainly which requirements it
|
|
18
|
+
* could not cover.
|
|
19
|
+
*/
|
|
20
|
+
import type { LoopExecutor } from '../convergence-loop.js';
|
|
21
|
+
import type { ArtifactKind, InteractionManifest, Probe, Requirement } from './types.js';
|
|
22
|
+
/** Split a requirements document into candidate requirement lines. */
|
|
23
|
+
export declare function extractRequirements(specText: string): Requirement[];
|
|
24
|
+
/**
|
|
25
|
+
* Probes that apply to any web artifact, with no knowledge of what it does.
|
|
26
|
+
* This is the floor: it cannot prove features work, but it does prove the thing
|
|
27
|
+
* loads, responds to a click, and is still running afterwards — which is
|
|
28
|
+
* precisely the class the visual gate reports as a pass.
|
|
29
|
+
*/
|
|
30
|
+
export declare function baselineWebProbes(requirementIds?: string[]): Probe[];
|
|
31
|
+
export interface MineOptions {
|
|
32
|
+
projectRoot: string;
|
|
33
|
+
kind: ArtifactKind;
|
|
34
|
+
entry: string;
|
|
35
|
+
/** The requirements text (mission, DESIGN.md, ledger plan). */
|
|
36
|
+
specText: string;
|
|
37
|
+
/** Source listing given to the model so it uses REAL identifiers. */
|
|
38
|
+
sourceDigest?: string;
|
|
39
|
+
executor?: LoopExecutor;
|
|
40
|
+
}
|
|
41
|
+
interface ModelManifestPart {
|
|
42
|
+
watch?: string[];
|
|
43
|
+
probes?: Probe[];
|
|
44
|
+
}
|
|
45
|
+
/** Strip a fence if the model added one despite instructions. */
|
|
46
|
+
export declare function parseMinedJson(raw: string): ModelManifestPart | null;
|
|
47
|
+
/**
|
|
48
|
+
* Build a manifest. Always returns one: the deterministic baseline is included
|
|
49
|
+
* even when the model is absent or returns junk, so the gate never silently
|
|
50
|
+
* degrades into "nothing to check".
|
|
51
|
+
*/
|
|
52
|
+
export declare function mineManifest(opts: MineOptions): Promise<InteractionManifest>;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=mine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mine.d.ts","sourceRoot":"","sources":["../../../src/delivery/interaction/mine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,KAAK,EACL,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAmBnE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,GAAE,MAAM,EAAO,GAAG,KAAK,EAAE,CA+BxE;AAmDD,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,UAAU,iBAAiB;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CAClB;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAUpE;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAsElF"}
|