@rulvar/store-conformance 1.111.0 → 1.112.0

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { JournalEntry, JournalStore, LeasableStore, TranscriptStore } from "@rulvar/core";
1
+ import { JournalEntry, JournalStore, LeasableStore, QuotaRule, TranscriptStore } from "@rulvar/core";
2
2
 
3
3
  //#region src/types.d.ts
4
4
  /**
@@ -64,6 +64,15 @@ declare function leasableStoreConformance(mk: StoreFactory<LeasableStore>, optio
64
64
  //#region src/fenced-writes.d.ts
65
65
  declare function fencedWritesConformance(mk: StoreFactory<LeasableStore>): ConformanceSuite;
66
66
  //#endregion
67
+ //#region src/quota-rules.d.ts
68
+ /**
69
+ * Constructs a limiter over the given rules; the suite closes whatever
70
+ * it returns (a `close` method is called and awaited when present), so
71
+ * factories may open real resources for the negative control.
72
+ */
73
+ type QuotaLimiterConstructor = (rules: readonly QuotaRule[]) => unknown;
74
+ declare function quotaRulesConformance(mk: QuotaLimiterConstructor): ConformanceSuite;
75
+ //#endregion
67
76
  //#region src/fenced-transcripts.d.ts
68
77
  /**
69
78
  * The paired factory product: the transcript store under test plus the
@@ -506,4 +515,4 @@ declare function foldStateSha256(entries: readonly JournalEntry[]): string;
506
515
  /** The reference hash; computed once from the kernel fold and frozen. */
507
516
  declare const GOLDEN_FOLD_STATE_SHA256 = "81e6ccff549fb3e6c1de4d34ba65b912162eba6f66403b5d5f23a3e1ec69243c";
508
517
  //#endregion
509
- export { type ConformanceCheck, type ConformanceSuite, DEFAULT_SOAK_QUORUM, type FencedTranscriptsFixture, GOLDEN_FOLD_JOURNAL, GOLDEN_FOLD_STATE_SHA256, KILL_POINT_SCENARIOS, type KillPointConformanceOptions, type KillPointEvent, type KillPointExpectation, type KillPointName, type KillPointObservation, type KillPointPhase, type KillPointScenario, type KillPointScenarioOptions, type KillPointTarget, type KillPointWorkerConfig, type KillPointWorkerHooks, type KillPointWorkflowKind, type MultiProcessSoakOptions, type MultiProcessSoakResult, type SoakAcceptSurface, type SoakActivity, type SoakEvent, type SoakProbeSurface, type SoakQuorum, type SoakWriterConfig, type SoakWriterHooks, type StoreFactory, type TestRegistrar, countSoakActivity, fencedTranscriptsConformance, fencedWritesConformance, foldStateSha256, journalStoreConformance, killPointConformance, killPointWorkerConfigFromEnv, leasableStoreConformance, makeSuite, materializeFoldState, parseKillPointReport, parseSoakReport, registerConformance, runKillPointScenario, runKillPointWorker, runMultiProcessSoak, runSoakWriter, soakWriterConfigFromEnv, stableStringify, verifySoakHistory };
518
+ export { type ConformanceCheck, type ConformanceSuite, DEFAULT_SOAK_QUORUM, type FencedTranscriptsFixture, GOLDEN_FOLD_JOURNAL, GOLDEN_FOLD_STATE_SHA256, KILL_POINT_SCENARIOS, type KillPointConformanceOptions, type KillPointEvent, type KillPointExpectation, type KillPointName, type KillPointObservation, type KillPointPhase, type KillPointScenario, type KillPointScenarioOptions, type KillPointTarget, type KillPointWorkerConfig, type KillPointWorkerHooks, type KillPointWorkflowKind, type MultiProcessSoakOptions, type MultiProcessSoakResult, type QuotaLimiterConstructor, type SoakAcceptSurface, type SoakActivity, type SoakEvent, type SoakProbeSurface, type SoakQuorum, type SoakWriterConfig, type SoakWriterHooks, type StoreFactory, type TestRegistrar, countSoakActivity, fencedTranscriptsConformance, fencedWritesConformance, foldStateSha256, journalStoreConformance, killPointConformance, killPointWorkerConfigFromEnv, leasableStoreConformance, makeSuite, materializeFoldState, parseKillPointReport, parseSoakReport, quotaRulesConformance, registerConformance, runKillPointScenario, runKillPointWorker, runMultiProcessSoak, runSoakWriter, soakWriterConfigFromEnv, stableStringify, verifySoakHistory };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { JournalOrderViolation, LeaseHeldError, Replayer, ResolutionFold, agentScope, buildDeriverRegistry, createCanonicalIdMinter, createEngine, defineWorkflow, deriveContentKey, dispositionHook, tool } from "@rulvar/core";
1
+ import { ConfigError, JournalOrderViolation, LeaseHeldError, Replayer, ResolutionFold, agentScope, buildDeriverRegistry, createCanonicalIdMinter, createEngine, defineWorkflow, deriveContentKey, dispositionHook, quotaRuleKey, tool } from "@rulvar/core";
2
2
  import { createHash } from "node:crypto";
3
3
  import { spawn } from "node:child_process";
4
4
  import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
