pf_app
The phantom: pf_segment and pf_bucket are computed from pf.log when the rows are served, so buildWhere had no column to compare and dropped them. Clicking one bucket's cell and scaling therefore wrote every bucket at that dimension intersection, while the panel showed only the bucket clicked. On the example slice that is 350,524.74 displayed against 503,446.08 written. They resolve exactly, without a new column: the name lives on the log row and every forecast row carries the pf_logid that points at it, so the predicate is pf_logid IN (SELECT id FROM pf.log WHERE <the same expression> = ...). Verified against version 29 -- the clause returns 350,524.74 over 12 rows. Any other pf_ key is now refused rather than skipped, since skipping is the mechanism by which a selection silently widens. pf_iter stays exempt: the client drops it deliberately, two cells differing only by iter band being the same slice. Client side they are ordinary columns in the loaded table, so both the dispatch path and the panel's own totals filter on them directly -- the latter matters as much, or the ledger reconciles against a wider selection than the operation writes. The ledger: excluded rows read "02 - Prior Year · FINAL" in amber rather than "reference · fixed" -- named by the segment a forecaster recognises instead of the iter band that happens to exclude it, and coloured because immovable is a property worth seeing before reading a number. When the whole selection is immovable it now says so in a sentence, where before it printed a row of zeros and left the reason to be inferred from the edit rows failing below. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| lib | ||
| public | ||
| routes | ||
| setup_sql | ||
| ui | ||
| .env.example | ||
| .gitignore | ||
| CLAUDE.md | ||
| install.sh | ||
| package-lock.json | ||
| package.json | ||
| PERSPECTIVE.md | ||
| pf_perspective_options.md | ||
| pf_spec.md | ||
| pf.sh | ||
| server.js | ||