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.
Files changed (105) hide show
  1. package/CHANGELOG.md +86 -54
  2. package/README.md +8 -4
  3. package/bin/rcf.js +145 -57
  4. package/fixtures/canary-manifest.json +9 -9
  5. package/guidance/README.md +1 -1
  6. package/guidance/build-cycle-playbook.md +51 -51
  7. package/guidance/build-cycle.md +7 -7
  8. package/guidance/document-model.md +1 -1
  9. package/guidance/elicitation-playbook.md +29 -29
  10. package/guidance/harness-template.md +10 -10
  11. package/guidance/managed/README.md +1 -1
  12. package/guidance/managed/agent-instructions-block.hash +1 -1
  13. package/guidance/managed/agent-instructions-block.md +9 -9
  14. package/guidance/manifest.json +1 -1
  15. package/guidance/overview.md +4 -4
  16. package/package.json +4 -6
  17. package/rcf/adrs/adr-008.json +1 -1
  18. package/rcf/adrs/adr-009.json +4 -4
  19. package/rcf/code-nodes/cn-016.json +1 -1
  20. package/rcf/code-nodes/cn-019.json +1 -1
  21. package/rcf/code-nodes/cn-020.json +1 -1
  22. package/rcf/code-nodes/cn-021.json +1 -1
  23. package/rcf/code-nodes/cn-022.json +1 -1
  24. package/rcf/code-nodes/cn-049.json +1 -1
  25. package/rcf/code-nodes/cn-055.json +1 -1
  26. package/rcf/code-nodes/cn-057.json +5 -5
  27. package/rcf/code-nodes/cn-061.json +1 -1
  28. package/rcf/code-nodes/cn-066.json +1 -1
  29. package/rcf/code-nodes/cn-069.json +1 -1
  30. package/rcf/fbs/fbs-005.json +1 -1
  31. package/rcf/fbs/fbs-006.json +2 -2
  32. package/rcf/fbs/fbs-007.json +1 -1
  33. package/rcf/fbs/fbs-014.json +1 -1
  34. package/rcf/fbs/fbs-015.json +9 -8
  35. package/rcf/fbs/fbs-016.json +1 -1
  36. package/rcf/fbs/fbs-017.json +1 -1
  37. package/rcf/fbs/fbs-018.json +2 -2
  38. package/rcf/requirements/req-008.json +1 -1
  39. package/rcf/requirements/req-009.json +2 -2
  40. package/rcf/requirements/req-010.json +1 -1
  41. package/rcf/test-suites/PENDING.md +2 -2
  42. package/rcf/test-suites/ts-004.json +1 -1
  43. package/rcf/test-suites/ts-006.json +3 -3
  44. package/rcf/test-suites/ts-008.json +2 -2
  45. package/rcf/test-suites/ts-009.json +2 -2
  46. package/rcf/test-suites/ts-017.json +1 -1
  47. package/rcf/test-suites/ts-024.json +1 -1
  48. package/rcf/test-suites/ts-025.json +32 -18
  49. package/rcf/test-suites/ts-026.json +1 -1
  50. package/rcf/test-suites/ts-027.json +7 -7
  51. package/rcf/test-suites/ts-028.json +1 -1
  52. package/rcf/user-stories/us-1001.json +10 -10
  53. package/rcf/user-stories/us-1002.json +12 -12
  54. package/rcf/user-stories/us-1003.json +6 -6
  55. package/rcf/user-stories/us-805.json +2 -2
  56. package/rcf/user-stories/us-901.json +13 -13
  57. package/src/blueprint/conflicts.js +15 -15
  58. package/src/blueprint/supersede.js +6 -6
  59. package/src/build/bundle.js +3 -3
  60. package/src/build/formatters/markdown.js +9 -9
  61. package/src/build/mark.js +3 -3
  62. package/src/build/queue.js +1 -1
  63. package/src/cli/blueprint.js +3 -3
  64. package/src/cli/browser-verify.js +1 -1
  65. package/src/cli/build.js +139 -69
  66. package/src/cli/coverage.js +1 -1
  67. package/src/cli/create.js +3 -3
  68. package/src/cli/delete.js +2 -2
  69. package/src/cli/design.js +10 -10
  70. package/src/cli/fbs.js +1 -1
  71. package/src/cli/finalise.js +22 -20
  72. package/src/cli/help.js +267 -95
  73. package/src/cli/impact.js +1 -1
  74. package/src/cli/intake.js +3 -3
  75. package/src/cli/link.js +3 -3
  76. package/src/cli/preflight.js +2 -2
  77. package/src/cli/read.js +1 -1
  78. package/src/cli/req-baseline.js +2 -2
  79. package/src/cli/req-classify.js +3 -3
  80. package/src/cli/review.js +1 -1
  81. package/src/cli/standards.js +1 -1
  82. package/src/cli/test-suite.js +1 -1
  83. package/src/cli/trace.js +1 -1
  84. package/src/cli/ui-baseline.js +3 -3
  85. package/src/cli/ui-classify.js +4 -4
  86. package/src/cli/update.js +2 -2
  87. package/src/cli/validate.js +2 -2
  88. package/src/cli/view.js +12 -10
  89. package/src/core/store/writer.js +1 -1
  90. package/src/design/writer.js +3 -3
  91. package/src/finalise/detect.js +32 -38
  92. package/src/finalise/index.js +0 -1
  93. package/src/finalise/install.js +9 -8
  94. package/src/finalise/spawn.js +14 -10
  95. package/src/mcp/tools.js +1 -1
  96. package/src/req-baseline/gate.js +1 -1
  97. package/src/ui-baseline/manifest-writer.js +2 -2
  98. package/src/verify/cli/cleanup.js +1 -1
  99. package/src/verify/cli/mcp.js +1 -1
  100. package/src/verify/cli/provision.js +1 -1
  101. package/src/verify/cli/report.js +1 -1
  102. package/src/verify/cli/run.js +1 -1
  103. package/src/view-supervisor/manifest-writer.js +2 -2
  104. package/bin/rcf-verify.js +0 -122
  105. package/src/verify/cli/help.js +0 -56
