Checkpoint: 893a1de325b5

Entire-Session: 260a4a9e-d060-4d86-982b-1bf5959b9b70
Entire-Strategy: manual-commit
Entire-Agent: Claude Code
Ephemeral-branch: entire/10b4fa5-e3b0c4
This commit is contained in:
2026-03-19 21:17:00 +01:00
parent 3bf53920f2
commit 0851f3f75d
6 changed files with 519 additions and 0 deletions

View File

@@ -0,0 +1 @@
sha256:4202939423b762601910b8a2503b87416d2f9a79e16465fa0f821cb7d06afcaf

View File

@@ -0,0 +1,18 @@
# Session Context
## User Prompts
### Prompt 1
Implement the following plan:
# Plan: Add RRDTool-style Average Consolidation Function to Resampler
## Context
The current downsampler in `cc-lib/v2/resampler` offers two algorithms:
- **LTTB** (LargestTriangleThreeBucket): Perceptually-aware — picks points that preserve visual shape (peaks/valleys). Used at all call sites.
- **SimpleResampler**: Decimation — picks every nth point. Fast but lossy.
Neither produces scientifically accurate averages over time intervals. RRDTool's **AVERAGE C...

274
89/3a1de325b5/0/full.jsonl Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,46 @@
{
"cli_version": "0.4.8",
"checkpoint_id": "893a1de325b5",
"session_id": "260a4a9e-d060-4d86-982b-1bf5959b9b70",
"strategy": "manual-commit",
"created_at": "2026-03-19T20:17:00.303981Z",
"branch": "feature/526-average-resample",
"checkpoints_count": 1,
"files_touched": [
"api/schema.graphqls",
"go.mod",
"go.sum",
"internal/api/api_test.go",
"internal/api/job.go",
"internal/archiver/archiver.go",
"internal/graph/generated/generated.go",
"internal/graph/model/models_gen.go",
"internal/graph/schema.resolvers.go",
"internal/graph/util.go",
"internal/metricdispatch/dataLoader.go",
"internal/metricdispatch/metricdata.go",
"internal/metricstoreclient/cc-metric-store.go",
"internal/repository/testdata/job.db",
"pkg/metricstore/api.go",
"pkg/metricstore/metricstore.go",
"pkg/metricstore/query.go"
],
"agent": "Claude Code",
"turn_id": "0c41556af804",
"token_usage": {
"input_tokens": 3156,
"cache_creation_tokens": 88301,
"cache_read_tokens": 4751651,
"output_tokens": 15445,
"api_call_count": 55
},
"initial_attribution": {
"calculated_at": "2026-03-19T20:17:00.00043Z",
"agent_lines": 146,
"human_added": 45,
"human_modified": 24,
"human_removed": 0,
"total_committed": 215,
"agent_percentage": 67.90697674418604
}
}

138
89/3a1de325b5/0/prompt.txt Normal file
View File

