clients: snapshot

This commit is contained in:
nym21
2026-01-14 09:37:43 +01:00
parent 25a0ebe51e
commit 922a0abb60
11 changed files with 24404 additions and 3752 deletions
+41 -1
View File
@@ -123,6 +123,9 @@ pub struct PatternBaseResult {
/// Whether this instance uses suffix mode (common prefix) or prefix mode (common suffix).
/// Used to check compatibility with the pattern's mode.
pub is_suffix_mode: bool,
/// The field parts (suffix in suffix mode, prefix in prefix mode) for each field.
/// Used to check if instance field parts match the pattern's field parts.
pub field_parts: HashMap<String, String>,
}
/// Get the metric base for a pattern instance by analyzing direct children.
@@ -141,6 +144,7 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
base: String::new(),
has_outlier: false,
is_suffix_mode: true, // default
field_parts: HashMap::new(),
};
}
@@ -150,6 +154,7 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
base: result.base,
has_outlier: result.has_outlier,
is_suffix_mode: result.is_suffix_mode,
field_parts: result.field_parts,
};
}
@@ -168,6 +173,7 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
base: result.base,
has_outlier: true,
is_suffix_mode: result.is_suffix_mode,
field_parts: result.field_parts,
};
}
}
@@ -179,14 +185,16 @@ pub fn get_pattern_instance_base(node: &TreeNode) -> PatternBaseResult {
base: String::new(),
has_outlier: false,
is_suffix_mode: true, // default
field_parts: HashMap::new(),
}
}
/// Result of try_find_base: base name, has_outlier flag, and is_suffix_mode flag.
/// Result of try_find_base: base name, has_outlier flag, is_suffix_mode flag, and field_parts.
struct FindBaseResult {
base: String,
has_outlier: bool,
is_suffix_mode: bool,
field_parts: HashMap<String, String>,
}
/// Try to find a common base from child names using prefix/suffix detection.
@@ -197,20 +205,52 @@ fn try_find_base(child_names: &[(String, String)], is_outlier_attempt: bool) ->
// Try common prefix first (suffix mode)
if let Some(prefix) = find_common_prefix(&leaf_names) {
let base = prefix.trim_end_matches('_').to_string();
let mut field_parts = HashMap::new();
for (field_name, leaf_name) in child_names {
// Compute the suffix part for this field
let suffix = if leaf_name == &base {
String::new()
} else {
leaf_name
.strip_prefix(&prefix)
.unwrap_or(leaf_name)
.to_string()
};
field_parts.insert(field_name.clone(), suffix);
}
return Some(FindBaseResult {
base,
has_outlier: is_outlier_attempt,
is_suffix_mode: true,
field_parts,
});
}
// Try common suffix (prefix mode)
if let Some(suffix) = find_common_suffix(&leaf_names) {
let base = suffix.trim_start_matches('_').to_string();
let mut field_parts = HashMap::new();
for (field_name, leaf_name) in child_names {
// Compute the prefix part for this field
let prefix_part = leaf_name
.strip_suffix(&suffix)
.map(|s| {
if s.is_empty() {
String::new()
} else if s.ends_with('_') {
s.to_string()
} else {
format!("{}_", s)
}
})
.unwrap_or_default();
field_parts.insert(field_name.clone(), prefix_part);
}
return Some(FindBaseResult {
base,
has_outlier: is_outlier_attempt,
is_suffix_mode: false,
field_parts,
});
}
+19 -9
View File
@@ -55,17 +55,20 @@ pub fn prepare_tree_node<'a>(
.map(|(f, _)| f.clone())
.collect();
// Skip if this matches a parameterizable pattern AND has no outlier AND mode matches
// Skip if this matches a parameterizable pattern AND has no outlier AND field parts match
let base_result = get_pattern_instance_base(node);
let mode_matches = pattern_lookup
let pattern_fully_matches = pattern_lookup
.get(&fields)
.and_then(|name| metadata.find_pattern(name))
.is_none_or(|p| p.is_suffix_mode() == base_result.is_suffix_mode);
.is_some_and(|p| {
p.is_suffix_mode() == base_result.is_suffix_mode
&& p.field_parts_match(&base_result.field_parts)
});
if let Some(pattern_name) = pattern_lookup.get(&fields)
&& pattern_name != name
&& metadata.is_parameterizable(pattern_name)
&& !base_result.has_outlier
&& mode_matches
&& pattern_fully_matches
{
return None;
}
@@ -89,16 +92,23 @@ pub fn prepare_tree_node<'a>(
.as_ref()
.is_some_and(|cf| metadata.matches_pattern(cf));
// Check if the pattern mode matches the instance mode
let mode_matches = child_fields
// Check if the pattern mode AND field parts match the instance
let pattern_fully_matches = child_fields
.as_ref()
.and_then(|cf| metadata.find_pattern_by_fields(cf))
.is_none_or(|p| p.is_suffix_mode() == base_result.is_suffix_mode);
.is_some_and(|p| {
// Mode must match (suffix vs prefix)
if p.is_suffix_mode() != base_result.is_suffix_mode {
return false;
}
// Field parts must also match
p.field_parts_match(&base_result.field_parts)
});
// should_inline determines if we generate an inline struct type
// We inline if: it's a branch AND (doesn't match any pattern OR mode doesn't match OR has outlier)
// We inline if: it's a branch AND (doesn't match any pattern OR pattern doesn't fully match OR has outlier)
let should_inline =
!is_leaf && (!matches_any_pattern || !mode_matches || base_result.has_outlier);
!is_leaf && (!matches_any_pattern || !pattern_fully_matches || base_result.has_outlier);
// Inline type name (only used when should_inline is true)
let inline_type_name = if should_inline {
+25 -1
View File
@@ -1,6 +1,6 @@
//! Structural pattern and field types.
use std::collections::BTreeSet;
use std::collections::{BTreeSet, HashMap};
use brk_types::Index;
@@ -47,6 +47,30 @@ impl StructuralPattern {
pub fn is_suffix_mode(&self) -> bool {
matches!(&self.mode, Some(PatternMode::Suffix { .. }))
}
/// Check if the given instance field parts match this pattern's field parts.
/// Returns true if all field parts in the pattern match the instance's field parts.
pub fn field_parts_match(&self, instance_field_parts: &HashMap<String, String>) -> bool {
match &self.mode {
Some(PatternMode::Suffix { relatives }) => {
// For each field in the pattern, check if the instance has the same suffix
relatives.iter().all(|(field_name, pattern_suffix)| {
instance_field_parts
.get(field_name)
.is_some_and(|instance_suffix| instance_suffix == pattern_suffix)
})
}
Some(PatternMode::Prefix { prefixes }) => {
// For each field in the pattern, check if the instance has the same prefix
prefixes.iter().all(|(field_name, pattern_prefix)| {
instance_field_parts
.get(field_name)
.is_some_and(|instance_prefix| instance_prefix == pattern_prefix)
})
}
None => false, // Non-parameterizable patterns don't use field parts
}
}
}
/// A field in a structural pattern.
+7975 -2334
View File
File diff suppressed because it is too large Load Diff
+8772 -870
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -379,11 +379,11 @@ export function createChartElement({
if (metric) {
signals.createEffect(index, (index) => {
// Get timestamp metric from tree based on index type
// timestampFixed has height only, timestamp has date-based indexes
// timestampMonotonic has height only, timestamp has date-based indexes
/** @type {AnyMetricPattern} */
const timeMetric =
index === "height"
? brk.metrics.blocks.time.timestampFixed
? brk.metrics.blocks.time.timestampMonotonic
: brk.metrics.blocks.time.timestamp;
/** @type {AnyMetricPattern} */
const valuesMetric = metric;
@@ -379,34 +379,34 @@ export function createCostBasisPercentilesSeries(ctx, list, useGroupName) {
const percentiles = tree.costBasis.percentiles;
return [
line({
metric: percentiles.costBasisPct10,
metric: percentiles.pct10,
name: useGroupName ? `${name} p10` : "p10",
color,
unit: Unit.usd,
defaultActive: false,
}),
line({
metric: percentiles.costBasisPct25,
metric: percentiles.pct25,
name: useGroupName ? `${name} p25` : "p25",
color,
unit: Unit.usd,
defaultActive: false,
}),
line({
metric: percentiles.costBasisPct50,
metric: percentiles.pct50,
name: useGroupName ? `${name} p50` : "p50",
color,
unit: Unit.usd,
}),
line({
metric: percentiles.costBasisPct75,
metric: percentiles.pct75,
name: useGroupName ? `${name} p75` : "p75",
color,
unit: Unit.usd,
defaultActive: false,
}),
line({
metric: percentiles.costBasisPct90,
metric: percentiles.pct90,
name: useGroupName ? `${name} p90` : "p90",
color,
unit: Unit.usd,
@@ -64,7 +64,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
["10y", "_10y"],
]).map(([id, key]) => {
const name = periodIdToName(id, true);
const priceAgo = lookback.priceAgo[key];
const priceAgo = lookback[key];
const priceReturns = returns.priceReturns[key];
const dcaCostBasis = dca.periodAveragePrice[key];
const dcaReturns = dca.periodReturns[key];
@@ -181,14 +181,15 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
{
name: "Returns",
title: "DCA Returns by Year",
bottom: dcaClasses.map(({ year, color, defaultActive, returns }) =>
baseline({
metric: returns,
name: `${year}`,
color,
defaultActive,
unit: Unit.percentage,
}),
bottom: dcaClasses.map(
({ year, color, defaultActive, returns }) =>
baseline({
metric: returns,
name: `${year}`,
color,
defaultActive,
unit: Unit.percentage,
}),
),
},
{
@@ -118,18 +118,6 @@ export function fromBitcoin(colors, pattern, title, color) {
return [
{ metric: pattern.base, title, color: color ?? colors.default },
{ metric: pattern.average, title: "Average", defaultActive: false },
{
metric: pattern.sum,
title: `${title} (sum)`,
color: colors.red,
defaultActive: false,
},
{
metric: pattern.cumulative,
title: `${title} (cum.)`,
color: colors.cyan,
defaultActive: false,
},
{
metric: pattern.max,
title: "Max",
@@ -333,20 +321,6 @@ export function fromFullnessPattern(colors, pattern, title, unit) {
unit,
defaultActive: false,
},
{
metric: pattern.sum,
title: `${title} sum`,
color: colors.blue,
unit,
defaultActive: false,
},
{
metric: pattern.cumulative,
title: `${title} cumulative`,
color: colors.indigo,
unit,
defaultActive: false,
},
{
metric: pattern.min,
title: `${title} min`,
+1 -1
View File
@@ -11,5 +11,5 @@
"lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
"skipLibCheck": true,
},
"exclude": ["assets", "./scripts/modules", "../../modules"],
"exclude": ["assets", "./scripts/modules"],
}