package/src/cli/build.js CHANGED
@@ -1,13 +1,15 @@
1
- // `rcf build` subcommand handler (Phase 6 §D1). One verb, four modes:
1
+ // `rcf build` group handler. 0.10.0 splits the old flag-based mode
2
+ // detection into three explicit sub-verbs; the internal semantics are
3
+ // unchanged.
2
4
  //
3
- // rcf build queue overview
4
- // rcf build <fbs-id> spec bundle for one FBS item
5
- // rcf build --next bundle for the next actionable item
6
- // rcf build <fbs-id> --mark <status> record a lifecycle transition
5
+ // rcf build queue queue overview
6
+ // rcf build bundle <fbs-id> spec bundle for one FBS item
7
+ // rcf build bundle --next bundle for the next actionable item
8
+ // rcf build mark <fbs-id> <status> record a lifecycle transition
7
9
  //
8
10
  // Positional is an FBS id ONLY: the FBS is the queue unit (one US's
9
11
  // ACs can span multiple FBS items, so US addressing is ambiguous by
10
- // construction). US ids exit 2 with a pointer at `rcf trace`.
12
+ // construction). US ids exit 2 with a pointer at `rcf audit trace`.
11
13
  //
12
14
  // Deterministic-only boundary (§D13): this verb assembles what the
13
15
  // tree says. It does not score bundle quality, detect under-specified
@@ -60,65 +62,71 @@ const OPTION_SPEC = {
60
62
  reason: { type: 'string' },
61
63
  };
62
64
 
63
- export const HELP = `Usage: rcf build [fbs-id] [options]
65
+ export const HELP = `Usage: rcf build <verb> [options]
64
66
 
65
67
  Assemble FBS spec bundles and drive the build queue (the SDD adapter).
66
- Four modes:
68
+ Three sub-verbs:
67
69
 
68
- rcf build Queue overview (the FBS queue as a table,
69
- with parallel-safe tier groups)
70
- rcf build <fbs-id> Spec bundle for one FBS item
71
- rcf build --next Bundle for the next actionable item
72
- rcf build <fbs-id> --mark <status> Record a lifecycle transition
70
+ rcf build queue Queue overview (the FBS queue as a
71
+ table, with parallel-safe tier groups)
72
+ rcf build bundle <fbs-id> Spec bundle for one FBS item
73
+ rcf build bundle --next Bundle for the next actionable item
74
+ rcf build mark <fbs-id> <status> Record a lifecycle transition
73
75
 
74
76
  The positional is an FBS id only. For 'which FBS items implement this
75
- story', use: rcf trace <us-id> --forward --format json
77
+ story', use: rcf audit trace <us-id> --forward --format json
76
78
 
77
79
  Lifecycle (forward-only): notStarted -> inProgress -> complete -> verified.
78
- The --mark ladder caps at 'complete': --mark verified is refused (exit 4)
79
- because 'verified' is written only by the finalise gate (rcf finalise) after
80
- an independent verify run. Backward transitions are also refused (exit 4);
81
- the deliberate-correction / manual-override escape hatch is:
82
- rcf update <fbs-id> --set executionStatus=<status>
80
+ The mark ladder caps at 'complete': 'verified' is refused (exit 4)
81
+ because it is written only by the finalise gate (rcf build finalise)
82
+ after an independent verify run. Backward transitions are also refused
83
+ (exit 4); the deliberate-correction / manual-override escape hatch is:
84
+ rcf define update <fbs-id> --set executionStatus=<status>
83
85
 
84
86
  Bundle assembly is mechanical and deterministic: it projects what the
85
87
  tree says. It does NOT judge whether the FBS is well-specified or the
86
88
  bundle sufficient - that belongs to a later prompting + MCP phase.
87
89
 
88
- Options:
90
+ Options (bundle):
89
91
  --next Select the next actionable FBS item (lowest
90
92
  buildOrder, notStarted, all dependencies
91
93
  satisfied) and emit its bundle
92
- --mark <status> Record a lifecycle transition (combines only
93
- with the positional and --quiet)
94
- --format <format> md (default) | json (queue + bundle modes)
95
- --out <path> Write the bundle to a file (bundle modes)
94
+ --format <format> md (default) | json
95
+ --out <path> Write the bundle to a file
96
96
  --strict Refuse (exit 4) a bundle for a blocked item;
97
97
  no effect with --next (it never selects
98
98
  blocked items)
99
- --no-code-nodes With --mark complete: declare this FBS as
99
+
100
+ Options (queue):
101
+ --format <format> md (default) | json
102
+
103
+ Options (mark):
104
+ --no-code-nodes With mark complete: declare this FBS as
100
105
  genuinely producing no traceable code
101
106
  (docs-only, config-only), recorded on the FBS
