create-quorum-router 0.1.15 → 0.1.16

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/README.md CHANGED
@@ -18,7 +18,7 @@ deno task intake
18
18
  deno task supabase:status
19
19
  ```
20
20
 
21
- Current package version: `create-quorum-router@0.1.15`. Releases are published
21
+ Current package version: `create-quorum-router@0.1.16`. Releases are published
22
22
  from an immutable Git tag through GitHub Actions OIDC Trusted Publishing.
23
23
 
24
24
  ## What the generated project supports
@@ -39,6 +39,12 @@ execution. Both demos are local-only; the hierarchy demo does not call provider
39
39
  APIs. On a new Deno installation, the first run resolves the pinned Zod
40
40
  dependency before execution.
41
41
 
42
+ Generated projects also export the opt-in
43
+ `resolveHierarchicalTaskCalibrationWithDriftGuard()` API. It can quarantine a
44
+ child whose Brier score is worse than its immediate parent by more than an
45
+ explicit caller threshold. This is outcome-metric drift handling, not semantic
46
+ label verification; it does not rename labels or affect routing authority.
47
+
42
48
  `deno task intake` is the first real setup command. It detects local provider
43
49
  wrappers, checks OAuth/session status, runs safe list-only model inventory where
44
50
  possible, writes redacted local health artifacts under `out/`, and recommends
@@ -3,7 +3,7 @@ const fs = require("fs");
3
3
  const path = require("path");
4
4
  const { spawnSync } = require("child_process");
5
5
 
6
- const VERSION = "0.1.15";
6
+ const VERSION = "0.1.16";
7
7
  const SUPPORTED_TEMPLATES = new Set(["basic"]);
8
8
 
9
9
  function usage() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-quorum-router",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Create a local QuorumRouter project.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  # QuorumRouter generated workspace
2
2
 
3
3
  This generated workspace contains the MIT-licensed QuorumRouter current release.
4
- npm latest targets v0.1.15.
4
+ npm latest targets v0.1.16.
5
5
 
6
6
  QuorumRouter is **MIT**. It is **open source**. Commercial and production use
7
7
  are permitted under the MIT License.
@@ -67,6 +67,13 @@ group that reaches the configured sample threshold. Groups never cross exact
67
67
  provider/model source boundaries, labels must not contain raw prompts, and the
68
68
  result remains advisory-only.
69
69
 
70
+ The scaffold also exports opt-in
71
+ `resolveHierarchicalTaskCalibrationWithDriftGuard()`. It can quarantine a child
72
+ whose Brier score is worse than its immediate parent by more than an explicit
73
+ caller threshold and continue parent fallback. This is an outcome-metric
74
+ heuristic, not semantic label verification; it does not rename labels or affect
75
+ routing authority.
76
+
70
77
  `intake` detects local provider wrappers, checks OAuth/session status, runs safe
71
78
  model inventory/list-only probes where possible, writes local health traces
72
79
  under `out/`, and recommends the next command.
@@ -488,6 +488,294 @@ export const HierarchicalTaskCalibrationSelectionSchema = z.object({
488
488
  }
489
489
  });
490
490
 
491
+ export const HierarchicalCalibrationDriftGuardOptionsSchema = z.object({
492
+ maximum_child_parent_brier_score_delta: z.number().finite().min(0).max(1),
493
+ }).strict();
494
+
495
+ const HIERARCHICAL_ROLLUP_TOLERANCE = 1e-9;
496
+
497
+ export const HierarchicalTaskCalibrationGuardedReportSchema =
498
+ HierarchicalTaskCalibrationReportSchema.superRefine((report, context) => {
499
+ report.groups.forEach((parent, parentIndex) => {
500
+ const childScope = parent.scope === "task_type"
501
+ ? "task_subtype"
502
+ : parent.scope === "task_subtype"
503
+ ? "prompt_pattern"
504
+ : undefined;
505
+ if (childScope === undefined) return;
506
+
507
+ const children = report.groups.filter((child) =>
508
+ child.scope === childScope && child.task_type === parent.task_type &&
509
+ child.source.provider === parent.source.provider &&
510
+ child.source.model === parent.source.model &&
511
+ (parent.scope === "task_type" ||
512
+ child.task_subtype === parent.task_subtype)
513
+ );
514
+ if (children.length === 0) return;
515
+
516
+ const childCount = children.reduce(
517
+ (sum, child) => sum + child.sample_count,
518
+ 0,
519
+ );
520
+ const remainderCount = parent.sample_count - childCount;
521
+ if (remainderCount < 0) {
522
+ context.addIssue({
523
+ code: "custom",
524
+ message:
525
+ "hierarchical child sample counts cannot exceed their parent",
526
+ path: ["groups", parentIndex, "sample_count"],
527
+ });
528
+ return;
529
+ }
530
+
531
+ for (
532
+ const metric of ["accuracy", "mean_confidence", "brier_score"] as const
533
+ ) {
534
+ const parentTotal = parent[metric] * parent.sample_count;
535
+ const childTotal = children.reduce(
536
+ (sum, child) => sum + child[metric] * child.sample_count,
537
+ 0,
538
+ );
539
+ const remainderTotal = parentTotal - childTotal;
540
+ if (
541
+ remainderTotal < -HIERARCHICAL_ROLLUP_TOLERANCE ||
542
+ remainderTotal > remainderCount + HIERARCHICAL_ROLLUP_TOLERANCE
543
+ ) {
544
+ context.addIssue({
545
+ code: "custom",
546
+ message:
547
+ `hierarchical ${metric} totals are incompatible with the parent roll-up`,
548
+ path: ["groups", parentIndex, metric],
549
+ });
550
+ }
551
+ }
552
+ });
553
+ });
554
+
555
+ export const HierarchicalCalibrationDriftStatusSchema = z.enum([
556
+ "not_applicable",
557
+ "not_evaluated",
558
+ "parent_unavailable",
559
+ "within_threshold",
560
+ "quarantined",
561
+ ]);
562
+
563
+ const HierarchicalGuardedCalibrationCandidateSchema = z.object({
564
+ scope: HierarchicalCalibrationScopeSchema,
565
+ sample_count: z.number().int().positive().max(MAX_CALIBRATION_OBSERVATIONS)
566
+ .nullable(),
567
+ sample_status: z.enum(["missing", "insufficient", "sufficient"]),
568
+ accuracy: z.number().finite().min(0).max(1).nullable(),
569
+ mean_confidence: z.number().finite().min(0).max(1).nullable(),
570
+ mean_calibration_bias: z.number().finite().min(-1).max(1).nullable(),
571
+ brier_score: z.number().finite().min(0).max(1).nullable(),
572
+ drift_status: HierarchicalCalibrationDriftStatusSchema,
573
+ parent_scope: HierarchicalCalibrationScopeSchema.nullable(),
574
+ child_parent_brier_score_delta: z.number().finite().min(-1).max(1).nullable(),
575
+ }).strict().superRefine((candidate, context) => {
576
+ const metrics = [
577
+ candidate.accuracy,
578
+ candidate.mean_confidence,
579
+ candidate.mean_calibration_bias,
580
+ candidate.brier_score,
581
+ ];
582
+ if (
583
+ (candidate.sample_status === "missing") !==
584
+ (candidate.sample_count === null)
585
+ ) {
586
+ context.addIssue({
587
+ code: "custom",
588
+ message: "missing candidates must have a null sample_count",
589
+ });
590
+ }
591
+ if (
592
+ candidate.sample_status === "missing"
593
+ ? metrics.some((metric) => metric !== null)
594
+ : metrics.some((metric) => metric === null)
595
+ ) {
596
+ context.addIssue({
597
+ code: "custom",
598
+ message:
599
+ "candidate metrics must be null exactly when the candidate is missing",
600
+ });
601
+ }
602
+ });
603
+
604
+ export const HierarchicalTaskCalibrationGuardedSelectionSchema = z.object({
605
+ schema_version: z.literal(
606
+ "quorum-router.hierarchical-guarded-selection.v1",
607
+ ),
608
+ advisory_only: z.literal(true),
609
+ query: HierarchicalTaskCalibrationQuerySchema,
610
+ requested_scope: HierarchicalCalibrationScopeSchema,
611
+ drift_guard: HierarchicalCalibrationDriftGuardOptionsSchema,
612
+ resolution_status: z.enum(["selected", "no_eligible_group"]),
613
+ selected_scope: HierarchicalCalibrationScopeSchema.nullable(),
614
+ candidates: z.array(HierarchicalGuardedCalibrationCandidateSchema).min(1)
615
+ .max(3),
616
+ selected_group: HierarchicalTaskCalibrationGroupSchema.optional(),
617
+ }).strict().superRefine((selection, context) => {
618
+ const queryScope = selection.query.prompt_pattern !== undefined
619
+ ? "prompt_pattern"
620
+ : selection.query.task_subtype !== undefined
621
+ ? "task_subtype"
622
+ : "task_type";
623
+ if (selection.requested_scope !== queryScope) {
624
+ context.addIssue({
625
+ code: "custom",
626
+ message: "requested_scope must match the query labels",
627
+ path: ["requested_scope"],
628
+ });
629
+ }
630
+
631
+ const expectedScopes: HierarchicalCalibrationScope[] =
632
+ selection.requested_scope === "prompt_pattern"
633
+ ? ["prompt_pattern", "task_subtype", "task_type"]
634
+ : selection.requested_scope === "task_subtype"
635
+ ? ["task_subtype", "task_type"]
636
+ : ["task_type"];
637
+ if (
638
+ JSON.stringify(selection.candidates.map((candidate) => candidate.scope)) !==
639
+ JSON.stringify(expectedScopes)
640
+ ) {
641
+ context.addIssue({
642
+ code: "custom",
643
+ message: "candidates must follow the requested scope fallback order",
644
+ path: ["candidates"],
645
+ });
646
+ }
647
+
648
+ selection.candidates.forEach((candidate, index) => {
649
+ const isRoot = candidate.scope === "task_type";
650
+ const immediateParent = selection.candidates[index + 1];
651
+ if (isRoot) {
652
+ if (
653
+ candidate.drift_status !== "not_applicable" ||
654
+ candidate.parent_scope !== null ||
655
+ candidate.child_parent_brier_score_delta !== null
656
+ ) {
657
+ context.addIssue({
658
+ code: "custom",
659
+ message: "task_type drift comparison must be not_applicable",
660
+ path: ["candidates", index],
661
+ });
662
+ }
663
+ return;
664
+ }
665
+
666
+ if (candidate.parent_scope !== immediateParent?.scope) {
667
+ context.addIssue({
668
+ code: "custom",
669
+ message: "child candidates must name their immediate parent scope",
670
+ path: ["candidates", index, "parent_scope"],
671
+ });
672
+ }
673
+ if (candidate.sample_status !== "sufficient") {
674
+ if (
675
+ candidate.drift_status !== "not_evaluated" ||
676
+ candidate.child_parent_brier_score_delta !== null
677
+ ) {
678
+ context.addIssue({
679
+ code: "custom",
680
+ message: "non-sufficient child drift must not be evaluated",
681
+ path: ["candidates", index],
682
+ });
683
+ }
684
+ return;
685
+ }
686
+ if (immediateParent?.sample_status !== "sufficient") {
687
+ if (
688
+ candidate.drift_status !== "parent_unavailable" ||
689
+ candidate.child_parent_brier_score_delta !== null
690
+ ) {
691
+ context.addIssue({
692
+ code: "custom",
693
+ message:
694
+ "a sufficient child without a sufficient parent is unavailable",
695
+ path: ["candidates", index],
696
+ });
697
+ }
698
+ return;
699
+ }
700
+
701
+ const delta = candidate.child_parent_brier_score_delta;
702
+ if (
703
+ delta === null || candidate.brier_score === null ||
704
+ immediateParent.brier_score === null
705
+ ) {
706
+ context.addIssue({
707
+ code: "custom",
708
+ message: "comparable child candidates require Brier score evidence",
709
+ path: ["candidates", index, "child_parent_brier_score_delta"],
710
+ });
711
+ return;
712
+ }
713
+ const rawDelta = candidate.brier_score - immediateParent.brier_score;
714
+ if (delta !== stableMetric(rawDelta)) {
715
+ context.addIssue({
716
+ code: "custom",
717
+ message: "Brier score delta must match the candidate metric snapshots",
718
+ path: ["candidates", index, "child_parent_brier_score_delta"],
719
+ });
720
+ }
721
+ const expectedStatus = rawDelta >
722
+ selection.drift_guard.maximum_child_parent_brier_score_delta
723
+ ? "quarantined"
724
+ : "within_threshold";
725
+ if (candidate.drift_status !== expectedStatus) {
726
+ context.addIssue({
727
+ code: "custom",
728
+ message: "drift_status must match the configured Brier score threshold",
729
+ path: ["candidates", index, "drift_status"],
730
+ });
731
+ }
732
+ });
733
+
734
+ const firstEligible = selection.candidates.find((candidate) =>
735
+ candidate.sample_status === "sufficient" &&
736
+ (candidate.drift_status === "within_threshold" ||
737
+ candidate.drift_status === "not_applicable")
738
+ );
739
+ if (firstEligible === undefined) {
740
+ if (
741
+ selection.resolution_status !== "no_eligible_group" ||
742
+ selection.selected_scope !== null ||
743
+ selection.selected_group !== undefined
744
+ ) {
745
+ context.addIssue({
746
+ code: "custom",
747
+ message: "no eligible candidate must produce no selection",
748
+ });
749
+ }
750
+ } else if (
751
+ selection.resolution_status !== "selected" ||
752
+ selection.selected_scope !== firstEligible.scope ||
753
+ selection.selected_group?.scope !== firstEligible.scope ||
754
+ selection.selected_group.sample_count !== firstEligible.sample_count ||
755
+ selection.selected_group.sample_status !== "sufficient" ||
756
+ selection.selected_group.accuracy !== firstEligible.accuracy ||
757
+ selection.selected_group.mean_confidence !==
758
+ firstEligible.mean_confidence ||
759
+ selection.selected_group.mean_calibration_bias !==
760
+ firstEligible.mean_calibration_bias ||
761
+ selection.selected_group.brier_score !== firstEligible.brier_score ||
762
+ selection.selected_group.task_type !== selection.query.task_type ||
763
+ selection.selected_group.source.provider !==
764
+ selection.query.source.provider ||
765
+ selection.selected_group.source.model !== selection.query.source.model ||
766
+ (firstEligible.scope !== "task_type" &&
767
+ selection.selected_group.task_subtype !== selection.query.task_subtype) ||
768
+ (firstEligible.scope === "prompt_pattern" &&
769
+ selection.selected_group.prompt_pattern !==
770
+ selection.query.prompt_pattern)
771
+ ) {
772
+ context.addIssue({
773
+ code: "custom",
774
+ message: "guarded selection must use the first eligible candidate",
775
+ });
776
+ }
777
+ });
778
+
491
779
  export const HierarchicalTaskCalibrationDecisionSchema = z.object({
492
780
  report: HierarchicalTaskCalibrationReportSchema,
493
781
  selection: HierarchicalTaskCalibrationSelectionSchema,
@@ -540,6 +828,29 @@ export const HierarchicalTaskCalibrationDecisionSchema = z.object({
540
828
  }
541
829
  });
542
830
 
831
+ export const HierarchicalTaskCalibrationGuardedDecisionSchema = z.object({
832
+ report: HierarchicalTaskCalibrationGuardedReportSchema,
833
+ selection: HierarchicalTaskCalibrationGuardedSelectionSchema,
834
+ }).strict().superRefine((decision, context) => {
835
+ const expected = resolveHierarchicalTaskCalibrationWithDriftGuard(
836
+ decision.report,
837
+ decision.selection.query,
838
+ decision.selection.drift_guard,
839
+ );
840
+ if (JSON.stringify(decision.selection) !== JSON.stringify(expected)) {
841
+ context.addIssue({
842
+ code: "custom",
843
+ message: "guarded selection must be derived from the aggregate report",
844
+ path: ["selection"],
845
+ });
846
+ }
847
+ });
848
+
849
+ export const HierarchicalTaskCalibrationAnyDecisionSchema = z.union([
850
+ HierarchicalTaskCalibrationDecisionSchema,
851
+ HierarchicalTaskCalibrationGuardedDecisionSchema,
852
+ ]);
853
+
543
854
  export type HierarchicalCalibrationScope = z.infer<
544
855
  typeof HierarchicalCalibrationScopeSchema
545
856
  >;
@@ -561,6 +872,18 @@ export type HierarchicalTaskCalibrationSelection = z.infer<
561
872
  export type HierarchicalTaskCalibrationDecision = z.infer<
562
873
  typeof HierarchicalTaskCalibrationDecisionSchema
563
874
  >;
875
+ export type HierarchicalCalibrationDriftGuardOptions = z.infer<
876
+ typeof HierarchicalCalibrationDriftGuardOptionsSchema
877
+ >;
878
+ export type HierarchicalTaskCalibrationGuardedSelection = z.infer<
879
+ typeof HierarchicalTaskCalibrationGuardedSelectionSchema
880
+ >;
881
+ export type HierarchicalTaskCalibrationGuardedDecision = z.infer<
882
+ typeof HierarchicalTaskCalibrationGuardedDecisionSchema
883
+ >;
884
+ export type HierarchicalTaskCalibrationAnyDecision = z.infer<
885
+ typeof HierarchicalTaskCalibrationAnyDecisionSchema
886
+ >;
564
887
 
565
888
  type HierarchicalGroupSeed = {
566
889
  scope: HierarchicalCalibrationScope;
@@ -745,3 +1068,124 @@ export function resolveHierarchicalTaskCalibration(
745
1068
  ...(selected_group === undefined ? {} : { selected_group }),
746
1069
  });
747
1070
  }
1071
+
1072
+ export function resolveHierarchicalTaskCalibrationWithDriftGuard(
1073
+ report: HierarchicalTaskCalibrationReport,
1074
+ query: HierarchicalTaskCalibrationQuery,
1075
+ driftGuard: HierarchicalCalibrationDriftGuardOptions,
1076
+ ): HierarchicalTaskCalibrationGuardedSelection {
1077
+ const parsedReport = HierarchicalTaskCalibrationGuardedReportSchema.parse(
1078
+ report,
1079
+ );
1080
+ const parsedQuery = HierarchicalTaskCalibrationQuerySchema.parse(query);
1081
+ const drift_guard = HierarchicalCalibrationDriftGuardOptionsSchema.parse(
1082
+ driftGuard,
1083
+ );
1084
+ const requested_scope: HierarchicalCalibrationScope =
1085
+ parsedQuery.prompt_pattern !== undefined
1086
+ ? "prompt_pattern"
1087
+ : parsedQuery.task_subtype !== undefined
1088
+ ? "task_subtype"
1089
+ : "task_type";
1090
+ const scopes: HierarchicalCalibrationScope[] = requested_scope ===
1091
+ "prompt_pattern"
1092
+ ? ["prompt_pattern", "task_subtype", "task_type"]
1093
+ : requested_scope === "task_subtype"
1094
+ ? ["task_subtype", "task_type"]
1095
+ : ["task_type"];
1096
+
1097
+ const matchingGroups = scopes.map((scope) =>
1098
+ parsedReport.groups.find((group) =>
1099
+ group.scope === scope && group.task_type === parsedQuery.task_type &&
1100
+ group.source.provider === parsedQuery.source.provider &&
1101
+ group.source.model === parsedQuery.source.model &&
1102
+ (scope === "task_type" ||
1103
+ group.task_subtype === parsedQuery.task_subtype) &&
1104
+ (scope !== "prompt_pattern" ||
1105
+ group.prompt_pattern === parsedQuery.prompt_pattern)
1106
+ )
1107
+ );
1108
+ const candidates = scopes.map((scope, index) => {
1109
+ const group = matchingGroups[index];
1110
+ const base = group === undefined
1111
+ ? {
1112
+ scope,
1113
+ sample_count: null,
1114
+ sample_status: "missing" as const,
1115
+ accuracy: null,
1116
+ mean_confidence: null,
1117
+ mean_calibration_bias: null,
1118
+ brier_score: null,
1119
+ }
1120
+ : {
1121
+ scope,
1122
+ sample_count: group.sample_count,
1123
+ sample_status: group.sample_status,
1124
+ accuracy: group.accuracy,
1125
+ mean_confidence: group.mean_confidence,
1126
+ mean_calibration_bias: group.mean_calibration_bias,
1127
+ brier_score: group.brier_score,
1128
+ };
1129
+ if (scope === "task_type") {
1130
+ return {
1131
+ ...base,
1132
+ drift_status: "not_applicable" as const,
1133
+ parent_scope: null,
1134
+ child_parent_brier_score_delta: null,
1135
+ };
1136
+ }
1137
+
1138
+ const parent_scope = scopes[index + 1] ?? null;
1139
+ if (group?.sample_status !== "sufficient") {
1140
+ return {
1141
+ ...base,
1142
+ drift_status: "not_evaluated" as const,
1143
+ parent_scope,
1144
+ child_parent_brier_score_delta: null,
1145
+ };
1146
+ }
1147
+ const parent = matchingGroups[index + 1];
1148
+ if (parent?.sample_status !== "sufficient") {
1149
+ return {
1150
+ ...base,
1151
+ drift_status: "parent_unavailable" as const,
1152
+ parent_scope,
1153
+ child_parent_brier_score_delta: null,
1154
+ };
1155
+ }
1156
+
1157
+ const rawDelta = group.brier_score - parent.brier_score;
1158
+ const child_parent_brier_score_delta = stableMetric(rawDelta);
1159
+ return {
1160
+ ...base,
1161
+ drift_status: rawDelta >
1162
+ drift_guard.maximum_child_parent_brier_score_delta
1163
+ ? "quarantined" as const
1164
+ : "within_threshold" as const,
1165
+ parent_scope,
1166
+ child_parent_brier_score_delta,
1167
+ };
1168
+ });
1169
+ const selectedCandidate = candidates.find((candidate) =>
1170
+ candidate.sample_status === "sufficient" &&
1171
+ (candidate.drift_status === "within_threshold" ||
1172
+ candidate.drift_status === "not_applicable")
1173
+ );
1174
+ const selected_group = selectedCandidate === undefined
1175
+ ? undefined
1176
+ : matchingGroups[candidates.indexOf(selectedCandidate)];
1177
+
1178
+ return HierarchicalTaskCalibrationGuardedSelectionSchema.parse({
1179
+ schema_version: "quorum-router.hierarchical-guarded-selection.v1",
1180
+ advisory_only: true,
1181
+ query: parsedQuery,
1182
+ requested_scope,
1183
+ drift_guard,
1184
+ resolution_status: selected_group === undefined
1185
+ ? "no_eligible_group"
1186
+ : "selected",
1187
+ selected_scope: selected_group?.scope ?? null,
1188
+ candidates,
1189
+ ...(selected_group === undefined ? {} : { selected_group }),
1190
+ });
1191
+ }