Skip to content

fix(consolidate): floor NULL demote target instead of nulling importance (#188)#191

Merged
edheltzel merged 2 commits into
mainfrom
worktree-harden-188-reclamp-null-floor
Jun 25, 2026
Merged

fix(consolidate): floor NULL demote target instead of nulling importance (#188)#191
edheltzel merged 2 commits into
mainfrom
worktree-harden-188-reclamp-null-floor

Conversation

@edheltzel

Copy link
Copy Markdown
Owner

Summary

Hardens the consolidate child re-clamp to deliver the floor-of-1 invariant its comment advertised, from the RedTeam gate on PR #184 (issue #145).

The demote re-clamp used MAX(1, MIN(importance, CAST(? AS INTEGER))). A NULL importance payload wrote NULL (CAST(NULL)→NULL, MIN/MAX with NULL→NULL), so the comment's claim that the floor of 1 is re-pinned "regardless of the supplied value" was overstated. Not reachable on the legit path (the planner always supplies an integer) and not a regression (pre-PR SET importance = ? nulled identically) — but it didn't fully deliver the asterisked invariant.

Changes

  1. SQL — wrap the bind in COALESCE(?, importance): MAX(1, MIN(CAST(COALESCE(?, importance) AS INTEGER), importance)). A NULL payload now no-ops to the current value and MAX(1, …) re-pins the floor for every input, NULL included. The "can only LOWER, never raise" guarantee is unchanged.
  2. Comment — tightened to state the real guarantee (NULL → no-op, floor honored for all inputs).
  3. Tests
    • NULL-floor: a NULL newImportance no-ops to the current value and never nulls the column (tests/hooks/consolidate-core.test.ts).
    • End-to-end spawn → err.stderr → parse link (the LOW from the same gate): a child emits a RECALL_CONSOLIDATE_PROGRESS marker then hangs past a short execSync timeout; the SIGTERM'd child's captured stderr is recovered by parseConsolidateProgress (tests/lib/consolidate.test.ts). Prior coverage proved the parser and the apply separately but never the live link.

Verification

  • bun run lint clean.
  • bun test — full suite 1191 pass / 0 fail (in-worktree, with node_modules resolvable). The 19 consolidate tests (incl. the two new ones) pass.

risk:low — defense-in-depth hardening on a non-reachable path; the legit planner path is unaffected.

Closes #188

…nce (#188)

The child re-clamp used MAX(1, MIN(importance, CAST(? AS INTEGER))), which
writes NULL when the payload importance is NULL (CAST(NULL)->NULL, MIN/MAX
with NULL->NULL) — so the comment's claimed floor-of-1 'regardless of the
supplied value' did not actually hold for NULL. Wrap the bind in
COALESCE(?, importance) so a NULL payload no-ops to the current value and
MAX(1, ...) re-pins the floor for every input. Tighten the comment to match
the real guarantee.

Tests: prove a NULL newImportance no-ops (never nulls the column), and add
the missing end-to-end spawn -> stderr -> parseConsolidateProgress link
(child emits a progress marker then hangs past a short timeout; the parser
recovers the committed counts from the killed child's captured stderr).

Closes #188
@edheltzel edheltzel merged commit 6097ba7 into main Jun 25, 2026
2 checks passed
@edheltzel edheltzel deleted the worktree-harden-188-reclamp-null-floor branch June 25, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

harden: consolidate re-clamp NULL-importance floor + e2e stderr→parser test (from #184 gate)

1 participant