diff --git a/CLAUDE.md b/CLAUDE.md index 9eea694..846e2e3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -140,11 +140,15 @@ single definition, shared with the `/data` cursor in `routes/operations.js` — `/agg` is generated, `/data` is not, and the two have to agree. The one hardcoded ordinal is `ADJUSTMENT_SEGMENT` = `'99 - Adjustments'`, which -keeps unlabelled adjustments last. Labelling an adjustment's own log row -overrides it, which is how one kind of adjustment is split out from the rest. -Unlabelled loads read plain `Unlabeled` and need no ordinal, since letters follow -digits in ASCII — unlike the old `'(adjustment)'`, where `(` is `0x28` against -digits from `0x30` and so sorted *first*. +keeps unlabelled adjustments after every *numbered* segment. That proviso is the +whole scheme, not a caveat on it: ordering is string ordering, so `99` only lands +last once the loads carry `01`–`0n`, and an unnumbered segment sorts after it +(digits precede letters — `9` is `0x39`, `A` is `0x41`). The old `'(adjustment)'` +sorted *first* for the same reason read the other way, `(` being `0x28`. +Unlabelled loads read plain `Unlabeled` and so land at the very end, which is +where a segment nobody has named belongs. Labelling an adjustment's own log row +overrides the fallback, which is how one kind of adjustment is split out from the +rest. **What this replaced.** The prefix used to be computed client-side, as Perspective expression columns (`pf_bucket_ord`, `pf_segment_ord`) built from @@ -158,10 +162,11 @@ two bytes, of which `isprint(0xC2)` is false). `DEAD_ORDER_EXPRS` in scheme. `pf.log.seq` and `pf.version.bucket_order` are no longer read; the columns remain. -Reordering now needs a page reload to show, because the label is part of the -aggregated row rather than something the pivot can re-derive. Changing labels on -an existing source also needs **Generate SQL** re-run — the load templates that -write `label` and `bucket` onto the log row are stored in `pf.sql`. +Relabelling now needs a page reload to show, because the label is part of the +aggregated row rather than something the pivot can re-derive. Editing a label +afterwards is a `PATCH /api/log/:logid` and needs nothing regenerated, but a +source registered before this change needs **Generate SQL** run once, so its +stored load templates write `label` and `bucket` onto the log row at all. ### Forecast operations POST to `/api/versions/:id/{scale|recode|clone}` → SQL executed with `RETURNING *` → new rows returned as JSON → `pspTable.update(rows)` — no full reload. In grain mode the operation's final CTE aggregates its own new rows to grain first; since `pf_logid` is part of `pf_gkey` those keys are always new, so `update()` **appends** and the view re-sums.