pi-mega-compact 0.20.13 → 0.20.15
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/config/vector-cortex-early.js +89 -0
- package/dist/config/vector-cortex-flag.js +25 -0
- package/dist/config/vector-cortex.js +43 -83
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/api-contracts/vector-cortex-economics.js +20 -0
- package/dist/extensions/dashboard-server/route-dispatch.js +7 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +2 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-economics.js +59 -0
- package/dist/src/config/vector-cortex-early.js +89 -0
- package/dist/src/config/vector-cortex-flag.js +25 -0
- package/dist/src/config/vector-cortex.js +43 -83
- package/dist/src/config.js +1 -1
- package/dist/src/vector-cortex/cache/_economics-fixture.js +41 -0
- package/dist/src/vector-cortex/cache/compiler.js +201 -0
- package/dist/src/vector-cortex/cache/economics-emit.js +85 -0
- package/dist/src/vector-cortex/migrations/request-hash-v2-ops.js +143 -0
- package/dist/src/vector-cortex/migrations/request-hash-v2-types.js +30 -0
- package/dist/src/vector-cortex/migrations/request-hash-v2.js +56 -0
- package/dist/src/vector-cortex/provider/economics-ids.js +29 -0
- package/dist/src/vector-cortex/provider/economics.js +176 -0
- package/dist/src/vector-cortex/provider/experiments.js +166 -0
- package/dist/vector-cortex/cache/_economics-fixture.js +41 -0
- package/dist/vector-cortex/cache/compiler.js +201 -0
- package/dist/vector-cortex/cache/economics-emit.js +85 -0
- package/dist/vector-cortex/migrations/request-hash-v2-ops.js +143 -0
- package/dist/vector-cortex/migrations/request-hash-v2-types.js +30 -0
- package/dist/vector-cortex/migrations/request-hash-v2.js +56 -0
- package/dist/vector-cortex/provider/economics-ids.js +29 -0
- package/dist/vector-cortex/provider/economics.js +176 -0
- package/dist/vector-cortex/provider/experiments.js +166 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-CB-U7ViX.js → AreaChart-CV8WqMmt.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-CB-U7ViX.js.map → AreaChart-CV8WqMmt.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-DnLw0fxA.js → BarChart-M-HEBq9l.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-DnLw0fxA.js.map → BarChart-M-HEBq9l.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-CjyTVDiP.js → CacheTab-DJ_yPAhP.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-CjyTVDiP.js.map → CacheTab-DJ_yPAhP.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-Bz3QEWam.js → EventsTab-DNVlKzt6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-Bz3QEWam.js.map → EventsTab-DNVlKzt6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-CUylEvEY.js → HealthTab-B5yjuInb.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-CUylEvEY.js.map → HealthTab-B5yjuInb.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Cz_hj_E7.js → MaintenanceTab-DoQedESF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Cz_hj_E7.js.map → MaintenanceTab-DoQedESF.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-Dh8brIR1.js → MemoryMapTab-CuL5CzdH.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-Dh8brIR1.js.map → MemoryMapTab-CuL5CzdH.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CkqSXc6e.js → MetricsTab-CZSTaCpK.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CkqSXc6e.js.map → MetricsTab-CZSTaCpK.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DGbJcx6d.js → OverviewTab-vkZlXRW6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DGbJcx6d.js.map → OverviewTab-vkZlXRW6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-BawS3nfF.js → ReposTab-DgPD96rF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-BawS3nfF.js.map → ReposTab-DgPD96rF.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-CUVnmYks.js → SessionsTab-XPbWh7XN.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-CUVnmYks.js.map → SessionsTab-XPbWh7XN.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-cxTuyZNk.js → SetupTab-Dz74XAtR.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-cxTuyZNk.js.map → SetupTab-Dz74XAtR.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-Cv5SENkE.js → TimeSavedCard-FynCpJdx.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-Cv5SENkE.js.map → TimeSavedCard-FynCpJdx.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-yl6BBG_F.js → TurnsTab-C7m3GDy0.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-yl6BBG_F.js.map → TurnsTab-C7m3GDy0.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-jRd_Iztk.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-jRd_Iztk.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-DKv-0xCQ.js → WikiTab-C6viLa0u.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-DKv-0xCQ.js.map → WikiTab-C6viLa0u.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-CVPrO4UU.js → button-mBEgbBVU.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-CVPrO4UU.js.map → button-mBEgbBVU.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-BFLnQJEo.js → card-CalUQAKG.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-BFLnQJEo.js.map → card-CalUQAKG.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-IUoLd1.js → generateCategoricalChart-CMmkuwj5.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-IUoLd1.js.map → generateCategoricalChart-CMmkuwj5.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-Do749WlW.js → index-Dz8GPBOE.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-Do749WlW.js.map → index-Dz8GPBOE.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-3uFnZmtq.js → switch-8QKO6CTU.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-3uFnZmtq.js.map → switch-8QKO6CTU.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-C1rYLeXe.js → toggle-9eCkWI4q.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-C1rYLeXe.js.map → toggle-9eCkWI4q.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-D1qzLzgR.js → useSSE-s6IqOKoD.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-D1qzLzgR.js.map → useSSE-s6IqOKoD.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/api/vector-cortex.ts +18 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexEconomicsCard.tsx +41 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +24 -114
- package/extensions/dashboard-client/src/tabs/useVectorCortexPoll.ts +123 -0
- package/extensions/dashboard-client/src/types/vector-cortex-vc7.ts +63 -0
- package/extensions/dashboard-client/src/types/vector-cortex.ts +5 -19
- package/extensions/dashboard-server/api-contracts/vector-cortex-economics.ts +47 -0
- package/extensions/dashboard-server/route-dispatch.ts +6 -0
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +12 -0
- package/extensions/dashboard-server/routes-vector-cortex-economics.ts +68 -0
- package/package.json +1 -1
- package/src/config/vector-cortex-early.ts +99 -0
- package/src/config/vector-cortex-flag.ts +24 -0
- package/src/config/vector-cortex.ts +55 -89
- package/src/config.ts +2 -0
- package/src/vector-cortex/cache/_economics-fixture.ts +128 -0
- package/src/vector-cortex/cache/compiler.ts +280 -0
- package/src/vector-cortex/cache/economics-emit.ts +116 -0
- package/src/vector-cortex/migrations/request-hash-v2-ops.ts +195 -0
- package/src/vector-cortex/migrations/request-hash-v2-types.ts +87 -0
- package/src/vector-cortex/migrations/request-hash-v2.ts +80 -0
- package/src/vector-cortex/provider/economics-ids.ts +38 -0
- package/src/vector-cortex/provider/economics.ts +289 -0
- package/src/vector-cortex/provider/experiments.ts +248 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-94fqVjat.js +0 -2
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-94fqVjat.js.map +0 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* request-hash-v2-ops.ts — M5 migration operational logic (copy/verify/switch).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from request-hash-v2.ts to keep the parent file under the 300-line
|
|
5
|
+
* soft limit (soft-as-hard gate). Pure logic over an injected M5Host;
|
|
6
|
+
* deterministic + testable; no console. PREVENT-002/011/PI-004 honored.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { invalidationKey } from "../topology/query.js";
|
|
10
|
+
import { M5_FAIL, REQUEST_HASH_LEGACY_VERSION, } from "./request-hash-v2-types.js";
|
|
11
|
+
/** Length-prefixed framing so the folded fields cannot alias. */
|
|
12
|
+
function field(value) {
|
|
13
|
+
return `${Buffer.byteLength(value, "utf8")}:${value}`;
|
|
14
|
+
}
|
|
15
|
+
const identity = (profileId, requestDigest) => `${profileId}::${requestDigest}`;
|
|
16
|
+
/**
|
|
17
|
+
* The authoritative v2 hash: SHA-256 over the version tag, profile, request
|
|
18
|
+
* digest, and economics version. Length-prefixed for injectivity, exactly as the
|
|
19
|
+
* crystal key encoder frames its fields.
|
|
20
|
+
*/
|
|
21
|
+
export function deriveRequestHashV2(profileId, requestDigest, economicsVersion) {
|
|
22
|
+
return createHash("sha256")
|
|
23
|
+
.update(field("request-hash-v2") +
|
|
24
|
+
field(profileId) +
|
|
25
|
+
field(requestDigest) +
|
|
26
|
+
field(economicsVersion), "utf8")
|
|
27
|
+
.digest("hex");
|
|
28
|
+
}
|
|
29
|
+
/** Derive the v2 row for one v1 row. */
|
|
30
|
+
export function deriveRequestHashRow(host, v1) {
|
|
31
|
+
const economicsVersion = host.economicsVersionOf(v1.profileId);
|
|
32
|
+
return {
|
|
33
|
+
profileId: v1.profileId,
|
|
34
|
+
// IDENTITY-PRESERVING: carried through verbatim, never re-derived.
|
|
35
|
+
requestDigest: v1.requestDigest,
|
|
36
|
+
economicsVersion,
|
|
37
|
+
hash: deriveRequestHashV2(v1.profileId, v1.requestDigest, economicsVersion),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Economics versions encode the generation they were minted under. We treat the
|
|
42
|
+
* trailing numeric segment as the generation; if it is not numeric the row is
|
|
43
|
+
* considered tied to generation 0 (always live unless explicitly invalidated).
|
|
44
|
+
*/
|
|
45
|
+
function generationFromEconomics(economicsVersion) {
|
|
46
|
+
const match = /(\d+)$/.exec(economicsVersion);
|
|
47
|
+
return match ? BigInt(match[1]) : 0n;
|
|
48
|
+
}
|
|
49
|
+
export function detectCollision(host) {
|
|
50
|
+
const byHash = new Map();
|
|
51
|
+
for (const v1 of host.v1Rows()) {
|
|
52
|
+
const row = deriveRequestHashRow(host, v1);
|
|
53
|
+
const prior = byHash.get(row.hash);
|
|
54
|
+
if (prior !== undefined &&
|
|
55
|
+
prior !== identity(v1.profileId, v1.requestDigest)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
byHash.set(row.hash, identity(v1.profileId, v1.requestDigest));
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
export function isGenerationInvalidated(host, row) {
|
|
63
|
+
const session = host.sessionOf(row.profileId);
|
|
64
|
+
const live = host.liveGenerationOf(session);
|
|
65
|
+
const keyForLive = invalidationKey(session, live);
|
|
66
|
+
const keyForRow = invalidationKey(session, generationFromEconomics(row.economicsVersion));
|
|
67
|
+
return keyForLive !== keyForRow;
|
|
68
|
+
}
|
|
69
|
+
export function m5Copy(host) {
|
|
70
|
+
const existing = new Map(host.existingV2().map((r) => [identity(r.profileId, r.requestDigest), r]));
|
|
71
|
+
const wanted = [];
|
|
72
|
+
for (const v1 of host.v1Rows()) {
|
|
73
|
+
const fresh = deriveRequestHashRow(host, v1);
|
|
74
|
+
if (isGenerationInvalidated(host, fresh))
|
|
75
|
+
continue;
|
|
76
|
+
const stored = existing.get(identity(v1.profileId, v1.requestDigest));
|
|
77
|
+
if (stored !== undefined &&
|
|
78
|
+
stored.hash === fresh.hash &&
|
|
79
|
+
stored.economicsVersion === fresh.economicsVersion) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
wanted.push(fresh);
|
|
83
|
+
}
|
|
84
|
+
if (wanted.length > 0)
|
|
85
|
+
host.putV2(wanted);
|
|
86
|
+
return { written: wanted, all: [...host.existingV2()] };
|
|
87
|
+
}
|
|
88
|
+
function dedupe(codes) {
|
|
89
|
+
const out = [];
|
|
90
|
+
for (const c of codes)
|
|
91
|
+
if (!out.includes(c))
|
|
92
|
+
out.push(c);
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
export function m5Verify(host) {
|
|
96
|
+
const codes = [];
|
|
97
|
+
const stored = host.existingV2();
|
|
98
|
+
const v1Rows = host.v1Rows();
|
|
99
|
+
const counts = new Map();
|
|
100
|
+
for (const r of stored) {
|
|
101
|
+
const id = identity(r.profileId, r.requestDigest);
|
|
102
|
+
counts.set(id, (counts.get(id) ?? 0) + 1);
|
|
103
|
+
}
|
|
104
|
+
const expected = new Set();
|
|
105
|
+
for (const v1 of v1Rows) {
|
|
106
|
+
const id = identity(v1.profileId, v1.requestDigest);
|
|
107
|
+
expected.add(id);
|
|
108
|
+
const n = counts.get(id) ?? 0;
|
|
109
|
+
if (n === 0)
|
|
110
|
+
codes.push(M5_FAIL.COPY_PARTIAL);
|
|
111
|
+
if (n > 1)
|
|
112
|
+
codes.push(M5_FAIL.COUNT_MISMATCH);
|
|
113
|
+
}
|
|
114
|
+
const v1Digests = new Set(v1Rows.map((r) => identity(r.profileId, r.requestDigest)));
|
|
115
|
+
for (const r of stored) {
|
|
116
|
+
const fresh = deriveRequestHashV2(r.profileId, r.requestDigest, r.economicsVersion);
|
|
117
|
+
if (r.hash !== fresh)
|
|
118
|
+
codes.push(M5_FAIL.DIGEST_MISMATCH);
|
|
119
|
+
const id = identity(r.profileId, r.requestDigest);
|
|
120
|
+
if (!v1Digests.has(id)) {
|
|
121
|
+
codes.push(expected.size > 0 ? M5_FAIL.IDENTITY_DRIFT : M5_FAIL.COUNT_MISMATCH);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (detectCollision(host))
|
|
125
|
+
codes.push(M5_FAIL.REQUEST_HASH_COLLISION);
|
|
126
|
+
return { ok: codes.length === 0, codes: dedupe(codes) };
|
|
127
|
+
}
|
|
128
|
+
export function m5Switch(host) {
|
|
129
|
+
if (host.activeVersion() !== REQUEST_HASH_LEGACY_VERSION) {
|
|
130
|
+
return { ok: false, codes: [M5_FAIL.NOT_ON_LEGACY] };
|
|
131
|
+
}
|
|
132
|
+
const verify = m5Verify(host);
|
|
133
|
+
if (!verify.ok)
|
|
134
|
+
return verify;
|
|
135
|
+
if (detectCollision(host))
|
|
136
|
+
return { ok: false, codes: [M5_FAIL.REQUEST_HASH_COLLISION] };
|
|
137
|
+
host.switchToV2();
|
|
138
|
+
return { ok: true, codes: [] };
|
|
139
|
+
}
|
|
140
|
+
export function migrateRequestHashV2(host) {
|
|
141
|
+
m5Copy(host);
|
|
142
|
+
return m5Switch(host);
|
|
143
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* request-hash-v2-types.ts — M5 request-hash-v2 migration types.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from request-hash-v2.ts to keep the parent file under the 300-line
|
|
5
|
+
* soft limit (soft-as-hard gate). Pure type + constant definitions; no logic.
|
|
6
|
+
* PREVENT-002/011/PI-004 honored.
|
|
7
|
+
*/
|
|
8
|
+
/** The active-version value the v2 pointer is switched to. */
|
|
9
|
+
export const REQUEST_HASH_V2_VERSION = 2;
|
|
10
|
+
/** The legacy (predecessor) active version. */
|
|
11
|
+
export const REQUEST_HASH_LEGACY_VERSION = 1;
|
|
12
|
+
/** M5 failure codes. */
|
|
13
|
+
export const M5_FAIL = {
|
|
14
|
+
COPY_PARTIAL: "M5_COPY_PARTIAL",
|
|
15
|
+
COUNT_MISMATCH: "M5_COUNT_MISMATCH",
|
|
16
|
+
DIGEST_MISMATCH: "M5_DIGEST_MISMATCH",
|
|
17
|
+
IDENTITY_DRIFT: "M5_IDENTITY_DRIFT",
|
|
18
|
+
/** Two distinct v1 rows map to the same v2 hash — blocks the switch. (VC7C) */
|
|
19
|
+
REQUEST_HASH_COLLISION: "M5_REQUEST_HASH_COLLISION",
|
|
20
|
+
/** The active pointer is not on v1; switching would be a no-op or a regression. */
|
|
21
|
+
NOT_ON_LEGACY: "M5_NOT_ON_LEGACY",
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Registered M5 conformance IDs (M5-001..020). The acceptance test reads these
|
|
25
|
+
* rows from the v2 `migrations/` domain and asserts each returns its manifest
|
|
26
|
+
* bytes or exactly its listed failure code. Mirrors M6_IDS / M4_IDS.
|
|
27
|
+
*/
|
|
28
|
+
export const M5_IDS = Array.from({ length: 20 }, (_v, i) => `M5-${String(i + 1).padStart(3, "0")}`);
|
|
29
|
+
/** Named M5 rows surfaced by the conformance corpus (mirrors M6_NAMED_IDS). */
|
|
30
|
+
export const M5_NAMED_IDS = ["M5-COLLIDE-002"];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/migrations/request-hash-v2.ts — M5 request-hash-v2 migration
|
|
3
|
+
* (COPY + VALIDATE + SWITCH).
|
|
4
|
+
*
|
|
5
|
+
* Delegate-shell: types + constants live in request-hash-v2-types.ts and the
|
|
6
|
+
* operational logic (copy/verify/switch/collision) lives in
|
|
7
|
+
* request-hash-v2-ops.ts. This file re-exports the public surface so callers
|
|
8
|
+
* import from a single module. Split to keep under the 300-line soft limit
|
|
9
|
+
* (soft-as-hard gate).
|
|
10
|
+
*
|
|
11
|
+
* M5 versions the canonical request hash: the predecessor hashed the outbound
|
|
12
|
+
* request under the v1 scheme; v2 folds in the provider profile's ECONOMICS
|
|
13
|
+
* version so a pricing/TTL/exclusion change cannot silently reuse a cache
|
|
14
|
+
* identity minted under different economics. Like M4/M6 it follows the
|
|
15
|
+
* copy/validate/switch contract:
|
|
16
|
+
*
|
|
17
|
+
* - copy: resumable per (profile, request) — an interrupted run resumes
|
|
18
|
+
* without duplicate rows or active-pointer drift.
|
|
19
|
+
* - validate: every v1 row has exactly one v2 row, every v2 digest re-hashes
|
|
20
|
+
* from its own declared fields, the migration is IDENTITY-PRESERVING
|
|
21
|
+
* (a v2 row carries the same `requestDigest` as its v1 source — v2
|
|
22
|
+
* changes how a CACHE KEY is derived, never what the request IS), and
|
|
23
|
+
* — the M5-specific invariant ADDED in VC7C — there are ZERO
|
|
24
|
+
* collisions: no two distinct v1 rows may map to one v2 hash. A
|
|
25
|
+
* collision (`M5_REQUEST_HASH_COLLISION`) means two different
|
|
26
|
+
* conversations would share a cache key, the most dangerous outcome
|
|
27
|
+
* in the subsystem, so it blocks the switch outright.
|
|
28
|
+
* - switch: ATOMICALLY flip the active pointer to v2 via `host.switchToV2()`.
|
|
29
|
+
* VC7B deferred this; VC7C performs it — but ONLY after re-validating
|
|
30
|
+
* against freshly-read host state at switch time.
|
|
31
|
+
*
|
|
32
|
+
* WHY THE COLLISION CHECK RUNS AT SWITCH TIME, NOT VALIDATE TIME. The brief's
|
|
33
|
+
* failure-injection contract is explicit: crash after M5 validation, inject a
|
|
34
|
+
* collision into host state, then resume — and the RESUMED run must detect
|
|
35
|
+
* `M5_REQUEST_HASH_COLLISION`. If the collision were detected only from the result
|
|
36
|
+
* of an earlier `m5Verify` call, the cached result would be replayed and the
|
|
37
|
+
* injected collision would be invisible. So `m5Switch` RE-READS the host (`v1Rows`,
|
|
38
|
+
* `existingV2`, `activeVersion`) and RE-RUNS the collision check against that live
|
|
39
|
+
* state. Validation is a precondition; the switch is the only place that proves the
|
|
40
|
+
* hazard is absent *right now*. This is the same resume-after-crash discipline as
|
|
41
|
+
* M4/M6: a migration that trusts a stale verification is a migration that loses
|
|
42
|
+
* data on restart.
|
|
43
|
+
*
|
|
44
|
+
* M6 INVALIDATION CONSUMPTION. A v2 request hash is only as trustworthy as the
|
|
45
|
+
* generation it was minted under. The switch consumes M6's structured invalidation
|
|
46
|
+
* keys via the REAL API (`invalidationKey` from `../topology/query.js`) rather than
|
|
47
|
+
* inventing one: when a v2 row's economics version maps to an invalidated router
|
|
48
|
+
* generation, that row cannot be promoted to active. We do not re-derive a
|
|
49
|
+
* generation here — topology is the authority on what generation is live — we only
|
|
50
|
+
* refuse to switch a row whose generation is dead. This keeps M5 from resurrecting
|
|
51
|
+
* cache identities tied to a generation the router has already invalidated.
|
|
52
|
+
*
|
|
53
|
+
* PREVENT-002/011/PI-004 honored.
|
|
54
|
+
*/
|
|
55
|
+
export { REQUEST_HASH_V2_VERSION, REQUEST_HASH_LEGACY_VERSION, M5_FAIL, M5_IDS, M5_NAMED_IDS, } from "./request-hash-v2-types.js";
|
|
56
|
+
export { deriveRequestHashV2, deriveRequestHashRow, detectCollision, isGenerationInvalidated, m5Copy, m5Verify, m5Switch, migrateRequestHashV2, } from "./request-hash-v2-ops.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/provider/economics-ids.ts — VC7B conformance ID registrations.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from economics.ts to keep that file under the 300-line soft limit
|
|
5
|
+
* (soft-as-hard gate). The ID ranges and named rows are pure data — splitting
|
|
6
|
+
* them out mirrors how vector-cortex-breakers.ts was extracted from
|
|
7
|
+
* vector-cortex.ts. economics.ts re-exports them so no consumer import path
|
|
8
|
+
* changes.
|
|
9
|
+
*
|
|
10
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Registered VC7B cache-economics conformance ID range (CACHE-001..015). The
|
|
14
|
+
* acceptance aggregator reads these rows from the v2 manifest and asserts each
|
|
15
|
+
* returns its manifest `ok`/`code`.
|
|
16
|
+
*/
|
|
17
|
+
export const CACHE_IDS = Array.from({ length: 15 }, (_v, i) => `CACHE-${String(i + 1).padStart(3, "0")}`);
|
|
18
|
+
/**
|
|
19
|
+
* Registered VC7B provider-economics conformance rows (PRO-024..030), continuing
|
|
20
|
+
* VC7A's PRO-016..023. These pin the ECONOMICS half of a provider profile:
|
|
21
|
+
* pricing validity, the exclusion-proof rule, and TTL/min-prefix eligibility.
|
|
22
|
+
*/
|
|
23
|
+
export const ECONOMICS_PROVIDER_IDS = Array.from({ length: 7 }, (_v, i) => `PRO-${String(i + 24).padStart(3, "0")}`);
|
|
24
|
+
/** Named VC7B conformance assertions (the sprint's headline rows). */
|
|
25
|
+
export const ECONOMICS_NAMED_IDS = [
|
|
26
|
+
"CACHE-COST-001",
|
|
27
|
+
"CACHE-EXCLUDE-002",
|
|
28
|
+
"CACHE-RANDOM-003",
|
|
29
|
+
];
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/provider/economics.ts — VC7B cache economics (ProviderProfileV1
|
|
3
|
+
* extension).
|
|
4
|
+
*
|
|
5
|
+
* VC7A proved a render can be FROZEN and reused. VC7B answers the question that
|
|
6
|
+
* immediately follows: is reusing it actually WORTH IT? Provider prompt caching
|
|
7
|
+
* is not free — a cache WRITE typically costs MORE than an uncached token, and a
|
|
8
|
+
* cache READ costs less. So a cache is profitable only when a written prefix is
|
|
9
|
+
* read back enough times, before its TTL expires, to repay the write premium.
|
|
10
|
+
* This file is that arithmetic and nothing else.
|
|
11
|
+
*
|
|
12
|
+
* THE NET-SAVINGS MODEL. For a prefix of `cachedTokens` tokens:
|
|
13
|
+
*
|
|
14
|
+
* baseline (no cache) = cachedTokens * basePrice * (writes + hits)
|
|
15
|
+
* actual (cached) = cachedTokens * (writePrice * writes + readPrice * hits)
|
|
16
|
+
* netSavings = baseline - actual
|
|
17
|
+
*
|
|
18
|
+
* A NEGATIVE `netSavings` is a real, expected, and important outcome: it means
|
|
19
|
+
* the cache LOST money (a prefix written once and never re-read always does, by
|
|
20
|
+
* exactly the write premium). We report it rather than clamping it at zero,
|
|
21
|
+
* because a floor at zero would make every rollout look free and would hide the
|
|
22
|
+
* single failure mode this sprint exists to detect.
|
|
23
|
+
*
|
|
24
|
+
* EXACT ARITHMETIC, NO FLOATS IN THE MONEY PATH. Prices are integer
|
|
25
|
+
* MICRO-UNITS per token (1e-6 of the provider's currency unit), never floating
|
|
26
|
+
* point. `0.1 + 0.2 !== 0.3` is not an acceptable property for a cost ledger, and
|
|
27
|
+
* accumulating float error across millions of tokens produces aggregates that
|
|
28
|
+
* silently disagree with the provider's own bill. All money is integer; only the
|
|
29
|
+
* derived RATIO is a float, and it is finite-guarded.
|
|
30
|
+
*
|
|
31
|
+
* EVERY EXCLUSION NEEDS A FIXTURE (the sprint's headline safety rule). A provider
|
|
32
|
+
* profile may declare that some request field does not affect cache identity —
|
|
33
|
+
* but an UNPROVEN exclusion is how you get silent cache poisoning: the renderer
|
|
34
|
+
* folds a field the provider actually keys on, two different requests collapse to
|
|
35
|
+
* one cache entry, and one conversation is served another's prefix. So an
|
|
36
|
+
* exclusion without a `fixtureId` (or with a blank one) is REJECTED here —
|
|
37
|
+
* `ECON_EXCLUSION_UNPROVEN` — rather than trusted. There is no override.
|
|
38
|
+
*
|
|
39
|
+
* ESTIMATE VS MEASURED. Every result is labeled. Only telemetry from a
|
|
40
|
+
* RANDOMIZED live assignment may be called `measured` and fed into a causal
|
|
41
|
+
* interval; shadow or non-randomized numbers are `estimate` and are excluded
|
|
42
|
+
* from causal aggregates (see `experiments.ts`). Mixing the two would let a
|
|
43
|
+
* self-selected population masquerade as a controlled experiment.
|
|
44
|
+
*
|
|
45
|
+
* PURE. No clock, no storage, no console, no network (PREVENT-PI-004 /
|
|
46
|
+
* PREVENT-011). Runs identically with `MEGACOMPACT_VC7B` on or off — the flag
|
|
47
|
+
* gates only the reporter/dashboard seam in `../cache/economics-emit.ts`.
|
|
48
|
+
*/
|
|
49
|
+
/** A non-negative safe integer — the only shape money and counts may take. */
|
|
50
|
+
function isCount(n) {
|
|
51
|
+
return Number.isSafeInteger(n) && n >= 0;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validate a profile's economics, enforcing the exclusion-proof rule.
|
|
55
|
+
*
|
|
56
|
+
* An exclusion claims "this field cannot affect provider cache identity". That
|
|
57
|
+
* claim is only as good as the fixture that proves it, so a profile carrying
|
|
58
|
+
* exclusions MUST name a `exclusionFixtureId`, and every individual exclusion
|
|
59
|
+
* must carry its own `fixtureId` too (VC5B already models that field; VC7B makes
|
|
60
|
+
* a blank one fatal instead of decorative). Returns deduplicated codes in a
|
|
61
|
+
* deterministic order.
|
|
62
|
+
*/
|
|
63
|
+
export function validateEconomics(econ, exclusions) {
|
|
64
|
+
const codes = new Set();
|
|
65
|
+
for (const n of [econ.basePrice, econ.readPrice, econ.writePrice, econ.ttlMs, econ.minPrefix]) {
|
|
66
|
+
if (!isCount(n))
|
|
67
|
+
codes.add("ECON_PRICE_INVALID");
|
|
68
|
+
}
|
|
69
|
+
// The headline rule: exclusions without a proving fixture are never trusted.
|
|
70
|
+
if (exclusions.length > 0) {
|
|
71
|
+
const id = econ.exclusionFixtureId;
|
|
72
|
+
if (id === null || id.trim() === "")
|
|
73
|
+
codes.add("ECON_EXCLUSION_UNPROVEN");
|
|
74
|
+
for (const ex of exclusions) {
|
|
75
|
+
if (ex.fixtureId.trim() === "")
|
|
76
|
+
codes.add("ECON_EXCLUSION_UNPROVEN");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const order = ["ECON_EXCLUSION_UNPROVEN", "ECON_PRICE_INVALID"];
|
|
80
|
+
return order.filter((c) => codes.has(c));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Validate a profile + its economics together. Convenience over
|
|
84
|
+
* `validateEconomics` for callers holding a whole `ProviderProfileV1`: the
|
|
85
|
+
* exclusion list is read from the profile itself, so the two can never disagree.
|
|
86
|
+
*/
|
|
87
|
+
export function validateProfileEconomics(profile, econ) {
|
|
88
|
+
return validateEconomics(econ, profile.excludedJsonPointers);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Hits required for ONE write to break even.
|
|
92
|
+
*
|
|
93
|
+
* One write costs `(writePrice - basePrice)` extra per token; each subsequent
|
|
94
|
+
* hit saves `(basePrice - readPrice)` per token. So break-even is the ceiling of
|
|
95
|
+
* premium/discount. Returns `null` when the cache can NEVER pay for itself
|
|
96
|
+
* (a read that costs at least as much as an uncached token) — reporting a huge
|
|
97
|
+
* number there would imply "just get more hits", which is false.
|
|
98
|
+
* Returns 0 when writing is already free or cheaper than not caching.
|
|
99
|
+
*/
|
|
100
|
+
export function breakEvenHits(econ) {
|
|
101
|
+
const premium = econ.writePrice - econ.basePrice;
|
|
102
|
+
const discount = econ.basePrice - econ.readPrice;
|
|
103
|
+
if (premium <= 0)
|
|
104
|
+
return 0;
|
|
105
|
+
if (discount <= 0)
|
|
106
|
+
return null;
|
|
107
|
+
return Math.ceil(premium / discount);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Compute net cache savings for observed (or shadow) usage.
|
|
111
|
+
*
|
|
112
|
+
* Pure integer arithmetic in micro-units. The only float is `savingsRatio`, and
|
|
113
|
+
* it is zero-guarded so a zero baseline yields 0 rather than NaN/Infinity — the
|
|
114
|
+
* sprint invariant is that every reported aggregate is FINITE.
|
|
115
|
+
*
|
|
116
|
+
* `evidence` is supplied by the caller and simply carried through: this function
|
|
117
|
+
* cannot know whether its inputs came from a randomized arm, and guessing would
|
|
118
|
+
* be exactly the mislabeling the causal rules forbid.
|
|
119
|
+
*/
|
|
120
|
+
export function computeEconomics(econ, usage, evidence) {
|
|
121
|
+
const codes = [];
|
|
122
|
+
for (const n of [econ.basePrice, econ.readPrice, econ.writePrice, econ.ttlMs, econ.minPrefix]) {
|
|
123
|
+
if (!isCount(n)) {
|
|
124
|
+
codes.push("ECON_PRICE_INVALID");
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (const n of [usage.cachedTokens, usage.writeCount, usage.hitCount]) {
|
|
129
|
+
if (!isCount(n)) {
|
|
130
|
+
codes.push("ECON_USAGE_INVALID");
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (codes.length > 0)
|
|
135
|
+
return { ok: false, codes };
|
|
136
|
+
const { cachedTokens, writeCount, hitCount } = usage;
|
|
137
|
+
const baselineCost = cachedTokens * econ.basePrice * (writeCount + hitCount);
|
|
138
|
+
const actualCost = cachedTokens * (econ.writePrice * writeCount + econ.readPrice * hitCount);
|
|
139
|
+
// Exactness is the whole point of the integer model: if any product leaves the
|
|
140
|
+
// safe-integer range the result is silently wrong, so we fail instead.
|
|
141
|
+
if (!Number.isSafeInteger(baselineCost) || !Number.isSafeInteger(actualCost)) {
|
|
142
|
+
return { ok: false, codes: ["ECON_OVERFLOW"] };
|
|
143
|
+
}
|
|
144
|
+
const netSavings = baselineCost - actualCost;
|
|
145
|
+
// Tokens served at the discounted read price — the cache's token-level benefit,
|
|
146
|
+
// independent of price (a hit re-reads the whole prefix).
|
|
147
|
+
const tokenSavings = cachedTokens * hitCount;
|
|
148
|
+
const savingsRatio = baselineCost === 0 ? 0 : netSavings / baselineCost;
|
|
149
|
+
return {
|
|
150
|
+
ok: true,
|
|
151
|
+
result: {
|
|
152
|
+
profileId: econ.profileId,
|
|
153
|
+
baselineCost,
|
|
154
|
+
actualCost,
|
|
155
|
+
netSavings,
|
|
156
|
+
tokenSavings,
|
|
157
|
+
savingsRatio,
|
|
158
|
+
breakEvenHits: breakEvenHits(econ),
|
|
159
|
+
evidence,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Whether a prefix is eligible to be cached at all: it must meet the profile's
|
|
165
|
+
* minimum prefix, and it must still be within TTL. A prefix below `minPrefix` is
|
|
166
|
+
* not "a small win", it is not cacheable by the provider at all.
|
|
167
|
+
*/
|
|
168
|
+
export function isCacheEligible(econ, prefixTokens, ageMs) {
|
|
169
|
+
if (!isCount(prefixTokens) || !isCount(ageMs))
|
|
170
|
+
return false;
|
|
171
|
+
return prefixTokens >= econ.minPrefix && ageMs < econ.ttlMs;
|
|
172
|
+
}
|
|
173
|
+
// Conformance ID ranges + named rows extracted to economics-ids.ts to keep this
|
|
174
|
+
// file under the 300-line soft limit (soft-as-hard gate). Re-exported here so no
|
|
175
|
+
// consumer import path changes.
|
|
176
|
+
export { CACHE_IDS, ECONOMICS_PROVIDER_IDS, ECONOMICS_NAMED_IDS, } from "./economics-ids.js";
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/provider/experiments.ts — VC7B session-level cache experiments.
|
|
3
|
+
*
|
|
4
|
+
* To claim a cache strategy CAUSED a saving you need a randomized comparison,
|
|
5
|
+
* not a before/after. This file assigns each session to an experiment arm and
|
|
6
|
+
* guarantees the two properties that make the resulting telemetry admissible as
|
|
7
|
+
* causal evidence.
|
|
8
|
+
*
|
|
9
|
+
* 1. STABLE, JOURNAL-FREE ASSIGNMENT. The arm is a pure function of
|
|
10
|
+
* `sha256(experimentId, sessionId)` — NOT a random draw recorded in a
|
|
11
|
+
* journal. So the assignment survives anything: process restart, a lost or
|
|
12
|
+
* corrupted journal, a different host, a replay months later. This is the
|
|
13
|
+
* sprint's unique failure-injection case (lose the journal after the first
|
|
14
|
+
* event, restart, and the same arm must come back), and a hash-derived arm
|
|
15
|
+
* passes it by construction rather than by careful recovery code. A journal
|
|
16
|
+
* can still be kept as an audit trail, but nothing DEPENDS on it.
|
|
17
|
+
*
|
|
18
|
+
* The corollary matters just as much: every event in one session shares one
|
|
19
|
+
* arm (CACHE-RANDOM-003). If a session could drift between arms mid-flight,
|
|
20
|
+
* its rows would appear in both arms of the comparison and the contrast would
|
|
21
|
+
* be measuring nothing.
|
|
22
|
+
*
|
|
23
|
+
* 2. RANDOMIZED ⇒ CAUSAL; EVERYTHING ELSE ⇒ ESTIMATE. Hashing a session id is
|
|
24
|
+
* randomization only when the id itself is unpredictable and every session is
|
|
25
|
+
* eligible. A FORCED arm (operator override), a SHADOW arm (computed but not
|
|
26
|
+
* served), and a non-randomized rollout are all labeled `estimate` and are
|
|
27
|
+
* excluded from causal intervals by `isCausallyAdmissible`. Shadow numbers are
|
|
28
|
+
* genuinely useful — they are just not evidence of an effect.
|
|
29
|
+
*
|
|
30
|
+
* WHY 10_000 BUCKETS. Bucket granularity bounds how finely traffic can be split;
|
|
31
|
+
* 10k gives 0.01% resolution, matching VC5C's rollout bucketing so the two
|
|
32
|
+
* subsystems partition traffic on the same scale rather than on quietly
|
|
33
|
+
* different ones.
|
|
34
|
+
*
|
|
35
|
+
* PURE. No clock, no storage, no console, no network (PREVENT-PI-004 /
|
|
36
|
+
* PREVENT-011). `assignedAt` is an INJECTED timestamp, never `Date.now()` read
|
|
37
|
+
* here, so assignment is fully reproducible in tests and replays. Runs
|
|
38
|
+
* identically with `MEGACOMPACT_VC7B` on or off.
|
|
39
|
+
*/
|
|
40
|
+
import { createHash } from "node:crypto";
|
|
41
|
+
/** The registered arms, in canonical bucket order. */
|
|
42
|
+
export const EXPERIMENT_ARMS = ["A", "B", "C"];
|
|
43
|
+
/** Bucket space: 10k buckets = 0.01% resolution (matches VC5C rollout). */
|
|
44
|
+
export const EXPERIMENT_BUCKETS = 10_000;
|
|
45
|
+
/** Even three-way split (the default): 3334 / 3333 / 3333 = 10000. */
|
|
46
|
+
export const EVEN_SPLIT = { A: 3334, B: 3333, C: 3333 };
|
|
47
|
+
/**
|
|
48
|
+
* Length-prefixed field framing, identical in spirit to the crystal key encoder:
|
|
49
|
+
* `<byteLength>:<value>` makes the concatenation injective, so experiment
|
|
50
|
+
* `"a"` + session `"b:c"` cannot collide with experiment `"a:b"` + session `"c"`.
|
|
51
|
+
* Without it, two different (experiment, session) pairs could share a bucket and
|
|
52
|
+
* a session could appear to switch arms when an experiment is renamed.
|
|
53
|
+
*/
|
|
54
|
+
function field(value) {
|
|
55
|
+
return `${Buffer.byteLength(value, "utf8")}:${value}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The stable bucket for a session: the low 32 bits of
|
|
59
|
+
* `sha256(experimentId, sessionId)`, modulo the bucket space.
|
|
60
|
+
*
|
|
61
|
+
* Deterministic and storage-free — this is what makes a lost assignment journal
|
|
62
|
+
* a non-event. Reading 4 bytes (rather than the whole digest) keeps the value in
|
|
63
|
+
* exact integer range; SHA-256's avalanche means any 32 bits are equidistributed.
|
|
64
|
+
*/
|
|
65
|
+
export function experimentBucket(experimentId, sessionId) {
|
|
66
|
+
const h = createHash("sha256")
|
|
67
|
+
.update(field(experimentId) + field(sessionId), "utf8")
|
|
68
|
+
.digest();
|
|
69
|
+
return h.readUInt32BE(0) % EXPERIMENT_BUCKETS;
|
|
70
|
+
}
|
|
71
|
+
/** Validate that a split covers the bucket space exactly once. */
|
|
72
|
+
export function validateSplit(split) {
|
|
73
|
+
for (const n of [split.A, split.B, split.C]) {
|
|
74
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return split.A + split.B + split.C === EXPERIMENT_BUCKETS;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Map a bucket to an arm under a split. Arms occupy contiguous bucket ranges in
|
|
81
|
+
* the fixed order A, B, C, so the mapping is stable: widening arm C's share can
|
|
82
|
+
* never reshuffle a session already sitting in arm A.
|
|
83
|
+
*/
|
|
84
|
+
export function armForBucket(bucket, split) {
|
|
85
|
+
if (bucket < split.A)
|
|
86
|
+
return "A";
|
|
87
|
+
if (bucket < split.A + split.B)
|
|
88
|
+
return "B";
|
|
89
|
+
return "C";
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Assign a session to an experiment arm.
|
|
93
|
+
*
|
|
94
|
+
* The default path is `randomized`: bucket = stable hash, arm = bucket's range.
|
|
95
|
+
* Passing `forced` overrides the arm and downgrades the source (and therefore
|
|
96
|
+
* causal admissibility) — the bucket is still computed and reported so the
|
|
97
|
+
* override remains auditable against what the session WOULD have got.
|
|
98
|
+
*
|
|
99
|
+
* `assignedAt` is injected by the caller. Assignment is a pure function of its
|
|
100
|
+
* arguments, so the same session always yields the same arm no matter when, or
|
|
101
|
+
* how many times, it is asked.
|
|
102
|
+
*/
|
|
103
|
+
export function assignExperiment(input) {
|
|
104
|
+
const codes = [];
|
|
105
|
+
if (input.experimentId.trim() === "" || input.sessionId.trim() === "") {
|
|
106
|
+
codes.push("EXP_ID_INVALID");
|
|
107
|
+
}
|
|
108
|
+
const split = input.split ?? EVEN_SPLIT;
|
|
109
|
+
if (!validateSplit(split))
|
|
110
|
+
codes.push("EXP_SPLIT_INVALID");
|
|
111
|
+
if (input.forced !== undefined && !EXPERIMENT_ARMS.includes(input.forced)) {
|
|
112
|
+
codes.push("EXP_ARM_UNKNOWN");
|
|
113
|
+
}
|
|
114
|
+
if (codes.length > 0)
|
|
115
|
+
return { ok: false, codes };
|
|
116
|
+
const bucket = experimentBucket(input.experimentId, input.sessionId);
|
|
117
|
+
const natural = armForBucket(bucket, split);
|
|
118
|
+
const arm = input.forced ?? natural;
|
|
119
|
+
// Precedence: a forced arm is self-selected, so it is never causal even when
|
|
120
|
+
// it happens to agree with the natural arm. Shadow is likewise non-causal.
|
|
121
|
+
const source = input.forced !== undefined ? "forced" : input.shadow === true ? "shadow" : "randomized";
|
|
122
|
+
return {
|
|
123
|
+
ok: true,
|
|
124
|
+
assignment: {
|
|
125
|
+
schema: "cache-experiment-v1",
|
|
126
|
+
experimentId: input.experimentId,
|
|
127
|
+
sessionId: input.sessionId,
|
|
128
|
+
arm,
|
|
129
|
+
bucket,
|
|
130
|
+
source,
|
|
131
|
+
assignedAt: input.assignedAt,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Whether an assignment's telemetry may enter a causal interval.
|
|
137
|
+
*
|
|
138
|
+
* ONLY `randomized`. This single predicate is what keeps forced and shadow rows
|
|
139
|
+
* out of the causal aggregate; every consumer computing an interval must filter
|
|
140
|
+
* through it rather than re-deriving the rule.
|
|
141
|
+
*/
|
|
142
|
+
export function isCausallyAdmissible(a) {
|
|
143
|
+
return a.source === "randomized";
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Keep only causally admissible assignments. The complement is not discarded by
|
|
147
|
+
* the caller — it is reported as `estimate` — but it never reaches an interval.
|
|
148
|
+
*/
|
|
149
|
+
export function causalOnly(assignments) {
|
|
150
|
+
return assignments.filter(isCausallyAdmissible);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Whether every assignment for one session agrees on the arm (CACHE-RANDOM-003).
|
|
154
|
+
* A session that appears in two arms would contaminate both sides of the
|
|
155
|
+
* comparison, so this is asserted directly rather than assumed.
|
|
156
|
+
*/
|
|
157
|
+
export function sessionArmsConsistent(assignments) {
|
|
158
|
+
const bySession = new Map();
|
|
159
|
+
for (const a of assignments) {
|
|
160
|
+
const seen = bySession.get(a.sessionId);
|
|
161
|
+
if (seen !== undefined && seen !== a.arm)
|
|
162
|
+
return false;
|
|
163
|
+
bySession.set(a.sessionId, a.arm);
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
166
|
+
}
|
package/extensions/dashboard-client/dist/assets/{AreaChart-CB-U7ViX.js → AreaChart-CV8WqMmt.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{b as R,c as W,m as T,i as C,d as F,A as ie,e as B,h as q,j as oe,k as G,l as se,n as le,u as ue,o as K,G as ce,p as J,q as Q,D as fe,g as pe,X as he,Y as de,f as me}from"./generateCategoricalChart-B-IUoLd1.js";import{R as p,F as ee,r as ve}from"./index-Do749WlW.js";var ye=["layout","type","stroke","connectNulls","isRange","ref"],be=["key"],te;function M(e){"@babel/helpers - typeof";return M=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},M(e)}function ae(e,t){if(e==null)return{};var r=Ae(e,t),a,n;if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],!(t.indexOf(a)>=0)&&Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}function Ae(e,t){if(e==null)return{};var r={};for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a)){if(t.indexOf(a)>=0)continue;r[a]=e[a]}return r}function D(){return D=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(e[a]=r[a])}return e},D.apply(this,arguments)}function U(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter(function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable})),r.push.apply(r,a)}return r}function S(e){for(var t=1;t<arguments.length;t++){var r=arguments[t]!=null?arguments[t]:{};t%2?U(Object(r),!0).forEach(function(a){E(e,a,r[a])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):U(Object(r)).forEach(function(a){Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(r,a))})}return e}function ge(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Z(e,t){for(var r=0;r<t.length;r++){var a=t[r];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,ne(a.key),a)}}function xe(e,t,r){return t&&Z(e.prototype,t),r&&Z(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}function Pe(e,t,r){return t=$(t),Oe(e,re()?Reflect.construct(t,r||[],$(e).constructor):t.apply(e,r))}function Oe(e,t){if(t&&(M(t)==="object"||typeof t=="function"))return t;if(t!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return Ee(e)}function Ee(e){if(e===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function re(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(re=function(){return!!e})()}function $(e){return $=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(r){return r.__proto__||Object.getPrototypeOf(r)},$(e)}function we(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),Object.defineProperty(e,"prototype",{writable:!1}),t&&X(e,t)}function X(e,t){return X=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(a,n){return a.__proto__=n,a},X(e,t)}function E(e,t,r){return t=ne(t),t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ne(e){var t=_e(e,"string");return M(t)=="symbol"?t:t+""}function _e(e,t){if(M(e)!="object"||!e)return e;var r=e[Symbol.toPrimitive];if(r!==void 0){var a=r.call(e,t);if(M(a)!="object")return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}var L=function(e){function t(){var r;ge(this,t);for(var a=arguments.length,n=new Array(a),i=0;i<a;i++)n[i]=arguments[i];return r=Pe(this,t,[].concat(n)),E(r,"state",{isAnimationFinished:!0}),E(r,"id",ue("recharts-area-")),E(r,"handleAnimationEnd",function(){var o=r.props.onAnimationEnd;r.setState({isAnimationFinished:!0}),K(o)&&o()}),E(r,"handleAnimationStart",function(){var o=r.props.onAnimationStart;r.setState({isAnimationFinished:!1}),K(o)&&o()}),r}return we(t,e),xe(t,[{key:"renderDots",value:function(a,n,i){var o=this.props.isAnimationActive,s=this.state.isAnimationFinished;if(o&&!s)return null;var u=this.props,l=u.dot,f=u.points,c=u.dataKey,h=R(this.props,!1),A=R(l,!0),g=f.map(function(v,O){var y=S(S(S({key:"dot-".concat(O),r:3},h),A),{},{index:O,cx:v.x,cy:v.y,dataKey:c,value:v.value,payload:v.payload,points:f});return t.renderDotItem(l,y)}),x={clipPath:a?"url(#clipPath-".concat(n?"":"dots-").concat(i,")"):null};return p.createElement(W,D({className:"recharts-area-dots"},x),g)}},{key:"renderHorizontalRect",value:function(a){var n=this.props,i=n.baseLine,o=n.points,s=n.strokeWidth,u=o[0].x,l=o[o.length-1].x,f=a*Math.abs(u-l),c=T(o.map(function(h){return h.y||0}));return C(i)&&typeof i=="number"?c=Math.max(i,c):i&&Array.isArray(i)&&i.length&&(c=Math.max(T(i.map(function(h){return h.y||0})),c)),C(c)?p.createElement("rect",{x:u<l?u:u-f,y:0,width:f,height:Math.floor(c+(s?parseInt("".concat(s),10):1))}):null}},{key:"renderVerticalRect",value:function(a){var n=this.props,i=n.baseLine,o=n.points,s=n.strokeWidth,u=o[0].y,l=o[o.length-1].y,f=a*Math.abs(u-l),c=T(o.map(function(h){return h.x||0}));return C(i)&&typeof i=="number"?c=Math.max(i,c):i&&Array.isArray(i)&&i.length&&(c=Math.max(T(i.map(function(h){return h.x||0})),c)),C(c)?p.createElement("rect",{x:0,y:u<l?u:u-f,width:c+(s?parseInt("".concat(s),10):1),height:Math.floor(f)}):null}},{key:"renderClipRect",value:function(a){var n=this.props.layout;return n==="vertical"?this.renderVerticalRect(a):this.renderHorizontalRect(a)}},{key:"renderAreaStatically",value:function(a,n,i,o){var s=this.props,u=s.layout,l=s.type,f=s.stroke,c=s.connectNulls,h=s.isRange;s.ref;var A=ae(s,ye);return p.createElement(W,{clipPath:i?"url(#clipPath-".concat(o,")"):null},p.createElement(F,D({},R(A,!0),{points:a,connectNulls:c,type:l,baseLine:n,layout:u,stroke:"none",className:"recharts-area-area"})),f!=="none"&&p.createElement(F,D({},R(this.props,!1),{className:"recharts-area-curve",layout:u,type:l,connectNulls:c,fill:"none",points:a})),f!=="none"&&h&&p.createElement(F,D({},R(this.props,!1),{className:"recharts-area-curve",layout:u,type:l,connectNulls:c,fill:"none",points:n})))}},{key:"renderAreaWithAnimation",value:function(a,n){var i=this,o=this.props,s=o.points,u=o.baseLine,l=o.isAnimationActive,f=o.animationBegin,c=o.animationDuration,h=o.animationEasing,A=o.animationId,g=this.state,x=g.prevPoints,v=g.prevBaseLine;return p.createElement(ie,{begin:f,duration:c,isActive:l,easing:h,from:{t:0},to:{t:1},key:"area-".concat(A),onAnimationEnd:this.handleAnimationEnd,onAnimationStart:this.handleAnimationStart},function(O){var y=O.t;if(x){var _=x.length/s.length,d=s.map(function(P,N){var k=Math.floor(N*_);if(x[k]){var j=x[k],I=B(j.x,P.x),V=B(j.y,P.y);return S(S({},P),{},{x:I(y),y:V(y)})}return P}),m;if(C(u)&&typeof u=="number"){var b=B(v,u);m=b(y)}else if(q(u)||oe(u)){var w=B(v,0);m=w(y)}else m=u.map(function(P,N){var k=Math.floor(N*_);if(v[k]){var j=v[k],I=B(j.x,P.x),V=B(j.y,P.y);return S(S({},P),{},{x:I(y),y:V(y)})}return P});return i.renderAreaStatically(d,m,a,n)}return p.createElement(W,null,p.createElement("defs",null,p.createElement("clipPath",{id:"animationClipPath-".concat(n)},i.renderClipRect(y))),p.createElement(W,{clipPath:"url(#animationClipPath-".concat(n,")")},i.renderAreaStatically(s,u,a,n)))})}},{key:"renderArea",value:function(a,n){var i=this.props,o=i.points,s=i.baseLine,u=i.isAnimationActive,l=this.state,f=l.prevPoints,c=l.prevBaseLine,h=l.totalLength;return u&&o&&o.length&&(!f&&h>0||!G(f,o)||!G(c,s))?this.renderAreaWithAnimation(a,n):this.renderAreaStatically(o,s,a,n)}},{key:"render",value:function(){var a,n=this.props,i=n.hide,o=n.dot,s=n.points,u=n.className,l=n.top,f=n.left,c=n.xAxis,h=n.yAxis,A=n.width,g=n.height,x=n.isAnimationActive,v=n.id;if(i||!s||!s.length)return null;var O=this.state.isAnimationFinished,y=s.length===1,_=ee("recharts-area",u),d=c&&c.allowDataOverflow,m=h&&h.allowDataOverflow,b=d||m,w=q(v)?this.id:v,P=(a=R(o,!1))!==null&&a!==void 0?a:{r:3,strokeWidth:2},N=P.r,k=N===void 0?3:N,j=P.strokeWidth,I=j===void 0?2:j,V=se(o)?o:{},Y=V.clipDot,H=Y===void 0?!0:Y,z=k*2+I;return p.createElement(W,{className:_},d||m?p.createElement("defs",null,p.createElement("clipPath",{id:"clipPath-".concat(w)},p.createElement("rect",{x:d?f:f-A/2,y:m?l:l-g/2,width:d?A:A*2,height:m?g:g*2})),!H&&p.createElement("clipPath",{id:"clipPath-dots-".concat(w)},p.createElement("rect",{x:f-z/2,y:l-z/2,width:A+z,height:g+z}))):null,y?null:this.renderArea(b,w),(o||y)&&this.renderDots(b,H,w),(!x||O)&&le.renderCallByParent(this.props,s))}}],[{key:"getDerivedStateFromProps",value:function(a,n){return a.animationId!==n.prevAnimationId?{prevAnimationId:a.animationId,curPoints:a.points,curBaseLine:a.baseLine,prevPoints:n.curPoints,prevBaseLine:n.curBaseLine}:a.points!==n.curPoints||a.baseLine!==n.curBaseLine?{curPoints:a.points,curBaseLine:a.baseLine}:null}}])}(ve.PureComponent);te=L;E(L,"displayName","Area");E(L,"defaultProps",{stroke:"#3182bd",fill:"#3182bd",fillOpacity:.6,xAxisId:0,yAxisId:0,legendType:"line",connectNulls:!1,points:[],dot:!1,activeDot:!0,hide:!1,isAnimationActive:!ce.isSsr,animationBegin:0,animationDuration:1500,animationEasing:"ease"});E(L,"getBaseValue",function(e,t,r,a){var n=e.layout,i=e.baseValue,o=t.props.baseValue,s=o??i;if(C(s)&&typeof s=="number")return s;var u=n==="horizontal"?a:r,l=u.scale.domain();if(u.type==="number"){var f=Math.max(l[0],l[1]),c=Math.min(l[0],l[1]);return s==="dataMin"?c:s==="dataMax"||f<0?f:Math.max(Math.min(l[0],l[1]),0)}return s==="dataMin"?l[0]:s==="dataMax"?l[1]:l[0]});E(L,"getComposedData",function(e){var t=e.props,r=e.item,a=e.xAxis,n=e.yAxis,i=e.xAxisTicks,o=e.yAxisTicks,s=e.bandSize,u=e.dataKey,l=e.stackedData,f=e.dataStartIndex,c=e.displayedData,h=e.offset,A=t.layout,g=l&&l.length,x=te.getBaseValue(t,r,a,n),v=A==="horizontal",O=!1,y=c.map(function(d,m){var b;g?b=l[f+m]:(b=J(d,u),Array.isArray(b)?O=!0:b=[x,b]);var w=b[1]==null||g&&J(d,u)==null;return v?{x:Q({axis:a,ticks:i,bandSize:s,entry:d,index:m}),y:w?null:n.scale(b[1]),value:b,payload:d}:{x:w?null:a.scale(b[1]),y:Q({axis:n,ticks:o,bandSize:s,entry:d,index:m}),value:b,payload:d}}),_;return g||O?_=y.map(function(d){var m=Array.isArray(d.value)?d.value[0]:null;return v?{x:d.x,y:m!=null&&d.y!=null?n.scale(m):null}:{x:m!=null?a.scale(m):null,y:d.y}}):_=v?n.scale(x):a.scale(x),S({points:y,baseLine:_,layout:A,isRange:O},h)});E(L,"renderDotItem",function(e,t){var r;if(p.isValidElement(e))r=p.cloneElement(e,t);else if(K(e))r=e(t);else{var a=ee("recharts-area-dot",typeof e!="boolean"?e.className:""),n=t.key,i=ae(t,be);r=p.createElement(fe,D({},i,{key:n,className:a}))}return r});var ke=pe({chartName:"AreaChart",GraphicalChild:L,axisComponents:[{axisType:"xAxis",AxisComp:he},{axisType:"yAxis",AxisComp:de}],formatAxisMap:me});export{ke as A,L as a};
|
|
2
|
-
//# sourceMappingURL=AreaChart-
|
|
1
|
+
import{b as R,c as W,m as T,i as C,d as F,A as ie,e as B,h as q,j as oe,k as G,l as se,n as le,u as ue,o as K,G as ce,p as J,q as Q,D as fe,g as pe,X as he,Y as de,f as me}from"./generateCategoricalChart-CMmkuwj5.js";import{R as p,F as ee,r as ve}from"./index-Dz8GPBOE.js";var ye=["layout","type","stroke","connectNulls","isRange","ref"],be=["key"],te;function M(e){"@babel/helpers - typeof";return M=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},M(e)}function ae(e,t){if(e==null)return{};var r=Ae(e,t),a,n;if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],!(t.indexOf(a)>=0)&&Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}function Ae(e,t){if(e==null)return{};var r={};for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a)){if(t.indexOf(a)>=0)continue;r[a]=e[a]}return r}function D(){return D=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(e[a]=r[a])}return e},D.apply(this,arguments)}function U(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter(function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable})),r.push.apply(r,a)}return r}function S(e){for(var t=1;t<arguments.length;t++){var r=arguments[t]!=null?arguments[t]:{};t%2?U(Object(r),!0).forEach(function(a){E(e,a,r[a])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):U(Object(r)).forEach(function(a){Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(r,a))})}return e}function ge(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Z(e,t){for(var r=0;r<t.length;r++){var a=t[r];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,ne(a.key),a)}}function xe(e,t,r){return t&&Z(e.prototype,t),r&&Z(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}function Pe(e,t,r){return t=$(t),Oe(e,re()?Reflect.construct(t,r||[],$(e).constructor):t.apply(e,r))}function Oe(e,t){if(t&&(M(t)==="object"||typeof t=="function"))return t;if(t!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return Ee(e)}function Ee(e){if(e===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function re(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(re=function(){return!!e})()}function $(e){return $=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(r){return r.__proto__||Object.getPrototypeOf(r)},$(e)}function we(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),Object.defineProperty(e,"prototype",{writable:!1}),t&&X(e,t)}function X(e,t){return X=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(a,n){return a.__proto__=n,a},X(e,t)}function E(e,t,r){return t=ne(t),t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ne(e){var t=_e(e,"string");return M(t)=="symbol"?t:t+""}function _e(e,t){if(M(e)!="object"||!e)return e;var r=e[Symbol.toPrimitive];if(r!==void 0){var a=r.call(e,t);if(M(a)!="object")return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}var L=function(e){function t(){var r;ge(this,t);for(var a=arguments.length,n=new Array(a),i=0;i<a;i++)n[i]=arguments[i];return r=Pe(this,t,[].concat(n)),E(r,"state",{isAnimationFinished:!0}),E(r,"id",ue("recharts-area-")),E(r,"handleAnimationEnd",function(){var o=r.props.onAnimationEnd;r.setState({isAnimationFinished:!0}),K(o)&&o()}),E(r,"handleAnimationStart",function(){var o=r.props.onAnimationStart;r.setState({isAnimationFinished:!1}),K(o)&&o()}),r}return we(t,e),xe(t,[{key:"renderDots",value:function(a,n,i){var o=this.props.isAnimationActive,s=this.state.isAnimationFinished;if(o&&!s)return null;var u=this.props,l=u.dot,f=u.points,c=u.dataKey,h=R(this.props,!1),A=R(l,!0),g=f.map(function(v,O){var y=S(S(S({key:"dot-".concat(O),r:3},h),A),{},{index:O,cx:v.x,cy:v.y,dataKey:c,value:v.value,payload:v.payload,points:f});return t.renderDotItem(l,y)}),x={clipPath:a?"url(#clipPath-".concat(n?"":"dots-").concat(i,")"):null};return p.createElement(W,D({className:"recharts-area-dots"},x),g)}},{key:"renderHorizontalRect",value:function(a){var n=this.props,i=n.baseLine,o=n.points,s=n.strokeWidth,u=o[0].x,l=o[o.length-1].x,f=a*Math.abs(u-l),c=T(o.map(function(h){return h.y||0}));return C(i)&&typeof i=="number"?c=Math.max(i,c):i&&Array.isArray(i)&&i.length&&(c=Math.max(T(i.map(function(h){return h.y||0})),c)),C(c)?p.createElement("rect",{x:u<l?u:u-f,y:0,width:f,height:Math.floor(c+(s?parseInt("".concat(s),10):1))}):null}},{key:"renderVerticalRect",value:function(a){var n=this.props,i=n.baseLine,o=n.points,s=n.strokeWidth,u=o[0].y,l=o[o.length-1].y,f=a*Math.abs(u-l),c=T(o.map(function(h){return h.x||0}));return C(i)&&typeof i=="number"?c=Math.max(i,c):i&&Array.isArray(i)&&i.length&&(c=Math.max(T(i.map(function(h){return h.x||0})),c)),C(c)?p.createElement("rect",{x:0,y:u<l?u:u-f,width:c+(s?parseInt("".concat(s),10):1),height:Math.floor(f)}):null}},{key:"renderClipRect",value:function(a){var n=this.props.layout;return n==="vertical"?this.renderVerticalRect(a):this.renderHorizontalRect(a)}},{key:"renderAreaStatically",value:function(a,n,i,o){var s=this.props,u=s.layout,l=s.type,f=s.stroke,c=s.connectNulls,h=s.isRange;s.ref;var A=ae(s,ye);return p.createElement(W,{clipPath:i?"url(#clipPath-".concat(o,")"):null},p.createElement(F,D({},R(A,!0),{points:a,connectNulls:c,type:l,baseLine:n,layout:u,stroke:"none",className:"recharts-area-area"})),f!=="none"&&p.createElement(F,D({},R(this.props,!1),{className:"recharts-area-curve",layout:u,type:l,connectNulls:c,fill:"none",points:a})),f!=="none"&&h&&p.createElement(F,D({},R(this.props,!1),{className:"recharts-area-curve",layout:u,type:l,connectNulls:c,fill:"none",points:n})))}},{key:"renderAreaWithAnimation",value:function(a,n){var i=this,o=this.props,s=o.points,u=o.baseLine,l=o.isAnimationActive,f=o.animationBegin,c=o.animationDuration,h=o.animationEasing,A=o.animationId,g=this.state,x=g.prevPoints,v=g.prevBaseLine;return p.createElement(ie,{begin:f,duration:c,isActive:l,easing:h,from:{t:0},to:{t:1},key:"area-".concat(A),onAnimationEnd:this.handleAnimationEnd,onAnimationStart:this.handleAnimationStart},function(O){var y=O.t;if(x){var _=x.length/s.length,d=s.map(function(P,N){var k=Math.floor(N*_);if(x[k]){var j=x[k],I=B(j.x,P.x),V=B(j.y,P.y);return S(S({},P),{},{x:I(y),y:V(y)})}return P}),m;if(C(u)&&typeof u=="number"){var b=B(v,u);m=b(y)}else if(q(u)||oe(u)){var w=B(v,0);m=w(y)}else m=u.map(function(P,N){var k=Math.floor(N*_);if(v[k]){var j=v[k],I=B(j.x,P.x),V=B(j.y,P.y);return S(S({},P),{},{x:I(y),y:V(y)})}return P});return i.renderAreaStatically(d,m,a,n)}return p.createElement(W,null,p.createElement("defs",null,p.createElement("clipPath",{id:"animationClipPath-".concat(n)},i.renderClipRect(y))),p.createElement(W,{clipPath:"url(#animationClipPath-".concat(n,")")},i.renderAreaStatically(s,u,a,n)))})}},{key:"renderArea",value:function(a,n){var i=this.props,o=i.points,s=i.baseLine,u=i.isAnimationActive,l=this.state,f=l.prevPoints,c=l.prevBaseLine,h=l.totalLength;return u&&o&&o.length&&(!f&&h>0||!G(f,o)||!G(c,s))?this.renderAreaWithAnimation(a,n):this.renderAreaStatically(o,s,a,n)}},{key:"render",value:function(){var a,n=this.props,i=n.hide,o=n.dot,s=n.points,u=n.className,l=n.top,f=n.left,c=n.xAxis,h=n.yAxis,A=n.width,g=n.height,x=n.isAnimationActive,v=n.id;if(i||!s||!s.length)return null;var O=this.state.isAnimationFinished,y=s.length===1,_=ee("recharts-area",u),d=c&&c.allowDataOverflow,m=h&&h.allowDataOverflow,b=d||m,w=q(v)?this.id:v,P=(a=R(o,!1))!==null&&a!==void 0?a:{r:3,strokeWidth:2},N=P.r,k=N===void 0?3:N,j=P.strokeWidth,I=j===void 0?2:j,V=se(o)?o:{},Y=V.clipDot,H=Y===void 0?!0:Y,z=k*2+I;return p.createElement(W,{className:_},d||m?p.createElement("defs",null,p.createElement("clipPath",{id:"clipPath-".concat(w)},p.createElement("rect",{x:d?f:f-A/2,y:m?l:l-g/2,width:d?A:A*2,height:m?g:g*2})),!H&&p.createElement("clipPath",{id:"clipPath-dots-".concat(w)},p.createElement("rect",{x:f-z/2,y:l-z/2,width:A+z,height:g+z}))):null,y?null:this.renderArea(b,w),(o||y)&&this.renderDots(b,H,w),(!x||O)&&le.renderCallByParent(this.props,s))}}],[{key:"getDerivedStateFromProps",value:function(a,n){return a.animationId!==n.prevAnimationId?{prevAnimationId:a.animationId,curPoints:a.points,curBaseLine:a.baseLine,prevPoints:n.curPoints,prevBaseLine:n.curBaseLine}:a.points!==n.curPoints||a.baseLine!==n.curBaseLine?{curPoints:a.points,curBaseLine:a.baseLine}:null}}])}(ve.PureComponent);te=L;E(L,"displayName","Area");E(L,"defaultProps",{stroke:"#3182bd",fill:"#3182bd",fillOpacity:.6,xAxisId:0,yAxisId:0,legendType:"line",connectNulls:!1,points:[],dot:!1,activeDot:!0,hide:!1,isAnimationActive:!ce.isSsr,animationBegin:0,animationDuration:1500,animationEasing:"ease"});E(L,"getBaseValue",function(e,t,r,a){var n=e.layout,i=e.baseValue,o=t.props.baseValue,s=o??i;if(C(s)&&typeof s=="number")return s;var u=n==="horizontal"?a:r,l=u.scale.domain();if(u.type==="number"){var f=Math.max(l[0],l[1]),c=Math.min(l[0],l[1]);return s==="dataMin"?c:s==="dataMax"||f<0?f:Math.max(Math.min(l[0],l[1]),0)}return s==="dataMin"?l[0]:s==="dataMax"?l[1]:l[0]});E(L,"getComposedData",function(e){var t=e.props,r=e.item,a=e.xAxis,n=e.yAxis,i=e.xAxisTicks,o=e.yAxisTicks,s=e.bandSize,u=e.dataKey,l=e.stackedData,f=e.dataStartIndex,c=e.displayedData,h=e.offset,A=t.layout,g=l&&l.length,x=te.getBaseValue(t,r,a,n),v=A==="horizontal",O=!1,y=c.map(function(d,m){var b;g?b=l[f+m]:(b=J(d,u),Array.isArray(b)?O=!0:b=[x,b]);var w=b[1]==null||g&&J(d,u)==null;return v?{x:Q({axis:a,ticks:i,bandSize:s,entry:d,index:m}),y:w?null:n.scale(b[1]),value:b,payload:d}:{x:w?null:a.scale(b[1]),y:Q({axis:n,ticks:o,bandSize:s,entry:d,index:m}),value:b,payload:d}}),_;return g||O?_=y.map(function(d){var m=Array.isArray(d.value)?d.value[0]:null;return v?{x:d.x,y:m!=null&&d.y!=null?n.scale(m):null}:{x:m!=null?a.scale(m):null,y:d.y}}):_=v?n.scale(x):a.scale(x),S({points:y,baseLine:_,layout:A,isRange:O},h)});E(L,"renderDotItem",function(e,t){var r;if(p.isValidElement(e))r=p.cloneElement(e,t);else if(K(e))r=e(t);else{var a=ee("recharts-area-dot",typeof e!="boolean"?e.className:""),n=t.key,i=ae(t,be);r=p.createElement(fe,D({},i,{key:n,className:a}))}return r});var ke=pe({chartName:"AreaChart",GraphicalChild:L,axisComponents:[{axisType:"xAxis",AxisComp:he},{axisType:"yAxis",AxisComp:de}],formatAxisMap:me});export{ke as A,L as a};
|
|
2
|
+
//# sourceMappingURL=AreaChart-CV8WqMmt.js.map
|