@orkestrel/study 0.0.1 → 0.0.3

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.
@@ -8,8 +8,8 @@ let _orkestrel_abort = require("@orkestrel/abort");
8
8
  * Keys the own self-identity every study error stamps on itself.
9
9
  * @remarks
10
10
  * The global symbol registry lets every package, ESM, CommonJS and captured copy read the same
11
- * key. The registry makes the key discoverable; it is a recognition mechanism, not an
12
- * unforgeable provenance marker.
11
+ * key. The registry makes the key discoverable; it recognizes the contract without proving
12
+ * its origin.
13
13
  */
14
14
  var STUDY_ERROR_BRAND = Symbol.for("@orkestrel/study.error");
15
15
  /** Caps a declared trial population before schedule allocation. */
@@ -24,6 +24,7 @@ var STUDY_ROLES = Object.freeze([
24
24
  "judge",
25
25
  "summary",
26
26
  "metadata",
27
+ "maintenance",
27
28
  "tool"
28
29
  ]);
29
30
  /** Lists every ceiling a run can stop at in report order. */
@@ -67,16 +68,18 @@ function omitStudyAbsent(value) {
67
68
  * ```
68
69
  */
69
70
  function normalizeStudyProfile(profile) {
70
- const { provider, qualification, settings, room, ...required } = profile;
71
+ const { provider, qualification, settings, record, room, ...required } = profile;
71
72
  return {
72
73
  ...required,
73
74
  room: omitStudyAbsent(room),
74
75
  ...provider === void 0 ? {} : { provider: {
75
76
  ...omitStudyAbsent(provider),
76
- digest: omitStudyAbsent(provider.digest)
77
+ digest: omitStudyAbsent(provider.digest),
78
+ ...provider.daemon === void 0 ? {} : { daemon: omitStudyAbsent(provider.daemon) }
77
79
  } },
78
80
  ...qualification === void 0 ? {} : { qualification },
79
- ...settings === void 0 ? {} : { settings }
81
+ ...settings === void 0 ? {} : { settings },
82
+ ...record === void 0 ? {} : { record }
80
83
  };
81
84
  }
82
85
  /**
@@ -150,7 +153,7 @@ function buildStudySchedule(definition, scenarios) {
150
153
  * @param rubric - The independently held grading declaration
151
154
  * @param profile - The execution bounds and model room
152
155
  * @returns Nothing when every cross-input invariant holds
153
- * @throws StudyError - Thrown when any input or cross-reference is invalid
156
+ * @throws StudyError - Thrown when any input or cross-reference is invalid, or a quality study has no capacity qualification
154
157
  * @example
155
158
  * ```ts
156
159
  * validateStudyInputs(definition, scenarios, rubric, profile)
@@ -167,6 +170,7 @@ function validateStudyInputs(definition, scenarios, rubric, profile) {
167
170
  }
168
171
  const covered = new Set(rubric.criteria.map((criterion) => (0, _orkestrel_contract.canonicalStringify)([criterion.scenario, criterion.goal]) ?? ""));
169
172
  for (const scenario of scenarios) for (const goal of scenario.goals) if (!covered.has((0, _orkestrel_contract.canonicalStringify)([scenario.id, goal.id]) ?? "")) throw new StudyError("CONFIG", "Every declared goal needs a criterion");
173
+ if (definition.purpose === "quality" && profile.qualification === void 0) throw new StudyError("CONFIG", "Quality studies require a capacity qualification");
170
174
  }
