rcf-lite 0.9.0 → 0.10.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/CHANGELOG.md +86 -54
- package/README.md +8 -4
- package/bin/rcf.js +145 -57
- package/fixtures/canary-manifest.json +9 -9
- package/guidance/README.md +1 -1
- package/guidance/build-cycle-playbook.md +51 -51
- package/guidance/build-cycle.md +7 -7
- package/guidance/document-model.md +1 -1
- package/guidance/elicitation-playbook.md +29 -29
- package/guidance/harness-template.md +10 -10
- package/guidance/managed/README.md +1 -1
- package/guidance/managed/agent-instructions-block.hash +1 -1
- package/guidance/managed/agent-instructions-block.md +9 -9
- package/guidance/manifest.json +1 -1
- package/guidance/overview.md +4 -4
- package/package.json +4 -6
- package/rcf/adrs/adr-008.json +1 -1
- package/rcf/adrs/adr-009.json +4 -4
- package/rcf/code-nodes/cn-016.json +1 -1
- package/rcf/code-nodes/cn-019.json +1 -1
- package/rcf/code-nodes/cn-020.json +1 -1
- package/rcf/code-nodes/cn-021.json +1 -1
- package/rcf/code-nodes/cn-022.json +1 -1
- package/rcf/code-nodes/cn-049.json +1 -1
- package/rcf/code-nodes/cn-055.json +1 -1
- package/rcf/code-nodes/cn-057.json +5 -5
- package/rcf/code-nodes/cn-061.json +1 -1
- package/rcf/code-nodes/cn-066.json +1 -1
- package/rcf/code-nodes/cn-069.json +1 -1
- package/rcf/fbs/fbs-005.json +1 -1
- package/rcf/fbs/fbs-006.json +2 -2
- package/rcf/fbs/fbs-007.json +1 -1
- package/rcf/fbs/fbs-014.json +1 -1
- package/rcf/fbs/fbs-015.json +9 -8
- package/rcf/fbs/fbs-016.json +1 -1
- package/rcf/fbs/fbs-017.json +1 -1
- package/rcf/fbs/fbs-018.json +2 -2
- package/rcf/requirements/req-008.json +1 -1
- package/rcf/requirements/req-009.json +2 -2
- package/rcf/requirements/req-010.json +1 -1
- package/rcf/test-suites/PENDING.md +2 -2
- package/rcf/test-suites/ts-004.json +1 -1
- package/rcf/test-suites/ts-006.json +3 -3
- package/rcf/test-suites/ts-008.json +2 -2
- package/rcf/test-suites/ts-009.json +2 -2
- package/rcf/test-suites/ts-017.json +1 -1
- package/rcf/test-suites/ts-024.json +1 -1
- package/rcf/test-suites/ts-025.json +32 -18
- package/rcf/test-suites/ts-026.json +1 -1
- package/rcf/test-suites/ts-027.json +7 -7
- package/rcf/test-suites/ts-028.json +1 -1
- package/rcf/user-stories/us-1001.json +10 -10
- package/rcf/user-stories/us-1002.json +12 -12
- package/rcf/user-stories/us-1003.json +6 -6
- package/rcf/user-stories/us-805.json +2 -2
- package/rcf/user-stories/us-901.json +13 -13
- package/src/blueprint/conflicts.js +15 -15
- package/src/blueprint/supersede.js +6 -6
- package/src/build/bundle.js +3 -3
- package/src/build/formatters/markdown.js +9 -9
- package/src/build/mark.js +3 -3
- package/src/build/queue.js +1 -1
- package/src/cli/blueprint.js +3 -3
- package/src/cli/browser-verify.js +1 -1
- package/src/cli/build.js +139 -69
- package/src/cli/coverage.js +1 -1
- package/src/cli/create.js +3 -3
- package/src/cli/delete.js +2 -2
- package/src/cli/design.js +10 -10
- package/src/cli/fbs.js +1 -1
- package/src/cli/finalise.js +22 -20
- package/src/cli/help.js +267 -95
- package/src/cli/impact.js +1 -1
- package/src/cli/intake.js +3 -3
- package/src/cli/link.js +3 -3
- package/src/cli/preflight.js +2 -2
- package/src/cli/read.js +1 -1
- package/src/cli/req-baseline.js +2 -2
- package/src/cli/req-classify.js +3 -3
- package/src/cli/review.js +1 -1
- package/src/cli/standards.js +1 -1
- package/src/cli/test-suite.js +1 -1
- package/src/cli/trace.js +1 -1
- package/src/cli/ui-baseline.js +3 -3
- package/src/cli/ui-classify.js +4 -4
- package/src/cli/update.js +2 -2
- package/src/cli/validate.js +2 -2
- package/src/cli/view.js +12 -10
- package/src/core/store/writer.js +1 -1
- package/src/design/writer.js +3 -3
- package/src/finalise/detect.js +32 -38
- package/src/finalise/index.js +0 -1
- package/src/finalise/install.js +9 -8
- package/src/finalise/spawn.js +14 -10
- package/src/mcp/tools.js +1 -1
- package/src/req-baseline/gate.js +1 -1
- package/src/ui-baseline/manifest-writer.js +2 -2
- package/src/verify/cli/cleanup.js +1 -1
- package/src/verify/cli/mcp.js +1 -1
- package/src/verify/cli/provision.js +1 -1
- package/src/verify/cli/report.js +1 -1
- package/src/verify/cli/run.js +1 -1
- package/src/view-supervisor/manifest-writer.js +2 -2
- package/bin/rcf-verify.js +0 -122
- package/src/verify/cli/help.js +0 -56
package/src/cli/validate.js
CHANGED
|
@@ -18,7 +18,7 @@ const OPTION_SPEC = {
|
|
|
18
18
|
'no-code': { type: 'boolean' },
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
export const HELP = `Usage: rcf validate [options]
|
|
21
|
+
export const HELP = `Usage: rcf define validate [options]
|
|
22
22
|
|
|
23
23
|
Walk the rcf/ tree and report schema-validation and broken-reference
|
|
24
24
|
issues. Exits 0 when clean, 3 on issues.
|
|
@@ -140,7 +140,7 @@ export async function main(argv, deps = {}) {
|
|
|
140
140
|
}
|
|
141
141
|
if (errors.length === 0) {
|
|
142
142
|
if (!flags.quiet) {
|
|
143
|
-
stdout.write('rcf validate: tree is clean.\n');
|
|
143
|
+
stdout.write('rcf define validate: tree is clean.\n');
|
|
144
144
|
// B4 (E2E matrix 2026-07-06-003): scaffold TODO placeholders were
|
|
145
145
|
// surviving to otherwise-valid trees unflagged. Non-blocking notice
|
|
146
146
|
// only - the exit code is unchanged.
|
package/src/cli/view.js
CHANGED
|
@@ -24,7 +24,7 @@ import { parsePersistUntil } from '../view-supervisor/persist-until.js';
|
|
|
24
24
|
export const DEFAULT_PORT = 4373;
|
|
25
25
|
export const SHUTDOWN_BUDGET_MS = 2000;
|
|
26
26
|
|
|
27
|
-
export const HELP = `Usage: rcf view [subverb] [options]
|
|
27
|
+
export const HELP = `Usage: rcf audit view [subverb] [options]
|
|
28
28
|
|
|
29
29
|
Serve the on-disk RCF tree as a live HTML review surface. Runs a
|
|
30
30
|
long-running HTTP + SSE server on 127.0.0.1 that watches rcf/ and pushes
|
|
@@ -32,10 +32,10 @@ tree updates to the connected browser tab. No on-disk output; no static
|
|
|
32
32
|
files are written.
|
|
33
33
|
|
|
34
34
|
Subverbs (spec §9.2):
|
|
35
|
-
rcf view
|
|
35
|
+
rcf audit view Foreground server (default; lifetime tied to
|
|
36
36
|
the invoking session). Backward-compatible
|
|
37
37
|
with pre-0.7.0 callers.
|
|
38
|
-
rcf view start [--detach|--foreground] [--persist-until <duration|iso>]
|
|
38
|
+
rcf audit view start [--detach|--foreground] [--persist-until <duration|iso>]
|
|
39
39
|
Start the server. --detach forks a supervised
|
|
40
40
|
background process that persists across the
|
|
41
41
|
parent session's death; the manifest carries
|
|
@@ -50,12 +50,14 @@ Subverbs (spec §9.2):
|
|
|
50
50
|
--detach; non-interactive callers keep
|
|
51
51
|
--foreground so a script does not orphan a
|
|
52
52
|
process.
|
|
53
|
-
rcf view status [--json]
|
|
53
|
+
rcf audit view status [--json]
|
|
54
|
+
Print the supervisor state:
|
|
54
55
|
running | stale | not-started.
|
|
55
|
-
rcf view stop
|
|
56
|
+
rcf audit view stop Send SIGTERM to the supervised process, wait
|
|
56
57
|
for a clean shutdown, and clear the manifest
|
|
57
58
|
record.
|
|
58
|
-
rcf view logs [--tail <n>]
|
|
59
|
+
rcf audit view logs [--tail <n>]
|
|
60
|
+
Print the supervisor log tail (default 200).
|
|
59
61
|
|
|
60
62
|
Options:
|
|
61
63
|
--port <n> Bind the HTTP server on the given port.
|
|
@@ -83,7 +85,7 @@ Security posture:
|
|
|
83
85
|
Shutdown:
|
|
84
86
|
Ctrl-C (SIGINT) or SIGTERM triggers a clean shutdown: watcher
|
|
85
87
|
closed, SSE connections drained with a shutdown event, port
|
|
86
|
-
released, 2s force-exit budget. Detached: rcf view stop sends
|
|
88
|
+
released, 2s force-exit budget. Detached: rcf audit view stop sends
|
|
87
89
|
SIGTERM to the supervisor and waits for a clean unwind.
|
|
88
90
|
|
|
89
91
|
Exit codes:
|
|
@@ -213,7 +215,7 @@ export function maybeAutoOpen({ target, noOpen, stream, env, stderr, spawnFn = s
|
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
/**
|
|
216
|
-
* Main entry for the `rcf view` subcommand. Mirrors the shape of the
|
|
218
|
+
* Main entry for the `rcf audit view` subcommand. Mirrors the shape of the
|
|
217
219
|
* old bin/rcf-view.js main().
|
|
218
220
|
*
|
|
219
221
|
* @param {string[]} argv - the argv slice *after* the "view" positional
|
|
@@ -278,7 +280,7 @@ export async function main(argv, deps = {}) {
|
|
|
278
280
|
});
|
|
279
281
|
} catch (err) {
|
|
280
282
|
if (/** @type {NodeJS.ErrnoException} */ (err).code === 'EADDRINUSE') {
|
|
281
|
-
stderr.write(`[error] usage port ${resolvedPort} is in use (another rcf view process, or a different service).\n`);
|
|
283
|
+
stderr.write(`[error] usage port ${resolvedPort} is in use (another rcf audit view process, or a different service).\n`);
|
|
282
284
|
stderr.write('Pass --port <n> or set RCF_VIEW_PORT to pick a free port.\n');
|
|
283
285
|
return 2;
|
|
284
286
|
}
|
|
@@ -286,7 +288,7 @@ export async function main(argv, deps = {}) {
|
|
|
286
288
|
return 1;
|
|
287
289
|
}
|
|
288
290
|
|
|
289
|
-
stdout.write(`rcf view server listening at ${server.url}\n`);
|
|
291
|
+
stdout.write(`rcf audit view server listening at ${server.url}\n`);
|
|
290
292
|
stdout.write('watching rcf/ - Ctrl-C to shut down\n');
|
|
291
293
|
|
|
292
294
|
maybeAutoOpen({
|
package/src/core/store/writer.js
CHANGED
|
@@ -1286,7 +1286,7 @@ export async function deleteDocument({ projectRoot, tree, id, options = {}, walk
|
|
|
1286
1286
|
if (rootKinds.has(kind)) {
|
|
1287
1287
|
return rcfError({
|
|
1288
1288
|
kind: 'usage',
|
|
1289
|
-
message: `delete: root singleton ${id} cannot be deleted via rcf delete`,
|
|
1289
|
+
message: `delete: root singleton ${id} cannot be deleted via rcf define delete`,
|
|
1290
1290
|
documentId: id,
|
|
1291
1291
|
});
|
|
1292
1292
|
}
|
package/src/design/writer.js
CHANGED
|
@@ -180,7 +180,7 @@ export async function writeMarkComplete({
|
|
|
180
180
|
return rcfError({
|
|
181
181
|
kind: 'usage',
|
|
182
182
|
message: `design --mark-complete: refused - ${fbsId} designStage is missing: ${missing.join(', ')}. `
|
|
183
|
-
+ 'Author the missing artefacts first via `rcf design ' + fbsId + ' journeys add ...`, `nav set ...`, or `theme-a11y set ...`.',
|
|
183
|
+
+ 'Author the missing artefacts first via `rcf define design ' + fbsId + ' journeys add ...`, `nav set ...`, or `theme-a11y set ...`.',
|
|
184
184
|
documentId: fbsId,
|
|
185
185
|
});
|
|
186
186
|
}
|
|
@@ -189,8 +189,8 @@ export async function writeMarkComplete({
|
|
|
189
189
|
return rcfError({
|
|
190
190
|
kind: 'usage',
|
|
191
191
|
message: `design --mark-complete: refused - ${fbsId} designStage.${disagreement.designStagePath} = ${JSON.stringify(disagreement.designValue)} conflicts with uiBaseline.defaults.${disagreement.path} = ${JSON.stringify(disagreement.baselineValue)} and there is no operatorOptOuts entry. `
|
|
192
|
-
+ 'Options: (1) change designStage to match, (2) rcf ui-baseline opt-out --field '
|
|
193
|
-
+ disagreement.path + ' --reason "..." (project override), (3) rcf update '
|
|
192
|
+
+ 'Options: (1) change designStage to match, (2) rcf discover ui-baseline opt-out --field '
|
|
193
|
+
+ disagreement.path + ' --reason "..." (project override), (3) rcf define update '
|
|
194
194
|
+ fbsId + ' --set designStage.' + disagreement.designStagePath + '=... (per-FBS override).',
|
|
195
195
|
documentId: fbsId,
|
|
196
196
|
});
|
package/src/finalise/detect.js
CHANGED
|
@@ -1,36 +1,35 @@
|
|
|
1
|
-
// rcf
|
|
2
|
-
// posture). The finalise gate MUST detect whether `rcf
|
|
3
|
-
// and, when it is absent,
|
|
4
|
-
//
|
|
1
|
+
// rcf verify install detection (spec §8.3, amendment 5 - install-together
|
|
2
|
+
// posture). The finalise gate MUST detect whether the `rcf` bin (which
|
|
3
|
+
// carries the `verify` group) is resolvable and, when it is absent,
|
|
4
|
+
// prompt to install rcf-lite - NEVER silently skip the ship gate (the
|
|
5
|
+
// one behaviour §8.3 explicitly forbids).
|
|
5
6
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// `
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
7
|
+
// The 0.10.0 CLI reorganisation folded the standalone `rcf-verify` bin
|
|
8
|
+
// into the umbrella `rcf` CLI as the `verify` group. Detection now
|
|
9
|
+
// resolves the `rcf` bin exclusively; there is no legacy fallback.
|
|
10
|
+
//
|
|
11
|
+
// Two detection routes, in order:
|
|
12
|
+
// 1. The `rcf` bin on PATH - the umbrella install exposes `rcf` as a
|
|
13
|
+
// global bin (`npm i -g rcf-lite`).
|
|
14
|
+
// 2. Package resolution from the project dir - the local-project
|
|
15
|
+
// install (`npm i rcf-lite` in a repo's node_modules) resolves the
|
|
16
|
+
// `rcf-lite` package and its `bin/rcf.js` entry point.
|
|
17
|
+
// Either route yields a concrete invocation the finalise spawn
|
|
18
|
+
// (spawn.js) uses verbatim. A miss returns { installed:false } and the
|
|
19
|
+
// caller enters the prompt-or-explicit-flag path.
|
|
18
20
|
|
|
19
21
|
import { access, constants } from 'node:fs/promises';
|
|
20
22
|
import { createRequire } from 'node:module';
|
|
21
23
|
import { delimiter, dirname, join, resolve } from 'node:path';
|
|
22
24
|
|
|
23
|
-
// VERIFY_PACKAGE is the
|
|
24
|
-
//
|
|
25
|
-
// as a resolution fallback for lockfiles still pinning the pre-0.7.1 scoped
|
|
26
|
-
// name; it is never displayed as an install target.
|
|
25
|
+
// VERIFY_PACKAGE is the install target and the name shown to operators
|
|
26
|
+
// in absent-verify messaging.
|
|
27
27
|
const VERIFY_PACKAGE = 'rcf-lite';
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const VERIFY_BIN = 'rcf-verify';
|
|
28
|
+
const VERIFY_PACKAGE_CANDIDATES = [VERIFY_PACKAGE];
|
|
29
|
+
const VERIFY_BIN = 'rcf';
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
|
-
* The concrete way to launch rcf
|
|
32
|
+
* The concrete way to launch the `rcf` bin as a fresh subprocess.
|
|
34
33
|
* - `{ command: '<abs-bin>', prefixArgs: [] }` for a PATH / shim bin
|
|
35
34
|
* (its own shebang runs it).
|
|
36
35
|
* - `{ command: process.execPath, prefixArgs: ['<abs-entry.js>'] }` for a
|
|
@@ -43,8 +42,8 @@ const VERIFY_BIN = 'rcf-verify';
|
|
|
43
42
|
*/
|
|
44
43
|
|
|
45
44
|
/**
|
|
46
|
-
* Scan PATH for an executable named `rcf
|
|
47
|
-
* `.
|
|
45
|
+
* Scan PATH for an executable named `rcf` (plus the Windows `.cmd` /
|
|
46
|
+
* `.exe` shim variants). Returns the first absolute path that exists
|
|
48
47
|
* and is executable, or null.
|
|
49
48
|
*
|
|
50
49
|
* @param {string} name
|
|
@@ -78,16 +77,11 @@ export async function findOnPath(name, { env = process.env } = {}) {
|
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
/**
|
|
81
|
-
* Resolve the rcf
|
|
82
|
-
* the normal node_modules resolution the caller's project sees. Returns
|
|
83
|
-
* absolute path to `bin/rcf
|
|
80
|
+
* Resolve the `rcf` bin entry point from a starting directory, following
|
|
81
|
+
* the normal node_modules resolution the caller's project sees. Returns
|
|
82
|
+
* the absolute path to `bin/rcf.js`, or null if the package is not
|
|
84
83
|
* installed / resolvable from there.
|
|
85
84
|
*
|
|
86
|
-
* Candidates are tried in the order defined by VERIFY_PACKAGE_CANDIDATES: the
|
|
87
|
-
* current umbrella (`rcf-lite`) first, then the deprecated scoped name
|
|
88
|
-
* (`@stravica-ai/rcf-verify-lite`) as a fallback for lockfiles pinned to it.
|
|
89
|
-
* The first candidate whose bin resolves and exists on disk wins.
|
|
90
|
-
*
|
|
91
85
|
* @param {string} fromDir - directory to resolve from (the project root / cwd)
|
|
92
86
|
* @returns {Promise<string|null>}
|
|
93
87
|
*/
|
|
@@ -119,9 +113,9 @@ export async function resolvePackageBin(fromDir) {
|
|
|
119
113
|
}
|
|
120
114
|
|
|
121
115
|
/**
|
|
122
|
-
* Detect whether rcf
|
|
123
|
-
*
|
|
124
|
-
*
|
|
116
|
+
* Detect whether the `rcf` bin (carrying the `verify` group) is
|
|
117
|
+
* resolvable and, if so, how to launch it. Deps are injectable so the
|
|
118
|
+
* finalise gate can be exercised without a real installed rcf-lite.
|
|
125
119
|
*
|
|
126
120
|
* @param {object} [deps]
|
|
127
121
|
* @param {string} [deps.cwd] - project dir to resolve a local install from
|
|
@@ -148,4 +142,4 @@ export async function detectVerify(deps = {}) {
|
|
|
148
142
|
return { installed: false, invocation: null };
|
|
149
143
|
}
|
|
150
144
|
|
|
151
|
-
export { VERIFY_PACKAGE,
|
|
145
|
+
export { VERIFY_PACKAGE, VERIFY_PACKAGE_CANDIDATES, VERIFY_BIN };
|
package/src/finalise/index.js
CHANGED
package/src/finalise/install.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
// Absent-verify handling (spec §8.3, amendment 5). When `rcf
|
|
2
|
-
//
|
|
1
|
+
// Absent-verify handling (spec §8.3, amendment 5). When the `rcf` bin
|
|
2
|
+
// (which now carries the `verify` group post-0.10.0) is not resolvable,
|
|
3
|
+
// the finalise gate MUST NOT silently skip - that recreates the
|
|
3
4
|
// false-confidence failure the whole programme exists to prevent. The
|
|
4
5
|
// sanctioned paths are exactly two, and nothing else:
|
|
5
6
|
// - interactive TTY -> prompt the operator to install now (y/N);
|
|
@@ -35,8 +36,8 @@ export function promptYesNo(question, { input = process.stdin, output = process.
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
|
-
* Install rcf-
|
|
39
|
-
*
|
|
39
|
+
* Install rcf-lite globally so the `rcf verify` group becomes
|
|
40
|
+
* resolvable. Streams npm's output to the operator. Returns the install
|
|
40
41
|
* process exit code.
|
|
41
42
|
*
|
|
42
43
|
* @param {object} [deps]
|
|
@@ -77,11 +78,11 @@ export async function resolveAbsentVerify({ installFlag, isTty }, io, deps = {})
|
|
|
77
78
|
let wantsInstall = false;
|
|
78
79
|
if (installFlag) {
|
|
79
80
|
// Explicit flag: the sanctioned non-interactive install path.
|
|
80
|
-
io.stdout.write(`[finalise] rcf
|
|
81
|
+
io.stdout.write(`[finalise] the rcf CLI (with verify) not found; installing ${VERIFY_PACKAGE} (--install-verify)...\n`);
|
|
81
82
|
wantsInstall = true;
|
|
82
83
|
} else if (isTty) {
|
|
83
84
|
// Interactive: prompt. Declining aborts (never a silent skip).
|
|
84
|
-
io.stderr.write(`[finalise] rcf-
|
|
85
|
+
io.stderr.write(`[finalise] rcf-lite is not installed. The ship gate cannot run without it.\n`);
|
|
85
86
|
wantsInstall = await prompt(`Install ${VERIFY_PACKAGE} now? [y/N]`, {
|
|
86
87
|
input: io.input, output: io.output,
|
|
87
88
|
});
|
|
@@ -89,7 +90,7 @@ export async function resolveAbsentVerify({ installFlag, isTty }, io, deps = {})
|
|
|
89
90
|
return {
|
|
90
91
|
action: 'abort',
|
|
91
92
|
code: 4,
|
|
92
|
-
reason: `finalise refused: rcf-
|
|
93
|
+
reason: `finalise refused: rcf-lite is required and install was declined. `
|
|
93
94
|
+ `Install it (npm i -g ${VERIFY_PACKAGE}) or re-run with --install-verify. `
|
|
94
95
|
+ `The ship gate is never skipped.`,
|
|
95
96
|
};
|
|
@@ -100,7 +101,7 @@ export async function resolveAbsentVerify({ installFlag, isTty }, io, deps = {})
|
|
|
100
101
|
return {
|
|
101
102
|
action: 'abort',
|
|
102
103
|
code: 4,
|
|
103
|
-
reason: `finalise refused: rcf-
|
|
104
|
+
reason: `finalise refused: rcf-lite is not installed and no TTY is available to prompt. `
|
|
104
105
|
+ `Install it (npm i -g ${VERIFY_PACKAGE}) or re-run with --install-verify. `
|
|
105
106
|
+ `The ship gate is never silently skipped.`,
|
|
106
107
|
};
|
package/src/finalise/spawn.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
// Fresh-subprocess invocation of `rcf
|
|
2
|
-
// load-bearing independence guarantee: build-lite's finalise step
|
|
3
|
-
// verify as a SEPARATE OS PROCESS with the isolation env - it
|
|
4
|
-
// verify's engine in-process, because the verifier
|
|
5
|
-
// cold session with zero build context (§9).
|
|
6
|
-
// gate; findings flow back via the
|
|
1
|
+
// Fresh-subprocess invocation of `rcf verify run` (spec §8.2). This is
|
|
2
|
+
// the load-bearing independence guarantee: build-lite's finalise step
|
|
3
|
+
// launches verify as a SEPARATE OS PROCESS with the isolation env - it
|
|
4
|
+
// MUST NOT import verify's engine in-process, because the verifier
|
|
5
|
+
// agent must start from a cold session with zero build context (§9).
|
|
6
|
+
// The subprocess exit code is the gate; findings flow back via the
|
|
7
|
+
// --out report file, never stdout scraping.
|
|
7
8
|
//
|
|
8
9
|
// The isolation env (core's ISOLATION_RECIPE, §7.3) is layered onto the child
|
|
9
10
|
// env here so the recipe travels with the process boundary exactly as §8.2
|
|
@@ -14,9 +15,11 @@ import { spawn } from 'node:child_process';
|
|
|
14
15
|
import { isolationEnv } from '#core/isolation';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* Assemble the `rcf
|
|
18
|
-
* Deterministic and pure so it is directly unit-testable; the exact
|
|
19
|
-
* the §8.2 invocation contract.
|
|
18
|
+
* Assemble the `rcf verify run` argument vector from finalise options.
|
|
19
|
+
* Deterministic and pure so it is directly unit-testable; the exact
|
|
20
|
+
* shape is the §8.2 invocation contract. The 0.10.0 CLI reorganisation
|
|
21
|
+
* prepends the `verify` group token; the run-verb arguments below are
|
|
22
|
+
* otherwise unchanged.
|
|
20
23
|
*
|
|
21
24
|
* @param {object} opts
|
|
22
25
|
* @param {string} opts.repo - RCF chain source (the project root)
|
|
@@ -32,6 +35,7 @@ import { isolationEnv } from '#core/isolation';
|
|
|
32
35
|
*/
|
|
33
36
|
export function buildVerifyArgs(opts) {
|
|
34
37
|
const args = [
|
|
38
|
+
'verify',
|
|
35
39
|
'run',
|
|
36
40
|
'--repo', opts.repo,
|
|
37
41
|
'--profile', opts.profile,
|
|
@@ -47,7 +51,7 @@ export function buildVerifyArgs(opts) {
|
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/**
|
|
50
|
-
* Spawn rcf
|
|
54
|
+
* Spawn `rcf verify run` as a fresh subprocess and resolve with its exit code.
|
|
51
55
|
* stdio is inherited by default so the operator sees verify's live progress
|
|
52
56
|
* and its verdict line; the report artifact is read separately by the caller.
|
|
53
57
|
*
|
package/src/mcp/tools.js
CHANGED
|
@@ -69,7 +69,7 @@ const ISSUE_SCHEMA = {
|
|
|
69
69
|
// success branch stays the verbatim envelope transcription (D8/D9).
|
|
70
70
|
const ERROR_PAYLOAD_SCHEMA = {
|
|
71
71
|
type: 'object',
|
|
72
|
-
description: 'Tool execution error payload (accompanies isError: true): the same issue shape rcf validate --json ships',
|
|
72
|
+
description: 'Tool execution error payload (accompanies isError: true): the same issue shape rcf define validate --json ships',
|
|
73
73
|
properties: {
|
|
74
74
|
ok: { const: false },
|
|
75
75
|
errors: { type: 'array', items: ISSUE_SCHEMA },
|
package/src/req-baseline/gate.js
CHANGED
|
@@ -73,7 +73,7 @@ export function formatStage1RefusalMessage({ fbsId, usId, reqId, openCandidates
|
|
|
73
73
|
const short = shortDescription(c.canonicalText);
|
|
74
74
|
lines.push(` ${c.baselineKey}: ${short}`);
|
|
75
75
|
}
|
|
76
|
-
lines.push(` Resolve: rcf req-baseline sweep --req ${reqId}`);
|
|
76
|
+
lines.push(` Resolve: rcf discover req-baseline sweep --req ${reqId}`);
|
|
77
77
|
return lines.join('\n');
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -210,14 +210,14 @@ export async function writeUiBaselineOptOut({
|
|
|
210
210
|
if (!priorBaseline) {
|
|
211
211
|
return rcfError({
|
|
212
212
|
kind: 'usage',
|
|
213
|
-
message: 'ui-baseline opt-out: no uiBaseline record exists yet; run \'rcf ui-baseline init\' first.',
|
|
213
|
+
message: 'ui-baseline opt-out: no uiBaseline record exists yet; run \'rcf discover ui-baseline init\' first.',
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
const normalisedField = String(field).startsWith('defaults.') ? String(field).slice('defaults.'.length) : String(field);
|
|
217
217
|
if (typeof isKnownField === 'function' && !isKnownField(normalisedField)) {
|
|
218
218
|
return rcfError({
|
|
219
219
|
kind: 'usage',
|
|
220
|
-
message: `ui-baseline opt-out: unknown baseline field '${normalisedField}' (see 'rcf ui-baseline show' for the field list).`,
|
|
220
|
+
message: `ui-baseline opt-out: unknown baseline field '${normalisedField}' (see 'rcf discover ui-baseline show' for the field list).`,
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
223
|
const isoNow = now.toISOString();
|
|
@@ -9,7 +9,7 @@ import { formatError, isRcfError } from '#core/errors';
|
|
|
9
9
|
|
|
10
10
|
import { readProvisionFile, cleanup } from '../provision/index.js';
|
|
11
11
|
|
|
12
|
-
export const HELP = `Usage: rcf
|
|
12
|
+
export const HELP = `Usage: rcf verify cleanup --provision <file> [--url <app-url>]
|
|
13
13
|
|
|
14
14
|
Tear down artefacts recorded in the --provision file (all prefixed
|
|
15
15
|
'zzverify-'). Reports what was removed and what could not be.
|
package/src/verify/cli/mcp.js
CHANGED
|
@@ -14,7 +14,7 @@ import { createToolRegistry } from '../mcp/tools.js';
|
|
|
14
14
|
|
|
15
15
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
16
16
|
|
|
17
|
-
export const HELP = `Usage: rcf
|
|
17
|
+
export const HELP = `Usage: rcf verify mcp [options]
|
|
18
18
|
|
|
19
19
|
Serve verify over the Model Context Protocol (local stdio). Exposes one tool,
|
|
20
20
|
rcf_verify_run, over the same in-process engine the CLI uses. stdout carries
|
|
@@ -11,7 +11,7 @@ import { formatError, isRcfError } from '#core/errors';
|
|
|
11
11
|
import { readChain } from '../chain/index.js';
|
|
12
12
|
import { runProvisioning } from '../provision/index.js';
|
|
13
13
|
|
|
14
|
-
export const HELP = `Usage: rcf
|
|
14
|
+
export const HELP = `Usage: rcf verify provision --repo <path> --url <app-url> --provision <file>
|
|
15
15
|
|
|
16
16
|
Stand up prerequisite accounts / sandboxes / seed data for a later run.
|
|
17
17
|
Credentials are written to the --provision FILE only, never echoed.
|
package/src/verify/cli/report.js
CHANGED
|
@@ -11,7 +11,7 @@ import { formatError, isRcfError } from '#core/errors';
|
|
|
11
11
|
import { parseReport } from '../report/index.js';
|
|
12
12
|
import { renderReport } from '../report/renderer.js';
|
|
13
13
|
|
|
14
|
-
export const HELP = `Usage: rcf
|
|
14
|
+
export const HELP = `Usage: rcf verify report <report-path> [--json]
|
|
15
15
|
|
|
16
16
|
Re-render a prior report artifact. Default output is the human-readable
|
|
17
17
|
summary; --json re-emits the parsed artifact as JSON.
|
package/src/verify/cli/run.js
CHANGED
|
@@ -29,7 +29,7 @@ const OPTION_SPEC = {
|
|
|
29
29
|
help: { type: 'boolean' },
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
export const HELP = `Usage: rcf
|
|
32
|
+
export const HELP = `Usage: rcf verify run [options]
|
|
33
33
|
|
|
34
34
|
Launch a fresh-context adversarial verifier against a running app and emit a
|
|
35
35
|
structured verdict stamped with the runtime it ran against.
|
|
@@ -19,13 +19,13 @@ export const DEFAULT_PID_PATH = '.rcf/view-server.pid';
|
|
|
19
19
|
*/
|
|
20
20
|
export const viewServerGitignoreEntry = Object.freeze({
|
|
21
21
|
path: '.rcf/view-server.pid',
|
|
22
|
-
owner: 'rcf view --detach (view-server pid file)',
|
|
22
|
+
owner: 'rcf audit view --detach (view-server pid file)',
|
|
23
23
|
since: '0.7.0',
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
export const viewServerLogGitignoreEntry = Object.freeze({
|
|
27
27
|
path: '.rcf/view-server.log',
|
|
28
|
-
owner: 'rcf view --detach (supervisor log)',
|
|
28
|
+
owner: 'rcf audit view --detach (supervisor log)',
|
|
29
29
|
since: '0.7.0',
|
|
30
30
|
});
|
|
31
31
|
|
package/bin/rcf-verify.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// The `rcf-verify` alias bin. Post 0.7.1 packaging consolidation the
|
|
3
|
-
// unified `rcf` CLI grew a `verify` subcommand that dispatches to the
|
|
4
|
-
// same handlers this file wires up; `rcf-verify` remains as a
|
|
5
|
-
// transition-grace alias (see docs/2026-08-06_packaging-consolidation-
|
|
6
|
-
// proposal.md R3). When run directly (as `rcf-verify <verb>` rather
|
|
7
|
-
// than through the routing `rcf verify <verb>`), the entrypoint emits
|
|
8
|
-
// a one-line stderr deprecation notice; behaviour is otherwise
|
|
9
|
-
// unchanged.
|
|
10
|
-
//
|
|
11
|
-
// Argv layout: `rcf-verify <subcommand> [args...]`. The first positional
|
|
12
|
-
// selects the subcommand handler; global --version / --help short-circuit
|
|
13
|
-
// before dispatch. The `main` export is also imported by bin/rcf.js as
|
|
14
|
-
// the `verify` subcommand handler, so the dispatcher lives in one place.
|
|
15
|
-
|
|
16
|
-
import { realpathSync } from 'node:fs';
|
|
17
|
-
import { readFile } from 'node:fs/promises';
|
|
18
|
-
import { dirname, resolve } from 'node:path';
|
|
19
|
-
import process from 'node:process';
|
|
20
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
21
|
-
|
|
22
|
-
import { main as runMain } from '../src/verify/cli/run.js';
|
|
23
|
-
import { main as reportMain } from '../src/verify/cli/report.js';
|
|
24
|
-
import { main as provisionMain } from '../src/verify/cli/provision.js';
|
|
25
|
-
import { main as cleanupMain } from '../src/verify/cli/cleanup.js';
|
|
26
|
-
import { main as mcpMain } from '../src/verify/cli/mcp.js';
|
|
27
|
-
import { main as helpMain, TOP_LEVEL_HELP } from '../src/verify/cli/help.js';
|
|
28
|
-
|
|
29
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
30
|
-
|
|
31
|
-
const SUBCOMMANDS = {
|
|
32
|
-
run: runMain,
|
|
33
|
-
report: reportMain,
|
|
34
|
-
provision: provisionMain,
|
|
35
|
-
cleanup: cleanupMain,
|
|
36
|
-
mcp: mcpMain,
|
|
37
|
-
help: helpMain,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @param {string[]} argv - argv minus node + script
|
|
42
|
-
* @param {object} [deps]
|
|
43
|
-
* @returns {Promise<number>}
|
|
44
|
-
*/
|
|
45
|
-
export async function main(argv, deps = {}) {
|
|
46
|
-
const stdout = deps.stdout ?? process.stdout;
|
|
47
|
-
const stderr = deps.stderr ?? process.stderr;
|
|
48
|
-
|
|
49
|
-
if (argv.length === 0) {
|
|
50
|
-
stdout.write(TOP_LEVEL_HELP);
|
|
51
|
-
return 0;
|
|
52
|
-
}
|
|
53
|
-
const first = argv[0];
|
|
54
|
-
if (first === '--version' || first === '-v') {
|
|
55
|
-
stdout.write(`rcf-verify ${await readPackageVersion()}\n`);
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
58
|
-
if (first === '--help' || first === '-h') {
|
|
59
|
-
stdout.write(TOP_LEVEL_HELP);
|
|
60
|
-
return 0;
|
|
61
|
-
}
|
|
62
|
-
const handler = SUBCOMMANDS[first];
|
|
63
|
-
if (!handler) {
|
|
64
|
-
stderr.write(`[error] usage unknown subcommand: ${first}\n`);
|
|
65
|
-
stderr.write(TOP_LEVEL_HELP);
|
|
66
|
-
return 2;
|
|
67
|
-
}
|
|
68
|
-
return await handler(argv.slice(1), deps);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function readPackageVersion() {
|
|
72
|
-
try {
|
|
73
|
-
const pkgPath = resolve(here, '..', 'package.json');
|
|
74
|
-
const pkg = JSON.parse(await readFile(pkgPath, 'utf8'));
|
|
75
|
-
return pkg.version ?? '0.0.0';
|
|
76
|
-
} catch {
|
|
77
|
-
return '0.0.0';
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Symlink-safe entry-point compare (mirrors build's bin/rcf.js). macOS `/tmp`
|
|
83
|
-
* is a symlink to `/private/tmp` and every `pnpm link` shim is a symlink;
|
|
84
|
-
* without realpath the isMain gate breaks and main() never runs.
|
|
85
|
-
*
|
|
86
|
-
* @param {string} metaUrl
|
|
87
|
-
* @param {string} argvPath
|
|
88
|
-
* @returns {boolean}
|
|
89
|
-
*/
|
|
90
|
-
export function isSameEntryPoint(metaUrl, argvPath) {
|
|
91
|
-
try {
|
|
92
|
-
const metaPath = fileURLToPath(metaUrl);
|
|
93
|
-
return realpathSync(metaPath) === realpathSync(argvPath);
|
|
94
|
-
} catch {
|
|
95
|
-
try {
|
|
96
|
-
return metaUrl === pathToFileURL(argvPath).href;
|
|
97
|
-
} catch {
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const isMain = process.argv[1] && isSameEntryPoint(import.meta.url, process.argv[1]);
|
|
104
|
-
if (isMain) {
|
|
105
|
-
// Transition-grace deprecation notice per proposal R3. Only fires when
|
|
106
|
-
// the alias bin is invoked directly (not when bin/rcf.js routes the
|
|
107
|
-
// `verify` subcommand through the exported `main`, since the isMain
|
|
108
|
-
// guard is false in that case). Suppressible via RCF_QUIET=1 for
|
|
109
|
-
// scripted callers who cannot tolerate stderr chatter.
|
|
110
|
-
if (!process.env.RCF_QUIET) {
|
|
111
|
-
process.stderr.write(
|
|
112
|
-
'[rcf-verify] deprecation: prefer `rcf verify` (the umbrella CLI subcommand). ' +
|
|
113
|
-
'The `rcf-verify` alias will be removed in a future major. Set RCF_QUIET=1 to silence.\n',
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
main(process.argv.slice(2))
|
|
117
|
-
.then((code) => process.exit(code))
|
|
118
|
-
.catch((err) => {
|
|
119
|
-
process.stderr.write(`[rcf-verify] unexpected failure: ${err.message}\n${err.stack}\n`);
|
|
120
|
-
process.exit(1);
|
|
121
|
-
});
|
|
122
|
-
}
|
package/src/verify/cli/help.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// Top-level and per-subcommand help (mirrors build's cli/help.js). British
|
|
2
|
-
// English, ASCII hyphens only.
|
|
3
|
-
|
|
4
|
-
import { HELP as RUN_HELP } from './run.js';
|
|
5
|
-
import { HELP as REPORT_HELP } from './report.js';
|
|
6
|
-
import { HELP as PROVISION_HELP } from './provision.js';
|
|
7
|
-
import { HELP as CLEANUP_HELP } from './cleanup.js';
|
|
8
|
-
import { HELP as MCP_HELP } from './mcp.js';
|
|
9
|
-
|
|
10
|
-
export const TOP_LEVEL_HELP = `Usage: rcf-verify <command> [options]
|
|
11
|
-
|
|
12
|
-
A fresh-context adversarial verifier. Given an RCF chain (the acceptance
|
|
13
|
-
contract) and a running app under a declared runtime profile, it launches an
|
|
14
|
-
isolated verifier agent that walks real user journeys adversarially and emits a
|
|
15
|
-
structured verdict stamped with the runtime it ran against.
|
|
16
|
-
|
|
17
|
-
This is an independent ship-readiness signal, not a correctness guarantee.
|
|
18
|
-
|
|
19
|
-
Commands:
|
|
20
|
-
run Run adversarial verification and emit a report artifact
|
|
21
|
-
report <path> Re-render a prior report artifact
|
|
22
|
-
provision Stand up prerequisite accounts/sandboxes/data standalone
|
|
23
|
-
cleanup Tear down provisioned artefacts (all prefixed 'zzverify-')
|
|
24
|
-
mcp Serve verify over MCP (local stdio)
|
|
25
|
-
help [command] Print help for a command
|
|
26
|
-
|
|
27
|
-
Options:
|
|
28
|
-
--version Print the package version and exit
|
|
29
|
-
--help Print this help and exit
|
|
30
|
-
|
|
31
|
-
Run 'rcf-verify help <command>' for command-specific help.
|
|
32
|
-
`;
|
|
33
|
-
|
|
34
|
-
const SUB_HELP = {
|
|
35
|
-
run: RUN_HELP,
|
|
36
|
-
report: REPORT_HELP,
|
|
37
|
-
provision: PROVISION_HELP,
|
|
38
|
-
cleanup: CLEANUP_HELP,
|
|
39
|
-
mcp: MCP_HELP,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @param {string[]} argv
|
|
44
|
-
* @param {object} [deps]
|
|
45
|
-
* @returns {Promise<number>}
|
|
46
|
-
*/
|
|
47
|
-
export async function main(argv, deps = {}) {
|
|
48
|
-
const stdout = deps.stdout ?? process.stdout;
|
|
49
|
-
const topic = argv[0];
|
|
50
|
-
if (topic && SUB_HELP[topic]) {
|
|
51
|
-
stdout.write(SUB_HELP[topic]);
|
|
52
|
-
return 0;
|
|
53
|
-
}
|
|
54
|
-
stdout.write(TOP_LEVEL_HELP);
|
|
55
|
-
return 0;
|
|
56
|
-
}
|