@@ -880,6 +880,67 @@ function fencedWritesConformance(mk) {
880
880
  ]);
881
881
  }
882
882
  //#endregion
883
+ //#region src/quota-rules.ts
884
+ /**
885
+ * quotaRulesConformance (RV704): the executable construction contract
886
+ * every reference QuotaLimiter shares. A rule set containing two
887
+ * byte-identical rules is refused at construction with a typed
888
+ * ConfigError naming both indexes and the canonical rule key, because
889
+ * the SAME duplicated configuration admits differently per storage:
890
+ * index-keyed memory buckets count each copy independently (the full
891
+ * cap), while key-keyed store buckets are debited once per matching
892
+ * copy (the cap divided by the copy count). Refusing the set before
893
+ * any admission is what keeps equal configurations equal on every
894
+ * storage.
895
+ */
896
+ const RULE_A = {
897
+ provider: "fake",
898
+ model: "fake:model",
899
+ requestsPerMinute: 4
900
+ };
901
+ const RULE_B = {
902
+ provider: "fake",
903
+ tokensPerMinute: 1e3
904
+ };
905
+ async function closeQuietly(made) {
906
+ if (typeof made !== "object" || made === null) return;
907
+ const close = made.close;
908
+ if (typeof close === "function") try {
909
+ await Promise.resolve(close.call(made));
910
+ } catch {}
911
+ }
912
+ function quotaRulesConformance(mk) {
913
+ return makeSuite("quotaRulesConformance", [{
914
+ id: "quota-duplicate-refused",
915
+ title: "a duplicated rule is refused at construction, naming both indexes and the key",
916
+ async run() {
917
+ let thrown;
918
+ try {
919
+ await closeQuietly(mk([
920
+ RULE_A,
921
+ RULE_B,
922
+ { ...RULE_A }
923
+ ]));
924
+ } catch (error) {
925
+ thrown = error;
926
+ }
927
+ ensure(thrown !== void 0, "quota-duplicate-refused", "constructing a limiter over a rule set with a duplicated rule must throw: the same set admits the full cap on index-keyed memory buckets and half the cap on key-keyed store buckets, so admitting the configuration breaks storage parity");
928
+ const shown = thrown instanceof Error ? `${thrown.name}: ${thrown.message}` : JSON.stringify(thrown);
929
+ ensure(thrown instanceof ConfigError, "quota-duplicate-refused", `the duplicate refusal must be the typed ConfigError, got ${shown}`);
930
+ const message = thrown.message;
931
+ ensure(message.includes("[2] duplicates ") && message.includes("[0]"), "quota-duplicate-refused", `the refusal must name both indexes of the duplicated rule, got: ${message}`);
932
+ ensure(message.includes(`(rule key ${quotaRuleKey(RULE_A)})`), "quota-duplicate-refused", `the refusal must name the canonical rule key, got: ${message}`);
933
+ ensure(message.includes("delete the duplicate"), "quota-duplicate-refused", `the refusal must name the remedy, got: ${message}`);
934
+ }
935
+ }, {
936
+ id: "quota-distinct-rules-admitted",
937
+ title: "distinct rules construct: the refusal is about identity, never about count",
938
+ async run() {
939
+ await closeQuietly(mk([RULE_A, RULE_B]));
940
+ }
941
+ }]);
942
+ }
943
+ //#endregion
883
944
  //#region src/fenced-transcripts.ts
884
945
  /**
885
946
  * fencedTranscriptsConformance (the fenced run state RFC, F2): the
@@ -2296,4 +2357,4 @@ function killPointConformance(options) {
2296
2357
  })));
2297
2358
  }
2298
2359
  //#endregion
2299
- export { DEFAULT_SOAK_QUORUM, GOLDEN_FOLD_JOURNAL, GOLDEN_FOLD_STATE_SHA256, KILL_POINT_SCENARIOS, countSoakActivity, fencedTranscriptsConformance, fencedWritesConformance, foldStateSha256, journalStoreConformance, killPointConformance, killPointWorkerConfigFromEnv, leasableStoreConformance, makeSuite, materializeFoldState, parseKillPointReport, parseSoakReport, registerConformance, runKillPointScenario, runKillPointWorker, runMultiProcessSoak, runSoakWriter, soakWriterConfigFromEnv, stableStringify, verifySoakHistory };
2360
+ export { DEFAULT_SOAK_QUORUM, GOLDEN_FOLD_JOURNAL, GOLDEN_FOLD_STATE_SHA256, KILL_POINT_SCENARIOS, countSoakActivity, fencedTranscriptsConformance, fencedWritesConformance, foldStateSha256, journalStoreConformance, killPointConformance, killPointWorkerConfigFromEnv, leasableStoreConformance, makeSuite, materializeFoldState, parseKillPointReport, parseSoakReport, quotaRulesConformance, registerConformance, runKillPointScenario, runKillPointWorker, runMultiProcessSoak, runSoakWriter, soakWriterConfigFromEnv, stableStringify, verifySoakHistory };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/store-conformance",
3
- "version": "1.111.0",
3
+ "version": "1.112.0",
4
4
  "description": "Rulvar executable store conformance kit (DEF-4).",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,7 +22,7 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@rulvar/core": "1.111.0"
25
+ "@rulvar/core": "1.112.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.20.1",