171
175
  /**
172
176
  * Computes arm intervals over the complete declared criterion horizon.
@@ -417,15 +421,46 @@ function isStudyProvider(value) {
417
421
  "url",
418
422
  "model",
419
423
  "digest"
420
- ], ["judge"]) || ![
424
+ ], ["judge", "daemon"]) || ![
421
425
  "entry",
422
426
  "url",
423
427
  "model"
424
428
  ].every((key) => (0, _orkestrel_contract.isNonEmptyString)(value[key])) || typeof value.url !== "string" || !(0, _orkestrel_contract.isRecord)(value.digest) || !matchesStudyKeys(value.digest, ["model"], ["judge"]) || !isStudyDigest(value.digest.model) || value.judge === void 0 !== (value.digest.judge === void 0) || value.judge !== void 0 && (!(0, _orkestrel_contract.isNonEmptyString)(value.judge) || !isStudyDigest(value.digest.judge))) return false;
425
429
  const url = new URL(value.url);
430
+ if (value.daemon !== void 0) {
431
+ if (!isStudyDaemon(value.daemon) || !/^http:\/\/127\.0\.0\.1:[0-9]+\/?$/.test(value.url) || Number(url.port) <= 0 || Number(url.port) === 11434) return false;
432
+ const daemon = value.daemon;
433
+ const digest = value.digest;
434
+ if (!daemon.models.every((model) => model.name === value.model && model.digest === digest.model || value.judge !== void 0 && model.name === value.judge && model.digest === digest.judge) || !daemon.models.some((model) => model.name === value.model && model.digest === digest.model) || value.judge !== void 0 && !daemon.models.some((model) => model.name === value.judge && model.digest === digest.judge)) return false;
435
+ }
426
436
  return ["http:", "https:"].includes(url.protocol) && url.username === "" && url.password === "" && url.search === "" && url.hash === "" && url.pathname === "/";
427
437
  });
428
438
  }
439
+ /** Checks whether an owned daemon declaration pins an absolute executable and distinct models.
440
+ * @param value - The candidate declaration.
441
+ * @returns True if executable, version, environment, and model identities are valid; false otherwise.
442
+ * @example
443
+ * ```ts
444
+ * isStudyDaemon({ executable: 'ollama' }) // false
445
+ * ```
446
+ */
447
+ function isStudyDaemon(value) {
448
+ return (0, _orkestrel_contract.holds)(() => {
449
+ if (!(0, _orkestrel_contract.isRecord)(value) || !matchesStudyKeys(value, [
450
+ "executable",
451
+ "digest",
452
+ "version",
453
+ "models"
454
+ ], ["environment"]) || typeof value.executable !== "string" || !/^(?:[A-Za-z]:[\\/]|\/(?!\/)|\\\\[^\\]+\\[^\\]+\\)/.test(value.executable) || value.executable.includes("\0") || value.executable.split(/[\\/]/).some((part) => part === "." || part === "..") || !isStudyDigest(value.digest) || !(0, _orkestrel_contract.isNonEmptyString)(value.version) || value.version.trim().length === 0 || value.version.includes("\0") || !(0, _orkestrel_contract.isArray)(value.models) || value.models.length === 0 || !value.models.every((model) => (0, _orkestrel_contract.isRecord)(model) && matchesStudyKeys(model, ["name", "digest"]) && (0, _orkestrel_contract.isNonEmptyString)(model.name) && model.name.trim().length > 0 && !model.name.includes("\0") && isStudyDigest(model.digest))) return false;
455
+ if (new Set(value.models.map((model) => (0, _orkestrel_contract.isRecord)(model) ? model.name : void 0)).size !== value.models.length) return false;
456
+ if (value.environment !== void 0) {
457
+ if (!(0, _orkestrel_contract.isRecord)(value.environment) || !matchesStudyKeys(value.environment, [], Object.keys(value.environment))) return false;
458
+ const entries = Object.entries(value.environment);
459
+ if (new Set(entries.map(([name]) => name.toLowerCase())).size !== entries.length || entries.some(([name, entry]) => name.length === 0 || /[=\0]/.test(name) || typeof entry !== "string" || entry.includes("\0"))) return false;
460
+ }
461
+ return true;
462
+ });
463
+ }
429
464
  /**
430
465
  * Checks whether a profile carries finite bounds and an optional explicit provider.
431
466
  * @param value - The candidate profile
@@ -447,10 +482,18 @@ function isStudyProfile(value) {
447
482
  ], [
448
483
  "provider",
449
484
  "qualification",
450
- "settings"
451
- ]) && isStudyName(value.name) && (0, _orkestrel_contract.isNonEmptyString)(value.agent) && (0, _orkestrel_contract.isArray)(value.roots) && (0, _orkestrel_contract.isJSONValue)(value.roots) && value.roots.length > 0 && value.roots.every((root) => typeof root === "string" && root.trim().length > 0) && new Set(value.roots).size === value.roots.length && (0, _orkestrel_contract.isNonEmptyString)(value.subject) && isStudyBounds(value.bounds) && isStudyRoom(value.room) && (value.provider === void 0 || isStudyProvider(value.provider)) && (value.qualification === void 0 || (0, _orkestrel_contract.isNonEmptyString)(value.qualification)) && (value.settings === void 0 || (0, _orkestrel_contract.isRecord)(value.settings) && (0, _orkestrel_contract.isJSONValue)(value.settings));
485
+ "settings",
486
+ "record"
487
+ ]) && isStudyName(value.name) && (0, _orkestrel_contract.isNonEmptyString)(value.agent) && (0, _orkestrel_contract.isArray)(value.roots) && (0, _orkestrel_contract.isJSONValue)(value.roots) && value.roots.length > 0 && value.roots.every((root) => typeof root === "string" && root.trim().length > 0) && new Set(value.roots).size === value.roots.length && (0, _orkestrel_contract.isNonEmptyString)(value.subject) && isStudyBounds(value.bounds) && isStudyRoom(value.room) && (value.provider === void 0 || isStudyProvider(value.provider)) && (value.record === void 0 || isStudyRecord(value.record)) && (value.qualification === void 0 || (0, _orkestrel_contract.isNonEmptyString)(value.qualification)) && (value.settings === void 0 || (0, _orkestrel_contract.isRecord)(value.settings) && (0, _orkestrel_contract.isJSONValue)(value.settings));
452
488
  });
453
489
  }
490
+ /** Checks whether a recording declaration bounds every serialized sidecar byte.
491
+ * @param value - The candidate declaration.
492
+ * @returns True if its byte allowance is a positive safe integer; false otherwise.
493
+ */
494
+ function isStudyRecord(value) {
495
+ return (0, _orkestrel_contract.holds)(() => (0, _orkestrel_contract.isRecord)(value) && matchesStudyKeys(value, ["bytes"]) && typeof value.bytes === "number" && Number.isSafeInteger(value.bytes) && value.bytes > 0);
496
+ }
454
497
  /**
455
498
  * Checks whether a byte identity is a lowercase SHA-256 digest.
456
499
  * @param value - The candidate identity
@@ -631,8 +674,10 @@ var StudyError = class extends Error {
631
674
  */