102
107
  and exempting it from the mark-complete CN gate
103
- --accept-block With --mark complete on a uiBearing FBS: accept
104
- a browserVerification block (or a missing record)
105
- and ship the FBS at complete. Requires --reason
106
- "..." (>= 20 chars). Records the reason on the
108
+ --accept-block With mark complete on a uiBearing FBS: accept
109
+ a browserVerification block and ship the FBS
110
+ at complete. Requires --reason "..." (>= 20
111
+ chars). Records the reason on the
107
112
  browserVerification.operatorShipDespiteBlockReason
108
113
  field. Track B ship-without-verified (spec §8.6).
109
114
  --reason "..." Reason string for --accept-block.
115
+
116
+ Global:
110
117
  --quiet Suppress non-error confirmations
111
118
  --help Print this help
112
119
 
113
- Mark-complete CN gate (D17): marking an FBS complete refuses (exit 3,
114
- missingCodeNodes) when any of its ACs carries no Code Node. Author CN
115
- coverage first, or pass --no-code-nodes for a genuinely no-code spec.
120
+ Mark-complete CN gate (D17): 'build mark <fbs-id> complete' refuses
121
+ (exit 3, missingCodeNodes) when any of its ACs carries no Code Node.
122
+ Author CN coverage first, or pass --no-code-nodes for a genuinely
123
+ no-code spec.
116
124
  `;
117
125
 
118
126
  const VALID_FORMATS = new Set(['md', 'json']);
119
127
 
120
128
  /**
121
- * @param {string[]} argv - argv slice after `build`
129
+ * @param {string[]} argv - argv slice after `build` (sub-verb-first).
122
130
  * @param {object} [deps]
123
131
  * @returns {Promise<number>}
124
132
  */
@@ -127,9 +135,71 @@ export async function main(argv, deps = {}) {
127
135
  const stderr = deps.stderr ?? process.stderr;
128
136
  const cwd = deps.cwd ?? process.cwd();
129
137
 
138
+ // Global --help before sub-verb dispatch.
139
+ if (argv[0] === '--help' || argv[0] === '-h') {
140
+ stdout.write(HELP);
141
+ return 0;
142
+ }
143
+ const subverb = argv[0];
144
+ if (!subverb) {
145
+ stdout.write(HELP);
146
+ return 0;
147
+ }
148
+ if (!['queue', 'bundle', 'mark'].includes(subverb)) {
149
+ stderr.write(`[error] usage build: unknown sub-verb '${subverb}' (expected queue | bundle | mark)\n`);
150
+ stderr.write(HELP);
151
+ return 2;
152
+ }
153
+
154
+ // Translate the sub-verb-first argv shape into the flag-based mode
155
+ // the internal implementation still consumes. The translation is
156
+ // one-way and only touches the argv layer; every internal check
157
+ // (positional discipline, flag-conflict rules, format validation)
158
+ // stays byte-identical.
159
+ //
160
+ // queue <extra-flags> -> queue mode
161
+ // bundle <fbs-id> <extra-flags> -> bundle mode
162
+ // bundle --next <extra-flags> -> next mode (bundle sub-verb)
163
+ // mark <fbs-id> <status> <extra> -> mark mode
164
+ const rest = argv.slice(1);
165
+ // `rcf build <sub-verb> --help` short-circuits to the shared HELP
166
+ // block before any sub-verb-specific positional check refuses.
167
+ if (rest.includes('--help') || rest.includes('-h')) {
168
+ stdout.write(HELP);
169
+ return 0;
170
+ }
171
+ let translated;
172
+ if (subverb === 'queue') {
173
+ // Refuse a stray positional so `rcf build queue <fbs-id>` is not silently
174
+ // treated as a bundle request.
175
+ if (rest.length > 0 && !rest[0].startsWith('-')) {
176
+ stderr.write(`[error] usage build queue: unexpected positional '${rest[0]}' (queue takes no positional)\n`);
177
+ return 2;
178
+ }
179
+ translated = rest;
180
+ } else if (subverb === 'bundle') {
181
+ // Either --next as the first token, or a positional fbs-id.
182
+ translated = rest;
183
+ } else { // mark
184
+ if (rest.length < 2) {
185
+ stderr.write('[error] usage build mark: requires <fbs-id> <status>\n');
186
+ return 2;
187
+ }
188
+ const [fbsId, status, ...tail] = rest;
189
+ if (fbsId.startsWith('-')) {
190
+ stderr.write('[error] usage build mark: first positional must be an FBS id, not a flag\n');
191
+ return 2;
192
+ }
193
+ if (status.startsWith('-')) {
194
+ stderr.write('[error] usage build mark: second positional must be a status word, not a flag\n');
195
+ return 2;
196
+ }
197
+ translated = [fbsId, '--mark', status, ...tail];
198
+ }
199
+
130
200
  let parsed;
131
201
  try {
132
- parsed = parseArgs({ args: argv, options: OPTION_SPEC, allowPositionals: true, strict: true });
202
+ parsed = parseArgs({ args: translated, options: OPTION_SPEC, allowPositionals: true, strict: true });
133
203
  } catch (err) {
134
204
  stderr.write(`[error] usage ${err.message}\n`);
135
205
  stderr.write(HELP);
@@ -150,43 +220,43 @@ export async function main(argv, deps = {}) {
150
220
  return 2;
151
221
  }
152
222
 
153
- // Mode detection + flag-conflict rules (§D1 / §D9).
223
+ // Sub-verb / flag consistency. The internal mode name below stays the
224
+ // same for readability; the sub-verb selects it deterministically.
154
225
  const usage = (message) => {
155
226
  stderr.write(`[error] usage build: ${message}\n`);
156
227
  return 2;
157
228
  };
158
- if (flags.next && positional) return usage('--next takes no positional');
159
- if (flags.mark !== undefined) {
160
- if (!positional) return usage('--mark requires an <fbs-id> positional');
161
- if (flags.next) return usage('--mark cannot combine with --next');
162
- if (flags.format !== undefined) return usage('--mark cannot combine with --format');
229
+ if (subverb === 'bundle') {
230
+ if (flags.mark !== undefined) return usage('bundle does not take --mark (use `rcf build mark`)');
231
+ if (flags.next && positional) return usage('bundle --next takes no positional');
232
+ if (!flags.next && !positional) return usage('bundle requires <fbs-id> or --next');
233
+ } else if (subverb === 'queue') {
234
+ if (flags.mark !== undefined) return usage('queue does not take --mark (use `rcf build mark`)');
235
+ if (flags.next) return usage('queue does not take --next (use `rcf build bundle --next`)');
236
+ if (positional) return usage('queue takes no positional');
237
+ if (flags.out !== undefined) return usage('--out is invalid in queue mode');
238
+ if (flags.strict) return usage('--strict applies to bundle modes only');
239
+ } else if (subverb === 'mark') {
240
+ if (!positional) return usage('mark requires an <fbs-id>');
241
+ if (flags.next) return usage('mark cannot combine with --next');
242
+ if (flags.format !== undefined) return usage('mark cannot combine with --format');
163
243
  if (flags.out !== undefined) return usage('--out is invalid in mark mode');
164
- if (flags.strict) return usage('--mark cannot combine with --strict');
244
+ if (flags.strict) return usage('mark cannot combine with --strict');
165
245
  }
166
246
  // Phase 10 (X2 CodeNode bridge, D17): --no-code-nodes only makes sense
167
247
  // declaring a spec complete with no traceable code.
168
248
  if (flags['no-code-nodes'] && flags.mark !== 'complete') {
169
- return usage('--no-code-nodes only combines with --mark complete');
249
+ return usage('--no-code-nodes only combines with `build mark <fbs-id> complete`');
170
250
  }
171
- // Track B (§8.6): --accept-block only makes sense with --mark complete
251
+ // Track B (§8.6): --accept-block only makes sense with mark complete
172
252
  // and requires --reason "...".
173
253
  if (flags['accept-block'] && flags.mark !== 'complete') {
174
- return usage('--accept-block only combines with --mark complete');
254
+ return usage('--accept-block only combines with `build mark <fbs-id> complete`');
175
255
  }
176
256
  if (flags['accept-block'] && (typeof flags.reason !== 'string' || flags.reason.length < 20)) {
177
257
  return usage('--accept-block requires --reason "..." with at least 20 characters');
178
258
  }
179
- const mode = flags.mark !== undefined
180
- ? 'mark'
181
- : flags.next
182
- ? 'next'
183
- : positional
184
- ? 'bundle'
185
- : 'queue';
186
- if (mode === 'queue') {
187
- if (flags.out !== undefined) return usage('--out is invalid in queue mode');
188
- if (flags.strict) return usage('--strict applies to bundle modes only');
189
- }
259
+ const mode = subverb === 'mark' ? 'mark' : subverb === 'queue' ? 'queue' : flags.next ? 'next' : 'bundle';
190
260
  const format = flags.format ?? 'md';
191
261
  if (!VALID_FORMATS.has(format)) {
192
262
  return usage(`unknown --format ${format} (expected md | json)`);
@@ -240,7 +310,7 @@ function classifyPositional(tree, id) {
240
310
  return rcfError({
241
311
  kind: 'usage',
242
312
  message: `build: ${id} is a user story, not an FBS id; the FBS is the queue unit. `
243
- + `To list the FBS items linked to this story: rcf trace ${id} --forward --format json`,
313
+ + `To list the FBS items linked to this story: rcf audit trace ${id} --forward --format json`,
244
314
  documentId: id,
245
315
  });
246
316
  }
@@ -308,7 +378,7 @@ async function emitNext({ tree, format, io }) {
308
378
  const unbacked = scanUnbackedServices(tree, next.fbsId);
309
379
  if (unbacked.length > 0) {
310
380
  const names = unbacked.map((u) => u.serviceId).join(', ');
311
- io.stderr.write(`[warn] build --next: ${next.fbsId} touches services not covered by any preFlightConfig (${names}); run 'rcf preflight' before Stage 4.\n`);
381
+ io.stderr.write(`[warn] build bundle --next: ${next.fbsId} touches services not covered by any preFlightConfig (${names}); run 'rcf discover preflight' before Stage 4.\n`);
312
382
  }
313
383
  // Track B (spec §4.4): always print the classifier verdict + signals
314
384
  // for the selected FBS. Transparent-by-default so a `notUi` verdict
@@ -384,7 +454,7 @@ async function runMark({ tree, projectRoot, fbsId, status, io, noCodeNodes = fal
384
454
  if (plan.to === 'inProgress') {
385
455
  const fbs = tree.byId.get(plan.fbsId);
386
456
  if (fbs?.uiBearing === true && !fbs?.designStage) {
387
- io.stderr.write(`[warn] build --mark inProgress: ${plan.fbsId} is uiBearing but has no designStage yet. Consider running 'rcf design ${plan.fbsId}' before Stage 2 build begins. Not a refusal; the hard gate fires at --mark complete.\n`);
457
+ io.stderr.write(`[warn] build mark ${plan.fbsId} inProgress: uiBearing FBS with no designStage yet. Consider running 'rcf define design ${plan.fbsId}' before Stage 2 build begins. Not a refusal; the hard gate fires at 'build mark <fbs-id> complete'.\n`);
388
458
  }
389
459
  }
390
460
 
@@ -403,8 +473,8 @@ async function runMark({ tree, projectRoot, fbsId, status, io, noCodeNodes = fal
403
473
  if (!designGate.ok) {
404
474
  io.stderr.write(`[error] refused build: ${plan.fbsId} is uiBearing but designStageComplete is not true on the FBS record.\n`
405
475
  + ' Complete the Design substage first:\n'
406
- + ` rcf design ${plan.fbsId} (dispatches the Design worker)\n`
407
- + ` rcf design ${plan.fbsId} --mark-complete (hand-authored equivalent, once all three artefacts are present)\n`);
476
+ + ` rcf define design ${plan.fbsId} (dispatches the Design worker)\n`
477
+ + ` rcf define design ${plan.fbsId} --mark-complete (hand-authored equivalent, once all three artefacts are present)\n`);
408
478
  return 4;
409
479
  }
410
480
 
@@ -430,8 +500,8 @@ async function runMark({ tree, projectRoot, fbsId, status, io, noCodeNodes = fal
430
500
  io.stderr.write(`[error] refused build: ${plan.fbsId} designStage.${disagreement.designStagePath} = ${JSON.stringify(disagreement.designValue)} conflicts with uiBaseline.defaults.${disagreement.path} = ${JSON.stringify(disagreement.baselineValue)} and there is no operatorOptOuts entry.\n`
431
501
  + ' Options:\n'
432
502
  + ` 1) Change designStage.${disagreement.designStagePath} to match the baseline.\n`
433
- + ` 2) rcf ui-baseline opt-out --field ${disagreement.path} --reason "..." (project-wide override).\n`
434
- + ` 3) rcf update ${plan.fbsId} --set designStage.${disagreement.designStagePath}=... (per-FBS override; records ack).\n`);
503
+ + ` 2) rcf discover ui-baseline opt-out --field ${disagreement.path} --reason "..." (project-wide override).\n`
504
+ + ` 3) rcf define update ${plan.fbsId} --set designStage.${disagreement.designStagePath}=... (per-FBS override; records ack).\n`);
435
505
  return 4;
436
506
  }
437
507
  }
@@ -465,19 +535,19 @@ async function runMark({ tree, projectRoot, fbsId, status, io, noCodeNodes = fal
465
535
  // ratify a real record. Two-command dance: acknowledged and
466
536
  // preferred.
467
537
  io.stderr.write(`[error] refused build: ${plan.fbsId} is uiBearing but no browserVerification record exists on the manifest.\n`
468
- + ` Run: rcf browser-verify ${plan.fbsId}\n`
538
+ + ` Run: rcf verify browser ${plan.fbsId}\n`
469
539
  + ` Then, if the resulting record is block or warn and you have decided to ship anyway, rerun with --accept-block --reason "..." on that record.\n`
470
540
  + ' (--accept-block requires an existing browserVerification record; it acknowledges a real verdict rather than skipping the gate.)\n');
471
541
  return 4;
472
542
  } else if (bvRecord.verdict === 'block' && !acceptBlock) {
473
543
  io.stderr.write(`[error] refused build: ${plan.fbsId} browserVerification ${bvRecord.id} verdict is 'block'.\n`
474
- + ' Re-run browser-verify after fixing the failures, or acknowledge with:\n'
475
- + ` rcf build ${plan.fbsId} --mark complete --accept-block --reason "..."\n`);
544
+ + ' Re-run verify browser after fixing the failures, or acknowledge with:\n'
545
+ + ` rcf build mark ${plan.fbsId} complete --accept-block --reason "..."\n`);
476
546
  return 4;
477
547
  } else if (bvRecord.verdict === 'warn' && !bvRecord.operatorAckAt) {
478
548
  io.stderr.write(`[error] refused build: ${plan.fbsId} browserVerification ${bvRecord.id} verdict is 'warn' but operatorAckAt is not set.\n`
479
549
  + ' Ack the warn verdict with:\n'
480
- + ` rcf browser-verify ${plan.fbsId} --ack\n`);
550
+ + ` rcf verify browser ${plan.fbsId} --ack\n`);
481
551
  return 4;
482
552
  }
483
553
  // Ship-without-verified: record the operator's reason on the bv
@@ -507,7 +577,7 @@ async function runMark({ tree, projectRoot, fbsId, status, io, noCodeNodes = fal
507
577
  if (!gate.ok) {
508
578
  const err = rcfError({
509
579
  kind: 'missingCodeNodes',
510
- message: `build --mark complete: refused - ${plan.fbsId} has AC(s) with no Code Node: ${gate.missingAcIds.join(', ')}. `
580
+ message: `build mark ${plan.fbsId} complete: refused - has AC(s) with no Code Node: ${gate.missingAcIds.join(', ')}. `
511
581
  + 'Author CN coverage for these ACs, or pass --no-code-nodes for a genuinely no-code (docs-only, config-only) spec.',
512
582
  documentId: plan.fbsId,
513
583
  field: 'acIds',
@@ -562,8 +632,8 @@ function emitClassifierSignal(io, tree, fbsId) {
562
632
  : ' [not yet ratified]';
563
633
  io.stderr.write(`[info] build: ui-classifier verdict=${block.verdict} reason=${block.reason} (${signalCount} signal(s))${suffix}\n`);
564
634
  if (block.verdict === 'ui' && fbs.uiBearing !== true) {
565
- io.stderr.write(` Classified as UI-bearing. Ratify with: rcf update ${fbsId} --set uiBearing=true\n`);
566
- io.stderr.write(` Override with: rcf update ${fbsId} --set uiBearing=false (if the classifier is wrong).\n`);
635
+ io.stderr.write(` Classified as UI-bearing. Ratify with: rcf define update ${fbsId} --set uiBearing=true\n`);
636
+ io.stderr.write(` Override with: rcf define update ${fbsId} --set uiBearing=false (if the classifier is wrong).\n`);
567
637
  }
568
638
  }
569
639
 
@@ -41,7 +41,7 @@ const OPTION_SPEC = {
41
41
  'require-approved': { type: 'boolean' },
42
42
  };
43
43
 
44
- export const HELP = `Usage: rcf coverage [scope-id] [options]
44
+ export const HELP = `Usage: rcf audit coverage [scope-id] [options]
45
45
 
46
46
  Report structural coverage over the REQ chain (PRD -> REQ -> US -> AC
47
47
  -> TS -> TC). A TC counts as covering its AC only when its testPointer
package/src/cli/create.js CHANGED
@@ -39,7 +39,7 @@ const OPTION_SPEC = {
39
39
  'derive-deps': { type: 'boolean' },
40
40
  };
41
41
 
42
- export const HELP = `Usage: rcf create <kind> [options]
42
+ export const HELP = `Usage: rcf define create <kind> [options]
43
43
 
44
44
  Kinds: req | us | ac | tac | adr | fbs | ts | tc | cn
45
45
 
@@ -158,7 +158,7 @@ export async function main(argv, deps = {}) {
158
158
  // repairing a broken tree is possible while net-new breakage is still
159
159
  // refused.
160
160
  if (walkResult.errors.length > 0) {
161
- stderr.write(`[warn] tree has ${walkResult.errors.length} pre-existing issue(s); proceeding - writes are validated against the post-write state (run 'rcf validate' for details)\n`);
161
+ stderr.write(`[warn] tree has ${walkResult.errors.length} pre-existing issue(s); proceeding - writes are validated against the post-write state (run 'rcf define validate' for details)\n`);
162
162
  }
163
163
 
164
164
  let fileBody = null;
@@ -304,7 +304,7 @@ export async function main(argv, deps = {}) {
304
304
  if (open.length > 0 && !flags.quiet) {
305
305
  const keys = open.map((c) => c.baselineKey).join(', ');
306
306
  stdout.write(`${result.id} has ${open.length} open baseline candidate${open.length === 1 ? '' : 's'}: ${keys}\n`);
307
- stdout.write(` Resolve: rcf req-baseline sweep --req ${usDoc.reqId}\n`);
307
+ stdout.write(` Resolve: rcf discover req-baseline sweep --req ${usDoc.reqId}\n`);
308
308
  }
309
309
  }
310
310
  } catch (err) {
package/src/cli/delete.js CHANGED
@@ -15,7 +15,7 @@ const OPTION_SPEC = {
15
15
  help: { type: 'boolean' },
16
16
  };
17
17
 
18
- export const HELP = `Usage: rcf delete <id> [options]
18
+ export const HELP = `Usage: rcf define delete <id> [options]
19
19
 
20
20
  Options:
21
21
  --cascade Also delete dependents and drop backrefs
@@ -64,7 +64,7 @@ export async function main(argv, deps = {}) {
64
64
  // the canonical repair. The writer gates on the POST-write tree state;
65
65
  // only net-new breakage refuses.
66
66
  if (walkResult.errors.length > 0) {
67
- stderr.write(`[warn] tree has ${walkResult.errors.length} pre-existing issue(s); proceeding - writes are validated against the post-write state (run 'rcf validate' for details)\n`);
67
+ stderr.write(`[warn] tree has ${walkResult.errors.length} pre-existing issue(s); proceeding - writes are validated against the post-write state (run 'rcf define validate' for details)\n`);
68
68
  }
69
69
 
70
70
  const result = await deleteDocument({
package/src/cli/design.js CHANGED
@@ -68,19 +68,19 @@ const OPTION_SPEC = {
68
68
  help: { type: 'boolean' },
69
69
  };
70
70
 
71
- export const HELP = `Usage: rcf design <fbs-id> [<sub-verb> ...] [options]
71
+ export const HELP = `Usage: rcf define design <fbs-id> [<sub-verb> ...] [options]
72
72
 
73
73
  Design substage verbs for a UI-bearing FBS. FBS positional is required
74
74
  and must match /^FBS-\\d+$/ (any other positional in that slot is a
75
75
  usage error, not an FBS lookup miss).
76
76
 
77
77
  Verb shapes:
78
- rcf design <fbs-id> Print the current design
78
+ rcf define design <fbs-id> Print the current design
79
79
  state and next-move options.
80
- rcf design <fbs-id> journeys add ... Append a journey.
81
- rcf design <fbs-id> nav set ... Overwrite navModel.
82
- rcf design <fbs-id> theme-a11y set ... Overwrite themeAndA11y.
83
- rcf design <fbs-id> --mark-complete Set designStageComplete: true.
80
+ rcf define design <fbs-id> journeys add ... Append a journey.
81
+ rcf define design <fbs-id> nav set ... Overwrite navModel.
82
+ rcf define design <fbs-id> theme-a11y set ... Overwrite themeAndA11y.
83
+ rcf define design <fbs-id> --mark-complete Set designStageComplete: true.
84
84
 
85
85
  journeys add options:
86
86
  --id <slug> Lowercase slug (a-z0-9-), unique within the FBS.
@@ -177,11 +177,11 @@ export async function main(argv, deps = {}) {
177
177
  return 2;
178
178
  }
179
179
  if (fbs.uiBearing !== true) {
180
- stderr.write(`[warn] design: ${fbsId} is not uiBearing (fbs.uiBearing is ${JSON.stringify(fbs.uiBearing)}); the Design substage is a no-op for non-UI FBS. Set uiBearing=true first (see 'rcf ui-classify ${fbsId}').\n`);
180
+ stderr.write(`[warn] design: ${fbsId} is not uiBearing (fbs.uiBearing is ${JSON.stringify(fbs.uiBearing)}); the Design substage is a no-op for non-UI FBS. Set uiBearing=true first (see 'rcf discover ui-classify ${fbsId}').\n`);
181
181
  }
182
182
  // Refuse Design substage writes when the baseline is missing (§6.2).
183
183
  if (fbs.uiBearing === true && !tree.manifest?.uiBaseline && subs.length > 0) {
184
- stderr.write(`[error] refused: ${fbsId} is uiBearing but no uiBaseline record exists on the manifest. Run: rcf ui-baseline init\n`);
184
+ stderr.write(`[error] refused: ${fbsId} is uiBearing but no uiBaseline record exists on the manifest. Run: rcf discover ui-baseline init\n`);
185
185
  return 4;
186
186
  }
187
187
 
@@ -229,11 +229,11 @@ function runShow({ tree, fbs, fbsId, stdout, flags }) {
229
229
  if (missing.length > 0) {
230
230
  stdout.write(` next: author the missing artefact(s): ${missing.join(', ')}\n`);
231
231
  } else if (fbs.designStageComplete !== true) {
232
- stdout.write(' next: rcf design ' + fbsId + ' --mark-complete\n');
232
+ stdout.write(' next: rcf define design ' + fbsId + ' --mark-complete\n');
233
233
  }
234
234
  const baseline = tree.manifest?.uiBaseline;
235
235
  if (fbs.uiBearing === true && !baseline) {
236
- stdout.write(' refused (once you begin authoring): rcf ui-baseline init must run first.\n');
236
+ stdout.write(' refused (once you begin authoring): rcf discover ui-baseline init must run first.\n');
237
237
  }
238
238
  return 0;
239
239
  }
package/src/cli/fbs.js CHANGED
@@ -30,7 +30,7 @@ const DEPENDS_ON_OPTION_SPEC = {
30
30
  help: { type: 'boolean' },
31
31
  };
32
32
 
33
- export const HELP = `Usage: rcf fbs <fbs-id> <verb> [options]
33
+ export const HELP = `Usage: rcf build fbs <fbs-id> <verb> [options]
34
34
 
35
35
  Verbs:
36
36
  depends-on Record a third-party service dependency on this FBS
@@ -78,21 +78,23 @@ const OPTION_SPEC = {
78
78
  help: { type: 'boolean' },
79
79
  };
80
80
 
81
- export const HELP = `Usage: rcf finalise <fbs-id> --url <deploy-url> [options]
81
+ export const HELP = `Usage: rcf build finalise <fbs-id> --url <deploy-url> [options]
82
82
 
83
- The ship gate. Promotes an FBS at status complete to verified ONLY when an
84
- independent rcf-verify run passes AND carries ship authority.
83
+ The ship gate. Promotes an FBS at status complete to verified ONLY when
84
+ an independent 'rcf verify run' passes AND carries ship authority.
85
85
 
86
- rcf-verify is launched as a FRESH SUBPROCESS (never in-process) so the
87
- verifier agent starts cold, with zero build context - its only inputs are the
88
- RCF chain (the acceptance contract) and the live URL. The gate is the
89
- subprocess exit code AND the report's ship authority: a run must both pass and
90
- carry SHIP authority (a 'deployed'-profile run, or a 'ci'/'local-dev' run with
91
- --parity-env) to promote. A correctness-only PASS holds without promoting.
92
- Findings flow back via the --out report file.
86
+ The verify run is launched as a FRESH SUBPROCESS (never in-process) so
87
+ the verifier agent starts cold, with zero build context - its only
88
+ inputs are the RCF chain (the acceptance contract) and the live URL.
89
+ The gate is the subprocess exit code AND the report's ship authority:
90
+ a run must both pass and carry SHIP authority (a 'deployed'-profile
91
+ run, or a 'ci'/'local-dev' run with --parity-env) to promote. A
92
+ correctness-only PASS holds without promoting. Findings flow back via
93
+ the --out report file.
93
94
 
94
- If rcf-verify is not installed, finalise PROMPTS to install it (install-together
95
- posture) - it never silently skips the gate. Off a TTY, pass --install-verify.
95
+ If rcf-lite is not installed, finalise PROMPTS to install it (install-
96
+ together posture) - it never silently skips the gate. Off a TTY, pass
97
+ --install-verify.
96
98
 
97
99
  Required:
98
100
  <fbs-id> The FBS item to finalise (must be 'complete')
@@ -110,7 +112,7 @@ Options:
110
112
  (default: ${DEFAULT_REPORT})
111
113
  --chain <PRD/ref> Which PRD/chain to verify against (default: repo's)
112
114
  --persona <name> Adversarial persona flavour
113
- --install-verify If rcf-verify is absent, install it without
115
+ --install-verify If rcf-lite is absent, install it without
114
116
  prompting (the sanctioned non-interactive path)
115
117
  --ship-without-verified Acknowledge MOCK-ONLY-DECLARED /
116
118
  BLOCKED-BY-DECLARATION per-AC verdicts on
@@ -130,7 +132,7 @@ Exit codes:
130
132
  2 usage error (bad flags, unknown / non-FBS id)
131
133
  3 schema validation or broken references (tree unreadable, or write refused)
132
134
  4 gate NOT passed - verify blocked ship, OR verify passed but the run lacks
133
- ship authority (a correctness-only HOLD), OR rcf-verify absent and install
135
+ ship authority (a correctness-only HOLD), OR rcf-lite absent and install
134
136
  declined/unavailable - the FBS is left unchanged, findings surfaced
135
137
  `;
