@orkestrel/brief 0.0.6 → 0.0.8

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.
@@ -4,7 +4,13 @@ let _orkestrel_interpret = require("@orkestrel/interpret");
4
4
  let _orkestrel_reason = require("@orkestrel/reason");
5
5
  let _orkestrel_emitter = require("@orkestrel/emitter");
6
6
  //#region src/core/constants.ts
7
- /** The twelve `TaskOperation` values, frozen. */
7
+ /**
8
+ * Lists the `TaskOperation` values, frozen.
9
+ *
10
+ * @remarks
11
+ * Compose the tuple rather than restating its members: `literalOf(TASK_OPERATIONS)` builds the
12
+ * guard and `parseEnum(value, TASK_OPERATIONS)` coerces a bare value against it.
13
+ */
8
14
  var TASK_OPERATIONS = Object.freeze([
9
15
  "create",
10
16
  "refactor",
@@ -19,7 +25,7 @@ var TASK_OPERATIONS = Object.freeze([
19
25
  "document",
20
26
  "plan"
21
27
  ]);
22
- /** The eight `TaskDomain` values, frozen. */
28
+ /** Lists the `TaskDomain` values, frozen. */
23
29
  var TASK_DOMAINS = Object.freeze([
24
30
  "code",
25
31
  "writing",
@@ -30,7 +36,7 @@ var TASK_DOMAINS = Object.freeze([
30
36
  "ops",
31
37
  "other"
32
38
  ]);
33
- /** The five `OutputFormat` values, frozen. */
39
+ /** Lists the `OutputFormat` values, frozen. */
34
40
  var OUTPUT_FORMATS = Object.freeze([
35
41
  "markdown",
36
42
  "json",
@@ -38,14 +44,14 @@ var OUTPUT_FORMATS = Object.freeze([
38
44
  "diff",
39
45
  "prose"
40
46
  ]);
41
- /** The three `RiskSeverity` values, frozen. */
47
+ /** Lists the `RiskSeverity` values, frozen. */
42
48
  var RISK_SEVERITIES = Object.freeze([
43
49
  "low",
44
50
  "medium",
45
51
  "high"
46
52
  ]);
47
53
  /**
48
- * Every published `Interpretation` member name, frozen.
54
+ * Lists every published `Interpretation` member name, frozen.
49
55
  *
50
56
  * @remarks
51
57
  * The capture list `BriefCompiler` hands `captureValue` at each interpret door — the borrowed
@@ -70,33 +76,32 @@ var INTERPRETATION_MEMBERS = Object.freeze([
70
76
  "prompt",
71
77
  "stages",
72
78
  "failures",
73
- "complete",
74
79
  "confidence",
75
80
  "digest"
76
81
  ]);
77
82
  /**
78
- * `16` — the default turn cap `briefToGoal` renders.
83
+ * Holds `16` — the default turn cap `briefToGoal` renders.
79
84
  *
80
85
  * @remarks
81
86
  * Domain-qualified so the barrel stays collision-free as sibling modules add their own
82
87
  * turn defaults.
83
88
  */
84
89
  var DEFAULT_BRIEF_TURNS = 16;
85
- /** `'gate'` — the id of the `gateDefinition()` logical definition. */
90
+ /** Holds `'gate'` — the id of the `buildGateDefinition()` logical definition. */
86
91
  var GATE_ID = "gate";
87
92
  /**
88
- * Every line terminator a brief field refuses.
93
+ * Matches every line terminator a brief field refuses.
89
94
  *
90
95
  * @remarks
91
- * The four ECMAScript line terminators, not just `\n`: a renderer that splits on any of
92
- * them would let the other three forge a markdown row. CRLF leads the alternation so a
93
- * Windows exemplar splits as ONE break rather than two, which would insert a blank line the
94
- * caller never wrote. Kept unanchored and stateless — no `g` flag — so `test` never carries
96
+ * Every ECMAScript line terminator, not only `\n`: a renderer that splits on any of them
97
+ * would let the others forge a markdown row. CRLF leads the alternation so a Windows
98
+ * exemplar splits as ONE break rather than two, which would insert a blank line the caller
99
+ * never wrote. Kept unanchored and stateless — no `g` flag — so `test` never carries
95
100
  * `lastIndex` between calls.
96
101
  */
97
102
  var LINE_BREAK_PATTERN = /\r\n|[\n\r\u2028\u2029]/;
98
103
  /**
99
- * The positive form of {@link LINE_BREAK_PATTERN}, for the shape DSL.
104
+ * Holds the positive form of {@link LINE_BREAK_PATTERN}, for a `stringShape` `pattern`.
100
105
  *
101
106
  * @remarks
102
107
  * `stringShape`'s `pattern` must MATCH an accepted value, so the guard's refusal regex
@@ -105,7 +110,7 @@ var LINE_BREAK_PATTERN = /\r\n|[\n\r\u2028\u2029]/;
105
110
  */
106
111
  var SINGLE_LINE_PATTERN = /^[^\n\r\u2028\u2029]*$/;
107
112
  /**
108
- * A string of one or more spaces and nothing else.
113
+ * Matches a string of one or more spaces and nothing else.
109
114
  *
110
115
  * @remarks
111
116
  * The one exemplar side `exampleToLines` must NOT pad. CommonMark strips a fully-blank code
@@ -119,9 +124,12 @@ var BLANK_PATTERN = /^ +$/;
119
124
  //#endregion
120
125
  //#region src/core/errors.ts
121
126
  /**
122
- * The one error class this package throws.
127
+ * Represents the one error class this package throws.
123
128
  *
124
129
  * @remarks
130
+ * Extends `Error` with a readonly `code` on the `BriefErrorCode` vocabulary and an optional
131
+ * readonly `context` record carrying whatever the raising site can supply.
132
+ *
125
133
  * Throws are reserved for caller misuse: `assertBrief`, `snapshotBrief`, and `pinBrief` on
126
134
  * off-contract data throw `INVALID`; any method after `destroy()` throws `DESTROYED`; and `BriefCompiler.gate` throws
127
135
  * `GATE_FAILED` when a borrowed reasoner returns a non-logical result. A stage that fails
@@ -149,10 +157,10 @@ var BriefError = class extends Error {
149
157
  }
150
158
  };
151
159
  /**
152
- * Narrow a caught value to a {@link BriefError}.
160
+ * Narrows a caught value to a {@link BriefError}.
153
161
  *
154
162
  * @param value - The caught value to inspect.
155
- * @returns `true` when `value` is a `BriefError`.
163
+ * @returns True if `value` is a `BriefError`; false otherwise.
156
164
  *
157
165
  * @example
158
166
  * ```ts
@@ -170,82 +178,100 @@ function isBriefError(value) {
170
178
  }
171
179
  //#endregion
172
180
  //#region src/core/shapers.ts
173
- /** A single-line string of any length, including empty. */
181
+ /** Describes a single-line string of any length, including empty — the shape mirror of `isText`. */
174
182
  var textShape = (0, _orkestrel_contract.stringShape)({ pattern: SINGLE_LINE_PATTERN });
175
- /** A non-empty single-line string — the shape mirror of `isLine`. */
183
+ /** Describes a non-empty single-line string — the shape mirror of `isLine`. */
176
184
  var lineShape = (0, _orkestrel_contract.stringShape)({
177
185
  min: 1,
178
186
  pattern: SINGLE_LINE_PATTERN
179
187
  });
180
- /** The `Task` shape — closed operation and domain vocabularies plus a non-empty statement. */
188
+ /**
189
+ * Describes the `Task` shape — closed operation and domain vocabularies plus a non-empty
190
+ * statement.
191
+ *
192
+ * @remarks
193
+ * `literalShape(TASK_OPERATIONS)` and `literalShape(TASK_DOMAINS)` compile the same tuples the
194
+ * guards read, and `statement` carries `min: 1`.
195
+ */
181
196
  var taskShape = (0, _orkestrel_contract.objectShape)({
182
197
  operation: (0, _orkestrel_contract.literalShape)(TASK_OPERATIONS),
183
198
  domain: (0, _orkestrel_contract.literalShape)(TASK_DOMAINS),
184
199
  statement: lineShape
185
200
  }, { description: "What the brief asks for, in one imperative sentence." });
186
- /** The `Reference` shape — a path and the note that justifies listing it. */
201
+ /** Describes the `Reference` shape — a path and the note that justifies listing it. */
187
202
  var referenceShape = (0, _orkestrel_contract.objectShape)({
188
203
  path: lineShape,
189
204
  note: lineShape
190
205
  }, { description: "One referenced path and why it is listed." });
191
- /** The `Manifest` shape — four disjoint reference partitions. */
206
+ /**
207
+ * Describes the `Manifest` shape — disjoint reference partitions.
208
+ *
209
+ * @remarks
210
+ * Each partition is an `arrayShape(referenceShape)`; disjointness is `validateBrief`'s pass
211
+ * rather than the shape's.
212
+ */
192
213
  var manifestShape = (0, _orkestrel_contract.objectShape)({
193
214
  read: (0, _orkestrel_contract.arrayShape)(referenceShape),
194
215
  edit: (0, _orkestrel_contract.arrayShape)(referenceShape),
195
216
  locked: (0, _orkestrel_contract.arrayShape)(referenceShape),
196
217
  forbidden: (0, _orkestrel_contract.arrayShape)(referenceShape)
197
- }, { description: "The four disjoint file partitions of a brief." });
198
- /** The `Outcome` shape — a one-based rank, the result text, and whether it gates done. */
218
+ }, { description: "The disjoint file partitions of a brief." });
219
+ /**
220
+ * Describes the `Outcome` shape — a one-based rank, the result text, and whether it gates done.
221
+ *
222
+ * @remarks
223
+ * `rank` is an `integerShape({ min: 1 })`, so a zero or fractional rank is off-contract.
224
+ */
199
225
  var outcomeShape = (0, _orkestrel_contract.objectShape)({
200
226
  rank: (0, _orkestrel_contract.integerShape)({ min: 1 }),
201
227
  text: lineShape,
202
228
  required: (0, _orkestrel_contract.booleanShape)()
203
229
  }, { description: "One ranked outcome — a result, never a step." });
204
- /** The `Given` shape — one categorized context fact. */
230
+ /** Describes the `Given` shape — one categorized context fact. */
205
231
  var givenShape = (0, _orkestrel_contract.objectShape)({
206
232
  category: lineShape,
207
233
  name: lineShape,
208
234
  value: textShape
209
235
  }, { description: "One context fact handed to the executor." });
210
- /** The `Example` shape — one input to output exemplar. */
236
+ /** Describes the `Example` shape — one input to output exemplar. */
211
237
  var exampleShape = (0, _orkestrel_contract.objectShape)({
212
238
  input: (0, _orkestrel_contract.stringShape)({ min: 1 }),
213
239
  output: (0, _orkestrel_contract.stringShape)({ min: 1 }),
214
240
  note: (0, _orkestrel_contract.optionalShape)(lineShape)
215
241
  }, { description: "One input to output exemplar." });
216
- /** The `Citation` shape — a name, a locator, and why the source is cited. */
242
+ /** Describes the `Citation` shape — a name, a locator, and why the source is cited. */
217
243
  var citationShape = (0, _orkestrel_contract.objectShape)({
218
244
  name: lineShape,
219
245
  url: lineShape,
220
246
  note: lineShape
221
247
  }, { description: "One external source; list order is the trust order." });
222
- /** The `Gap` shape — an unknown, whether it blocks, and the candidates that would close it. */
248
+ /** Describes the `Gap` shape — an unknown, whether it blocks, and the candidates that would close it. */
223
249
  var gapShape = (0, _orkestrel_contract.objectShape)({
224
250
  field: lineShape,
225
251
  question: lineShape,
226
252
  blocking: (0, _orkestrel_contract.booleanShape)(),
227
253
  candidates: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.arrayShape)(lineShape))
228
254
  }, { description: "One unresolved decision; blocking means the gate fails closed." });
229
- /** The `Risk` shape — a closed severity, the risk, and its mitigation. */
255
+ /** Describes the `Risk` shape — a closed severity, the risk, and its mitigation. */
230
256
  var riskShape = (0, _orkestrel_contract.objectShape)({
231
257
  severity: (0, _orkestrel_contract.literalShape)(RISK_SEVERITIES),
232
258
  text: lineShape,
233
259
  mitigation: lineShape
234
260
  }, { description: "One pre-empted risk and the mitigation that answers it." });
235
- /** The `Output` shape — a closed format plus its optional refinements. */
261
+ /** Describes the `Output` shape — a closed format plus its optional refinements. */
236
262
  var outputShape = (0, _orkestrel_contract.objectShape)({
237
263
  format: (0, _orkestrel_contract.literalShape)(OUTPUT_FORMATS),
238
264
  sections: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.arrayShape)(lineShape)),
239
265
  include: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.arrayShape)(lineShape)),
