@vorionsys/atsf-core 0.2.4 → 0.3.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/CHANGELOG.md +1 -0
- package/LICENSE +1 -1
- package/README.md +82 -29
- package/dist/adapters/base-adapter.d.ts +94 -0
- package/dist/adapters/base-adapter.d.ts.map +1 -0
- package/dist/adapters/base-adapter.js +233 -0
- package/dist/adapters/base-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +9 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +5 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/types.d.ts +83 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +4 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/webhook-handler.d.ts +64 -0
- package/dist/adapters/webhook-handler.d.ts.map +1 -0
- package/dist/adapters/webhook-handler.js +170 -0
- package/dist/adapters/webhook-handler.js.map +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +2 -0
- package/dist/api/server.js.map +1 -1
- package/dist/arbitration/index.d.ts +0 -8
- package/dist/arbitration/index.d.ts.map +1 -1
- package/dist/arbitration/index.js +2 -0
- package/dist/arbitration/index.js.map +1 -1
- package/dist/arbitration/types.d.ts.map +1 -1
- package/dist/arbitration/types.js +2 -8
- package/dist/arbitration/types.js.map +1 -1
- package/dist/basis/evaluator.d.ts +0 -5
- package/dist/basis/evaluator.d.ts.map +1 -1
- package/dist/basis/evaluator.js +2 -0
- package/dist/basis/evaluator.js.map +1 -1
- package/dist/basis/index.d.ts.map +1 -1
- package/dist/basis/index.js +2 -0
- package/dist/basis/index.js.map +1 -1
- package/dist/basis/parser.d.ts +28 -28
- package/dist/basis/parser.d.ts.map +1 -1
- package/dist/basis/parser.js +2 -0
- package/dist/basis/parser.js.map +1 -1
- package/dist/basis/types.d.ts.map +1 -1
- package/dist/basis/types.js +2 -3
- package/dist/basis/types.js.map +1 -1
- package/dist/chain/index.d.ts +0 -8
- package/dist/chain/index.d.ts.map +1 -1
- package/dist/chain/index.js +2 -0
- package/dist/chain/index.js.map +1 -1
- package/dist/cognigate/index.d.ts +0 -8
- package/dist/cognigate/index.d.ts.map +1 -1
- package/dist/cognigate/index.js +2 -0
- package/dist/cognigate/index.js.map +1 -1
- package/dist/common/adapters.d.ts.map +1 -1
- package/dist/common/adapters.js +2 -8
- package/dist/common/adapters.js.map +1 -1
- package/dist/common/config.d.ts.map +1 -1
- package/dist/common/config.js +2 -0
- package/dist/common/config.js.map +1 -1
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +2 -0
- package/dist/common/index.js.map +1 -1
- package/dist/common/logger.d.ts.map +1 -1
- package/dist/common/logger.js +2 -0
- package/dist/common/logger.js.map +1 -1
- package/dist/common/types.d.ts +7 -7
- package/dist/common/types.d.ts.map +1 -1
- package/dist/common/types.js +2 -9
- package/dist/common/types.js.map +1 -1
- package/dist/containment/index.d.ts +0 -8
- package/dist/containment/index.d.ts.map +1 -1
- package/dist/containment/index.js +2 -0
- package/dist/containment/index.js.map +1 -1
- package/dist/containment/types.d.ts.map +1 -1
- package/dist/containment/types.js +2 -8
- package/dist/containment/types.js.map +1 -1
- package/dist/contracts/index.d.ts +0 -8
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +2 -0
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/contracts/types.js +2 -8
- package/dist/contracts/types.js.map +1 -1
- package/dist/crewai/callback.d.ts +0 -7
- package/dist/crewai/callback.d.ts.map +1 -1
- package/dist/crewai/callback.js +2 -0
- package/dist/crewai/callback.js.map +1 -1
- package/dist/crewai/executor.d.ts +0 -7
- package/dist/crewai/executor.d.ts.map +1 -1
- package/dist/crewai/executor.js +2 -0
- package/dist/crewai/executor.js.map +1 -1
- package/dist/crewai/index.d.ts.map +1 -1
- package/dist/crewai/index.js +2 -0
- package/dist/crewai/index.js.map +1 -1
- package/dist/crewai/tools.d.ts.map +1 -1
- package/dist/crewai/tools.js +2 -7
- package/dist/crewai/tools.js.map +1 -1
- package/dist/crewai/types.d.ts.map +1 -1
- package/dist/crewai/types.js +2 -7
- package/dist/crewai/types.js.map +1 -1
- package/dist/enforce/index.d.ts +0 -15
- package/dist/enforce/index.d.ts.map +1 -1
- package/dist/enforce/index.js +3 -1
- package/dist/enforce/index.js.map +1 -1
- package/dist/enforce/trust-aware-enforcement-service.d.ts +0 -15
- package/dist/enforce/trust-aware-enforcement-service.d.ts.map +1 -1
- package/dist/enforce/trust-aware-enforcement-service.js +2 -0
- package/dist/enforce/trust-aware-enforcement-service.js.map +1 -1
- package/dist/governance/fluid-workflow.d.ts +0 -8
- package/dist/governance/fluid-workflow.d.ts.map +1 -1
- package/dist/governance/fluid-workflow.js +2 -0
- package/dist/governance/fluid-workflow.js.map +1 -1
- package/dist/governance/index.d.ts +0 -8
- package/dist/governance/index.d.ts.map +1 -1
- package/dist/governance/index.js +2 -0
- package/dist/governance/index.js.map +1 -1
- package/dist/governance/proof-bridge.d.ts.map +1 -1
- package/dist/governance/proof-bridge.js +2 -12
- package/dist/governance/proof-bridge.js.map +1 -1
- package/dist/governance/types.d.ts.map +1 -1
- package/dist/governance/types.js +2 -8
- package/dist/governance/types.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/intent/index.d.ts +0 -13
- package/dist/intent/index.d.ts.map +1 -1
- package/dist/intent/index.js +4 -2
- package/dist/intent/index.js.map +1 -1
- package/dist/intent/persistent-intent-service.d.ts +0 -15
- package/dist/intent/persistent-intent-service.d.ts.map +1 -1
- package/dist/intent/persistent-intent-service.js +2 -0
- package/dist/intent/persistent-intent-service.js.map +1 -1
- package/dist/intent/supabase-intent-repository.d.ts +0 -17
- package/dist/intent/supabase-intent-repository.d.ts.map +1 -1
- package/dist/intent/supabase-intent-repository.js +2 -0
- package/dist/intent/supabase-intent-repository.js.map +1 -1
- package/dist/intent-gateway/index.d.ts +499 -0
- package/dist/intent-gateway/index.d.ts.map +1 -0
- package/dist/intent-gateway/index.js +1332 -0
- package/dist/intent-gateway/index.js.map +1 -0
- package/dist/langchain/callback.d.ts +0 -7
- package/dist/langchain/callback.d.ts.map +1 -1
- package/dist/langchain/callback.js +2 -0
- package/dist/langchain/callback.js.map +1 -1
- package/dist/langchain/executor.d.ts +0 -7
- package/dist/langchain/executor.d.ts.map +1 -1
- package/dist/langchain/executor.js +2 -0
- package/dist/langchain/executor.js.map +1 -1
- package/dist/langchain/index.d.ts.map +1 -1
- package/dist/langchain/index.js +2 -0
- package/dist/langchain/index.js.map +1 -1
- package/dist/langchain/tools.d.ts.map +1 -1
- package/dist/langchain/tools.js +2 -7
- package/dist/langchain/tools.js.map +1 -1
- package/dist/langchain/types.d.ts.map +1 -1
- package/dist/langchain/types.js +2 -7
- package/dist/langchain/types.js.map +1 -1
- package/dist/layers/implementations/L0-request-format.d.ts.map +1 -1
- package/dist/layers/implementations/L0-request-format.js +2 -0
- package/dist/layers/implementations/L0-request-format.js.map +1 -1
- package/dist/layers/implementations/L1-input-size.d.ts.map +1 -1
- package/dist/layers/implementations/L1-input-size.js +2 -0
- package/dist/layers/implementations/L1-input-size.js.map +1 -1
- package/dist/layers/implementations/L2-charset-sanitizer.d.ts.map +1 -1
- package/dist/layers/implementations/L2-charset-sanitizer.js +2 -0
- package/dist/layers/implementations/L2-charset-sanitizer.js.map +1 -1
- package/dist/layers/implementations/L3-schema-conformance.d.ts.map +1 -1
- package/dist/layers/implementations/L3-schema-conformance.js +2 -0
- package/dist/layers/implementations/L3-schema-conformance.js.map +1 -1
- package/dist/layers/implementations/L4-injection-detector.d.ts.map +1 -1
- package/dist/layers/implementations/L4-injection-detector.js +2 -0
- package/dist/layers/implementations/L4-injection-detector.js.map +1 -1
- package/dist/layers/implementations/L5-rate-limiter.d.ts.map +1 -1
- package/dist/layers/implementations/L5-rate-limiter.js +2 -0
- package/dist/layers/implementations/L5-rate-limiter.js.map +1 -1
- package/dist/layers/implementations/index.d.ts.map +1 -1
- package/dist/layers/implementations/index.js +2 -0
- package/dist/layers/implementations/index.js.map +1 -1
- package/dist/layers/index.d.ts +0 -8
- package/dist/layers/index.d.ts.map +1 -1
- package/dist/layers/index.js +2 -0
- package/dist/layers/index.js.map +1 -1
- package/dist/layers/types.d.ts.map +1 -1
- package/dist/layers/types.js +2 -8
- package/dist/layers/types.js.map +1 -1
- package/dist/paramesphere/activation-collector.d.ts +128 -0
- package/dist/paramesphere/activation-collector.d.ts.map +1 -0
- package/dist/paramesphere/activation-collector.js +260 -0
- package/dist/paramesphere/activation-collector.js.map +1 -0
- package/dist/paramesphere/cognitive-envelope.d.ts +73 -0
- package/dist/paramesphere/cognitive-envelope.d.ts.map +1 -0
- package/dist/paramesphere/cognitive-envelope.js +209 -0
- package/dist/paramesphere/cognitive-envelope.js.map +1 -0
- package/dist/paramesphere/envelope-integration.d.ts +60 -0
- package/dist/paramesphere/envelope-integration.d.ts.map +1 -0
- package/dist/paramesphere/envelope-integration.js +93 -0
- package/dist/paramesphere/envelope-integration.js.map +1 -0
- package/dist/paramesphere/fingerprint-monitor.d.ts +136 -0
- package/dist/paramesphere/fingerprint-monitor.d.ts.map +1 -0
- package/dist/paramesphere/fingerprint-monitor.js +212 -0
- package/dist/paramesphere/fingerprint-monitor.js.map +1 -0
- package/dist/paramesphere/fingerprint-store.d.ts +85 -0
- package/dist/paramesphere/fingerprint-store.d.ts.map +1 -0
- package/dist/paramesphere/fingerprint-store.js +68 -0
- package/dist/paramesphere/fingerprint-store.js.map +1 -0
- package/dist/paramesphere/index.d.ts +21 -0
- package/dist/paramesphere/index.d.ts.map +1 -0
- package/dist/paramesphere/index.js +18 -0
- package/dist/paramesphere/index.js.map +1 -0
- package/dist/paramesphere/monitor-integration.d.ts +37 -0
- package/dist/paramesphere/monitor-integration.d.ts.map +1 -0
- package/dist/paramesphere/monitor-integration.js +81 -0
- package/dist/paramesphere/monitor-integration.js.map +1 -0
- package/dist/paramesphere/paramesphere-engine.d.ts +111 -0
- package/dist/paramesphere/paramesphere-engine.d.ts.map +1 -0
- package/dist/paramesphere/paramesphere-engine.js +542 -0
- package/dist/paramesphere/paramesphere-engine.js.map +1 -0
- package/dist/paramesphere/types.d.ts +142 -0
- package/dist/paramesphere/types.d.ts.map +1 -0
- package/dist/paramesphere/types.js +4 -0
- package/dist/paramesphere/types.js.map +1 -0
- package/dist/persistence/file.d.ts +0 -7
- package/dist/persistence/file.d.ts.map +1 -1
- package/dist/persistence/file.js +2 -0
- package/dist/persistence/file.js.map +1 -1
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +2 -0
- package/dist/persistence/index.js.map +1 -1
- package/dist/persistence/memory.d.ts.map +1 -1
- package/dist/persistence/memory.js +2 -7
- package/dist/persistence/memory.js.map +1 -1
- package/dist/persistence/sqlite.d.ts +0 -8
- package/dist/persistence/sqlite.d.ts.map +1 -1
- package/dist/persistence/sqlite.js +3 -1
- package/dist/persistence/sqlite.js.map +1 -1
- package/dist/persistence/supabase.d.ts.map +1 -1
- package/dist/persistence/supabase.js +3 -8
- package/dist/persistence/supabase.js.map +1 -1
- package/dist/persistence/types.d.ts.map +1 -1
- package/dist/persistence/types.js +2 -7
- package/dist/persistence/types.js.map +1 -1
- package/dist/phase6/ceiling.d.ts +0 -16
- package/dist/phase6/ceiling.d.ts.map +1 -1
- package/dist/phase6/ceiling.js +2 -0
- package/dist/phase6/ceiling.js.map +1 -1
- package/dist/phase6/context.d.ts +0 -17
- package/dist/phase6/context.d.ts.map +1 -1
- package/dist/phase6/context.js +2 -0
- package/dist/phase6/context.js.map +1 -1
- package/dist/phase6/index.d.ts.map +1 -1
- package/dist/phase6/index.js +2 -0
- package/dist/phase6/index.js.map +1 -1
- package/dist/phase6/presets.d.ts +0 -16
- package/dist/phase6/presets.d.ts.map +1 -1
- package/dist/phase6/presets.js +5 -3
- package/dist/phase6/presets.js.map +1 -1
- package/dist/phase6/provenance.d.ts +0 -15
- package/dist/phase6/provenance.d.ts.map +1 -1
- package/dist/phase6/provenance.js +2 -0
- package/dist/phase6/provenance.js.map +1 -1
- package/dist/phase6/role-gates/index.d.ts.map +1 -1
- package/dist/phase6/role-gates/index.js +2 -0
- package/dist/phase6/role-gates/index.js.map +1 -1
- package/dist/phase6/role-gates/kernel.d.ts.map +1 -1
- package/dist/phase6/role-gates/kernel.js +2 -0
- package/dist/phase6/role-gates/kernel.js.map +1 -1
- package/dist/phase6/role-gates/policy.d.ts.map +1 -1
- package/dist/phase6/role-gates/policy.js +2 -11
- package/dist/phase6/role-gates/policy.js.map +1 -1
- package/dist/phase6/role-gates.d.ts +0 -16
- package/dist/phase6/role-gates.d.ts.map +1 -1
- package/dist/phase6/role-gates.js +2 -0
- package/dist/phase6/role-gates.js.map +1 -1
- package/dist/phase6/types.d.ts +45 -16
- package/dist/phase6/types.d.ts.map +1 -1
- package/dist/phase6/types.js +49 -0
- package/dist/phase6/types.js.map +1 -1
- package/dist/phase6/weight-presets/canonical.d.ts.map +1 -1
- package/dist/phase6/weight-presets/canonical.js +2 -0
- package/dist/phase6/weight-presets/canonical.js.map +1 -1
- package/dist/phase6/weight-presets/deltas.d.ts.map +1 -1
- package/dist/phase6/weight-presets/deltas.js +2 -10
- package/dist/phase6/weight-presets/deltas.js.map +1 -1
- package/dist/phase6/weight-presets/index.d.ts.map +1 -1
- package/dist/phase6/weight-presets/index.js +2 -0
- package/dist/phase6/weight-presets/index.js.map +1 -1
- package/dist/phase6/weight-presets/merger.d.ts +0 -10
- package/dist/phase6/weight-presets/merger.d.ts.map +1 -1
- package/dist/phase6/weight-presets/merger.js +2 -0
- package/dist/phase6/weight-presets/merger.js.map +1 -1
- package/dist/proof/index.d.ts +3 -10
- package/dist/proof/index.d.ts.map +1 -1
- package/dist/proof/index.js +27 -9
- package/dist/proof/index.js.map +1 -1
- package/dist/proof/merkle.d.ts +0 -16
- package/dist/proof/merkle.d.ts.map +1 -1
- package/dist/proof/merkle.js +2 -0
- package/dist/proof/merkle.js.map +1 -1
- package/dist/proof/zk-proofs.d.ts +0 -18
- package/dist/proof/zk-proofs.d.ts.map +1 -1
- package/dist/proof/zk-proofs.js +2 -0
- package/dist/proof/zk-proofs.js.map +1 -1
- package/dist/provenance/index.d.ts +0 -8
- package/dist/provenance/index.d.ts.map +1 -1
- package/dist/provenance/index.js +2 -0
- package/dist/provenance/index.js.map +1 -1
- package/dist/provenance/types.d.ts.map +1 -1
- package/dist/provenance/types.js +2 -8
- package/dist/provenance/types.js.map +1 -1
- package/dist/sandbox-training/challenges.d.ts.map +1 -1
- package/dist/sandbox-training/challenges.js +2 -8
- package/dist/sandbox-training/challenges.js.map +1 -1
- package/dist/sandbox-training/graduation.d.ts.map +1 -1
- package/dist/sandbox-training/graduation.js +2 -8
- package/dist/sandbox-training/graduation.js.map +1 -1
- package/dist/sandbox-training/index.d.ts.map +1 -1
- package/dist/sandbox-training/index.js +2 -0
- package/dist/sandbox-training/index.js.map +1 -1
- package/dist/sandbox-training/promotion-service.d.ts.map +1 -1
- package/dist/sandbox-training/promotion-service.js +2 -11
- package/dist/sandbox-training/promotion-service.js.map +1 -1
- package/dist/sandbox-training/runner.d.ts.map +1 -1
- package/dist/sandbox-training/runner.js +2 -8
- package/dist/sandbox-training/runner.js.map +1 -1
- package/dist/sandbox-training/scorer.d.ts.map +1 -1
- package/dist/sandbox-training/scorer.js +2 -8
- package/dist/sandbox-training/scorer.js.map +1 -1
- package/dist/sandbox-training/types.d.ts.map +1 -1
- package/dist/sandbox-training/types.js +2 -8
- package/dist/sandbox-training/types.js.map +1 -1
- package/dist/trust-engine/ceiling-enforcement/audit.d.ts +0 -8
- package/dist/trust-engine/ceiling-enforcement/audit.d.ts.map +1 -1
- package/dist/trust-engine/ceiling-enforcement/audit.js +2 -8
- package/dist/trust-engine/ceiling-enforcement/audit.js.map +1 -1
- package/dist/trust-engine/ceiling-enforcement/index.d.ts.map +1 -1
- package/dist/trust-engine/ceiling-enforcement/index.js +2 -0
- package/dist/trust-engine/ceiling-enforcement/index.js.map +1 -1
- package/dist/trust-engine/ceiling-enforcement/kernel.d.ts.map +1 -1
- package/dist/trust-engine/ceiling-enforcement/kernel.js +2 -0
- package/dist/trust-engine/ceiling-enforcement/kernel.js.map +1 -1
- package/dist/trust-engine/context-policy/enforcement.d.ts +0 -9
- package/dist/trust-engine/context-policy/enforcement.d.ts.map +1 -1
- package/dist/trust-engine/context-policy/enforcement.js +2 -9
- package/dist/trust-engine/context-policy/enforcement.js.map +1 -1
- package/dist/trust-engine/context-policy/factory.d.ts.map +1 -1
- package/dist/trust-engine/context-policy/factory.js +2 -0
- package/dist/trust-engine/context-policy/factory.js.map +1 -1
- package/dist/trust-engine/context-policy/index.d.ts.map +1 -1
- package/dist/trust-engine/context-policy/index.js +2 -0
- package/dist/trust-engine/context-policy/index.js.map +1 -1
- package/dist/trust-engine/creation-modifiers/index.d.ts.map +1 -1
- package/dist/trust-engine/creation-modifiers/index.js +2 -0
- package/dist/trust-engine/creation-modifiers/index.js.map +1 -1
- package/dist/trust-engine/creation-modifiers/types.d.ts.map +1 -1
- package/dist/trust-engine/creation-modifiers/types.js +2 -0
- package/dist/trust-engine/creation-modifiers/types.js.map +1 -1
- package/dist/trust-engine/decay-profiles.d.ts.map +1 -1
- package/dist/trust-engine/decay-profiles.js +2 -14
- package/dist/trust-engine/decay-profiles.js.map +1 -1
- package/dist/trust-engine/index.d.ts +418 -80
- package/dist/trust-engine/index.d.ts.map +1 -1
- package/dist/trust-engine/index.js +1048 -186
- package/dist/trust-engine/index.js.map +1 -1
- package/dist/trust-engine/phase6-types.d.ts +3 -13
- package/dist/trust-engine/phase6-types.d.ts.map +1 -1
- package/dist/trust-engine/phase6-types.js +5 -13
- package/dist/trust-engine/phase6-types.js.map +1 -1
- package/dist/trust-engine/trust-verifier.d.ts +121 -0
- package/dist/trust-engine/trust-verifier.d.ts.map +1 -0
- package/dist/trust-engine/trust-verifier.js +226 -0
- package/dist/trust-engine/trust-verifier.js.map +1 -0
- package/package.json +140 -135
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { ParameSphereConfig, ParameSphereFingerprint, ActivationStats, FingerprintComparison, DriftResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compute the top-K singular values of a matrix using the deflated
|
|
4
|
+
* power-iteration method.
|
|
5
|
+
*
|
|
6
|
+
* Given an m × n matrix A (stored row-major in a flat Float64Array),
|
|
7
|
+
* this iteratively finds the largest singular value via the power method
|
|
8
|
+
* on A^T A, then deflates the matrix and repeats for the next largest.
|
|
9
|
+
*
|
|
10
|
+
* @param data Row-major flat array of the matrix.
|
|
11
|
+
* @param rows Number of rows (m).
|
|
12
|
+
* @param cols Number of columns (n).
|
|
13
|
+
* @param k Number of singular values to extract.
|
|
14
|
+
* @returns Float64Array of length min(k, min(m,n)) with the top
|
|
15
|
+
* singular values in descending order.
|
|
16
|
+
*/
|
|
17
|
+
declare function topKSingularValues(data: Float64Array, rows: number, cols: number, k: number): Float64Array;
|
|
18
|
+
declare function cosineSimilarity(a: Float64Array, b: Float64Array): number;
|
|
19
|
+
declare function l2Distance(a: Float64Array, b: Float64Array): number;
|
|
20
|
+
/**
|
|
21
|
+
* Select which layer indices to sample.
|
|
22
|
+
*
|
|
23
|
+
* Uses a deterministic spread strategy: always include first and last layer,
|
|
24
|
+
* then fill in evenly-spaced layers up to the target count.
|
|
25
|
+
*/
|
|
26
|
+
declare function selectLayers(totalLayers: number, ratio: number): number[];
|
|
27
|
+
export declare class ParameSphereEngine {
|
|
28
|
+
private readonly config;
|
|
29
|
+
private baseline;
|
|
30
|
+
private cache;
|
|
31
|
+
/** Cached singular values from the last computation, keyed by layer index. */
|
|
32
|
+
private prevSingularValues;
|
|
33
|
+
/** Optional persistent store for fingerprints and baselines. */
|
|
34
|
+
private readonly store;
|
|
35
|
+
/** Entity ID for store operations. */
|
|
36
|
+
private readonly entityId;
|
|
37
|
+
constructor(config?: Partial<ParameSphereConfig>);
|
|
38
|
+
/**
|
|
39
|
+
* Compute a full fingerprint from scratch.
|
|
40
|
+
*
|
|
41
|
+
* @param weights Array of weight matrices, one per layer.
|
|
42
|
+
* Each Float32Array is treated as a flat row-major
|
|
43
|
+
* matrix. The engine infers rows/cols by assuming a
|
|
44
|
+
* roughly square shape (sqrt heuristic) unless the
|
|
45
|
+
* layer is clearly rectangular.
|
|
46
|
+
* @param activationStats Optional per-layer activation statistics.
|
|
47
|
+
*/
|
|
48
|
+
computeFingerprint(weights: Float32Array[], activationStats?: ActivationStats[]): ParameSphereFingerprint;
|
|
49
|
+
/**
|
|
50
|
+
* Incremental fingerprint update.
|
|
51
|
+
*
|
|
52
|
+
* Re-uses cached singular values where the delta is negligible, only
|
|
53
|
+
* recomputing layers whose weights have changed significantly.
|
|
54
|
+
*/
|
|
55
|
+
updateFingerprint(newWeights: Float32Array[], activationStats?: ActivationStats[]): ParameSphereFingerprint;
|
|
56
|
+
/**
|
|
57
|
+
* Compare two fingerprints.
|
|
58
|
+
*/
|
|
59
|
+
compareFingerprints(a: ParameSphereFingerprint, b: ParameSphereFingerprint): FingerprintComparison;
|
|
60
|
+
/**
|
|
61
|
+
* Store a fingerprint as the drift-detection baseline.
|
|
62
|
+
*
|
|
63
|
+
* When a persistent store is configured, the baseline is also saved
|
|
64
|
+
* to the store so it survives process restarts.
|
|
65
|
+
*/
|
|
66
|
+
setBaseline(fingerprint: ParameSphereFingerprint): void;
|
|
67
|
+
/**
|
|
68
|
+
* Check drift of a current fingerprint against the stored baseline.
|
|
69
|
+
*
|
|
70
|
+
* When a persistent store is configured and no in-memory baseline exists,
|
|
71
|
+
* the engine attempts to load the baseline from the store before comparing.
|
|
72
|
+
* Use the async overload `checkDriftAsync` if your store backend is truly
|
|
73
|
+
* async; this synchronous version will throw if neither in-memory nor store
|
|
74
|
+
* baseline is available.
|
|
75
|
+
*/
|
|
76
|
+
checkDrift(current: ParameSphereFingerprint): DriftResult;
|
|
77
|
+
/**
|
|
78
|
+
* Async drift check that loads baseline from store if needed.
|
|
79
|
+
*
|
|
80
|
+
* Preferred when using a persistent store: on the first call after a
|
|
81
|
+
* restart, this method transparently restores the baseline from the
|
|
82
|
+
* store so drift detection resumes seamlessly.
|
|
83
|
+
*/
|
|
84
|
+
checkDriftAsync(current: ParameSphereFingerprint): Promise<DriftResult>;
|
|
85
|
+
/**
|
|
86
|
+
* Clear the incremental cache and baseline.
|
|
87
|
+
*/
|
|
88
|
+
clearCache(): void;
|
|
89
|
+
/** Get the current cache of recent fingerprints. */
|
|
90
|
+
getCache(): readonly ParameSphereFingerprint[];
|
|
91
|
+
private buildFingerprint;
|
|
92
|
+
/** Pull activation stats into a flat Float64Array for the composite vector. */
|
|
93
|
+
private extractActivationVector;
|
|
94
|
+
private emptyFingerprint;
|
|
95
|
+
/** Convert a ParameSphereFingerprint to a StoredFingerprint for persistence. */
|
|
96
|
+
private toStoredFingerprint;
|
|
97
|
+
/** Reconstruct a ParameSphereFingerprint from a StoredFingerprint. */
|
|
98
|
+
private fromStoredFingerprint;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Infer a (rows, cols) shape from a flat array length.
|
|
102
|
+
*
|
|
103
|
+
* Heuristic: find the factor pair closest to sqrt that gives a valid
|
|
104
|
+
* factorisation. Falls back to (1, length) for primes / small arrays.
|
|
105
|
+
*/
|
|
106
|
+
declare function inferShape(length: number): {
|
|
107
|
+
rows: number;
|
|
108
|
+
cols: number;
|
|
109
|
+
};
|
|
110
|
+
export { topKSingularValues, selectLayers, inferShape, cosineSimilarity, l2Distance };
|
|
111
|
+
//# sourceMappingURL=paramesphere-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paramesphere-engine.d.ts","sourceRoot":"","sources":["../../src/paramesphere/paramesphere-engine.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,EACf,qBAAqB,EACrB,WAAW,EACZ,MAAM,YAAY,CAAC;AAuBpB;;;;;;;;;;;;;;GAcG;AACH,iBAAS,kBAAkB,CACzB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,GACR,YAAY,CAoDd;AAoED,iBAAS,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAYlE;AAED,iBAAS,UAAU,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAQ5D;AAMD;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBlE;AAMD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,KAAK,CAAiC;IAE9C,8EAA8E;IAC9E,OAAO,CAAC,kBAAkB,CAAwC;IAElE,gEAAgE;IAChE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,sCAAsC;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAElC,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAmBhD;;;;;;;;;OASG;IACH,kBAAkB,CAChB,OAAO,EAAE,YAAY,EAAE,EACvB,eAAe,CAAC,EAAE,eAAe,EAAE,GAClC,uBAAuB;IAoB1B;;;;;OAKG;IACH,iBAAiB,CACf,UAAU,EAAE,YAAY,EAAE,EAC1B,eAAe,CAAC,EAAE,eAAe,EAAE,GAClC,uBAAuB;IAsC1B;;OAEG;IACH,mBAAmB,CACjB,CAAC,EAAE,uBAAuB,EAC1B,CAAC,EAAE,uBAAuB,GACzB,qBAAqB;IAsBxB;;;;;OAKG;IACH,WAAW,CAAC,WAAW,EAAE,uBAAuB,GAAG,IAAI;IAWvD;;;;;;;;OAQG;IACH,UAAU,CAAC,OAAO,EAAE,uBAAuB,GAAG,WAAW;IAazD;;;;;;OAMG;IACG,eAAe,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC;IAU7E;;OAEG;IACH,UAAU,IAAI,IAAI;IAMlB,oDAAoD;IACpD,QAAQ,IAAI,SAAS,uBAAuB,EAAE;IAQ9C,OAAO,CAAC,gBAAgB;IA8CxB,+EAA+E;IAC/E,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,gBAAgB;IAkBxB,gFAAgF;IAChF,OAAO,CAAC,mBAAmB;IA6B3B,sEAAsE;IACtE,OAAO,CAAC,qBAAqB;CAc9B;AAwBD;;;;;GAKG;AACH,iBAAS,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAWlE;AAGD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2024-2026 Vorion LLC
|
|
3
|
+
/**
|
|
4
|
+
* ParameSphere SVD Fingerprinting Engine
|
|
5
|
+
*
|
|
6
|
+
* Production implementation of the SVD-based model fingerprinting system
|
|
7
|
+
* described in the Vorion patent specification. Uses power-iteration to
|
|
8
|
+
* extract the top-K singular values from sampled weight matrices, combines
|
|
9
|
+
* them with activation statistics, and produces a cryptographic hash of
|
|
10
|
+
* the composite fingerprint vector.
|
|
11
|
+
*
|
|
12
|
+
* Key design choices:
|
|
13
|
+
* - Power iteration for SVD: no external linear-algebra library needed.
|
|
14
|
+
* - Float64Array internally for precision; inputs accepted as Float32Array.
|
|
15
|
+
* - Incremental updates cache previous singular values and compute deltas.
|
|
16
|
+
* - Dual-hash option (SHA-256 + SHA3-256) for high-assurance use cases.
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
import * as nodeCrypto from 'node:crypto';
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Defaults
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const DEFAULT_CONFIG = {
|
|
25
|
+
K: 64,
|
|
26
|
+
layerSampleRatio: 0.15,
|
|
27
|
+
cacheSize: 5,
|
|
28
|
+
driftThreshold: 0.05,
|
|
29
|
+
dualHash: false,
|
|
30
|
+
};
|
|
31
|
+
// Power iteration parameters
|
|
32
|
+
const POWER_ITER_MAX = 300;
|
|
33
|
+
const POWER_ITER_TOL = 1e-10;
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Helpers — Linear Algebra via Power Iteration
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Compute the top-K singular values of a matrix using the deflated
|
|
39
|
+
* power-iteration method.
|
|
40
|
+
*
|
|
41
|
+
* Given an m × n matrix A (stored row-major in a flat Float64Array),
|
|
42
|
+
* this iteratively finds the largest singular value via the power method
|
|
43
|
+
* on A^T A, then deflates the matrix and repeats for the next largest.
|
|
44
|
+
*
|
|
45
|
+
* @param data Row-major flat array of the matrix.
|
|
46
|
+
* @param rows Number of rows (m).
|
|
47
|
+
* @param cols Number of columns (n).
|
|
48
|
+
* @param k Number of singular values to extract.
|
|
49
|
+
* @returns Float64Array of length min(k, min(m,n)) with the top
|
|
50
|
+
* singular values in descending order.
|
|
51
|
+
*/
|
|
52
|
+
function topKSingularValues(data, rows, cols, k) {
|
|
53
|
+
const rank = Math.min(rows, cols, k);
|
|
54
|
+
const sigmas = new Float64Array(rank);
|
|
55
|
+
// Work on a copy so deflation doesn't mutate the input.
|
|
56
|
+
const A = new Float64Array(data);
|
|
57
|
+
for (let s = 0; s < rank; s++) {
|
|
58
|
+
// --- power iteration on A^T A to find the dominant right singular vector ---
|
|
59
|
+
let v = new Float64Array(cols);
|
|
60
|
+
// Initialise v with a deterministic pseudo-random vector (seeded on s).
|
|
61
|
+
for (let j = 0; j < cols; j++) {
|
|
62
|
+
v[j] = Math.sin((s + 1) * (j + 1) * 0.7071);
|
|
63
|
+
}
|
|
64
|
+
normalizeVec(v);
|
|
65
|
+
let sigma = 0;
|
|
66
|
+
for (let iter = 0; iter < POWER_ITER_MAX; iter++) {
|
|
67
|
+
// u = A * v
|
|
68
|
+
const u = matVecMul(A, rows, cols, v);
|
|
69
|
+
sigma = vecNorm(u);
|
|
70
|
+
if (sigma < 1e-15)
|
|
71
|
+
break;
|
|
72
|
+
scaleVec(u, 1 / sigma);
|
|
73
|
+
// v_new = A^T * u
|
|
74
|
+
const vNew = matTransVecMul(A, rows, cols, u);
|
|
75
|
+
const sigmaNew = vecNorm(vNew);
|
|
76
|
+
if (sigmaNew < 1e-15)
|
|
77
|
+
break;
|
|
78
|
+
scaleVec(vNew, 1 / sigmaNew);
|
|
79
|
+
// Convergence check: |sigma - sigmaNew| / sigma
|
|
80
|
+
const diff = Math.abs(sigma - sigmaNew);
|
|
81
|
+
v = vNew;
|
|
82
|
+
sigma = sigmaNew;
|
|
83
|
+
if (diff < POWER_ITER_TOL * sigma)
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
sigmas[s] = sigma;
|
|
87
|
+
// Deflate: A <- A - sigma * u * v^T
|
|
88
|
+
const u = matVecMul(A, rows, cols, v);
|
|
89
|
+
const uNorm = vecNorm(u);
|
|
90
|
+
if (uNorm > 1e-15) {
|
|
91
|
+
scaleVec(u, 1 / uNorm);
|
|
92
|
+
for (let i = 0; i < rows; i++) {
|
|
93
|
+
for (let j = 0; j < cols; j++) {
|
|
94
|
+
A[i * cols + j] -= sigma * u[i] * v[j];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return sigmas;
|
|
100
|
+
}
|
|
101
|
+
/** Multiply matrix A (m×n, row-major) by vector v (length n). */
|
|
102
|
+
function matVecMul(A, m, n, v) {
|
|
103
|
+
const result = new Float64Array(m);
|
|
104
|
+
for (let i = 0; i < m; i++) {
|
|
105
|
+
let sum = 0;
|
|
106
|
+
const rowOff = i * n;
|
|
107
|
+
for (let j = 0; j < n; j++) {
|
|
108
|
+
sum += A[rowOff + j] * v[j];
|
|
109
|
+
}
|
|
110
|
+
result[i] = sum;
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
/** Multiply A^T (n×m) by vector u (length m). */
|
|
115
|
+
function matTransVecMul(A, m, n, u) {
|
|
116
|
+
const result = new Float64Array(n);
|
|
117
|
+
for (let j = 0; j < n; j++) {
|
|
118
|
+
let sum = 0;
|
|
119
|
+
for (let i = 0; i < m; i++) {
|
|
120
|
+
sum += A[i * n + j] * u[i];
|
|
121
|
+
}
|
|
122
|
+
result[j] = sum;
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
/** Euclidean norm of a vector. */
|
|
127
|
+
function vecNorm(v) {
|
|
128
|
+
let sum = 0;
|
|
129
|
+
for (let i = 0; i < v.length; i++)
|
|
130
|
+
sum += v[i] * v[i];
|
|
131
|
+
return Math.sqrt(sum);
|
|
132
|
+
}
|
|
133
|
+
/** In-place normalisation. */
|
|
134
|
+
function normalizeVec(v) {
|
|
135
|
+
const n = vecNorm(v);
|
|
136
|
+
if (n > 1e-15)
|
|
137
|
+
scaleVec(v, 1 / n);
|
|
138
|
+
}
|
|
139
|
+
/** In-place scalar multiply. */
|
|
140
|
+
function scaleVec(v, s) {
|
|
141
|
+
for (let i = 0; i < v.length; i++)
|
|
142
|
+
v[i] *= s;
|
|
143
|
+
}
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
// Helpers — Hashing
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
function sha256Hex(bytes) {
|
|
148
|
+
return nodeCrypto.createHash('sha256').update(bytes).digest('hex');
|
|
149
|
+
}
|
|
150
|
+
function sha3_256Hex(bytes) {
|
|
151
|
+
return nodeCrypto.createHash('sha3-256').update(bytes).digest('hex');
|
|
152
|
+
}
|
|
153
|
+
/** Convert a Float64Array to its raw byte representation. */
|
|
154
|
+
function float64ToBytes(arr) {
|
|
155
|
+
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
156
|
+
}
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// Helpers — Geometry
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
function cosineSimilarity(a, b) {
|
|
161
|
+
const len = Math.min(a.length, b.length);
|
|
162
|
+
let dot = 0;
|
|
163
|
+
let normA = 0;
|
|
164
|
+
let normB = 0;
|
|
165
|
+
for (let i = 0; i < len; i++) {
|
|
166
|
+
dot += a[i] * b[i];
|
|
167
|
+
normA += a[i] * a[i];
|
|
168
|
+
normB += b[i] * b[i];
|
|
169
|
+
}
|
|
170
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
171
|
+
return denom < 1e-15 ? 0 : dot / denom;
|
|
172
|
+
}
|
|
173
|
+
function l2Distance(a, b) {
|
|
174
|
+
const len = Math.min(a.length, b.length);
|
|
175
|
+
let sum = 0;
|
|
176
|
+
for (let i = 0; i < len; i++) {
|
|
177
|
+
const d = a[i] - b[i];
|
|
178
|
+
sum += d * d;
|
|
179
|
+
}
|
|
180
|
+
return Math.sqrt(sum);
|
|
181
|
+
}
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
// Layer Sampling
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
/**
|
|
186
|
+
* Select which layer indices to sample.
|
|
187
|
+
*
|
|
188
|
+
* Uses a deterministic spread strategy: always include first and last layer,
|
|
189
|
+
* then fill in evenly-spaced layers up to the target count.
|
|
190
|
+
*/
|
|
191
|
+
function selectLayers(totalLayers, ratio) {
|
|
192
|
+
if (totalLayers <= 0)
|
|
193
|
+
return [];
|
|
194
|
+
if (totalLayers === 1)
|
|
195
|
+
return [0];
|
|
196
|
+
const count = Math.max(2, Math.min(totalLayers, Math.ceil(totalLayers * ratio)));
|
|
197
|
+
if (count >= totalLayers) {
|
|
198
|
+
return Array.from({ length: totalLayers }, (_, i) => i);
|
|
199
|
+
}
|
|
200
|
+
const indices = new Set();
|
|
201
|
+
indices.add(0);
|
|
202
|
+
indices.add(totalLayers - 1);
|
|
203
|
+
const step = (totalLayers - 1) / (count - 1);
|
|
204
|
+
for (let i = 1; i < count - 1; i++) {
|
|
205
|
+
indices.add(Math.round(i * step));
|
|
206
|
+
}
|
|
207
|
+
return Array.from(indices).sort((a, b) => a - b);
|
|
208
|
+
}
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// ParameSphereEngine
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
export class ParameSphereEngine {
|
|
213
|
+
config;
|
|
214
|
+
baseline = null;
|
|
215
|
+
cache = [];
|
|
216
|
+
/** Cached singular values from the last computation, keyed by layer index. */
|
|
217
|
+
prevSingularValues = new Map();
|
|
218
|
+
/** Optional persistent store for fingerprints and baselines. */
|
|
219
|
+
store;
|
|
220
|
+
/** Entity ID for store operations. */
|
|
221
|
+
entityId;
|
|
222
|
+
constructor(config) {
|
|
223
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
224
|
+
if (this.config.layerSampleRatio <= 0 || this.config.layerSampleRatio > 1) {
|
|
225
|
+
throw new Error('layerSampleRatio must be in (0, 1]');
|
|
226
|
+
}
|
|
227
|
+
if (this.config.K < 1) {
|
|
228
|
+
throw new Error('K must be >= 1');
|
|
229
|
+
}
|
|
230
|
+
this.store = this.config.store;
|
|
231
|
+
this.entityId = this.config.entityId;
|
|
232
|
+
if (this.store && !this.entityId) {
|
|
233
|
+
throw new Error('entityId is required when a fingerprint store is provided');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// -----------------------------------------------------------------------
|
|
237
|
+
// Public API
|
|
238
|
+
// -----------------------------------------------------------------------
|
|
239
|
+
/**
|
|
240
|
+
* Compute a full fingerprint from scratch.
|
|
241
|
+
*
|
|
242
|
+
* @param weights Array of weight matrices, one per layer.
|
|
243
|
+
* Each Float32Array is treated as a flat row-major
|
|
244
|
+
* matrix. The engine infers rows/cols by assuming a
|
|
245
|
+
* roughly square shape (sqrt heuristic) unless the
|
|
246
|
+
* layer is clearly rectangular.
|
|
247
|
+
* @param activationStats Optional per-layer activation statistics.
|
|
248
|
+
*/
|
|
249
|
+
computeFingerprint(weights, activationStats) {
|
|
250
|
+
if (weights.length === 0) {
|
|
251
|
+
return this.emptyFingerprint(0);
|
|
252
|
+
}
|
|
253
|
+
const sampledLayers = selectLayers(weights.length, this.config.layerSampleRatio);
|
|
254
|
+
const allSigmas = [];
|
|
255
|
+
for (const idx of sampledLayers) {
|
|
256
|
+
const w = weights[idx];
|
|
257
|
+
const { rows, cols } = inferShape(w.length);
|
|
258
|
+
const data = float32ToFloat64(w);
|
|
259
|
+
const sigmas = topKSingularValues(data, rows, cols, this.config.K);
|
|
260
|
+
allSigmas.push(sigmas);
|
|
261
|
+
this.prevSingularValues.set(idx, new Float64Array(sigmas));
|
|
262
|
+
}
|
|
263
|
+
return this.buildFingerprint(allSigmas, sampledLayers, weights.length, activationStats);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Incremental fingerprint update.
|
|
267
|
+
*
|
|
268
|
+
* Re-uses cached singular values where the delta is negligible, only
|
|
269
|
+
* recomputing layers whose weights have changed significantly.
|
|
270
|
+
*/
|
|
271
|
+
updateFingerprint(newWeights, activationStats) {
|
|
272
|
+
if (newWeights.length === 0) {
|
|
273
|
+
return this.emptyFingerprint(0);
|
|
274
|
+
}
|
|
275
|
+
const sampledLayers = selectLayers(newWeights.length, this.config.layerSampleRatio);
|
|
276
|
+
const allSigmas = [];
|
|
277
|
+
for (const idx of sampledLayers) {
|
|
278
|
+
const w = newWeights[idx];
|
|
279
|
+
const { rows, cols } = inferShape(w.length);
|
|
280
|
+
const data = float32ToFloat64(w);
|
|
281
|
+
const sigmas = topKSingularValues(data, rows, cols, this.config.K);
|
|
282
|
+
// Compute delta from cached if available
|
|
283
|
+
const prev = this.prevSingularValues.get(idx);
|
|
284
|
+
if (prev && prev.length === sigmas.length) {
|
|
285
|
+
// Use incremental low-rank update: if delta is tiny, blend with prev
|
|
286
|
+
let maxDelta = 0;
|
|
287
|
+
for (let i = 0; i < sigmas.length; i++) {
|
|
288
|
+
const d = Math.abs(sigmas[i] - prev[i]);
|
|
289
|
+
if (d > maxDelta)
|
|
290
|
+
maxDelta = d;
|
|
291
|
+
}
|
|
292
|
+
// If max delta < 1% of largest singular value, use cached (saves downstream noise)
|
|
293
|
+
const largest = Math.max(sigmas[0] || 0, prev[0] || 0);
|
|
294
|
+
if (largest > 0 && maxDelta / largest < 0.01) {
|
|
295
|
+
allSigmas.push(prev);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
this.prevSingularValues.set(idx, new Float64Array(sigmas));
|
|
300
|
+
allSigmas.push(sigmas);
|
|
301
|
+
}
|
|
302
|
+
return this.buildFingerprint(allSigmas, sampledLayers, newWeights.length, activationStats);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Compare two fingerprints.
|
|
306
|
+
*/
|
|
307
|
+
compareFingerprints(a, b) {
|
|
308
|
+
const sim = cosineSimilarity(a.vector, b.vector);
|
|
309
|
+
const dist = 1 - sim;
|
|
310
|
+
const l2 = l2Distance(a.vector, b.vector);
|
|
311
|
+
// Max singular-value delta across sampled layers
|
|
312
|
+
let maxSVDelta = 0;
|
|
313
|
+
const len = Math.min(a.singularValues.length, b.singularValues.length);
|
|
314
|
+
for (let i = 0; i < len; i++) {
|
|
315
|
+
const d = Math.abs(a.singularValues[i] - b.singularValues[i]);
|
|
316
|
+
if (d > maxSVDelta)
|
|
317
|
+
maxSVDelta = d;
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
cosineSimilarity: sim,
|
|
321
|
+
cosineDistance: dist,
|
|
322
|
+
l2Distance: l2,
|
|
323
|
+
driftDetected: dist > this.config.driftThreshold,
|
|
324
|
+
maxSingularValueDelta: maxSVDelta,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Store a fingerprint as the drift-detection baseline.
|
|
329
|
+
*
|
|
330
|
+
* When a persistent store is configured, the baseline is also saved
|
|
331
|
+
* to the store so it survives process restarts.
|
|
332
|
+
*/
|
|
333
|
+
setBaseline(fingerprint) {
|
|
334
|
+
this.baseline = fingerprint;
|
|
335
|
+
if (this.store && this.entityId) {
|
|
336
|
+
const stored = this.toStoredFingerprint(fingerprint);
|
|
337
|
+
this.store.setBaseline(this.entityId, stored).catch(() => {
|
|
338
|
+
/* persistence is best-effort */
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Check drift of a current fingerprint against the stored baseline.
|
|
344
|
+
*
|
|
345
|
+
* When a persistent store is configured and no in-memory baseline exists,
|
|
346
|
+
* the engine attempts to load the baseline from the store before comparing.
|
|
347
|
+
* Use the async overload `checkDriftAsync` if your store backend is truly
|
|
348
|
+
* async; this synchronous version will throw if neither in-memory nor store
|
|
349
|
+
* baseline is available.
|
|
350
|
+
*/
|
|
351
|
+
checkDrift(current) {
|
|
352
|
+
if (!this.baseline) {
|
|
353
|
+
throw new Error('No baseline set — call setBaseline() first');
|
|
354
|
+
}
|
|
355
|
+
const comparison = this.compareFingerprints(this.baseline, current);
|
|
356
|
+
return {
|
|
357
|
+
drifted: comparison.driftDetected,
|
|
358
|
+
cosineDistance: comparison.cosineDistance,
|
|
359
|
+
maxSingularValueDelta: comparison.maxSingularValueDelta,
|
|
360
|
+
comparison,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Async drift check that loads baseline from store if needed.
|
|
365
|
+
*
|
|
366
|
+
* Preferred when using a persistent store: on the first call after a
|
|
367
|
+
* restart, this method transparently restores the baseline from the
|
|
368
|
+
* store so drift detection resumes seamlessly.
|
|
369
|
+
*/
|
|
370
|
+
async checkDriftAsync(current) {
|
|
371
|
+
if (!this.baseline && this.store && this.entityId) {
|
|
372
|
+
const stored = await this.store.getBaseline(this.entityId);
|
|
373
|
+
if (stored) {
|
|
374
|
+
this.baseline = this.fromStoredFingerprint(stored);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return this.checkDrift(current);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Clear the incremental cache and baseline.
|
|
381
|
+
*/
|
|
382
|
+
clearCache() {
|
|
383
|
+
this.prevSingularValues.clear();
|
|
384
|
+
this.cache = [];
|
|
385
|
+
this.baseline = null;
|
|
386
|
+
}
|
|
387
|
+
/** Get the current cache of recent fingerprints. */
|
|
388
|
+
getCache() {
|
|
389
|
+
return this.cache;
|
|
390
|
+
}
|
|
391
|
+
// -----------------------------------------------------------------------
|
|
392
|
+
// Internal
|
|
393
|
+
// -----------------------------------------------------------------------
|
|
394
|
+
buildFingerprint(allSigmas, sampledLayers, totalLayers, activationStats) {
|
|
395
|
+
// Flatten singular values
|
|
396
|
+
const flatSigmas = concatFloat64Arrays(allSigmas);
|
|
397
|
+
// Build composite vector: singular values ‖ activation stat values
|
|
398
|
+
const statValues = this.extractActivationVector(activationStats, sampledLayers);
|
|
399
|
+
const vector = concatFloat64Arrays([flatSigmas, statValues]);
|
|
400
|
+
// Cryptographic hash
|
|
401
|
+
const bytes = float64ToBytes(vector);
|
|
402
|
+
const sha256 = sha256Hex(bytes);
|
|
403
|
+
const sha3 = this.config.dualHash ? sha3_256Hex(bytes) : undefined;
|
|
404
|
+
const fp = {
|
|
405
|
+
vector,
|
|
406
|
+
sha256,
|
|
407
|
+
sha3_256: sha3,
|
|
408
|
+
sampledLayers,
|
|
409
|
+
singularValues: flatSigmas,
|
|
410
|
+
timestamp: new Date().toISOString(),
|
|
411
|
+
totalLayers,
|
|
412
|
+
};
|
|
413
|
+
// Cache management
|
|
414
|
+
this.cache.push(fp);
|
|
415
|
+
if (this.cache.length > this.config.cacheSize) {
|
|
416
|
+
this.cache.shift();
|
|
417
|
+
}
|
|
418
|
+
// Persist to store (fire-and-forget — errors are intentionally swallowed
|
|
419
|
+
// so the hot path is never blocked by a slow or failing backend).
|
|
420
|
+
if (this.store && this.entityId) {
|
|
421
|
+
const stored = this.toStoredFingerprint(fp, activationStats);
|
|
422
|
+
this.store.saveFingerprint(this.entityId, stored).catch(() => {
|
|
423
|
+
/* persistence is best-effort */
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
return fp;
|
|
427
|
+
}
|
|
428
|
+
/** Pull activation stats into a flat Float64Array for the composite vector. */
|
|
429
|
+
extractActivationVector(stats, sampledLayers) {
|
|
430
|
+
if (!stats || stats.length === 0)
|
|
431
|
+
return new Float64Array(0);
|
|
432
|
+
// Four values per sampled layer with stats
|
|
433
|
+
const values = [];
|
|
434
|
+
for (const idx of sampledLayers) {
|
|
435
|
+
if (idx < stats.length) {
|
|
436
|
+
const s = stats[idx];
|
|
437
|
+
values.push(s.mean, s.stddev, s.kurtosis, s.skewness);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return Float64Array.from(values);
|
|
441
|
+
}
|
|
442
|
+
emptyFingerprint(totalLayers) {
|
|
443
|
+
const vector = new Float64Array(0);
|
|
444
|
+
const bytes = float64ToBytes(vector);
|
|
445
|
+
return {
|
|
446
|
+
vector,
|
|
447
|
+
sha256: sha256Hex(bytes),
|
|
448
|
+
sha3_256: this.config.dualHash ? sha3_256Hex(bytes) : undefined,
|
|
449
|
+
sampledLayers: [],
|
|
450
|
+
singularValues: new Float64Array(0),
|
|
451
|
+
timestamp: new Date().toISOString(),
|
|
452
|
+
totalLayers,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
// -----------------------------------------------------------------------
|
|
456
|
+
// Store conversion helpers
|
|
457
|
+
// -----------------------------------------------------------------------
|
|
458
|
+
/** Convert a ParameSphereFingerprint to a StoredFingerprint for persistence. */
|
|
459
|
+
toStoredFingerprint(fp, activationStats) {
|
|
460
|
+
const stored = {
|
|
461
|
+
entityId: this.entityId,
|
|
462
|
+
hash: fp.sha256,
|
|
463
|
+
singularValues: Array.from(fp.singularValues),
|
|
464
|
+
createdAt: new Date(fp.timestamp),
|
|
465
|
+
metadata: {
|
|
466
|
+
sampledLayers: fp.sampledLayers,
|
|
467
|
+
totalLayers: fp.totalLayers,
|
|
468
|
+
sha3_256: fp.sha3_256,
|
|
469
|
+
vectorLength: fp.vector.length,
|
|
470
|
+
// Store the full vector as a plain array for reconstruction
|
|
471
|
+
vector: Array.from(fp.vector),
|
|
472
|
+
},
|
|
473
|
+
};
|
|
474
|
+
if (activationStats && activationStats.length > 0) {
|
|
475
|
+
stored.activationStats = activationStats.map((s) => ({
|
|
476
|
+
mean: s.mean,
|
|
477
|
+
stddev: s.stddev,
|
|
478
|
+
kurtosis: s.kurtosis,
|
|
479
|
+
skewness: s.skewness,
|
|
480
|
+
}));
|
|
481
|
+
}
|
|
482
|
+
return stored;
|
|
483
|
+
}
|
|
484
|
+
/** Reconstruct a ParameSphereFingerprint from a StoredFingerprint. */
|
|
485
|
+
fromStoredFingerprint(stored) {
|
|
486
|
+
const meta = (stored.metadata ?? {});
|
|
487
|
+
const vectorArr = meta.vector;
|
|
488
|
+
const vector = vectorArr ? Float64Array.from(vectorArr) : Float64Array.from(stored.singularValues);
|
|
489
|
+
return {
|
|
490
|
+
vector,
|
|
491
|
+
sha256: stored.hash,
|
|
492
|
+
sha3_256: meta.sha3_256,
|
|
493
|
+
sampledLayers: meta.sampledLayers ?? [],
|
|
494
|
+
singularValues: Float64Array.from(stored.singularValues),
|
|
495
|
+
timestamp: stored.createdAt.toISOString(),
|
|
496
|
+
totalLayers: meta.totalLayers ?? 0,
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
// ---------------------------------------------------------------------------
|
|
501
|
+
// Utility
|
|
502
|
+
// ---------------------------------------------------------------------------
|
|
503
|
+
function float32ToFloat64(src) {
|
|
504
|
+
const dst = new Float64Array(src.length);
|
|
505
|
+
for (let i = 0; i < src.length; i++)
|
|
506
|
+
dst[i] = src[i];
|
|
507
|
+
return dst;
|
|
508
|
+
}
|
|
509
|
+
function concatFloat64Arrays(arrays) {
|
|
510
|
+
let totalLen = 0;
|
|
511
|
+
for (const a of arrays)
|
|
512
|
+
totalLen += a.length;
|
|
513
|
+
const result = new Float64Array(totalLen);
|
|
514
|
+
let offset = 0;
|
|
515
|
+
for (const a of arrays) {
|
|
516
|
+
result.set(a, offset);
|
|
517
|
+
offset += a.length;
|
|
518
|
+
}
|
|
519
|
+
return result;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Infer a (rows, cols) shape from a flat array length.
|
|
523
|
+
*
|
|
524
|
+
* Heuristic: find the factor pair closest to sqrt that gives a valid
|
|
525
|
+
* factorisation. Falls back to (1, length) for primes / small arrays.
|
|
526
|
+
*/
|
|
527
|
+
function inferShape(length) {
|
|
528
|
+
if (length <= 0)
|
|
529
|
+
return { rows: 0, cols: 0 };
|
|
530
|
+
if (length === 1)
|
|
531
|
+
return { rows: 1, cols: 1 };
|
|
532
|
+
const sqrt = Math.floor(Math.sqrt(length));
|
|
533
|
+
for (let r = sqrt; r >= 1; r--) {
|
|
534
|
+
if (length % r === 0) {
|
|
535
|
+
return { rows: r, cols: length / r };
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return { rows: 1, cols: length };
|
|
539
|
+
}
|
|
540
|
+
// Export helpers for testing
|
|
541
|
+
export { topKSingularValues, selectLayers, inferShape, cosineSimilarity, l2Distance };
|
|
542
|
+
//# sourceMappingURL=paramesphere-engine.js.map
|