@@ -0,0 +1,138 @@
Implement the following plan:
# Plan: Add RRDTool-style Average Consolidation Function to Resampler
## Context
The current downsampler in `cc-lib/v2/resampler` offers two algorithms:
- **LTTB** (LargestTriangleThreeBucket): Perceptually-aware — picks points that preserve visual shape (peaks/valleys). Used at all call sites.
- **SimpleResampler**: Decimation — picks every nth point. Fast but lossy.
Neither produces scientifically accurate averages over time intervals. RRDTool's **AVERAGE Consolidation Function (CF)** divides data into fixed-size buckets and computes the arithmetic mean of all points in each bucket. This is the standard approach for monitoring data where the true mean per interval matters more than visual fidelity (e.g., for statistics, SLA reporting, capacity planning).
The goal: add an `AverageResampler` to cc-lib, then expose it as a per-query option in cc-backend's GraphQL API so the frontend/caller can choose the algorithm.
---
## Part 1: cc-lib changes (`/Users/jan/prg/CC/cc-lib/`)
### 1a. Add `AverageResampler` to `resampler/resampler.go`
New exported function with the same signature as existing resamplers:
```go
func AverageResampler(data []schema.Float, oldFrequency int64, newFrequency int64) ([]schema.Float, int64, error)
```
**Algorithm (RRDTool AVERAGE CF):**
1. Call `validateFrequency()` for early-exit checks (reuses existing validation).
2. Compute `step = newFrequency / oldFrequency` (points per bucket).
3. For each bucket of `step` consecutive points, compute arithmetic mean skipping NaN values. If all values in a bucket are NaN, output NaN for that bucket.
4. Return averaged data, `newFrequency`, nil.
**NaN handling**: Skip NaN values and average only valid points (consistent with RRDTool behavior and `AddStats()` in `pkg/metricstore/api.go`). This differs from LTTB which propagates NaN if *any* bucket point is NaN.
### 1b. Add `ResamplerFunc` type and lookup
Add a function type and string-based lookup to make algorithm selection easy for consumers:
```go
// ResamplerFunc is the signature shared by all resampler algorithms.
type ResamplerFunc func(data []schema.Float, oldFrequency int64, newFrequency int64) ([]schema.Float, int64, error)
// GetResampler returns the resampler function for the given name.
// Valid names: "lttb" (default), "average", "simple". Empty string returns LTTB.
func GetResampler(name string) (ResamplerFunc, error)
```
### 1c. Add tests to `resampler/resampler_test.go`
Following the existing test patterns (table-driven, same helper functions):
- Basic averaging: `[1,2,3,4,5,6]` step=2 → `[1.5, 3.5, 5.5]`
- NaN skipping within buckets
- All-NaN bucket → NaN output
- Early-exit conditions (same set as SimpleResampler/LTTB tests)
- Frequency validation errors
- Benchmark: `BenchmarkAverageResampler`
---
## Part 2: cc-backend changes (`/Users/jan/tmp/cc-backend/`)
### 2a. Add `replace` directive to `go.mod`
```
replace github.com/ClusterCockpit/cc-lib/v2 => ../../prg/CC/cc-lib
```
### 2b. Add GraphQL enum and query parameter
In `api/schema.graphqls`, add enum and parameter to both queries that accept `resolution`:
```graphql
enum ResampleAlgo {
LTTB
AVERAGE
SIMPLE
}
```
Add `resampleAlgo: ResampleAlgo` parameter to:
- `jobMetrics(id: ID!, metrics: [String!], scopes: [MetricScope!], resolution: Int, resampleAlgo: ResampleAlgo): [JobMetricWithName!]!`
- `nodeMetricsList(..., resolution: Int, resampleAlgo: ResampleAlgo): NodesResultList!`
Then run `make graphql` to regenerate.
### 2c. Update resolvers to pass algorithm through
**`internal/graph/schema.resolvers.go`**:
`JobMetrics` resolver (line ~501): accept new `resampleAlgo *model.ResampleAlgo` parameter (auto-generated by gqlgen), convert to string, pass to `LoadData`.
`NodeMetricsList` resolver (line ~875): same treatment, pass to `LoadNodeListData`.
### 2d. Thread algorithm through data loading
**`internal/metricdispatch/dataLoader.go`**:
- `LoadData()` (line 85): add `resampleAlgo string` parameter. Use `resampler.GetResampler(resampleAlgo)` to get the function, call it instead of hardcoded `resampler.LargestTriangleThreeBucket` at line 145.
- `LoadNodeListData()` (line 409): add `resampleAlgo string` parameter, pass through to `InternalMetricStore.LoadNodeListData`.
**`pkg/metricstore/query.go`**:
- `InternalMetricStore.LoadNodeListData()` (line 616): add `resampleAlgo string` to signature, include in `APIQueryRequest` or pass to `MemoryStore.Read`.
**`pkg/metricstore/metricstore.go`**:
- `MemoryStore.Read()` (line ~682): add `resampleAlgo string` parameter. At line 740, use `resampler.GetResampler(resampleAlgo)` instead of hardcoded LTTB.
### 2e. Update cache key
**`internal/metricdispatch/dataLoader.go`**: The `cacheKey()` function must include the algorithm name so different algorithms don't serve stale cached results.
---
## Files to modify
| File | Repo | Change |
|------|------|--------|
| `resampler/resampler.go` | cc-lib | Add `AverageResampler`, `ResamplerFunc`, `GetResampler` |
| `resampler/resampler_test.go` | cc-lib | Add tests + benchmark |
| `go.mod` | cc-backend | Add `replace` directive |
| `api/schema.graphqls` | cc-backend | Add `ResampleAlgo` enum, update query params |
| `internal/graph/generated/` | cc-backend | Regenerated (`make graphql`) |
| `internal/graph/schema.resolvers.go` | cc-backend | Pass algorithm to data loaders |
| `internal/metricdispatch/dataLoader.go` | cc-backend | Thread algorithm to resampler calls, update cache key |
| `pkg/metricstore/query.go` | cc-backend | Thread algorithm through `LoadNodeListData` |
| `pkg/metricstore/metricstore.go` | cc-backend | Thread algorithm through `Read()`, use `GetResampler` |
## Verification
1. `cd /Users/jan/prg/CC/cc-lib && go test ./resampler/...` — new + existing tests pass
2. `cd /Users/jan/tmp/cc-backend && make graphql` — GraphQL code regenerates cleanly
3. `make` — full build succeeds
4. `make test` — all existing tests pass
5. Manual: GraphQL playground query with `resampleAlgo: AVERAGE` vs default LTTB — average produces smoother curves without artificial peak preservation
If you need specific details from before exiting plan mode (like exact code snippets, error messages, or content you generated), read the full transcript at: /Users/jan/.claude/projects/-Users-jan-tmp-cc-backend/190ae749-6a19-47a7-82da-dba5a0e7402d.jsonl

View File

@@ -0,0 +1,42 @@
{
"cli_version": "0.4.8",
"checkpoint_id": "893a1de325b5",
"strategy": "manual-commit",
"branch": "feature/526-average-resample",
"checkpoints_count": 1,
"files_touched": [
"api/schema.graphqls",
"go.mod",
"go.sum",
"internal/api/api_test.go",
"internal/api/job.go",
"internal/archiver/archiver.go",
"internal/graph/generated/generated.go",
"internal/graph/model/models_gen.go",
"internal/graph/schema.resolvers.go",
"internal/graph/util.go",
"internal/metricdispatch/dataLoader.go",
"internal/metricdispatch/metricdata.go",
"internal/metricstoreclient/cc-metric-store.go",
"internal/repository/testdata/job.db",
"pkg/metricstore/api.go",
"pkg/metricstore/metricstore.go",
"pkg/metricstore/query.go"
],
"sessions": [
{
"metadata": "/89/3a1de325b5/0/metadata.json",
"transcript": "/89/3a1de325b5/0/full.jsonl",
"context": "/89/3a1de325b5/0/context.md",
"content_hash": "/89/3a1de325b5/0/content_hash.txt",
"prompt": "/89/3a1de325b5/0/prompt.txt"
}
],
"token_usage": {
"input_tokens": 3156,
"cache_creation_tokens": 88301,
"cache_read_tokens": 4751651,
"output_tokens": 15445,
"api_call_count": 55
}
}