240
266
  exclude: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.arrayShape)(lineShape))
241
267
  }, { description: "The closed shape of the deliverable." });
242
- /** The `Proof` shape — the claim and the command that settles it. */
268
+ /** Describes the `Proof` shape — the claim and the command that settles it. */
243
269
  var proofShape = (0, _orkestrel_contract.objectShape)({
244
270
  text: lineShape,
245
271
  command: lineShape
246
272
  }, { description: "One mechanical, transcript-provable check." });
247
273
  /**
248
- * The whole `Brief` shape, section shapes composed.
274
+ * Describes the whole `Brief` shape, section shapes composed.
249
275
  *
250
276
  * @remarks
251
277
  * `trace` and `hash` are optional because `pinBrief` fills them; an unpinned draft is
@@ -272,40 +298,86 @@ var briefShape = (0, _orkestrel_contract.objectShape)({
272
298
  //#endregion
273
299
  //#region src/core/validators.ts
274
300
  /**
275
- * `true` when the value is a string holding no line terminator, empty included.
301
+ * Checks whether the value is a string holding no line terminator, empty included.
276
302
  *
277
303
  * @remarks
278
304
  * `briefToMarkdown` renders each brief field as ONE markdown row, so a field carrying a
279
305
  * line break would forge a heading or an extra manifest row — which is how a rendered
280
306
  * prompt and `briefToDispatch`'s path sets could disagree about the same brief.
307
+ *
308
+ * @param value - The value to inspect.
309
+ * @returns True if `value` is a string holding no line terminator, empty included; false
310
+ * otherwise.
281
311
  */
282
312
  var isText = (value) => (0, _orkestrel_contract.isString)(value) && !LINE_BREAK_PATTERN.test(value);
283
- /** `true` when the value is a non-empty string holding no line terminator. */
313
+ /**
314
+ * Checks whether the value is a non-empty string holding no line terminator.
315
+ *
316
+ * @remarks
317
+ * The shape of nearly every brief field: a path, a note, a statement, a rule, and a command
318
+ * all narrow through it.
319
+ *
320
+ * @param value - The value to inspect.
321
+ * @returns True if `value` is a non-empty string holding no line terminator; false otherwise.
322
+ */
284
323
  var isLine = (0, _orkestrel_contract.andOf)(_orkestrel_contract.isNonEmptyString, isText);
285
- /** `true` when the value is one of the twelve `TaskOperation` literals. */
324
+ /**
325
+ * Checks whether the value is one of the `TaskOperation` literals.
326
+ *
327
+ * @param value - The value to inspect.
328
+ * @returns True if `value` is one of the `TaskOperation` literals; false otherwise.
329
+ */
286
330
  var isTaskOperation = (0, _orkestrel_contract.literalOf)(TASK_OPERATIONS);
287
- /** `true` when the value is one of the eight `TaskDomain` literals. */
331
+ /**
332
+ * Checks whether the value is one of the `TaskDomain` literals.
333
+ *
334
+ * @param value - The value to inspect.
335
+ * @returns True if `value` is one of the `TaskDomain` literals; false otherwise.
336
+ */
288
337
  var isTaskDomain = (0, _orkestrel_contract.literalOf)(TASK_DOMAINS);
289
- /** `true` when the value is one of the five `OutputFormat` literals. */
338
+ /**
339
+ * Checks whether the value is one of the `OutputFormat` literals.
340
+ *
341
+ * @param value - The value to inspect.
342
+ * @returns True if `value` is one of the `OutputFormat` literals; false otherwise.
343
+ */
290
344
  var isOutputFormat = (0, _orkestrel_contract.literalOf)(OUTPUT_FORMATS);
291
- /** `true` when the value is one of the three `RiskSeverity` literals. */
345
+ /**
346
+ * Checks whether the value is one of the `RiskSeverity` literals.
347
+ *
348
+ * @param value - The value to inspect.
349
+ * @returns True if `value` is one of the `RiskSeverity` literals; false otherwise.
350
+ */
292
351
  var isRiskSeverity = (0, _orkestrel_contract.literalOf)(RISK_SEVERITIES);
293
- /** `true` when the value is a well-formed `Task` — both vocabularies closed, statement one line. */
352
+ /**
353
+ * Checks whether the value is a well-formed `Task` — both vocabularies closed, statement one line.
354
+ *
355
+ * @param value - The value to inspect.
356
+ * @returns True if `value` is a well-formed `Task`; false otherwise.
357
+ */
294
358
  var isTask = (0, _orkestrel_contract.recordOf)({
295
359
  operation: isTaskOperation,
296
360
  domain: isTaskDomain,
297
361
  statement: isLine
298
362
  });
299
- /** `true` when the value is a well-formed `Reference` — both members required, both single-line. */
363
+ /**
364
+ * Checks whether the value is a well-formed `Reference` — both members required, both single-line.
365
+ *
366
+ * @param value - The value to inspect.
367
+ * @returns True if `value` is a well-formed `Reference`; false otherwise.
368
+ */
300
369
  var isReference = (0, _orkestrel_contract.recordOf)({
301
370
  path: isLine,
302
371
  note: isLine
303
372
  });
304
373
  /**
305
- * `true` when the value is a well-formed `Manifest`.
374
+ * Checks whether the value is a well-formed `Manifest`.
306
375
  *
307
376
  * @remarks
308
377
  * Partition presence only — disjointness is `validateBrief`'s semantic pass.
378
+ *
379
+ * @param value - The value to inspect.
380
+ * @returns True if `value` is a well-formed `Manifest`; false otherwise.
309
381
  */