136
138
 
@@ -210,7 +212,7 @@ export async function main(argv, deps = {}) {
210
212
  const currentStatus = fbs.executionStatus;
211
213
  if (!FINALISABLE_STATUSES.has(currentStatus)) {
212
214
  stderr.write(`[error] refused finalise: ${fbsId} is '${currentStatus}'; the finalise gate promotes 'complete' -> 'verified'. `
213
- + `Mark it complete first: rcf build ${fbsId} --mark complete\n`);
215
+ + `Mark it complete first: rcf build mark ${fbsId} complete\n`);
214
216
  return 4;
215
217
  }
216
218
 
@@ -237,7 +239,7 @@ export async function main(argv, deps = {}) {
237
239
  ? await deps.detectVerify({ cwd: projectRoot })
238
240
  : await detectVerify({ cwd: projectRoot });
239
241
  if (!detection.installed) {
240
- stderr.write('[error] unexpected rcf-verify still not resolvable after install; install it manually and re-run.\n');
242
+ stderr.write('[error] unexpected the rcf bin still not resolvable after install; install it manually and re-run.\n');
241
243
  return 1;
242
244
  }
243
245
  }
@@ -257,7 +259,7 @@ export async function main(argv, deps = {}) {
257
259
  });
258
260
 
259
261
  if (!quiet) {
260
- stdout.write(`[finalise] launching rcf-verify (fresh subprocess) against ${flags.url} [profile=${profile}]...\n`);
262
+ stdout.write(`[finalise] launching rcf verify run (fresh subprocess) against ${flags.url} [profile=${profile}]...\n`);
261
263
  }
