From 3299bfe10b21234aed50366afd9b1f2ce373f7e3 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Thu, 17 Sep 2026 22:45:56 -0400 Subject: [PATCH] Be exact about what the 99 fallback does It puts adjustments after every *numbered* segment, not last outright: on the existing version, whose segments are still named AOP and YTD Sales with no prefix, "99 - Adjustments" sorts first, because digits precede letters. That is the scheme working as designed rather than an edge case, so the note says so. Also corrects the regeneration claim: editing a label is a PATCH and needs nothing regenerated. Generate SQL is a one-time thing per source, so its stored load templates write label and bucket at all. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) 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.