@orkestrel/brief 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/index.cjs +147 -8
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +79 -10
- package/dist/src/core/index.d.ts +79 -10
- package/dist/src/core/index.js +146 -9
- package/dist/src/core/index.js.map +1 -1
- package/package.json +13 -12
|
@@ -31,6 +31,15 @@ import { Subject } from '@orkestrel/reason';
|
|
|
31
31
|
* nothing, so it is an assertion rather than a factory. Reserve it for programmer-error
|
|
32
32
|
* contexts where invalidity is a bug.
|
|
33
33
|
*
|
|
34
|
+
* Intake NARROWS, and transfers no ownership. What comes back is the caller's own object,
|
|
35
|
+
* so a member carried on an accessor can answer this guard one way and a later reader
|
|
36
|
+
* another. The division is deliberate: the borrowed-engine law governs values this package
|
|
37
|
+
* pulls across a seam it called, and a value handed in at the door stays the caller's.
|
|
38
|
+
* `snapshotBrief` is the ownership door, and `pinBrief`, `BriefManager`, `briefToMarkdown`,
|
|
39
|
+
* `briefToGoal`, and `briefToDispatch` take it. `briefToSubject`, `briefToContent`, and
|
|
40
|
+
* `briefToTrace` read the value they are handed instead, so a caller reaching one of those
|
|
41
|
+
* directly owns that reading. Pass `assertBrief` a value you already own.
|
|
42
|
+
*
|
|
34
43
|
* @param data - The candidate brief data.
|
|
35
44
|
* @returns The same value, now known to satisfy {@link Brief}.
|
|
36
45
|
* @throws {@link BriefError} `INVALID` when `data` fails `isBrief`.
|
|
@@ -173,22 +182,31 @@ import { Subject } from '@orkestrel/reason';
|
|
|
173
182
|
* is FIXED: readiness is this package's contract, not a caller setting.
|
|
174
183
|
*
|
|
175
184
|
* A borrowed engine is the caller's own code, not an attacker, and this package does not
|
|
176
|
-
* treat it as one. The line is OWNERSHIP, and it produces
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* - Every value a borrowed engine returns is OWNED AT ARRIVAL — copied where
|
|
180
|
-
*
|
|
181
|
-
*
|
|
185
|
+
* treat it as one. The line is OWNERSHIP, and it produces obligations worth stating because
|
|
186
|
+
* none of them is enforced in code:
|
|
187
|
+
*
|
|
188
|
+
* - Every value a borrowed engine returns is OWNED AT ARRIVAL — copied where a structured
|
|
189
|
+
* clone can carry it, captured into a frozen plain view where it cannot — and read once,
|
|
190
|
+
* where that copy or capture takes the reading. The captured view is what the `Briefing`
|
|
191
|
+
* replays, exactly as the clone arm always produced: a member the caller's prototype
|
|
192
|
+
* carries, outside the published contract, does not survive capture, and it never survived
|
|
193
|
+
* a structured clone either. What the engine does with its own object afterwards cannot
|
|
194
|
+
* reach a `Briefing`.
|
|
182
195
|
* - Both returns are shape-checked with their packages' published guards — reasons' logical
|
|
183
196
|
* result guard for the verdict, interprets' interpretation guard at both of the interpret
|
|
184
197
|
* stage's doors. A malformed value at either door records `INTERPRET_FAILED` instead of
|
|
185
198
|
* escaping `compile` as a raw throw, and a supplied interpretation whose snapshot copy
|
|
186
|
-
* loses prototype-carried members is
|
|
199
|
+
* loses prototype-carried members is captured rather than refused.
|
|
187
200
|
* - Neither engine is narrowed past its published contract. `Entity.value` is `unknown` and
|
|
188
201
|
* `LogicalResult` is an interface a class instance satisfies, so a value JSON cannot
|
|
189
|
-
* express is on-contract
|
|
190
|
-
*
|
|
191
|
-
*
|
|
202
|
+
* express is on-contract: its uncloneable leaves keep their identity inside the captured
|
|
203
|
+
* view rather than being refused.
|
|
204
|
+
* - `actions` and `domains` are read as option slots ONCE, at construction, so replacing
|
|
205
|
+
* either property on the options object afterwards changes nothing. The map each slot
|
|
206
|
+
* names is dereferenced on every `compile`, and each lookup captures its mapping once
|
|
207
|
+
* through the own descriptor. Mutating a map between calls therefore changes what the next
|
|
208
|
+
* call derives, while a mapping that answers differently on a second read cannot change
|
|
209
|
+
* what one call already derived.
|
|
192
210
|
*
|
|
193
211
|
* Whether the engine is correct, and whether it answers the same way twice, remain the
|
|
194
212
|
* caller's own problem.
|
|
@@ -638,6 +656,32 @@ import { Subject } from '@orkestrel/reason';
|
|
|
638
656
|
*/
|
|
639
657
|
export declare function briefToTrace(source: Brief): string;
|
|
640
658
|
|
|
659
|
+
/**
|
|
660
|
+
* Captures one stable, frozen view of a foreign contract value.
|
|
661
|
+
*
|
|
662
|
+
* @remarks
|
|
663
|
+
* Rebuilds the root and every reachable plain container from its own enumerable members.
|
|
664
|
+
* Unknown own members survive. Each published member absent from that copied own set is read
|
|
665
|
+
* once and materialized, which admits a class that supplies its contract through prototype
|
|
666
|
+
* accessors without leaving later reads attached to the live instance. Non-container leaves
|
|
667
|
+
* retain their identity, including functions that `structuredClone` cannot carry.
|
|
668
|
+
*
|
|
669
|
+
* @param source - The foreign value to capture.
|
|
670
|
+
* @param members - The published root member names to materialize when absent from its own set.
|
|
671
|
+
* @returns A deeply frozen plain view, or `source` itself when it is a primitive.
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* ```ts
|
|
675
|
+
* import { captureValue } from '@orkestrel/brief'
|
|
676
|
+
*
|
|
677
|
+
* const leaf = () => 'ready'
|
|
678
|
+
* const owned = captureValue({ leaf }, ['leaf'])
|
|
679
|
+
* Reflect.get(owned, 'leaf') === leaf // true — an uncloneable leaf keeps its identity
|
|
680
|
+
* Object.isFrozen(owned) // true
|
|
681
|
+
* ```
|
|
682
|
+
*/
|
|
683
|
+
export declare function captureValue(source: unknown, members: readonly string[]): unknown;
|
|
684
|
+
|
|
641
685
|
/**
|
|
642
686
|
* One external source — what it is called, where it lives, and why it is cited.
|
|
643
687
|
*
|
|
@@ -1307,6 +1351,22 @@ import { Subject } from '@orkestrel/reason';
|
|
|
1307
1351
|
value: StringShape;
|
|
1308
1352
|
}, false>;
|
|
1309
1353
|
|
|
1354
|
+
/**
|
|
1355
|
+
* Every published `Interpretation` member name, frozen.
|
|
1356
|
+
*
|
|
1357
|
+
* @remarks
|
|
1358
|
+
* The capture list `BriefCompiler` hands `captureValue` at each interpret door — the borrowed
|
|
1359
|
+
* engine's return, and the caller's supplied interpretation. A class instance carries its
|
|
1360
|
+
* contract on the prototype, so the captured view materializes exactly the members named here,
|
|
1361
|
+
* and a name missing from the list is a member the view drops.
|
|
1362
|
+
*
|
|
1363
|
+
* The `satisfies` clause refuses a name `Interpretation` does not declare, and it holds the
|
|
1364
|
+
* element type at the listed names rather than widening it to `string`. That is what lets the
|
|
1365
|
+
* equality assertion beside the capture cases refuse a list that has fallen short of the
|
|
1366
|
+
* published shape.
|
|
1367
|
+
*/
|
|
1368
|
+
export declare const INTERPRETATION_MEMBERS: readonly ("text" | "normalized" | "intent" | "entities" | "subject" | "definition" | "mappings" | "ambiguities" | "prompt" | "stages" | "failures" | "complete" | "confidence" | "digest")[];
|
|
1369
|
+
|
|
1310
1370
|
/**
|
|
1311
1371
|
* The `interpret` phase snapshot — raw text in, an `Interpretation` out.
|
|
1312
1372
|
*
|
|
@@ -1572,6 +1632,15 @@ import { Subject } from '@orkestrel/reason';
|
|
|
1572
1632
|
* all fail the same way — `undefined`, never a throw. Coerce a bare vocabulary value with
|
|
1573
1633
|
* `parseEnum` from `@orkestrel/contract` against the exported tuple instead.
|
|
1574
1634
|
*
|
|
1635
|
+
* The half of the intake pair that is OWNED BY CONSTRUCTION, which is what separates it from
|
|
1636
|
+
* `assertBrief`. The argument is text, so the graph the guard reads is one `JSON.parse` built
|
|
1637
|
+
* inside this call: it carries no caller identity, no accessor, and no alias back into anything
|
|
1638
|
+
* the caller still holds, and the parse-and-guard primitive this file imports from
|
|
1639
|
+
* `@orkestrel/contract` returns that same parsed graph rather than a second reading of it.
|
|
1640
|
+
* Every member `isBrief` checked therefore answers a later reader identically. The value is
|
|
1641
|
+
* fresh rather than frozen, so the caller owns it outright — reach for `snapshotBrief` when the
|
|
1642
|
+
* value came from code instead of from text.
|
|
1643
|
+
*
|
|
1575
1644
|
* @param value - The JSON text to parse.
|
|
1576
1645
|
* @returns The `Brief` when the parsed value satisfies `isBrief`, otherwise `undefined`.
|
|
1577
1646
|
*
|
package/dist/src/core/index.d.ts
CHANGED
|
@@ -31,6 +31,15 @@ import { Subject } from '@orkestrel/reason';
|
|
|
31
31
|
* nothing, so it is an assertion rather than a factory. Reserve it for programmer-error
|
|
32
32
|
* contexts where invalidity is a bug.
|
|
33
33
|
*
|
|
34
|
+
* Intake NARROWS, and transfers no ownership. What comes back is the caller's own object,
|
|
35
|
+
* so a member carried on an accessor can answer this guard one way and a later reader
|
|
36
|
+
* another. The division is deliberate: the borrowed-engine law governs values this package
|
|
37
|
+
* pulls across a seam it called, and a value handed in at the door stays the caller's.
|
|
38
|
+
* `snapshotBrief` is the ownership door, and `pinBrief`, `BriefManager`, `briefToMarkdown`,
|
|
39
|
+
* `briefToGoal`, and `briefToDispatch` take it. `briefToSubject`, `briefToContent`, and
|
|
40
|
+
* `briefToTrace` read the value they are handed instead, so a caller reaching one of those
|
|
41
|
+
* directly owns that reading. Pass `assertBrief` a value you already own.
|
|
42
|
+
*
|
|
34
43
|
* @param data - The candidate brief data.
|
|
35
44
|
* @returns The same value, now known to satisfy {@link Brief}.
|
|
36
45
|
* @throws {@link BriefError} `INVALID` when `data` fails `isBrief`.
|
|
@@ -173,22 +182,31 @@ import { Subject } from '@orkestrel/reason';
|
|
|
173
182
|
* is FIXED: readiness is this package's contract, not a caller setting.
|
|
174
183
|
*
|
|
175
184
|
* A borrowed engine is the caller's own code, not an attacker, and this package does not
|
|
176
|
-
* treat it as one. The line is OWNERSHIP, and it produces
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* - Every value a borrowed engine returns is OWNED AT ARRIVAL — copied where
|
|
180
|
-
*
|
|
181
|
-
*
|
|
185
|
+
* treat it as one. The line is OWNERSHIP, and it produces obligations worth stating because
|
|
186
|
+
* none of them is enforced in code:
|
|
187
|
+
*
|
|
188
|
+
* - Every value a borrowed engine returns is OWNED AT ARRIVAL — copied where a structured
|
|
189
|
+
* clone can carry it, captured into a frozen plain view where it cannot — and read once,
|
|
190
|
+
* where that copy or capture takes the reading. The captured view is what the `Briefing`
|
|
191
|
+
* replays, exactly as the clone arm always produced: a member the caller's prototype
|
|
192
|
+
* carries, outside the published contract, does not survive capture, and it never survived
|
|
193
|
+
* a structured clone either. What the engine does with its own object afterwards cannot
|
|
194
|
+
* reach a `Briefing`.
|
|
182
195
|
* - Both returns are shape-checked with their packages' published guards — reasons' logical
|
|
183
196
|
* result guard for the verdict, interprets' interpretation guard at both of the interpret
|
|
184
197
|
* stage's doors. A malformed value at either door records `INTERPRET_FAILED` instead of
|
|
185
198
|
* escaping `compile` as a raw throw, and a supplied interpretation whose snapshot copy
|
|
186
|
-
* loses prototype-carried members is
|
|
199
|
+
* loses prototype-carried members is captured rather than refused.
|
|
187
200
|
* - Neither engine is narrowed past its published contract. `Entity.value` is `unknown` and
|
|
188
201
|
* `LogicalResult` is an interface a class instance satisfies, so a value JSON cannot
|
|
189
|
-
* express is on-contract
|
|
190
|
-
*
|
|
191
|
-
*
|
|
202
|
+
* express is on-contract: its uncloneable leaves keep their identity inside the captured
|
|
203
|
+
* view rather than being refused.
|
|
204
|
+
* - `actions` and `domains` are read as option slots ONCE, at construction, so replacing
|
|
205
|
+
* either property on the options object afterwards changes nothing. The map each slot
|
|
206
|
+
* names is dereferenced on every `compile`, and each lookup captures its mapping once
|
|
207
|
+
* through the own descriptor. Mutating a map between calls therefore changes what the next
|
|
208
|
+
* call derives, while a mapping that answers differently on a second read cannot change
|
|
209
|
+
* what one call already derived.
|
|
192
210
|
*
|
|
193
211
|
* Whether the engine is correct, and whether it answers the same way twice, remain the
|
|
194
212
|
* caller's own problem.
|
|
@@ -638,6 +656,32 @@ import { Subject } from '@orkestrel/reason';
|
|
|
638
656
|
*/
|
|
639
657
|
export declare function briefToTrace(source: Brief): string;
|
|
640
658
|
|
|
659
|
+
/**
|
|
660
|
+
* Captures one stable, frozen view of a foreign contract value.
|
|
661
|
+
*
|
|
662
|
+
* @remarks
|
|
663
|
+
* Rebuilds the root and every reachable plain container from its own enumerable members.
|
|
664
|
+
* Unknown own members survive. Each published member absent from that copied own set is read
|
|
665
|
+
* once and materialized, which admits a class that supplies its contract through prototype
|
|
666
|
+
* accessors without leaving later reads attached to the live instance. Non-container leaves
|
|
667
|
+
* retain their identity, including functions that `structuredClone` cannot carry.
|
|
668
|
+
*
|
|
669
|
+
* @param source - The foreign value to capture.
|
|
670
|
+
* @param members - The published root member names to materialize when absent from its own set.
|
|
671
|
+
* @returns A deeply frozen plain view, or `source` itself when it is a primitive.
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* ```ts
|
|
675
|
+
* import { captureValue } from '@orkestrel/brief'
|
|
676
|
+
*
|
|
677
|
+
* const leaf = () => 'ready'
|
|
678
|
+
* const owned = captureValue({ leaf }, ['leaf'])
|
|
679
|
+
* Reflect.get(owned, 'leaf') === leaf // true — an uncloneable leaf keeps its identity
|
|
680
|
+
* Object.isFrozen(owned) // true
|
|
681
|
+
* ```
|
|
682
|
+
*/
|
|
683
|
+
export declare function captureValue(source: unknown, members: readonly string[]): unknown;
|
|
684
|
+
|
|
641
685
|
/**
|
|
642
686
|
* One external source — what it is called, where it lives, and why it is cited.
|
|
643
687
|
*
|
|
@@ -1307,6 +1351,22 @@ import { Subject } from '@orkestrel/reason';
|
|
|
1307
1351
|
value: StringShape;
|
|
1308
1352
|
}, false>;
|
|
1309
1353
|
|
|
1354
|
+
/**
|
|
1355
|
+
* Every published `Interpretation` member name, frozen.
|
|
1356
|
+
*
|
|
1357
|
+
* @remarks
|
|
1358
|
+
* The capture list `BriefCompiler` hands `captureValue` at each interpret door — the borrowed
|
|
1359
|
+
* engine's return, and the caller's supplied interpretation. A class instance carries its
|
|
1360
|
+
* contract on the prototype, so the captured view materializes exactly the members named here,
|
|
1361
|
+
* and a name missing from the list is a member the view drops.
|
|
1362
|
+
*
|
|
1363
|
+
* The `satisfies` clause refuses a name `Interpretation` does not declare, and it holds the
|
|
1364
|
+
* element type at the listed names rather than widening it to `string`. That is what lets the
|
|
1365
|
+
* equality assertion beside the capture cases refuse a list that has fallen short of the
|
|
1366
|
+
* published shape.
|
|
1367
|
+
*/
|
|
1368
|
+
export declare const INTERPRETATION_MEMBERS: readonly ("text" | "normalized" | "intent" | "entities" | "subject" | "definition" | "mappings" | "ambiguities" | "prompt" | "stages" | "failures" | "complete" | "confidence" | "digest")[];
|
|
1369
|
+
|
|
1310
1370
|
/**
|
|
1311
1371
|
* The `interpret` phase snapshot — raw text in, an `Interpretation` out.
|
|
1312
1372
|
*
|
|
@@ -1572,6 +1632,15 @@ import { Subject } from '@orkestrel/reason';
|
|
|
1572
1632
|
* all fail the same way — `undefined`, never a throw. Coerce a bare vocabulary value with
|
|
1573
1633
|
* `parseEnum` from `@orkestrel/contract` against the exported tuple instead.
|
|
1574
1634
|
*
|
|
1635
|
+
* The half of the intake pair that is OWNED BY CONSTRUCTION, which is what separates it from
|
|
1636
|
+
* `assertBrief`. The argument is text, so the graph the guard reads is one `JSON.parse` built
|
|
1637
|
+
* inside this call: it carries no caller identity, no accessor, and no alias back into anything
|
|
1638
|
+
* the caller still holds, and the parse-and-guard primitive this file imports from
|
|
1639
|
+
* `@orkestrel/contract` returns that same parsed graph rather than a second reading of it.
|
|
1640
|
+
* Every member `isBrief` checked therefore answers a later reader identically. The value is
|
|
1641
|
+
* fresh rather than frozen, so the caller owns it outright — reach for `snapshotBrief` when the
|
|
1642
|
+
* value came from code instead of from text.
|
|
1643
|
+
*
|
|
1575
1644
|
* @param value - The JSON text to parse.
|
|
1576
1645
|
* @returns The `Brief` when the parsed value satisfies `isBrief`, otherwise `undefined`.
|
|
1577
1646
|
*
|
package/dist/src/core/index.js
CHANGED
|
@@ -44,6 +44,36 @@ var RISK_SEVERITIES = Object.freeze([
|
|
|
44
44
|
"high"
|
|
45
45
|
]);
|
|
46
46
|
/**
|
|
47
|
+
* Every published `Interpretation` member name, frozen.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* The capture list `BriefCompiler` hands `captureValue` at each interpret door — the borrowed
|
|
51
|
+
* engine's return, and the caller's supplied interpretation. A class instance carries its
|
|
52
|
+
* contract on the prototype, so the captured view materializes exactly the members named here,
|
|
53
|
+
* and a name missing from the list is a member the view drops.
|
|
54
|
+
*
|
|
55
|
+
* The `satisfies` clause refuses a name `Interpretation` does not declare, and it holds the
|
|
56
|
+
* element type at the listed names rather than widening it to `string`. That is what lets the
|
|
57
|
+
* equality assertion beside the capture cases refuse a list that has fallen short of the
|
|
58
|
+
* published shape.
|
|
59
|
+
*/
|
|
60
|
+
var INTERPRETATION_MEMBERS = Object.freeze([
|
|
61
|
+
"text",
|
|
62
|
+
"normalized",
|
|
63
|
+
"intent",
|
|
64
|
+
"entities",
|
|
65
|
+
"subject",
|
|
66
|
+
"definition",
|
|
67
|
+
"mappings",
|
|
68
|
+
"ambiguities",
|
|
69
|
+
"prompt",
|
|
70
|
+
"stages",
|
|
71
|
+
"failures",
|
|
72
|
+
"complete",
|
|
73
|
+
"confidence",
|
|
74
|
+
"digest"
|
|
75
|
+
]);
|
|
76
|
+
/**
|
|
47
77
|
* `16` — the default turn cap `briefToGoal` renders.
|
|
48
78
|
*
|
|
49
79
|
* @remarks
|
|
@@ -369,6 +399,84 @@ var isBrief = recordOf({
|
|
|
369
399
|
//#endregion
|
|
370
400
|
//#region src/core/cloners.ts
|
|
371
401
|
/**
|
|
402
|
+
* Captures one stable, frozen view of a foreign contract value.
|
|
403
|
+
*
|
|
404
|
+
* @remarks
|
|
405
|
+
* Rebuilds the root and every reachable plain container from its own enumerable members.
|
|
406
|
+
* Unknown own members survive. Each published member absent from that copied own set is read
|
|
407
|
+
* once and materialized, which admits a class that supplies its contract through prototype
|
|
408
|
+
* accessors without leaving later reads attached to the live instance. Non-container leaves
|
|
409
|
+
* retain their identity, including functions that `structuredClone` cannot carry.
|
|
410
|
+
*
|
|
411
|
+
* @param source - The foreign value to capture.
|
|
412
|
+
* @param members - The published root member names to materialize when absent from its own set.
|
|
413
|
+
* @returns A deeply frozen plain view, or `source` itself when it is a primitive.
|
|
414
|
+
*
|
|
415
|
+
* @example
|
|
416
|
+
* ```ts
|
|
417
|
+
* import { captureValue } from '@orkestrel/brief'
|
|
418
|
+
*
|
|
419
|
+
* const leaf = () => 'ready'
|
|
420
|
+
* const owned = captureValue({ leaf }, ['leaf'])
|
|
421
|
+
* Reflect.get(owned, 'leaf') === leaf // true — an uncloneable leaf keeps its identity
|
|
422
|
+
* Object.isFrozen(owned) // true
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
function captureValue(source, members) {
|
|
426
|
+
if (source === null || typeof source !== "object" && typeof source !== "function") return source;
|
|
427
|
+
const target = Array.isArray(source) ? [] : Object.create(null);
|
|
428
|
+
const seen = new WeakMap([[source, target]]);
|
|
429
|
+
const captured = [target];
|
|
430
|
+
const pending = [[
|
|
431
|
+
source,
|
|
432
|
+
target,
|
|
433
|
+
members
|
|
434
|
+
]];
|
|
435
|
+
while (pending.length > 0) {
|
|
436
|
+
const frame = pending.pop();
|
|
437
|
+
if (frame === void 0) continue;
|
|
438
|
+
const [current, view, expected] = frame;
|
|
439
|
+
const entries = [];
|
|
440
|
+
const copied = /* @__PURE__ */ new Set();
|
|
441
|
+
for (const key of Reflect.ownKeys(current)) {
|
|
442
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(current, key);
|
|
443
|
+
if (descriptor === void 0 || !descriptor.enumerable) continue;
|
|
444
|
+
copied.add(key);
|
|
445
|
+
entries.push([key, "value" in descriptor ? descriptor.value : Reflect.get(current, key)]);
|
|
446
|
+
}
|
|
447
|
+
for (const key of expected ?? []) if (!copied.has(key)) entries.push([key, Reflect.get(current, key)]);
|
|
448
|
+
for (const [key, value] of entries) {
|
|
449
|
+
let owned = value;
|
|
450
|
+
if (value !== null && typeof value === "object") {
|
|
451
|
+
const existing = seen.get(value);
|
|
452
|
+
if (existing !== void 0) owned = existing;
|
|
453
|
+
else {
|
|
454
|
+
const prototype = Reflect.getPrototypeOf(value);
|
|
455
|
+
if (Array.isArray(value) || prototype === null || prototype === Object.prototype) {
|
|
456
|
+
const branch = Array.isArray(value) ? [] : Object.create(null);
|
|
457
|
+
seen.set(value, branch);
|
|
458
|
+
captured.push(branch);
|
|
459
|
+
pending.push([
|
|
460
|
+
value,
|
|
461
|
+
branch,
|
|
462
|
+
void 0
|
|
463
|
+
]);
|
|
464
|
+
owned = branch;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
Reflect.defineProperty(view, key, {
|
|
469
|
+
value: owned,
|
|
470
|
+
enumerable: true,
|
|
471
|
+
configurable: false,
|
|
472
|
+
writable: false
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
for (const view of captured) Object.freeze(view);
|
|
477
|
+
return target;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
372
480
|
* Return a deeply owned, deeply frozen copy of a brief, refusing anything off-contract.
|
|
373
481
|
*
|
|
374
482
|
* @remarks
|
|
@@ -1163,6 +1271,15 @@ function errorToMessage(error) {
|
|
|
1163
1271
|
* nothing, so it is an assertion rather than a factory. Reserve it for programmer-error
|
|
1164
1272
|
* contexts where invalidity is a bug.
|
|
1165
1273
|
*
|
|
1274
|
+
* Intake NARROWS, and transfers no ownership. What comes back is the caller's own object,
|
|
1275
|
+
* so a member carried on an accessor can answer this guard one way and a later reader
|
|
1276
|
+
* another. The division is deliberate: the borrowed-engine law governs values this package
|
|
1277
|
+
* pulls across a seam it called, and a value handed in at the door stays the caller's.
|
|
1278
|
+
* `snapshotBrief` is the ownership door, and `pinBrief`, `BriefManager`, `briefToMarkdown`,
|
|
1279
|
+
* `briefToGoal`, and `briefToDispatch` take it. `briefToSubject`, `briefToContent`, and
|
|
1280
|
+
* `briefToTrace` read the value they are handed instead, so a caller reaching one of those
|
|
1281
|
+
* directly owns that reading. Pass `assertBrief` a value you already own.
|
|
1282
|
+
*
|
|
1166
1283
|
* @param data - The candidate brief data.
|
|
1167
1284
|
* @returns The same value, now known to satisfy {@link Brief}.
|
|
1168
1285
|
* @throws {@link BriefError} `INVALID` when `data` fails `isBrief`.
|
|
@@ -1502,8 +1619,10 @@ function deriveStatement(text) {
|
|
|
1502
1619
|
* ```
|
|
1503
1620
|
*/
|
|
1504
1621
|
function deriveTask(intent, text, actions, domains) {
|
|
1505
|
-
const
|
|
1506
|
-
const
|
|
1622
|
+
const operationDescriptor = Object.getOwnPropertyDescriptor(actions, intent.action);
|
|
1623
|
+
const domainDescriptor = Object.getOwnPropertyDescriptor(domains, intent.domain);
|
|
1624
|
+
const operation = operationDescriptor === void 0 ? void 0 : "value" in operationDescriptor ? operationDescriptor.value : operationDescriptor.get === void 0 ? void 0 : Reflect.apply(operationDescriptor.get, actions, []);
|
|
1625
|
+
const domain = domainDescriptor === void 0 ? void 0 : "value" in domainDescriptor ? domainDescriptor.value : domainDescriptor.get === void 0 ? void 0 : Reflect.apply(domainDescriptor.get, domains, []);
|
|
1507
1626
|
if (!isTaskOperation(operation) || !isTaskDomain(domain)) return void 0;
|
|
1508
1627
|
const statement = deriveStatement(text);
|
|
1509
1628
|
return statement.length === 0 ? void 0 : task(operation, domain, statement);
|
|
@@ -1569,6 +1688,15 @@ function deriveGaps(ambiguities) {
|
|
|
1569
1688
|
* all fail the same way — `undefined`, never a throw. Coerce a bare vocabulary value with
|
|
1570
1689
|
* `parseEnum` from `@orkestrel/contract` against the exported tuple instead.
|
|
1571
1690
|
*
|
|
1691
|
+
* The half of the intake pair that is OWNED BY CONSTRUCTION, which is what separates it from
|
|
1692
|
+
* `assertBrief`. The argument is text, so the graph the guard reads is one `JSON.parse` built
|
|
1693
|
+
* inside this call: it carries no caller identity, no accessor, and no alias back into anything
|
|
1694
|
+
* the caller still holds, and the parse-and-guard primitive this file imports from
|
|
1695
|
+
* `@orkestrel/contract` returns that same parsed graph rather than a second reading of it.
|
|
1696
|
+
* Every member `isBrief` checked therefore answers a later reader identically. The value is
|
|
1697
|
+
* fresh rather than frozen, so the caller owns it outright — reach for `snapshotBrief` when the
|
|
1698
|
+
* value came from code instead of from text.
|
|
1699
|
+
*
|
|
1572
1700
|
* @param value - The JSON text to parse.
|
|
1573
1701
|
* @returns The `Brief` when the parsed value satisfies `isBrief`, otherwise `undefined`.
|
|
1574
1702
|
*
|
|
@@ -1879,7 +2007,15 @@ var BriefCompiler = class {
|
|
|
1879
2007
|
}
|
|
1880
2008
|
gate(source) {
|
|
1881
2009
|
this.#refuseDestroyed();
|
|
1882
|
-
const ruled = attempt(() => this.#own(this.#reason.reason(briefToSubject(source), gateDefinition())
|
|
2010
|
+
const ruled = attempt(() => this.#own(this.#reason.reason(briefToSubject(source), gateDefinition()), [
|
|
2011
|
+
"reasoning",
|
|
2012
|
+
"conclusion",
|
|
2013
|
+
"rules",
|
|
2014
|
+
"count",
|
|
2015
|
+
"success",
|
|
2016
|
+
"trace",
|
|
2017
|
+
"errors"
|
|
2018
|
+
]));
|
|
1883
2019
|
if (!ruled.success) throw new BriefError("GATE_FAILED", errorToMessage(ruled.error), {
|
|
1884
2020
|
stage: "gate",
|
|
1885
2021
|
field: "reason"
|
|
@@ -1902,14 +2038,14 @@ var BriefCompiler = class {
|
|
|
1902
2038
|
#snapshot(input) {
|
|
1903
2039
|
return freezeDeep(structuredClone(input));
|
|
1904
2040
|
}
|
|
1905
|
-
#own(value) {
|
|
2041
|
+
#own(value, members) {
|
|
1906
2042
|
const cloned = attempt(() => structuredClone(value));
|
|
1907
|
-
return
|
|
2043
|
+
return cloned.success ? freezeDeep(cloned.value) : captureValue(value, members);
|
|
1908
2044
|
}
|
|
1909
2045
|
#read(input, raw, stages, failures) {
|
|
1910
2046
|
const text = input.text;
|
|
1911
2047
|
if (text !== void 0) {
|
|
1912
|
-
const read = attempt(() => this.#own(this.#interpret.interpret(text)));
|
|
2048
|
+
const read = attempt(() => this.#own(this.#interpret.interpret(text), INTERPRETATION_MEMBERS));
|
|
1913
2049
|
if (read.success && isInterpretation(read.value)) {
|
|
1914
2050
|
stages.push(Object.freeze({
|
|
1915
2051
|
stage: "interpret",
|
|
@@ -1934,7 +2070,8 @@ var BriefCompiler = class {
|
|
|
1934
2070
|
const supplied = input.interpretation;
|
|
1935
2071
|
if (supplied === void 0 || isInterpretation(supplied)) return supplied;
|
|
1936
2072
|
const live = raw.interpretation;
|
|
1937
|
-
|
|
2073
|
+
const captured = attempt(() => captureValue(live, INTERPRETATION_MEMBERS));
|
|
2074
|
+
if (captured.success && isInterpretation(captured.value)) return captured.value;
|
|
1938
2075
|
const message = "The supplied interpretation does not satisfy the published shape";
|
|
1939
2076
|
stages.push(Object.freeze({
|
|
1940
2077
|
stage: "interpret",
|
|
@@ -1958,7 +2095,7 @@ var BriefCompiler = class {
|
|
|
1958
2095
|
code: "BLOCKED",
|
|
1959
2096
|
message: `Gate refused: ${unready.join(", ")}`
|
|
1960
2097
|
};
|
|
1961
|
-
if (
|
|
2098
|
+
if (verdict === void 0) return void 0;
|
|
1962
2099
|
const refused = verdict.rules.filter((entry) => !entry.conclusion).map((entry) => entry.id).join(", ");
|
|
1963
2100
|
if (refused.length === 0) return {
|
|
1964
2101
|
stage: "gate",
|
|
@@ -2092,6 +2229,6 @@ function createBriefContract() {
|
|
|
2092
2229
|
return createContract(briefShape);
|
|
2093
2230
|
}
|
|
2094
2231
|
//#endregion
|
|
2095
|
-
export { BLANK_PATTERN, BriefCompiler, BriefError, BriefManager, DEFAULT_BRIEF_TURNS, GATE_ID, LINE_BREAK_PATTERN, OUTPUT_FORMATS, RISK_SEVERITIES, SINGLE_LINE_PATTERN, TASK_DOMAINS, TASK_OPERATIONS, assertBrief, brief, briefShape, briefToContent, briefToDispatch, briefToGoal, briefToHash, briefToMarkdown, briefToSubject, briefToTrace, 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 };
|
|
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 };
|
|
2096
2233
|
|
|
2097
2234
|
//# sourceMappingURL=index.js.map
|