fix(charts): align spectrum ticks and add validate workflow (#28)

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR makes three focused changes: restructures `AGENTS.md` with clearer sections for coding agents, adds a `validate` convenience script to `package.json`, and fixes x-axis tick alignment in `SpectrumStatsChart.svelte`.

The chart fix is the most substantive change. The previous implementation used a `[-0.5, n-0.5]` x-axis range with index-based tick callbacks (`_value, idx`), which caused tick label/grid misalignment. The new approach shifts the axis to `[0, n-1]` and replaces the index-based callbacks with a value-based approach via a new `getBucketStartForTickValue` helper. This helper safely maps a Chart.js tick value (a float near an integer) back to the correct `bucketStarts` entry, with bounds and precision checks. The logic is correct and consistent with how other charts in the codebase (`IPChart`, `ProtocolChart`) handle tick formatting.

**Key observations:**
- The `validate` script runs `prettier --write .` (mutating) before `lint`, which is appropriate for agent/local use but would silently auto-fix formatting if adopted in CI rather than failing on unformatted code. The existing `ci.yaml` does not use `validate` and continues using separate `typecheck` + `lint` steps.
- The tick fix is duplicated in both the initial chart creation path and the chart update path — this is consistent with the existing pattern in the component.
- `autoSkip: false` with `stepSize: 1` is consistent with other charts in the codebase and is safe since `formatTickLabel` returns `''` for most ticks, keeping the chart legible.

<h3>Confidence Score: 4/5</h3>

- Safe to merge — the chart fix is logically correct and the validate script is a low-risk addition.
- The spectrum tick alignment fix uses a well-guarded helper function with explicit bounds and type checks, and the approach is consistent with how other charts in the codebase work. The `validate` script's use of `prettier --write` before `lint` is intentional for agent use but is not a regression since CI does not adopt it. No breaking changes, no data mutations, no security concerns.
- No files require special attention, though the `validate` script in `package.json` should not be adopted verbatim in CI without replacing `prettier --write` with `prettier --check`.

<h3>Important Files Changed</h3>




| Filename | Overview |
|----------|----------|
| AGENTS.md | Documentation-only restructuring: clearer section headers, expanded Git/CLI guidance, and references to the new `npm run validate` command. No logic issues. |
| netflow-webapp/package.json | Adds a `validate` convenience script (`format && lint && check`). The `format` step writes files before `lint` runs, which is intentional for agent use but could mask formatting drift if adopted in CI. |
| netflow-webapp/src/lib/components/charts/SpectrumStatsChart.svelte | Replaces index-based tick/grid callbacks with a value-based approach using a new `getBucketStartForTickValue` helper, and shifts x-axis range from [-0.5, n-0.5] to [0, n-1]. Logic is sound but the `validate` script mentioned in the PR title is not integrated into the existing CI workflow. |

</details>



<h3>Flowchart</h3>

```mermaid
flowchart TD
    A["Chart.js tick callback\n(value: unknown)"] --> B["getBucketStartForTickValue(value)"]
    B --> C{Is value a finite\ninteger within bounds?}
    C -- No --> D["return null"]
    C -- Yes --> E["bucketStarts[roundedIndex]"]
    E --> F["formatTickLabel(bucketStart, granularity, index)"]
    D --> G["return ''  (empty tick label)"]
    F --> H["Return formatted label\nor '' if not a boundary"]

    A2["Chart.js grid.color callback\n(ctx: {tick?: {value?}})"] --> B2["getBucketStartForTickValue(ctx.tick?.value)"]
    B2 --> C2{bucketStart found?}
    C2 -- No --> D2["rgba(0,0,0,0.02)\n(subtle)"]
    C2 -- Yes --> E2["shouldHighlightTick(bucketStart, granularity, index)"]
    E2 -- true --> F2["rgba(0,0,0,0.08)\n(highlighted)"]
    E2 -- false --> G2["rgba(0,0,0,0.02)\n(subtle)"]
```

<sub>Last reviewed commit: 083b19b</sub>

<!-- greptile_other_comments_section -->

<!-- /greptile_comment -->
2ed632de47oliver committed on 2/17/2026, 7:33:14 PM· committed by GitHubparents1adc85a083b19b
3 files changedLine totals unavailable