310
382
  var isManifest = (0, _orkestrel_contract.recordOf)({
311
383
  read: (0, _orkestrel_contract.arrayOf)(isReference),
@@ -313,50 +385,83 @@ var isManifest = (0, _orkestrel_contract.recordOf)({
313
385
  locked: (0, _orkestrel_contract.arrayOf)(isReference),
314
386
  forbidden: (0, _orkestrel_contract.arrayOf)(isReference)
315
387
  });
316
- /** `true` when the value is a well-formed `Outcome` — `rank` a positive integer. */
388
+ /**
389
+ * Checks whether the value is a well-formed `Outcome` — `rank` a positive integer.
390
+ *
391
+ * @param value - The value to inspect.
392
+ * @returns True if `value` is a well-formed `Outcome`; false otherwise.
393
+ */
317
394
  var isOutcome = (0, _orkestrel_contract.recordOf)({
318
395
  rank: (0, _orkestrel_contract.andOf)(_orkestrel_contract.isInteger, (0, _orkestrel_contract.boundsOf)(1)),
319
396
  text: isLine,
320
397
  required: _orkestrel_contract.isBoolean
321
398
  });
322
- /** `true` when the value is a well-formed `Given` — `value` may be empty but stays one line. */
399
+ /**
400
+ * Checks whether the value is a well-formed `Given` — its `value` may be empty but stays one line.
401
+ *
402
+ * @param value - The value to inspect.
403
+ * @returns True if `value` is a well-formed `Given`; false otherwise.
404
+ */
323
405
  var isGiven = (0, _orkestrel_contract.recordOf)({
324
406
  category: isLine,
325
407
  name: isLine,
326
408
  value: isText
327
409
  });
328
410
  /**
329
- * `true` when the value is a well-formed `Example`.
411
+ * Checks whether the value is a well-formed `Example`.
330
412
  *
331
413
  * @remarks
332
414
  * An exemplar's two sides are the ONLY members a brief lets span lines, because they
333
415
  * carry code. `briefToMarkdown` fences them rather than rendering them as a row.
416
+ *
417
+ * @param value - The value to inspect.
418
+ * @returns True if `value` is a well-formed `Example`; false otherwise.
334
419
  */
335
420
  var isExample = (0, _orkestrel_contract.recordOf)({
336
421
  input: _orkestrel_contract.isNonEmptyString,
337
422
  output: _orkestrel_contract.isNonEmptyString,
338
423
  note: isLine
339
424
  }, ["note"]);
340
- /** `true` when the value is a well-formed `Citation` — all three members single-line. */
425
+ /**
426
+ * Checks whether the value is a well-formed `Citation` — every member single-line.
427
+ *
428
+ * @param value - The value to inspect.
429
+ * @returns True if `value` is a well-formed `Citation`; false otherwise.
430
+ */
341
431
  var isCitation = (0, _orkestrel_contract.recordOf)({
342
432
  name: isLine,
343
433
  url: isLine,
344
434
  note: isLine
345
435
  });
346
- /** `true` when the value is a well-formed `Gap`. */
436
+ /**
437
+ * Checks whether the value is a well-formed `Gap`.
438
+ *
439
+ * @param value - The value to inspect.
440
+ * @returns True if `value` is a well-formed `Gap`; false otherwise.
441
+ */
347
442
  var isGap = (0, _orkestrel_contract.recordOf)({
348
443
  field: isLine,
349
444
  question: isLine,
350
445
  blocking: _orkestrel_contract.isBoolean,
351
446
  candidates: (0, _orkestrel_contract.arrayOf)(isLine)
352
447
  }, ["candidates"]);
353
- /** `true` when the value is a well-formed `Risk` — `severity` on the closed vocabulary. */
448
+ /**
449
+ * Checks whether the value is a well-formed `Risk` — `severity` on the closed vocabulary.
450
+ *
451
+ * @param value - The value to inspect.
452
+ * @returns True if `value` is a well-formed `Risk`; false otherwise.
453
+ */
354
454
  var isRisk = (0, _orkestrel_contract.recordOf)({
355
455
  severity: isRiskSeverity,
356
456
  text: isLine,
357
457
  mitigation: isLine
358
458
  });
359
- /** `true` when the value is a well-formed `Output` — `format` on the closed vocabulary. */
459
+ /**
460
+ * Checks whether the value is a well-formed `Output` — `format` on the closed vocabulary.
461
+ *
462
+ * @param value - The value to inspect.
463
+ * @returns True if `value` is a well-formed `Output`; false otherwise.
464
+ */
360
465
  var isOutput = (0, _orkestrel_contract.recordOf)({
361
466
  format: isOutputFormat,
362
467
  sections: (0, _orkestrel_contract.arrayOf)(isLine),
@@ -367,17 +472,25 @@ var isOutput = (0, _orkestrel_contract.recordOf)({
367
472
  "include",
368
473
  "exclude"
369
474
  ]);
370
- /** `true` when the value is a well-formed `Proof`. */
475
+ /**
476
+ * Checks whether the value is a well-formed `Proof`.
477
+ *
478
+ * @param value - The value to inspect.
479
+ * @returns True if `value` is a well-formed `Proof`; false otherwise.
480
+ */
371
481
  var isProof = (0, _orkestrel_contract.recordOf)({
372
482
  text: isLine,
373
483
  command: isLine
374
484
  });
375
485
  /**
376
- * `true` when the value satisfies the whole exact-record `Brief` contract.
486
+ * Checks whether the value satisfies the whole exact-record `Brief` contract.
377
487
  *
378
488
  * @remarks
379
489
  * Every section must be present; an extra key fails. `trace` and `hash` are the only
380
490
  * optional members, because `pinBrief` rather than the author fills them.
491
+ *
492
+ * @param value - The value to inspect.
493
+ * @returns True if `value` satisfies the whole exact-record `Brief` contract; false otherwise.
381
494
  */
382
495
  var isBrief = (0, _orkestrel_contract.recordOf)({
383
496
  task: isTask,
@@ -478,7 +591,7 @@ function captureValue(source, members) {
478
591
  return target;
479
592
  }
480
593
  /**
481
- * Return a deeply owned, deeply frozen copy of a brief, refusing anything off-contract.
594
+ * Returns a deeply owned, deeply frozen copy of a brief, refusing anything off-contract.
482
595
  *
483
596
  * @remarks
484
597
  * The one reading boundary this package has, used by the pin, the registry, and every
@@ -502,10 +615,10 @@ function captureValue(source, members) {
502
615
  *
503
616
  * @example
504
617
  * ```ts
505
- * import { brief, outcome, snapshotBrief, task } from '@orkestrel/brief'
618
+ * import { buildBrief, buildOutcome, buildTask, snapshotBrief } from '@orkestrel/brief'
506
619
  *
507
- * const outcomes = [outcome(1, 'shipped')]
508
- * const owned = snapshotBrief(brief(task('plan', 'ops', 'Plan the release.'), { outcomes }))
620
+ * const outcomes = [buildOutcome(1, 'shipped')]
621
+ * const owned = snapshotBrief(buildBrief(buildTask('plan', 'ops', 'Plan the release.'), { outcomes }))
509
622
  * owned.outcomes === outcomes // false — the alias is broken
510
623
  * Object.isFrozen(owned.outcomes) // true
511
624
  * ```
@@ -518,7 +631,7 @@ function snapshotBrief(source) {
518
631
  //#endregion
519
632
  //#region src/core/helpers.ts
520
633
  /**
521
- * Build a `Task`.
634
+ * Assembles a `Task` from an operation, a domain, and a statement.
522
635
  *
523
636
  * @param operation - What the brief asks for, from the closed operation vocabulary.
524
637
  * @param domain - The subject matter, from the closed domain vocabulary.
@@ -527,12 +640,12 @@ function snapshotBrief(source) {
527
640
  *
528
641
  * @example
529
642
  * ```ts
530
- * import { task } from '@orkestrel/brief'
643
+ * import { buildTask } from '@orkestrel/brief'
531
644
  *
532
- * task('refactor', 'code', 'Refactor useForm to native browser form APIs.')
645
+ * buildTask('refactor', 'code', 'Refactor useForm to native browser form APIs.')
533
646
  * ```
534
647
  */
535
- function task(operation, domain, statement) {
648
+ function buildTask(operation, domain, statement) {
536
649
  return {
537
650
  operation,
538
651
  domain,
@@ -540,7 +653,11 @@ function task(operation, domain, statement) {
540
653
  };
541
654
  }
542
655
  /**
543
- * Build a `Reference`.
656
+ * Assembles a `Reference` from a path and the note that justifies listing it.
657
+ *
658
+ * @remarks
659
+ * The one builder for an authority entry and a manifest entry alike: the container the record
660
+ * lands in is what says whether the path is ranked or permitted.
544
661
  *
545
662
  * @param path - The referenced path or glob.
546
663
  * @param note - Why the path is listed.
@@ -548,31 +665,31 @@ function task(operation, domain, statement) {
548
665
  *
549
666
  * @example
550
667
  * ```ts
551
- * import { reference } from '@orkestrel/brief'
668
+ * import { buildReference } from '@orkestrel/brief'
552
669
  *
553
- * reference('AGENTS.md', 'project law') // { path: 'AGENTS.md', note: 'project law' }
670
+ * buildReference('AGENTS.md', 'project law') // { path: 'AGENTS.md', note: 'project law' }
554
671
  * ```
555
672
  */
556
- function reference(path, note) {
673
+ function buildReference(path, note) {
557
674
  return {
558
675
  path,
559
676
  note
560
677
  };
561
678
  }
562
679
  /**
563
- * Build a `Manifest`, defaulting every absent partition to an empty list.
680
+ * Assembles a `Manifest`, defaulting every absent partition to an empty list.
564
681
  *
565
682
  * @param partitions - The partitions to fill; a partial literal is enough.
566
- * @returns A fresh `Manifest` with all four partitions present.
683
+ * @returns A fresh `Manifest` with every partition present.
567
684
  *
568
685
  * @example
569
686
  * ```ts
570
- * import { manifest, reference } from '@orkestrel/brief'
687
+ * import { buildManifest, buildReference } from '@orkestrel/brief'
571
688
  *
572
- * manifest({ edit: [reference('src/core/helpers.ts', 'implementation')] })
689
+ * buildManifest({ edit: [buildReference('src/core/helpers.ts', 'implementation')] })
573
690
  * ```
574
691
  */
575
- function manifest(partitions) {
692
+ function buildManifest(partitions) {
576
693
  return {
577
694
  read: partitions?.read ?? [],
578
695
  edit: partitions?.edit ?? [],
@@ -581,22 +698,23 @@ function manifest(partitions) {
581
698
  };
582
699
  }
583
700
  /**
584
- * Build an `Outcome`.
701
+ * Assembles an `Outcome` from a rank and its result text.
585
702
  *
586
703
  * @param rank - The one-based rank; lower ranks matter more.
587
704
  * @param text - The result, never a step.
588
- * @param required - Whether the outcome gates "done"; defaults to `true`.
705
+ * @param required - If `true`, the outcome gates "done"; if `false`, it is desirable but not
706
+ * blocking. Default: `true`.
589
707
  * @returns A fresh `Outcome`.
590
708
  *
591
709
  * @example
592
710
  * ```ts
593
- * import { outcome } from '@orkestrel/brief'
711
+ * import { buildOutcome } from '@orkestrel/brief'
594
712
  *
595
- * outcome(1, 'useForm uses native FormData with no behavior change') // required: true
596
- * outcome(2, 'the diff stays under 200 lines', false)
713
+ * buildOutcome(1, 'useForm uses native FormData with no behavior change') // required: true
714
+ * buildOutcome(2, 'the diff stays under 200 lines', false)
597
715
  * ```
598
716
  */
599
- function outcome(rank, text, required = true) {
717
+ function buildOutcome(rank, text, required = true) {
600
718
  return {
601
719
  rank,
602
720
  text,
@@ -604,7 +722,7 @@ function outcome(rank, text, required = true) {
604
722
  };
605
723
  }
606
724
  /**
607
- * Build a `Given`.
725
+ * Assembles a `Given` from a category, a name, and a value.
608
726
  *
609
727
  * @param category - The kind of fact — a convention, a version, a constraint.
610
728
  * @param name - The fact's name.
@@ -613,12 +731,12 @@ function outcome(rank, text, required = true) {
613
731
  *
614
732
  * @example
615
733
  * ```ts
616
- * import { given } from '@orkestrel/brief'
734
+ * import { buildGiven } from '@orkestrel/brief'
617
735
  *
618
- * given('convention', 'indentation', 'tabs')
736
+ * buildGiven('convention', 'indentation', 'tabs')
619
737
  * ```
620
738
  */
621
- function given(category, name, value) {
739
+ function buildGiven(category, name, value) {
622
740
  return {
623
741
  category,
624
742
  name,
@@ -626,32 +744,32 @@ function given(category, name, value) {
626
744
  };
627
745
  }
628
746
  /**
629
- * Build an `Example`.
747
+ * Assembles an `Example` from an exemplar input and its expected output.
630
748
  *
631
749
  * @param input - The exemplar input.
632
- * @param result - The expected output for that input.
750
+ * @param output - The expected output for that input.
633
751
  * @param note - Optional detail; the key is OMITTED when absent.
634
752
  * @returns A fresh `Example`.
635
753
  *
636
754
  * @example
637
755
  * ```ts
638
- * import { example } from '@orkestrel/brief'
756
+ * import { buildExample } from '@orkestrel/brief'
639
757
  *
640
- * example('<input required>', 'validity read from el.validity')
758
+ * buildExample('<input required>', 'validity read from el.validity')
641
759
  * ```
642
760
  */
643
- function example(input, result, note) {
761
+ function buildExample(input, output, note) {
644
762
  return note === void 0 ? {
645
763
  input,
646
- output: result
764
+ output
647
765
  } : {
648
766
  input,
649
- output: result,
767
+ output,
650
768
  note
651
769
  };
652
770
  }
653
771
  /**
654
- * Build a `Citation`.
772
+ * Assembles a `Citation` from a name, a URL, and the note that justifies citing it.
655
773
  *
656
774
  * @param name - The source's display name.
657
775
  * @param url - Where the source lives.
@@ -660,16 +778,16 @@ function example(input, result, note) {
660
778
  *
661
779
  * @example
662
780
  * ```ts
663
- * import { citation } from '@orkestrel/brief'
781
+ * import { buildCitation } from '@orkestrel/brief'
664
782
  *
665
- * citation(
783
+ * buildCitation(
666
784
  * 'MDN Constraint Validation',
667
785
  * 'https://developer.mozilla.org/',
668
786
  * 'the native validity behavior being adopted',
669
787
  * )
670
788
  * ```
671
789
  */
672
- function citation(name, url, note) {
790
+ function buildCitation(name, url, note) {
673
791
  return {
674
792
  name,
675
793
  url,
@@ -677,23 +795,23 @@ function citation(name, url, note) {
677
795
  };
678
796
  }
679
797
  /**
680
- * Build a `Gap`.
798
+ * Assembles a `Gap` from the section it belongs to and the question that would close it.
681
799
  *
682
800
  * @param field - The brief section the unknown belongs to.
683
801
  * @param question - The question that would close it.
684
- * @param overrides - Optional `blocking` (defaults `false`) and `candidates`; an absent
685
- * `candidates` key is OMITTED entirely.
802
+ * @param overrides - Optional `blocking` and `candidates`; an absent `candidates` key is
803
+ * OMITTED entirely. Default: `blocking: false`.
686
804
  * @returns A fresh `Gap`.
687
805
  *
688
806
  * @example
689
807
  * ```ts
690
- * import { gap } from '@orkestrel/brief'
808
+ * import { buildGap } from '@orkestrel/brief'
691
809
  *
692
- * gap('rules', 'Should validation message wording change?') // blocking: false
693
- * gap('output', 'Diff or full files?', { blocking: true, candidates: ['diff', 'code'] })
810
+ * buildGap('rules', 'Does validation message wording need to change?') // blocking: false
811
+ * buildGap('output', 'Diff or full files?', { blocking: true, candidates: ['diff', 'code'] })
694
812
  * ```
695
813
  */
696
- function gap(field, question, overrides) {
814
+ function buildGap(field, question, overrides) {
697
815
  const blocking = overrides?.blocking ?? false;
698
816
  return overrides?.candidates === void 0 ? {
699
817
  field,
@@ -707,7 +825,7 @@ function gap(field, question, overrides) {
707
825
  };
708
826
  }
709
827
  /**
710
- * Build a `Risk`.
828
+ * Assembles a `Risk` from a severity, what could go wrong, and the mitigation that answers it.
711
829
  *
712
830
  * @param severity - The closed severity.
713
831
  * @param text - What could go wrong.
@@ -716,12 +834,12 @@ function gap(field, question, overrides) {
716
834
  *
717
835
  * @example
718
836
  * ```ts
719
- * import { risk } from '@orkestrel/brief'
837
+ * import { buildRisk } from '@orkestrel/brief'
720
838
  *
721
- * risk('medium', 'native validation differs subtly', 'assert message and state in tests')
839
+ * buildRisk('medium', 'native validation differs subtly', 'assert message and state in tests')
722
840
  * ```
723
841
  */
724
- function risk(severity, text, mitigation) {
842
+ function buildRisk(severity, text, mitigation) {
725
843
  return {
726
844
  severity,
727
845
  text,
@@ -729,7 +847,7 @@ function risk(severity, text, mitigation) {
729
847
  };
730
848
  }
731
849
  /**
732
- * Build an `Output`.
850
+ * Assembles an `Output` from a format plus its optional refinements.
733
851
  *
734
852
  * @param format - The closed deliverable format.
735
853
  * @param overrides - Optional `sections` / `include` / `exclude`; absent keys are OMITTED.
@@ -737,13 +855,13 @@ function risk(severity, text, mitigation) {
737
855
  *
738
856
  * @example
739
857
  * ```ts
740
- * import { output } from '@orkestrel/brief'
858
+ * import { buildOutput } from '@orkestrel/brief'
741
859
  *
742
- * output('markdown') // { format: 'markdown' }
743
- * output('diff', { include: ['updated useForm.ts'] })
860
+ * buildOutput('markdown') // { format: 'markdown' }
861
+ * buildOutput('diff', { include: ['updated useForm.ts'] })
744
862
  * ```
745
863
  */
746
- function output(format, overrides) {
864
+ function buildOutput(format, overrides) {
747
865
  return {
748
866
  format,
749
867
  ...overrides?.sections === void 0 ? {} : { sections: overrides.sections },
@@ -752,7 +870,7 @@ function output(format, overrides) {
752
870
  };
753
871
  }
754
872
  /**
755
- * Build a `Proof`.
873
+ * Assembles a `Proof` from what the check settles and the command that settles it.
756
874
  *
757
875
  * @param text - What the check settles.
758
876
  * @param command - The command whose exit signal settles it.
@@ -760,41 +878,41 @@ function output(format, overrides) {
760
878
  *
761
879
  * @example
762
880
  * ```ts
763
- * import { proof } from '@orkestrel/brief'
881
+ * import { buildProof } from '@orkestrel/brief'
764
882
  *
765
- * proof('type-check and lint pass', 'npm run check')
883
+ * buildProof('type-check and lint pass', 'npm run check')
766
884
  * ```
767
885
  */
768
- function proof(text, command) {
886
+ function buildProof(text, command) {
769
887
  return {
770
888
  text,
771
889
  command
772
890
  };
773
891
  }
774
892
  /**
775
- * Build a `Brief` from a `Task` plus section overrides.
893
+ * Assembles a `Brief` from a `Task` plus section overrides.
776
894
  *
777
895
  * @param subject - The task the brief is about.
778
- * @param overrides - Any sections to fill; every absent collection defaults to `[]`,
779
- * `output` defaults to `output('markdown')`, and `trace` / `hash` stay OMITTED so
780
- * `pinBrief` can fill them.
896
+ * @param overrides - Any sections to fill; `trace` / `hash` stay OMITTED so `pinBrief` can
897
+ * fill them. Default: `[]` for every absent collection and `buildOutput('markdown')` for
898
+ * `output`.
781
899
  * @returns A fresh, unpinned `Brief`.
782
900
  *
783
901
  * @example
784
902
  * ```ts
785
- * import { brief, outcome, proof, task } from '@orkestrel/brief'
903
+ * import { buildBrief, buildOutcome, buildProof, buildTask } from '@orkestrel/brief'
786
904
  *
787
- * brief(task('audit', 'code', 'Audit the barrel for undocumented exports.'), {
788
- * outcomes: [outcome(1, 'every export appears in the guide')],
789
- * proofs: [proof('parity passes', 'npm run test:guides')],
905
+ * buildBrief(buildTask('audit', 'code', 'Audit the barrel for undocumented exports.'), {
906
+ * outcomes: [buildOutcome(1, 'every export appears in the guide')],
907
+ * proofs: [buildProof('parity passes', 'npm run test:guides')],
790
908
  * })
791
909
  * ```
792
910
  */
793
- function brief(subject, overrides) {
911
+ function buildBrief(subject, overrides) {
794
912
  return {
795
913
  task: subject,
796
914
  authority: overrides?.authority ?? [],
797
- manifest: overrides?.manifest ?? manifest(),
915
+ manifest: overrides?.manifest ?? buildManifest(),
798
916
  outcomes: overrides?.outcomes ?? [],
799
917
  rules: overrides?.rules ?? [],
800
918
  invariants: overrides?.invariants ?? [],
@@ -804,17 +922,17 @@ function brief(subject, overrides) {
804
922
  citations: overrides?.citations ?? [],
805
923
  gaps: overrides?.gaps ?? [],
806
924
  risks: overrides?.risks ?? [],
807
- output: overrides?.output ?? output("markdown"),
925
+ output: overrides?.output ?? buildOutput("markdown"),
808
926
  proofs: overrides?.proofs ?? []
809
927
  };
810
928
  }
811
929
  /**
812
- * Build the fail-closed readiness gate as a reasons `LogicalDefinition`.
930
+ * Assembles the fail-closed readiness gate as a reasons `LogicalDefinition`.
813
931
  *
814
932
  * @remarks
815
- * Six readiness rules each derive one named fact from `briefToSubject`'s measures, and a
816
- * final `ready` rule conjoins all six. Forward chaining reports the LAST rule's
817
- * conclusion, so `LogicalResult.conclusion` is exactly `ready`.
933
+ * Each readiness rule derives one named fact from `briefToSubject`'s measures, and a final
934
+ * `ready` rule conjoins them all. Forward chaining reports the LAST rule's conclusion, so
935
+ * `LogicalResult.conclusion` is exactly `ready`.
818
936
  *
819
937
  * The gate takes NO parameters, and that is deliberate rather than unfinished. The
820
938
  * reasoner overlays every derived fact into one flat namespace, so a caller rule named
@@ -828,50 +946,50 @@ function brief(subject, overrides) {
828
946
  *
829
947
  * @example
830
948
  * ```ts
831
- * import { briefToSubject, gateDefinition } from '@orkestrel/brief'
949
+ * import { briefToSubject, buildGateDefinition } from '@orkestrel/brief'
832
950
  * import { createLogicalReasoner, createReason } from '@orkestrel/reason'
833
951
  *
834
952
  * const reason = createReason({ reasoners: [createLogicalReasoner()] })
835
- * const verdict = reason.reason(briefToSubject(pinned), gateDefinition())
953
+ * const verdict = reason.reason(briefToSubject(pinned), buildGateDefinition())
836
954
  * reason.destroy()
837
955
  * ```
838
956
  */
839
- function gateDefinition() {
957
+ function buildGateDefinition() {
840
958
  const readiness = [
841
- (0, _orkestrel_reason.rule)("specified", [(0, _orkestrel_reason.atom)("blocking", "equals", 0)], (0, _orkestrel_reason.atom)("specified", "equals", true)),
842
- (0, _orkestrel_reason.rule)("aimed", [(0, _orkestrel_reason.compound)("and", [(0, _orkestrel_reason.atom)("outcomes", "above", 0), (0, _orkestrel_reason.atom)("required", "above", 0)])], (0, _orkestrel_reason.atom)("aimed", "equals", true)),
843
- (0, _orkestrel_reason.rule)("proven", [(0, _orkestrel_reason.atom)("proofs", "above", 0)], (0, _orkestrel_reason.atom)("proven", "equals", true)),
844
- (0, _orkestrel_reason.rule)("disjoint", [(0, _orkestrel_reason.atom)("overlaps", "equals", 0)], (0, _orkestrel_reason.atom)("disjoint", "equals", true)),
845
- (0, _orkestrel_reason.rule)("granted", [(0, _orkestrel_reason.atom)("ungranted", "equals", 0)], (0, _orkestrel_reason.atom)("granted", "equals", true)),
846
- (0, _orkestrel_reason.rule)("single", [(0, _orkestrel_reason.atom)("sentences", "equals", 1)], (0, _orkestrel_reason.atom)("single", "equals", true))
959
+ (0, _orkestrel_reason.createRule)("specified", [(0, _orkestrel_reason.createAtom)("blocking", "equals", 0)], (0, _orkestrel_reason.createAtom)("specified", "equals", true)),
960
+ (0, _orkestrel_reason.createRule)("aimed", [(0, _orkestrel_reason.createCompound)("and", [(0, _orkestrel_reason.createAtom)("outcomes", "above", 0), (0, _orkestrel_reason.createAtom)("required", "above", 0)])], (0, _orkestrel_reason.createAtom)("aimed", "equals", true)),
961
+ (0, _orkestrel_reason.createRule)("proven", [(0, _orkestrel_reason.createAtom)("proofs", "above", 0)], (0, _orkestrel_reason.createAtom)("proven", "equals", true)),
962
+ (0, _orkestrel_reason.createRule)("disjoint", [(0, _orkestrel_reason.createAtom)("overlaps", "equals", 0)], (0, _orkestrel_reason.createAtom)("disjoint", "equals", true)),
963
+ (0, _orkestrel_reason.createRule)("granted", [(0, _orkestrel_reason.createAtom)("ungranted", "equals", 0)], (0, _orkestrel_reason.createAtom)("granted", "equals", true)),
964
+ (0, _orkestrel_reason.createRule)("single", [(0, _orkestrel_reason.createAtom)("sentences", "equals", 1)], (0, _orkestrel_reason.createAtom)("single", "equals", true))
847
965
  ];
848
- return (0, _orkestrel_reason.logicalDefinition)(GATE_ID, "Brief readiness", [...readiness, (0, _orkestrel_reason.rule)("ready", [(0, _orkestrel_reason.compound)("and", readiness.map((entry) => (0, _orkestrel_reason.atom)(entry.id, "equals", true)))], (0, _orkestrel_reason.atom)("ready", "equals", true))]);
966
+ return (0, _orkestrel_reason.createLogicalDefinition)(GATE_ID, "Brief readiness", [...readiness, (0, _orkestrel_reason.createRule)("ready", [(0, _orkestrel_reason.createCompound)("and", readiness.map((entry) => (0, _orkestrel_reason.createAtom)(entry.id, "equals", true)))], (0, _orkestrel_reason.createAtom)("ready", "equals", true))]);
849
967
  }
850
968
  /**
851
- * The readiness rules a brief fails, computed directly from its own measures.
969
+ * Lists the readiness rules a brief fails, computed directly from its own measures.
852
970
  *
853
971
  * @remarks
854
- * The gate's decision, in code. `gateDefinition()` states the same six rules as data for a
972
+ * The gate's decision, in code. `buildGateDefinition()` states the same rules as data for a
855
973
  * reasoner to narrate, and a narration is not a decision: `BriefCompilerOptions.reason` lets a
856
974
  * caller supply the engine, and an engine that answers "met" to everything would otherwise
857
975
  * emit a brief with no proofs. `compile` refuses on THIS and keeps the verdict for its
858
976
  * trace, so a supplied engine can add detail and never remove a refusal.
859
977
  *
860
- * The two must agree. `tests/src/core/helpers.test.ts` drives both over one value set, which
861
- * is what stops the data and the code from drifting apart.
978
+ * The data and the code must agree. `tests/src/core/helpers.test.ts` drives both over one
979
+ * value set, which is what stops them from drifting apart.
862
980
  *
863
981
  * @param source - The brief to measure.
864
982
  * @returns The unmet rule ids, in gate order; empty when the brief is ready.
865
983
  *
866
984
  * @example
867
985
  * ```ts
868
- * import { brief, findUnmetRules, outcome, proof, task } from '@orkestrel/brief'
986
+ * import { buildBrief, buildOutcome, buildProof, buildTask, findUnmetRules } from '@orkestrel/brief'
869
987
  *
870
- * findUnmetRules(brief(task('plan', 'ops', 'Plan the release.'))) // ['aimed', 'proven']
988
+ * findUnmetRules(buildBrief(buildTask('plan', 'ops', 'Plan the release.'))) // ['aimed', 'proven']
871
989
  * findUnmetRules(
872
- * brief(task('plan', 'ops', 'Plan the release.'), {
873
- * outcomes: [outcome(1, 'shipped')],
874
- * proofs: [proof('x', 'npm test')],
990
+ * buildBrief(buildTask('plan', 'ops', 'Plan the release.'), {
991
+ * outcomes: [buildOutcome(1, 'shipped')],
992
+ * proofs: [buildProof('x', 'npm test')],
875
993
  * }),
876
994
  * ) // []
877
995
  * ```
@@ -887,7 +1005,7 @@ function findUnmetRules(source) {
887
1005
  return unready;
888
1006
  }
889
1007
  /**
890
- * Count the sentences a statement holds.
1008
+ * Counts the sentences a statement holds.
891
1009
  *
892
1010
  * @remarks
893
1011
  * A terminator run (`.`, `!`, `?`) followed by whitespace or the end of the text closes one
@@ -925,17 +1043,21 @@ function countSentences(statement) {
925
1043
  return /[.!?]$/u.test(text) ? matches.length : matches.length + 1;
926
1044
  }
927
1045
  /**
928
- * The gaps that block emission.
1046
+ * Lists the gaps that block emission.
1047
+ *
1048
+ * @remarks
1049
+ * A non-empty result means the gate must fail closed: a blocking gap has no safe default, so
1050
+ * the compile yields a visible incomplete `Briefing` carrying the questions instead of a brief.
929
1051
  *
930
1052
  * @param source - The brief to inspect.
931
1053
  * @returns Every gap carrying `blocking: true`, in declaration order.
932
1054
  *
933
1055
  * @example
934
1056
  * ```ts
935
- * import { brief, findBlockingGaps, gap, task } from '@orkestrel/brief'
1057
+ * import { buildBrief, buildGap, buildTask, findBlockingGaps } from '@orkestrel/brief'
936
1058
  *
937
- * const draft = brief(task('plan', 'ops', 'Plan the release.'), {
938
- * gaps: [gap('output', 'Diff or files?', { blocking: true })],
1059
+ * const draft = buildBrief(buildTask('plan', 'ops', 'Plan the release.'), {
1060
+ * gaps: [buildGap('output', 'Diff or files?', { blocking: true })],
939
1061
  * })
940
1062
  * findBlockingGaps(draft).length // 1
941
1063
  * ```
@@ -944,18 +1066,18 @@ function findBlockingGaps(source) {
944
1066
  return source.gaps.filter((entry) => entry.blocking);
945
1067
  }
946
1068
  /**
947
- * The authority paths the manifest never grants access to.
1069
+ * Lists the authority paths the manifest never grants access to.
948
1070
  *
949
1071
  * @remarks
950
1072
  * An authority the executor cannot open is an instruction it cannot follow, so every ranked
951
- * path must appear in `read`, `edit`, or `locked`. Those three are the grants: `locked` is a
1073
+ * path must appear in `read`, `edit`, or `locked`. Those are the grants: `locked` is a
952
1074
  * grant, because read-only is exactly what obeying a file requires.
953
1075
  *
954
- * This subsumes the narrower question of an authority sitting in `forbidden`. The four
955
- * partitions are disjoint — `findManifestOverlaps` and the `disjoint` rule enforce it — so a
956
- * forbidden path is in none of the three grants and is reported here. An authority named in
957
- * NO partition at all is reported for the same reason, and that is the case a forbidden-only
958
- * check misses entirely: the brief simply never says the executor may open what it must obey.
1076
+ * This subsumes the narrower question of an authority sitting in `forbidden`. The partitions
1077
+ * are disjoint — `findManifestOverlaps` and the `disjoint` rule enforce it — so a forbidden
1078
+ * path is in none of the grants and is reported here. An authority named in NO partition at
1079
+ * all is reported for the same reason, and that is the case a forbidden-only check misses
1080
+ * entirely: the brief never says the executor may open what it must obey.
959
1081
  *
960
1082
  * Paths are compared as EXACT strings, matching `findManifestOverlaps`. A glob is never
961
1083
  * expanded, so `read: 'guides/**'` does not grant `authority: 'guides/brief.md'`. State a
@@ -966,11 +1088,17 @@ function findBlockingGaps(source) {
966
1088
  *
967
1089
  * @example
968
1090
  * ```ts
969
- * import { brief, findUngrantedAuthority, manifest, reference, task } from '@orkestrel/brief'
970
- *
971
- * const draft = brief(task('debug', 'code', 'Fix the leak.'), {
972
- * authority: [reference('AGENTS.md', 'project law')],
973
- * manifest: manifest(),
1091
+ * import {
1092
+ * buildBrief,
1093
+ * buildManifest,
1094
+ * buildReference,
1095
+ * buildTask,
1096
+ * findUngrantedAuthority,
1097
+ * } from '@orkestrel/brief'
1098
+ *
1099
+ * const draft = buildBrief(buildTask('debug', 'code', 'Fix the leak.'), {
1100
+ * authority: [buildReference('AGENTS.md', 'project law')],
1101
+ * manifest: buildManifest(),
974
1102
  * })
975
1103
  * findUngrantedAuthority(draft) // ['AGENTS.md'] — ranked, but no partition opens it
976
1104
  * ```
@@ -986,10 +1114,10 @@ function findUngrantedAuthority(source) {
986
1114
  return ungranted;
987
1115
  }
988
1116
  /**
989
- * The paths appearing in more than one manifest partition.
1117
+ * Lists the paths appearing in more than one manifest partition.
990
1118
  *
991
1119
  * @remarks
992
- * Duplicates WITHIN one partition are not an overlap; the four partitions must be
1120
+ * Duplicates WITHIN one partition are not an overlap; the partitions must be
993
1121
  * mutually disjoint, which is what `validateBrief` errors on.
994
1122
  *
995
1123
  * Paths are compared as EXACT strings. A glob is never expanded, so `edit: 'app/file.ts'`
@@ -1001,12 +1129,18 @@ function findUngrantedAuthority(source) {
1001
1129
  *
1002
1130
  * @example
1003
1131
  * ```ts
1004
- * import { brief, findManifestOverlaps, manifest, reference, task } from '@orkestrel/brief'
1005
- *
1006
- * const draft = brief(task('debug', 'code', 'Fix the leak.'), {
1007
- * manifest: manifest({
1008
- * edit: [reference('src/core/BriefCompiler.ts', 'the leaking pipeline')],
1009
- * locked: [reference('src/core/BriefCompiler.ts', 'the published contract')],
1132
+ * import {
1133
+ * buildBrief,
1134
+ * buildManifest,
1135
+ * buildReference,
1136
+ * buildTask,
1137
+ * findManifestOverlaps,
1138
+ * } from '@orkestrel/brief'
1139
+ *
1140
+ * const draft = buildBrief(buildTask('debug', 'code', 'Fix the leak.'), {
1141
+ * manifest: buildManifest({
1142
+ * edit: [buildReference('src/core/BriefCompiler.ts', 'the leaking pipeline')],
1143
+ * locked: [buildReference('src/core/BriefCompiler.ts', 'the published contract')],
1010
1144
  * }),
1011
1145
  * })
1012
1146
  * findManifestOverlaps(draft) // ['src/core/BriefCompiler.ts']
@@ -1026,7 +1160,7 @@ function findManifestOverlaps(source) {
1026
1160
  return overlaps;
1027
1161
  }
1028
1162
  /**
1029
- * The open gaps with no assumption to stand on.
1163
+ * Lists the open gaps with no assumption to stand on.
1030
1164
  *
1031
1165
  * @remarks
1032
1166
  * The discipline is exactly one recorded assumption per open gap, so the open gaps past
@@ -1038,10 +1172,10 @@ function findManifestOverlaps(source) {
1038
1172
  *
1039
1173
  * @example
1040
1174
  * ```ts
1041
- * import { brief, findUnpairedGaps, gap, task } from '@orkestrel/brief'
1175
+ * import { buildBrief, buildGap, buildTask, findUnpairedGaps } from '@orkestrel/brief'
1042
1176
  *
1043
- * const draft = brief(task('plan', 'ops', 'Plan the release.'), {
1044
- * gaps: [gap('rules', 'Keep the wording?'), gap('output', 'Diff or files?')],
1177
+ * const draft = buildBrief(buildTask('plan', 'ops', 'Plan the release.'), {
1178
+ * gaps: [buildGap('rules', 'Keep the wording?'), buildGap('output', 'Diff or files?')],
1045
1179
  * assumptions: ['Wording is preserved.'],
1046
1180
  * })
1047
1181
  * findUnpairedGaps(draft).length // 1
@@ -1051,16 +1185,16 @@ function findUnpairedGaps(source) {
1051
1185
  return source.gaps.filter((entry) => !entry.blocking).slice(source.assumptions.length);
1052
1186
  }
1053
1187
  /**
1054
- * Project a brief into the reasons `Subject` of readiness measures the gate reads.
1188
+ * Projects a brief into the reasons `Subject` of readiness measures the gate reads.
1055
1189
  *
1056
1190
  * @param source - The brief to measure.
1057
- * @returns A flat record of counts plus the task's two vocabulary values.
1191
+ * @returns A flat record of counts plus the task's vocabulary values.
1058
1192
  *
1059
1193
  * @example
1060
1194
  * ```ts
1061
- * import { brief, briefToSubject, proof, task } from '@orkestrel/brief'
1195
+ * import { briefToSubject, buildBrief, buildProof, buildTask } from '@orkestrel/brief'
1062
1196
  *
1063
- * briefToSubject(brief(task('test', 'code', 'Cover the gate.'), { proofs: [proof('x', 'y')] }))
1197
+ * briefToSubject(buildBrief(buildTask('test', 'code', 'Cover the gate.'), { proofs: [buildProof('x', 'y')] }))
1064
1198
  * // { operation: 'test', domain: 'code', sentences: 1, proofs: 1, … }
1065
1199
  * ```
1066
1200
  */
@@ -1087,7 +1221,7 @@ function briefToSubject(source) {
1087
1221
  };
1088
1222
  }
1089
1223
  /**
1090
- * The semantic pass over an already-shape-valid brief.
1224
+ * Runs the semantic pass over an already-shape-valid brief.
1091
1225
  *
1092
1226
  * @remarks
1093
1227
  * ERRORS are the structural violations no assumption can paper over: a manifest
@@ -1101,11 +1235,11 @@ function briefToSubject(source) {
1101
1235
  *
1102
1236
  * @example
1103
1237
  * ```ts
1104
- * import { brief, proof, task, validateBrief } from '@orkestrel/brief'
1238
+ * import { buildBrief, buildProof, buildTask, validateBrief } from '@orkestrel/brief'
1105
1239
  *
1106
- * validateBrief(brief(task('plan', 'ops', 'Plan the release.'))) // valid: false — no proofs
1240
+ * validateBrief(buildBrief(buildTask('plan', 'ops', 'Plan the release.'))) // valid: false — no proofs
1107
1241
  * validateBrief(
1108
- * brief(task('plan', 'ops', 'Plan the release.'), { proofs: [proof('ok', 'npm test')] }),
1242
+ * buildBrief(buildTask('plan', 'ops', 'Plan the release.'), { proofs: [buildProof('ok', 'npm test')] }),
1109
1243
  * ) // valid: true
1110
1244
  * ```
1111
1245
  */
@@ -1133,7 +1267,7 @@ function validateBrief(source) {
1133
1267
  };
1134
1268
  }
1135
1269
  /**
1136
- * The canonical structural digest of a brief's content.
1270
+ * Computes the canonical structural digest of a brief's content.
1137
1271
  *
1138
1272
  * @remarks
1139
1273
  * `trace` and `hash` are stripped before digesting, so the value is the identity of what
@@ -1145,9 +1279,9 @@ function validateBrief(source) {
1145
1279
  *
1146
1280
  * @example
1147
1281
  * ```ts
1148
- * import { brief, briefToHash, pinBrief, task } from '@orkestrel/brief'
1282
+ * import { briefToHash, buildBrief, buildTask, pinBrief } from '@orkestrel/brief'
1149
1283
  *
1150
- * const draft = brief(task('plan', 'ops', 'Plan the release.'))
1284
+ * const draft = buildBrief(buildTask('plan', 'ops', 'Plan the release.'))
1151
1285
  * briefToHash(draft) === briefToHash(pinBrief(draft)) // true — pinning does not move it
1152
1286
  * ```
1153
1287
  */
@@ -1155,7 +1289,7 @@ function briefToHash(source) {
1155
1289
  return (0, _orkestrel_interpret.digestValue)(briefToContent(source));
1156
1290
  }
1157
1291
  /**
1158
- * The canonical text of exactly what a brief's hash describes.
1292
+ * Renders the canonical text of exactly what a brief's hash describes.
1159
1293
  *
1160
1294
  * @remarks
1161
1295
  * `trace` and `hash` are stripped, then interprets `canonicalize` renders the rest in a
@@ -1167,9 +1301,9 @@ function briefToHash(source) {
1167
1301
  *
1168
1302
  * @example
1169
1303
  * ```ts
1170
- * import { brief, briefToContent, pinBrief, task } from '@orkestrel/brief'
1304
+ * import { briefToContent, buildBrief, buildTask, pinBrief } from '@orkestrel/brief'
1171
1305
  *
1172
- * const draft = brief(task('plan', 'ops', 'Plan the release.'))
1306
+ * const draft = buildBrief(buildTask('plan', 'ops', 'Plan the release.'))
1173
1307
  * briefToContent(draft) === briefToContent(pinBrief(draft)) // true — pinning adds no content
1174
1308
  * ```
1175
1309
  */
@@ -1178,7 +1312,7 @@ function briefToContent(source) {
1178
1312
  return (0, _orkestrel_interpret.canonicalize)(content);
1179
1313
  }
1180
1314
  /**
1181
- * Freeze a value and everything reachable from it.
1315
+ * Freezes a value and everything reachable from it.
1182
1316
  *
1183
1317
  * @remarks
1184
1318
  * `Object.freeze` is SHALLOW, so freezing a record leaves every nested array and object
@@ -1192,7 +1326,7 @@ function briefToContent(source) {
1192
1326
  * Reaches PLAIN objects and arrays, which is the whole of a `Brief` — it is JSON-serializable
1193
1327
  * by contract. A `Map`, `Set`, or typed array is frozen as an object and its CONTENTS are left
1194
1328
  * writable, and `Object.isFrozen` reports `true` for it either way. Nothing this package
1195
- * produces contains one; a caller freezing their own value should know the limit.
1329
+ * produces contains one; the limit lands on a caller freezing their own value.
1196
1330
  *
1197
1331
  * @param value - The value to freeze in place; returned for convenience.
1198
1332
  * @returns The same value, now deeply frozen.
@@ -1209,7 +1343,7 @@ function freezeDeep(value) {
1209
1343
  return freezeBranch(value, /* @__PURE__ */ new WeakSet());
1210
1344
  }
1211
1345
  /**
1212
- * Freeze one branch of a value graph, skipping what the visited set already holds.
1346
+ * Freezes one branch of a value graph, skipping what the visited set already holds.
1213
1347
  *
1214
1348
  * @param value - The branch to freeze.
1215
1349
  * @param seen - The objects already frozen on this walk; what makes a cycle terminate.
@@ -1231,7 +1365,7 @@ function freezeBranch(value, seen) {
1231
1365
  return value;
1232
1366
  }
1233
1367
  /**
1234
- * Render a value thrown by a stage into a message.
1368
+ * Renders a value thrown by a stage into a message.
1235
1369
  *
1236
1370
  * @remarks
1237
1371
  * TOTAL: it never throws, for any input. That is load-bearing rather than tidy, because this
@@ -1240,7 +1374,7 @@ function freezeBranch(value, seen) {
1240
1374
  * falsifies the package's central promise that a failing stage yields an incomplete
1241
1375
  * `Briefing` rather than an exception.
1242
1376
  *
1243
- * Three real inputs used to throw: an `Error` subclass whose `message` getter throws, a value
1377
+ * Real inputs used to throw: an `Error` subclass whose `message` getter throws, a value
1244
1378
  * whose string conversion throws, and a null-prototype object, which has no inherited
1245
1379
  * conversion for String() to reach. Each is wrapped, and an unreadable value degrades to its
1246
1380
  * type rather than propagating.
@@ -1264,10 +1398,10 @@ function errorToMessage(error) {
1264
1398
  return `an unreadable ${typeof error} was thrown`;
1265
1399
  }
1266
1400
  /**
1267
- * Narrow unknown data to a `Brief`, throwing when it is off-contract.
1401
+ * Narrows unknown data to a `Brief`, throwing when it is off-contract.
1268
1402
  *
1269
1403
  * @remarks
1270
- * The throwing half of the intake pair: this returns its argument by IDENTITY once the
1404
+ * The throwing half of the intake pair: this returns its argument by IDENTITY after the
1271
1405
  * guard passes, while `parseBrief` returns `undefined` for bad input. It constructs
1272
1406
  * nothing, so it is an assertion rather than a factory. Reserve it for programmer-error
1273
1407
  * contexts where invalidity is a bug.
@@ -1281,24 +1415,24 @@ function errorToMessage(error) {
1281
1415
  * `briefToTrace` read the value they are handed instead, so a caller reaching one of those
1282
1416
  * directly owns that reading. Pass `assertBrief` a value you already own.
1283
1417
  *
1284
- * @param data - The candidate brief data.
1418
+ * @param value - The candidate brief value.
1285
1419
  * @returns The same value, now known to satisfy {@link Brief}.
1286
- * @throws {@link BriefError} `INVALID` when `data` fails `isBrief`.
1420
+ * @throws {@link BriefError} `INVALID` when `value` fails `isBrief`.
1287
1421
  *
1288
1422
  * @example
1289
1423
  * ```ts
1290
- * import { assertBrief, brief, proof, task } from '@orkestrel/brief'
1424
+ * import { assertBrief, buildBrief, buildProof, buildTask } from '@orkestrel/brief'
1291
1425
  *
1292
- * assertBrief(brief(task('plan', 'ops', 'Plan the release.'), { proofs: [proof('x', 'y')] }))
1426
+ * assertBrief(buildBrief(buildTask('plan', 'ops', 'Plan the release.'), { proofs: [buildProof('x', 'y')] }))
1293
1427
  * assertBrief({ task: { operation: 'plan', domain: 'ops', statement: 'x.' } }) // throws INVALID
1294
1428
  * ```
1295
1429
  */
1296
- function assertBrief(data) {
1297
- if (!isBrief(data)) throw new BriefError("INVALID", "Brief failed the exact-record contract", { field: "brief" });
1298
- return data;
1430
+ function assertBrief(value) {
1431
+ if (!isBrief(value)) throw new BriefError("INVALID", "Brief failed the exact-record contract", { field: "brief" });
1432
+ return value;
1299
1433
  }
1300
1434
  /**
1301
- * Return a fresh brief with `trace` and `hash` derived from its own content.
1435
+ * Returns a fresh brief with `trace` and `hash` derived from its own content.
1302
1436
  *
1303
1437
  * @remarks
1304
1438
  * Deterministic: no clock, no randomness, no run-specific data. Any existing `trace` /
@@ -1314,9 +1448,9 @@ function assertBrief(data) {
1314
1448
  *
1315
1449
  * @example
1316
1450
  * ```ts
1317
- * import { brief, pinBrief, task } from '@orkestrel/brief'
1451
+ * import { buildBrief, buildTask, pinBrief } from '@orkestrel/brief'
1318
1452
  *
1319
- * const pinned = pinBrief(brief(task('document', 'writing', 'Write the brief guide.')))
1453
+ * const pinned = pinBrief(buildBrief(buildTask('document', 'writing', 'Write the brief guide.')))
1320
1454
  * pinned.hash // an 8-hex-digit structural digest
1321
1455
  * pinned.trace // 'document/writing · outcomes:0 · gaps:0/0 · proofs:0'
1322
1456
  * ```
@@ -1331,7 +1465,7 @@ function pinBrief(source) {
1331
1465
  });
1332
1466
  }
1333
1467
  /**
1334
- * The one-line census `pinBrief` stamps onto a brief.
1468
+ * Renders the one-line census `pinBrief` stamps onto a brief.
1335
1469
  *
1336
1470
  * @remarks
1337
1471
  * Extracted so it has ONE implementation. `pinBrief` derives it and `BriefManager` re-derives
@@ -1344,9 +1478,9 @@ function pinBrief(source) {
1344
1478
  *
1345
1479
  * @example
1346
1480
  * ```ts
1347
- * import { brief, briefToTrace, task } from '@orkestrel/brief'
1481
+ * import { briefToTrace, buildBrief, buildTask } from '@orkestrel/brief'
1348
1482
  *
1349
- * briefToTrace(brief(task('document', 'writing', 'Write the guide.')))
1483
+ * briefToTrace(buildBrief(buildTask('document', 'writing', 'Write the guide.')))
1350
1484
  * // 'document/writing · outcomes:0 · gaps:0/0 · proofs:0'
1351
1485
  * ```
1352
1486
  */
@@ -1359,7 +1493,7 @@ function briefToTrace(source) {
1359
1493
  ].join(" · ");
1360
1494
  }
1361
1495
  /**
1362
- * Render one exemplar as markdown lines.
1496
+ * Renders one exemplar as markdown lines.
1363
1497
  *
1364
1498
  * @remarks
1365
1499
  * An `Example`'s two sides are the only brief members permitted to span lines, so a
@@ -1371,9 +1505,9 @@ function briefToTrace(source) {
1371
1505
  *
1372
1506
  * @example
1373
1507
  * ```ts
1374
- * import { example, exampleToLines } from '@orkestrel/brief'
1508
+ * import { buildExample, exampleToLines } from '@orkestrel/brief'
1375
1509
  *
1376
- * exampleToLines(example('<input required>', 'el.validity')) // ['- ` <input required> ` → ` el.validity `']
1510
+ * exampleToLines(buildExample('<input required>', 'el.validity')) // ['- ` <input required> ` → ` el.validity `']
1377
1511
  * ```
1378
1512
  */
1379
1513
  function exampleToLines(entry) {
@@ -1404,20 +1538,21 @@ function exampleToLines(entry) {
1404
1538
  ];
1405
1539
  }
1406
1540
  /**
1407
- * Project a brief into the copy-ready agent prompt.
1541
+ * Projects a brief into the copy-ready agent prompt.
1408
1542
  *
1409
1543
  * @remarks
1410
- * Paths are REFERENCED, never inlined the executor retrieves them. An empty section is
1411
- * omitted entirely, so the rendering carries no filler an executor must read past.
1544
+ * Sections render in authority order, so the executor meets what wins a conflict before what
1545
+ * it may touch. Paths are referenced, never inlined the executor retrieves them. An empty
1546
+ * section is omitted entirely, so the rendering carries no filler an executor must read past.
1412
1547
  *
1413
- * @param source - The brief to render.
1548
+ * @param input - The brief to render.
1414
1549
  * @returns The markdown prompt.
1415
1550
  *
1416
1551
  * @example
1417
1552
  * ```ts
1418
- * import { brief, briefToMarkdown, task } from '@orkestrel/brief'
1553
+ * import { briefToMarkdown, buildBrief, buildTask } from '@orkestrel/brief'
1419
1554
  *
1420
- * briefToMarkdown(brief(task('review', 'code', 'Review the gate rules.')))
1555
+ * briefToMarkdown(buildBrief(buildTask('review', 'code', 'Review the gate rules.')))
1421
1556
  * // '# Brief: Review the gate rules.\n\nreview · code\n\n## Output\n\n- format: markdown\n'
1422
1557
  * ```
1423
1558
  */
@@ -1511,21 +1646,21 @@ function briefToMarkdown(input) {
1511
1646
  return lines.join("\n");
1512
1647
  }
1513
1648
  /**
1514
- * Project a brief into a `/goal` completion condition.
1649
+ * Projects a brief into a `/goal` completion condition.
1515
1650
  *
1516
1651
  * @remarks
1517
1652
  * The proofs' commands VERBATIM plus a turn cap — the goal never adds a condition the
1518
1653
  * brief does not carry.
1519
1654
  *
1520
- * @param source - The brief to render.
1521
- * @param turns - The turn cap; defaults to `DEFAULT_BRIEF_TURNS`.
1655
+ * @param input - The brief to render.
1656
+ * @param turns - The turn cap. Default: `DEFAULT_BRIEF_TURNS`.
1522
1657
  * @returns The one-line completion condition.
1523
1658
  *
1524
1659
  * @example
1525
1660
  * ```ts
1526
- * import { brief, briefToGoal, proof, task } from '@orkestrel/brief'
1661
+ * import { briefToGoal, buildBrief, buildProof, buildTask } from '@orkestrel/brief'
1527
1662
  *
1528
- * briefToGoal(brief(task('test', 'code', 'Cover the gate.'), { proofs: [proof('x', 'npm test')] }))
1663
+ * briefToGoal(buildBrief(buildTask('test', 'code', 'Cover the gate.'), { proofs: [buildProof('x', 'npm test')] }))
1529
1664
  * // 'Done when every proof passes: npm test exits 0. Cap: 16 turns.'
1530
1665
  * ```
1531
1666
  */
@@ -1534,27 +1669,34 @@ function briefToGoal(input, turns = 16) {
1534
1669
  return `Done when every proof passes: ${source.proofs.length === 0 ? "no proofs recorded" : source.proofs.map((entry) => `${entry.command} exits 0`).join("; ")}. Cap: ${String(turns)} turns.`;
1535
1670
  }
1536
1671
  /**
1537
- * Project a brief into a subagent `Dispatch`.
1672
+ * Projects a brief into a subagent `Dispatch`.
1538
1673
  *
1539
1674
  * @remarks
1540
- * `edit` is exactly `manifest.edit`, so two dispatches whose `edit` sets do not intersect
1541
- * can run concurrently under the same brief without conflict.
1675
+ * `edit` is exactly `manifest.edit` — the owned set — so two dispatches whose `edit` sets do
1676
+ * not intersect can run concurrently under the same brief without conflict. `locked` and
1677
+ * `forbidden` cross unchanged as the do-not-touch sets.
1542
1678
  *
1543
- * `authority` is exactly `brief.authority` in rank order, and it is a SEPARATE axis from the
1544
- * four permission sets rather than a fifth partition — a ranked path normally also appears in
1679
+ * `authority` is exactly `brief.authority` in rank order, and it is a separate axis from the
1680
+ * permission sets rather than a further partition — a ranked path normally also appears in
1545
1681
  * `read` or `locked`, because the executor has to open what it obeys. It is projected as
1546
1682
  * paths so a machine consumer never has to parse `prompt`, which is written for a model.
1547
1683
  *
1548
- * @param source - The brief to project.
1549
- * @returns The dispatch — the rendered prompt, the ranked authority, and the four path sets.
1684
+ * @param input - The brief to project.
1685
+ * @returns The dispatch — the rendered prompt, the ranked authority, and the path sets.
1550
1686
  *
1551
1687
  * @example
1552
1688
  * ```ts
1553
- * import { brief, briefToDispatch, manifest, reference, task } from '@orkestrel/brief'
1554
- *
1555
- * const draft = brief(task('migrate', 'code', 'Migrate the stores.'), {
1556
- * authority: [reference('AGENTS.md', 'project law')],
1557
- * manifest: manifest({ edit: [reference('src/core/stores/**', 'the legacy stores')] }),
1689
+ * import {
1690
+ * briefToDispatch,
1691
+ * buildBrief,
1692
+ * buildManifest,
1693
+ * buildReference,
1694
+ * buildTask,
1695
+ * } from '@orkestrel/brief'
1696
+ *
1697
+ * const draft = buildBrief(buildTask('migrate', 'code', 'Migrate the stores.'), {
1698
+ * authority: [buildReference('AGENTS.md', 'project law')],
1699
+ * manifest: buildManifest({ edit: [buildReference('src/core/stores/**', 'the legacy stores')] }),
1558
1700
  * })
1559
1701
  * briefToDispatch(draft).edit // ['src/core/stores/**']
1560
1702
  * briefToDispatch(draft).authority // ['AGENTS.md']
@@ -1572,36 +1714,39 @@ function briefToDispatch(input) {
1572
1714
  };
1573
1715
  }
1574
1716
  /**
1575
- * Derive one imperative statement from free text.
1717
+ * Derives one imperative statement from free text.
1576
1718
  *
1577
1719
  * @remarks
1578
1720
  * Whitespace collapses, the first character uppercases, and a terminator is appended
1579
1721
  * when the text carries none. Nothing else is invented.
1580
1722
  *
1581
1723
  * @param text - The raw request text.
1582
- * @returns The statement, or `''` for empty or whitespace-only text.
1724
+ * @returns The statement, or `undefined` for empty or whitespace-only text.
1583
1725
  *
1584
1726
  * @example
1585
1727
  * ```ts
1586
1728
  * import { deriveStatement } from '@orkestrel/brief'
1587
1729
  *
1588
1730
  * deriveStatement(' clean up useForm ') // 'Clean up useForm.'
1589
- * deriveStatement('') // ''
1731
+ * deriveStatement('') // undefined
1590
1732
  * ```
1591
1733
  */
1592
1734
  function deriveStatement(text) {
1593
1735
  const collapsed = (0, _orkestrel_interpret.collapseWhitespace)(text);
1594
- if (collapsed.length === 0) return "";
1736
+ if (collapsed.length === 0) return void 0;
1595
1737
  const capitalized = collapsed.charAt(0).toUpperCase() + collapsed.slice(1);
1596
1738
  return /[.!?]$/u.test(capitalized) ? capitalized : `${capitalized}.`;
1597
1739
  }
1598
1740
  /**
1599
- * Derive a `Task` from an interprets `Intent` through the caller's vocabularies.
1741
+ * Derives a `Task` from an interprets `Intent` through the caller's vocabularies.
1600
1742
  *
1601
1743
  * @remarks
1602
1744
  * The vocabularies are the CALLER's policy: this maps and never guesses. An action or
1603
1745
  * domain the caller did not map — or mapped to an off-vocabulary value — yields
1604
- * `undefined` rather than an invented task. Inherited keys never resolve.
1746
+ * `undefined` rather than an invented task. Inherited keys never resolve. `Intent.action`
1747
+ * and `Intent.domain` are optional, because `classifyIntent` leaves an unmatched axis
1748
+ * absent, and an absent axis is unmapped by definition: it yields `undefined` before
1749
+ * either vocabulary is read.
1605
1750
  *
1606
1751
  * @param intent - The classified intent from an interpret pipeline.
1607
1752
  * @param text - The text the statement derives from.
@@ -1620,16 +1765,17 @@ function deriveStatement(text) {
1620
1765
  * ```
1621
1766
  */
1622
1767
  function deriveTask(intent, text, actions, domains) {
1768
+ if (intent.action === void 0 || intent.domain === void 0) return void 0;
1623
1769
  const operationDescriptor = Object.getOwnPropertyDescriptor(actions, intent.action);
1624
1770
  const domainDescriptor = Object.getOwnPropertyDescriptor(domains, intent.domain);
1625
1771
  const operation = operationDescriptor === void 0 ? void 0 : "value" in operationDescriptor ? operationDescriptor.value : operationDescriptor.get === void 0 ? void 0 : Reflect.apply(operationDescriptor.get, actions, []);
1626
1772
  const domain = domainDescriptor === void 0 ? void 0 : "value" in domainDescriptor ? domainDescriptor.value : domainDescriptor.get === void 0 ? void 0 : Reflect.apply(domainDescriptor.get, domains, []);
1627
1773
  if (!isTaskOperation(operation) || !isTaskDomain(domain)) return void 0;
1628
1774
  const statement = deriveStatement(text);
1629
- return statement.length === 0 ? void 0 : task(operation, domain, statement);
1775
+ return statement === void 0 ? void 0 : buildTask(operation, domain, statement);
1630
1776
  }
1631
1777
  /**
1632
- * Derive `Given[]` from an interprets `Entity[]`.
1778
+ * Derives `Given[]` from an interprets `Entity[]`.
1633
1779
  *
1634
1780
  * @remarks
1635
1781
  * Every extracted entity becomes one `extracted` fact. A nameless entity is dropped; an
@@ -1648,10 +1794,10 @@ function deriveTask(intent, text, actions, domains) {
1648
1794
  * ```
1649
1795
  */
1650
1796
  function deriveGivens(entities) {
1651
- return entities.filter((entity) => entity.name.length > 0).map((entity) => given("extracted", entity.name, typeof entity.value === "string" ? entity.value : typeof entity.value === "object" && entity.value !== null ? (0, _orkestrel_interpret.canonicalize)(entity.value) : String(entity.value)));
1797
+ return entities.filter((entity) => entity.name.length > 0).map((entity) => buildGiven("extracted", entity.name, typeof entity.value === "string" ? entity.value : typeof entity.value === "object" && entity.value !== null ? (0, _orkestrel_interpret.canonicalize)(entity.value) : String(entity.value)));
1652
1798
  }
1653
1799
  /**
1654
- * Derive `Gap[]` from an interprets `Ambiguity[]`.
1800
+ * Derives `Gap[]` from an interprets `Ambiguity[]`.
1655
1801
  *
1656
1802
  * @remarks
1657
1803
  * A REQUIRED ambiguity becomes a BLOCKING gap — the gate must fail closed on it. The
@@ -1672,7 +1818,7 @@ function deriveGivens(entities) {
1672
1818
  function deriveGaps(ambiguities) {
1673
1819
  return ambiguities.map((ambiguity) => {
1674
1820
  const candidates = ambiguity.candidates.filter((candidate) => candidate.length > 0);
1675
- return gap((0, _orkestrel_reason.formatField)(ambiguity.field), ambiguity.question, {
1821
+ return buildGap((0, _orkestrel_reason.formatField)(ambiguity.field), ambiguity.question, {
1676
1822
  blocking: ambiguity.required,
1677
1823
  ...candidates.length === 0 ? {} : { candidates }
1678
1824
  });
@@ -1681,7 +1827,7 @@ function deriveGaps(ambiguities) {
1681
1827
  //#endregion
1682
1828
  //#region src/core/parsers.ts
1683
1829
  /**
1684
- * Parse a JSON string into a `Brief`.
1830
+ * Parses a JSON string into a `Brief`.
1685
1831
  *
1686
1832
  * @remarks
1687
1833
  * The parse-then-trust boundary for a stored brief, a tool argument, or an agent's
@@ -1715,7 +1861,7 @@ function parseBrief(value) {
1715
1861
  //#endregion
1716
1862
  //#region src/core/BriefManager.ts
1717
1863
  /**
1718
- * The self-owning, versioned and content-hashed brief registry.
1864
+ * Implements the self-owning, versioned and content-hashed brief registry.
1719
1865
  *
1720
1866
  * @remarks
1721
1867
  * Record ids are MINTED from each brief's own content hash unless the caller names one,
@@ -1725,10 +1871,10 @@ function parseBrief(value) {
1725
1871
  *
1726
1872
  * @example
1727
1873
  * ```ts
1728
- * import { BriefManager, brief, task } from '@orkestrel/brief'
1874
+ * import { BriefManager, buildBrief, buildTask } from '@orkestrel/brief'
1729
1875
  *
1730
1876
  * const briefs = new BriefManager()
1731
- * const record = briefs.add(brief(task('document', 'writing', 'Write the brief guide.')))
1877
+ * const record = briefs.add(buildBrief(buildTask('document', 'writing', 'Write the brief guide.')))
1732
1878
  * record.id === record.hash // true
1733
1879
  * briefs.destroy()
1734
1880
  * ```
@@ -1755,7 +1901,7 @@ var BriefManager = class {
1755
1901
  get emitter() {
1756
1902
  return this.#emitter;
1757
1903
  }
1758
- get size() {
1904
+ get count() {
1759
1905
  return this.#records.size;
1760
1906
  }
1761
1907
  has(id) {
@@ -1770,9 +1916,9 @@ var BriefManager = class {
1770
1916
  this.#refuseDestroyed();
1771
1917
  return [...this.#records.values()];
1772
1918
  }
1773
- add(source, options) {
1919
+ add(brief, options) {
1774
1920
  this.#refuseDestroyed();
1775
- const record = this.#stage(source, this.#records, options);
1921
+ const record = this.#stage(brief, this.#records, options);
1776
1922
  this.#commit(record);
1777
1923
  return record;
1778
1924
  }
@@ -1839,7 +1985,7 @@ var BriefManager = class {
1839
1985
  //#endregion
1840
1986
  //#region src/core/BriefCompiler.ts
1841
1987
  /**
1842
- * The compilation orchestrator — the four-stage `[interpret, draft, gate, pin]` pipeline.
1988
+ * Implements the compilation orchestrator — the `[interpret, draft, gate, pin]` pipeline.
1843
1989
  *
1844
1990
  * @remarks
1845
1991
  * `compile` is genuinely SYNCHRONOUS and never throws for a brief it cannot emit: a
@@ -1849,13 +1995,13 @@ var BriefManager = class {
1849
1995
  *
1850
1996
  * @example
1851
1997
  * ```ts
1852
- * import { BriefCompiler, proof, task } from '@orkestrel/brief'
1998
+ * import { BriefCompiler, buildProof, buildTask } from '@orkestrel/brief'
1853
1999
  *
1854
2000
  * const compiler = new BriefCompiler()
1855
2001
  * const briefing = compiler.compile({
1856
- * task: task('audit', 'code', 'Audit the barrel for undocumented exports.'),
2002
+ * task: buildTask('audit', 'code', 'Audit the barrel for undocumented exports.'),
1857
2003
  * outcomes: [{ rank: 1, text: 'every export appears in the guide', required: true }],
1858
- * proofs: [proof('parity passes', 'npm run test:guides')],
2004
+ * proofs: [buildProof('parity passes', 'npm run test:guides')],
1859
2005
  * })
1860
2006
  * briefing.brief !== undefined // true — the presence of the brief IS the completeness test
1861
2007
  * compiler.destroy()
@@ -2006,9 +2152,9 @@ var BriefCompiler = class {
2006
2152
  this.#emitter.emit("compile", briefing);
2007
2153
  return briefing;
2008
2154
  }
2009
- gate(source) {
2155
+ gate(brief) {
2010
2156
  this.#refuseDestroyed();
2011
- const ruled = (0, _orkestrel_contract.attempt)(() => this.#own(this.#reason.reason(briefToSubject(source), gateDefinition()), [
2157
+ const ruled = (0, _orkestrel_contract.attempt)(() => this.#own(this.#reason.reason(briefToSubject(brief), buildGateDefinition()), [
2012
2158
  "reasoning",
2013
2159
  "conclusion",
2014
2160
  "rules",
@@ -2097,7 +2243,7 @@ var BriefCompiler = class {
2097
2243
  message: `Gate refused: ${unready.join(", ")}`
2098
2244
  };
2099
2245
  if (verdict === void 0) return void 0;
2100
- const refused = verdict.rules.filter((entry) => !entry.conclusion).map((entry) => entry.id).join(", ");
2246
+ const refused = verdict.rules.filter((entry) => !entry.applied).map((entry) => entry.id).join(", ");
2101
2247
  if (refused.length === 0) return {
2102
2248
  stage: "gate",
2103
2249
  code: "BLOCKED",
@@ -2112,7 +2258,7 @@ var BriefCompiler = class {
2112
2258
  #unresolved(interpretation, failures) {
2113
2259
  if (interpretation !== void 0) return [];
2114
2260
  if (!failures.some((entry) => entry.stage === "interpret")) return [];
2115
- return [gap("gaps", "The interpret stage failed, so the request is unread and its unknowns are unknown", { blocking: true })];
2261
+ return [buildGap("gaps", "The interpret stage failed, so the request is unread and its unknowns are unknown", { blocking: true })];
2116
2262
  }
2117
2263
  #draft(input, interpretation, unresolved) {
2118
2264
  const derived = interpretation === void 0 ? void 0 : deriveTask(interpretation.intent, interpretation.text, this.#actions, this.#domains);
@@ -2121,9 +2267,9 @@ var BriefCompiler = class {
2121
2267
  stage: "draft",
2122
2268
  field: "task"
2123
2269
  });
2124
- return snapshotBrief(brief(subject, {
2270
+ return snapshotBrief(buildBrief(subject, {
2125
2271
  authority: input.authority ?? [],
2126
- manifest: input.manifest ?? manifest(),
2272
+ manifest: input.manifest ?? buildManifest(),
2127
2273
  outcomes: input.outcomes ?? [],
2128
2274
  rules: input.rules ?? [],
2129
2275
  invariants: input.invariants ?? [],
@@ -2137,7 +2283,7 @@ var BriefCompiler = class {
2137
2283
  ...input.gaps ?? []
2138
2284
  ],
2139
2285
  risks: input.risks ?? [],
2140
- output: input.output ?? output("markdown"),
2286
+ output: input.output ?? buildOutput("markdown"),
2141
2287
  proofs: input.proofs ?? []
2142
2288
  }));
2143
2289
  }
@@ -2165,7 +2311,7 @@ var BriefCompiler = class {
2165
2311
  //#endregion
2166
2312
  //#region src/core/factories.ts
2167
2313
  /**
2168
- * Create a compilation orchestrator.
2314
+ * Creates a compilation orchestrator.
2169
2315
  *
2170
2316
  * @remarks
2171
2317
  * With no engines supplied the compiler wires its own: a default `createInterpret()`
@@ -2173,9 +2319,49 @@ var BriefCompiler = class {
2173
2319
  * `createReason` carrying one `LogicalReasoner` for the gate. Pass your own to share
2174
2320
  * instances or observe their emitters — the compiler destroys ONLY what it created.
2175
2321
  *
2176
- * @param options - Engines to borrow, the two intent vocabularies, and emitter hooks.
2322
+ * @param options - Engines to borrow, the `actions` and `domains` intent vocabularies, and
2323
+ * emitter hooks.
2177
2324
  * @returns A working {@link BriefCompilerInterface}.
2178
2325
  *
2326
+ * @example Compile and project a brief
2327
+ * ```ts
2328
+ * import {
2329
+ * briefToGoal,
2330
+ * briefToMarkdown,
2331
+ * buildOutcome,
2332
+ * buildProof,
2333
+ * buildTask,
2334
+ * createBriefCompiler,
2335
+ * } from '@orkestrel/brief'
2336
+ *
2337
+ * const compiler = createBriefCompiler()
2338
+ *
2339
+ * const briefing = compiler.compile({
2340
+ * task: buildTask('refactor', 'code', 'Refactor useForm to native browser form APIs.'),
2341
+ * authority: [{ path: 'AGENTS.md', note: 'project law; wins every conflict' }],
2342
+ * manifest: {
2343
+ * read: [
2344
+ * { path: 'AGENTS.md', note: 'project law; wins every conflict' },
2345
+ * { path: 'guides/browser.md', note: 'the composable contract' },
2346
+ * ],
2347
+ * edit: [{ path: 'src/browser/composables/useForm.ts', note: 'the composable being refactored' }],
2348
+ * locked: [{ path: 'src/browser/types.ts', note: 'the published contract' }],
2349
+ * forbidden: [{ path: 'app/**', note: 'out of scope' }],
2350
+ * },
2351
+ * outcomes: [buildOutcome(1, 'useForm uses native FormData with no behavior change')],
2352
+ * proofs: [buildProof('type-check and lint pass', 'npm run check')],
2353
+ * })
2354
+ *
2355
+ * briefing.brief !== undefined // true — the brief is present exactly when the gate passed
2356
+ * if (briefing.brief !== undefined) {
2357
+ * briefToMarkdown(briefing.brief) // the copy-ready agent prompt
2358
+ * briefToGoal(briefing.brief) // the /goal completion condition
2359
+ * }
2360
+ *
2361
+ * compiler.emitter.on('block', (questions) => questions.length)
2362
+ * compiler.destroy()
2363
+ * ```
2364
+ *
2179
2365
  * @example
2180
2366
  * ```ts
2181
2367
  * import { createBriefCompiler } from '@orkestrel/brief'
@@ -2188,7 +2374,7 @@ function createBriefCompiler(options) {
2188
2374
  return new BriefCompiler(options);
2189
2375
  }
2190
2376
  /**
2191
- * Create a brief registry.
2377
+ * Creates a brief registry.
2192
2378
  *
2193
2379
  * @param options - An optional seed collection plus emitter hooks.
2194
2380
  * @returns A working {@link BriefManagerInterface}.
@@ -2198,7 +2384,7 @@ function createBriefCompiler(options) {
2198
2384
  * import { createBriefManager } from '@orkestrel/brief'
2199
2385
  *
2200
2386
  * const briefs = createBriefManager()
2201
- * briefs.size // 0
2387
+ * briefs.count // 0
2202
2388
  * briefs.destroy()
2203
2389
  * ```
2204
2390
  */
@@ -2206,7 +2392,7 @@ function createBriefManager(options) {
2206
2392
  return new BriefManager(options);
2207
2393
  }
2208
2394
  /**
2209
- * Compile `briefShape` into a guard, parser, JSON Schema, and seeded generator bundle.
2395
+ * Compiles `briefShape` into a guard, parser, JSON Schema, and seeded generator bundle.
2210
2396
  *
2211
2397
  * @remarks
2212
2398
  * The schema is what a tool boundary needs — hand it to `schemaToParameters` — and
@@ -2244,7 +2430,6 @@ exports.SINGLE_LINE_PATTERN = SINGLE_LINE_PATTERN;
2244
2430
  exports.TASK_DOMAINS = TASK_DOMAINS;
2245
2431
  exports.TASK_OPERATIONS = TASK_OPERATIONS;
2246
2432
  exports.assertBrief = assertBrief;
2247
- exports.brief = brief;
2248
2433
  exports.briefShape = briefShape;
2249
2434
  exports.briefToContent = briefToContent;
2250
2435
  exports.briefToDispatch = briefToDispatch;
@@ -2253,8 +2438,20 @@ exports.briefToHash = briefToHash;
2253
2438
  exports.briefToMarkdown = briefToMarkdown;
2254
2439
  exports.briefToSubject = briefToSubject;
2255
2440
  exports.briefToTrace = briefToTrace;
2441
+ exports.buildBrief = buildBrief;
2442
+ exports.buildCitation = buildCitation;
2443
+ exports.buildExample = buildExample;
2444
+ exports.buildGap = buildGap;
2445
+ exports.buildGateDefinition = buildGateDefinition;
2446
+ exports.buildGiven = buildGiven;
2447
+ exports.buildManifest = buildManifest;
2448
+ exports.buildOutcome = buildOutcome;
2449
+ exports.buildOutput = buildOutput;
2450
+ exports.buildProof = buildProof;
2451
+ exports.buildReference = buildReference;
2452
+ exports.buildRisk = buildRisk;
2453
+ exports.buildTask = buildTask;
2256
2454
  exports.captureValue = captureValue;
2257
- exports.citation = citation;
2258
2455
  exports.citationShape = citationShape;
2259
2456
  exports.countSentences = countSentences;
2260
2457
  exports.createBriefCompiler = createBriefCompiler;
@@ -2265,7 +2462,6 @@ exports.deriveGivens = deriveGivens;
2265
2462
  exports.deriveStatement = deriveStatement;
2266
2463
  exports.deriveTask = deriveTask;
2267
2464
  exports.errorToMessage = errorToMessage;
2268
- exports.example = example;
2269
2465
  exports.exampleShape = exampleShape;
2270
2466
  exports.exampleToLines = exampleToLines;
2271
2467
  exports.findBlockingGaps = findBlockingGaps;
@@ -2275,10 +2471,7 @@ exports.findUnmetRules = findUnmetRules;
2275
2471
  exports.findUnpairedGaps = findUnpairedGaps;
2276
2472
  exports.freezeBranch = freezeBranch;
2277
2473
  exports.freezeDeep = freezeDeep;
2278
- exports.gap = gap;
2279
2474
  exports.gapShape = gapShape;
2280
- exports.gateDefinition = gateDefinition;
2281
- exports.given = given;
2282
2475
  exports.givenShape = givenShape;
2283
2476
  exports.isBrief = isBrief;
2284
2477
  exports.isBriefError = isBriefError;
@@ -2300,22 +2493,15 @@ exports.isTaskDomain = isTaskDomain;
2300
2493
  exports.isTaskOperation = isTaskOperation;
2301
2494
  exports.isText = isText;
2302
2495
  exports.lineShape = lineShape;
2303
- exports.manifest = manifest;
2304
2496
  exports.manifestShape = manifestShape;
2305
- exports.outcome = outcome;
2306
2497
  exports.outcomeShape = outcomeShape;
2307
- exports.output = output;
2308
2498
  exports.outputShape = outputShape;
2309
2499
  exports.parseBrief = parseBrief;
2310
2500
  exports.pinBrief = pinBrief;
2311
- exports.proof = proof;
2312
2501
  exports.proofShape = proofShape;
2313
- exports.reference = reference;
2314
2502
  exports.referenceShape = referenceShape;
2315
- exports.risk = risk;
2316
2503
  exports.riskShape = riskShape;
2317
2504
  exports.snapshotBrief = snapshotBrief;
2318
- exports.task = task;
2319
2505
  exports.taskShape = taskShape;
2320
2506
  exports.textShape = textShape;
2321
2507
  exports.validateBrief = validateBrief;