mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2026-03-23 16:17:30 +01:00
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:
1
89/3a1de325b5/0/content_hash.txt
Normal file
1
89/3a1de325b5/0/content_hash.txt
Normal file
@@ -0,0 +1 @@
|
||||
sha256:4202939423b762601910b8a2503b87416d2f9a79e16465fa0f821cb7d06afcaf
|
||||
18
89/3a1de325b5/0/context.md
Normal file
18
89/3a1de325b5/0/context.md
Normal 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
274
89/3a1de325b5/0/full.jsonl
Normal file
File diff suppressed because one or more lines are too long
46
89/3a1de325b5/0/metadata.json
Normal file
46
89/3a1de325b5/0/metadata.json
Normal 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
138
89/3a1de325b5/0/prompt.txt
Normal 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
|
||||
42
89/3a1de325b5/metadata.json
Normal file
42
89/3a1de325b5/metadata.json
Normal 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user