262
264
 
263
265
  let spawnResult;
@@ -267,7 +269,7 @@ export async function main(argv, deps = {}) {
267
269
  : await spawnVerify({ invocation: detection.invocation, verifyArgs, cwd: projectRoot }, deps);
268
270
  } catch (err) {
269
271
  writeUnexpectedFailure(
270
- rcfError({ kind: 'ioFailure', message: `finalise: could not launch rcf-verify: ${err.message}`, stack: err.stack }),
272
+ rcfError({ kind: 'ioFailure', message: `finalise: could not launch rcf verify: ${err.message}`, stack: err.stack }),
271
273
  stderr,
272
274
  );
273
275
  return 1;
@@ -293,7 +295,7 @@ export async function main(argv, deps = {}) {
293
295
  const passLoaded = await (deps.loadReport ? deps.loadReport(outPath, deps) : loadReport(outPath, deps));
294
296
  const authority = passLoaded.ok ? passLoaded.report.verdictAuthority : undefined;
295
297
  if (authority !== 'ship') {
296
- stderr.write(`[finalise] HOLD: rcf-verify passed but this run carries '${authority ?? 'unknown'}' authority, `
298
+ stderr.write(`[finalise] HOLD: rcf verify passed but this run carries '${authority ?? 'unknown'}' authority, `
297
299
  + `not 'ship'; ${fbsId} left '${currentStatus}'.\n`);
298
300
  stderr.write('Only a \'deployed\'-profile run - or a \'ci\'/\'local-dev\' run with --parity-env asserting the '
299
301
  + 'runtime is edge-identical to prod - carries ship authority and can promote to verified. '
@@ -359,7 +361,7 @@ export async function main(argv, deps = {}) {
359
361
 
360
362
  // Gate NOT passed. The FBS stays put; surface the findings from the report
361
363
  // (the §5.4 verify -> fix -> re-verify seam), then fail non-zero.
362
- stderr.write(`[finalise] gate NOT passed (rcf-verify exit ${spawnResult.code}); ${fbsId} left '${currentStatus}'.\n`);
364
+ stderr.write(`[finalise] gate NOT passed (rcf verify exit ${spawnResult.code}); ${fbsId} left '${currentStatus}'.\n`);
363
365
  const loaded = await (deps.loadReport ? deps.loadReport(outPath, deps) : loadReport(outPath, deps));
364
366
  if (loaded.ok) {
365
367
  stderr.write(summariseReport(loaded.report));