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