632
675
  constructor(code, message, failure) {
633
676
  super(message);
634
- Object.defineProperty(this, STUDY_ERROR_BRAND, {
677
+ _orkestrel_contract.INTRINSICS.define(this, STUDY_ERROR_BRAND, {
635
678
  value: this,
679
+ enumerable: false,
680
+ writable: false,
636
681
  configurable: true
637
682
  });
638
683
  this.name = "StudyError";
@@ -641,14 +686,15 @@ var StudyError = class extends Error {
641
686
  }
642
687
  };
643
688
  /**
644
- * Narrows a caught value to an attributable study error.
689
+ * Narrows a caught value to a branded study error with valid failure attribution.
645
690
  * @remarks
646
- * Recognition combines the native `Error` base, a subclass prototype, the fixed name, a declared
647
- * study code, and an own {@link STUDY_ERROR_BRAND} descriptor whose value is the error itself.
691
+ * Recognition combines the native `Error` base, a subclass prototype, a declared study code,
692
+ * valid optional failure members, and an own {@link STUDY_ERROR_BRAND} descriptor whose value is
693
+ * the error itself. Subclasses can replace the name.
648
694
  * The global key is recognized across package, ESM, CommonJS and captured module copies; it is
649
- * not unforgeable provenance. A transparent proxy is refused because its forwarded descriptor
695
+ * not proof of origin. A transparent proxy is refused because its forwarded descriptor
650
696
  * stores the target, and an unbranded copy, an inherited brand, or a property-only lookalike
651
- * stays outside the type. Hostile property access returns false instead of throwing.
697
+ * stays outside the type. Throwing property access returns false instead of throwing.
652
698
  * @param value - The caught value
653
699
  * @returns True if the value is a study error; false otherwise
654
700
  * @example
@@ -657,7 +703,28 @@ var StudyError = class extends Error {
657
703
  * ```
658
704
  */
659
705
  function isStudyError(value) {
660
- return (0, _orkestrel_contract.isError)(value) && (0, _orkestrel_contract.holds)(() => Object.getPrototypeOf(value) !== Error.prototype && value.name === "StudyError" && Object.getOwnPropertyDescriptor(value, STUDY_ERROR_BRAND)?.value === value && "code" in value && isStudyErrorCode(value.code));
706
+ return (0, _orkestrel_contract.holds)(() => {
707
+ if (!(value instanceof _orkestrel_contract.INTRINSICS.error) || _orkestrel_contract.INTRINSICS.prototype(value) === _orkestrel_contract.INTRINSICS.error.prototype) return false;
708
+ const brand = _orkestrel_contract.INTRINSICS.describe(value, STUDY_ERROR_BRAND)?.value;
709
+ const code = _orkestrel_contract.INTRINSICS.reflect.read(value, "code");
710
+ const failure = _orkestrel_contract.INTRINSICS.reflect.read(value, "failure");
711
+ const stack = _orkestrel_contract.INTRINSICS.reflect.read(value, "stack");
712
+ if (brand !== value || !isStudyErrorCode(code) || typeof _orkestrel_contract.INTRINSICS.reflect.read(value, "name") !== "string" || typeof _orkestrel_contract.INTRINSICS.reflect.read(value, "message") !== "string" || stack !== void 0 && typeof stack !== "string") return false;
713
+ if (failure === void 0) return true;
714
+ if (!(0, _orkestrel_contract.isObject)(failure)) return false;
715
+ const cause = _orkestrel_contract.INTRINSICS.reflect.read(failure, "cause");
716
+ const message = _orkestrel_contract.INTRINSICS.reflect.read(failure, "message");
717
+ const role = _orkestrel_contract.INTRINSICS.reflect.read(failure, "role");
718
+ const stop = _orkestrel_contract.INTRINSICS.reflect.read(failure, "stop");
719
+ if (!isStudyCause(cause) || typeof message !== "string" || role !== void 0 && !isStudyRole(role)) return false;
720
+ if (stop === void 0) return true;
721
+ if (!(0, _orkestrel_contract.isObject)(stop)) return false;
722
+ const layer = _orkestrel_contract.INTRINSICS.reflect.read(stop, "layer");
723
+ const id = _orkestrel_contract.INTRINSICS.reflect.read(stop, "id");
724
+ const max = _orkestrel_contract.INTRINSICS.reflect.read(stop, "max");
725
+ const consumed = _orkestrel_contract.INTRINSICS.reflect.read(stop, "consumed");
726
+ return isStudyLayer(layer) && typeof id === "string" && (max === void 0 || (0, _orkestrel_contract.isNumber)(max)) && (consumed === void 0 || (0, _orkestrel_contract.isNumber)(consumed));
727
+ });
661
728
  }
662
729
  //#endregion
663
730
  //#region src/core/parsers.ts
@@ -921,8 +988,8 @@ function computeStudyOutputStop(bytes, limit, outputs) {
921
988
  };
922
989
  }
923
990
  /**
924
- * Records an error that escaped admitted work as the failure of its ticket.
925
- * @param ticket - The admitted request whose work escaped
991
+ * Records an error thrown by admitted work as the failure of its ticket.
992
+ * @param ticket - The admitted request whose work threw
926
993
  * @param error - The caught value, read through `readStudyFailure`
927
994
  * @param role - The responsibility that replaces any role the reading carries; Default: the carried role, else the ticket's admitted role
928
995
  * @remarks
@@ -931,7 +998,7 @@ function computeStudyOutputStop(bytes, limit, outputs) {
931
998
  * so the parent's ownership is respected rather than inferred as local settlement. A refusal
932
999
  * thrown by the ticket's own settlement propagates.
933
1000
  * @throws Thrown when the ticket's settlement refuses the failure.
934
- * @example Fail an escaped request
1001
+ * @example Fail an admitted request
935
1002
  * ```ts
936
1003
  * import type { StudyTicket } from '@orkestrel/study'
937
1004
  * import { failStudyTicket } from '@orkestrel/study'
@@ -1877,6 +1944,22 @@ function buildStudyAgentDispatch(dispatch) {
1877
1944
  //#endregion
1878
1945
  //#region src/core/agents/validators.ts
1879
1946
  /**
1947
+ * Checks whether a value is a gauge with a finite positive scale and a finite nonnegative overhead.
1948
+ * @param value - The candidate gauge; additional members are admitted
1949
+ * @returns True if the gauge readings are finite and within their bounds; false otherwise
1950
+ * @example
1951
+ * ```ts
1952
+ * isStudyAgentGauge({ scale: 1, overhead: 0 }) // true
1953
+ * ```
1954
+ */
1955
+ function isStudyAgentGauge(value) {
1956
+ return (0, _orkestrel_contract.holds)(() => {
1957
+ if (!(0, _orkestrel_contract.isObject)(value) || !("scale" in value) || !("overhead" in value)) return false;
1958
+ const { scale, overhead } = value;
1959
+ return (0, _orkestrel_contract.isFiniteNumber)(scale) && scale > 0 && (0, _orkestrel_contract.isFiniteNumber)(overhead) && overhead >= 0;
1960
+ });
1961
+ }
1962
+ /**
1880
1963
  * Checks whether a namespace exposes the Agent capabilities the instrumentation invokes.
1881
1964
  * @remarks
1882
1965
  * The guard reads only `estimateRequest`, `measureRequest`, and `isAgentError`, so a namespace
@@ -2020,10 +2103,12 @@ exports.computeStudyOutputStop = computeStudyOutputStop;
2020
2103
  exports.computeStudyScores = computeStudyScores;
2021
2104
  exports.failStudyTicket = failStudyTicket;
2022
2105
  exports.failureToStudyError = failureToStudyError;
2106
+ exports.isStudyAgentGauge = isStudyAgentGauge;
2023
2107
  exports.isStudyAgentRuntime = isStudyAgentRuntime;
2024
2108
  exports.isStudyBounds = isStudyBounds;
2025
2109
  exports.isStudyCause = isStudyCause;
2026
2110
  exports.isStudyCriterion = isStudyCriterion;
2111
+ exports.isStudyDaemon = isStudyDaemon;
2027
2112
  exports.isStudyDefinition = isStudyDefinition;
2028
2113
  exports.isStudyDigest = isStudyDigest;
2029
2114
  exports.isStudyError = isStudyError;
@@ -2038,6 +2123,7 @@ exports.isStudyName = isStudyName;
2038
2123
  exports.isStudyProduct = isStudyProduct;
2039
2124
  exports.isStudyProfile = isStudyProfile;
2040
2125
  exports.isStudyProvider = isStudyProvider;
2126
+ exports.isStudyRecord = isStudyRecord;
2041
2127
  exports.isStudyRole = isStudyRole;
2042
2128
  exports.isStudyRoom = isStudyRoom;
2043
2129
  exports.isStudyRubric = isStudyRubric;