Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 41 additions & 15 deletions .github/workflows/half-state-patrol.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,16 +11,39 @@ name: Half-State Patrol
# Every divergence from upstream is listed here, once, so a future re-sync knows
# exactly what it must not clobber:
#
# 1. `PM_SWEEP_CLOSED_WINDOW_PAGES: 0` on the sweep step — H22's closed-card
# reader is OFF in this install. Measured 2026-08-24: 815 closed cards here
# carry `pm:dispatched`, and ~347 of the 400 issues in upstream's window
# carry some `pm:*` residue label (~87%, against the 26% upstream measured).
# Stripping `pm:*` on close was never this lane's practice, so H22 here
# reports the CONVENTION, not a defect — ~347 rows that would consume the
# whole body budget and trim every other predicate out of the anchor. The
# sweeper says "UNREAD, not clean" in its summary rather than reporting 0.
# ⛔ Re-enabling is a BACKFILL decision (strip the residue first), never a
# quiet default flip. The script's default is still upstream's 4.
# 1. `PM_SWEEP_CLOSED_FLOOR` on the sweep step — H22's closed-card reader is
# ON here, but judges only cards closed on/after the cutover date. It read
# `PM_SWEEP_CLOSED_WINDOW_PAGES: 0` (reader fully OFF) until 2026-08-28.
#
# The measurement that forced the hold, taken 2026-08-24: 815 closed cards
# here carry `pm:dispatched`, and ~347 of the 400 issues in upstream's
# window carry some `pm:*` residue label (~87%, against the 26% upstream
# measured). At that density H22 reports the CONVENTION, not a defect —
# ~347 rows that consume the whole body budget and trim every other
# predicate out of the anchor.
#
# objectui#5985 recorded that as a two-way choice: either stripping is the
# rule (and ~815 closed cards need a BACKFILL first) or the row is simply
# not wanted here. The dated floor is the third option both readings omit.
# `pm:*` on a card closed before the convention existed is inert history —
# the dispatch loop reads state on OPEN cards only — so judging from the
# cutover forward buys the row's whole value (residue produced from now
# on, while the paired write is still a live duty) at zero backfill and
# zero historical noise. ⛔ NO bulk label backfill of closed cards was run
# and none is owed; the sweeper writes no label under any code path.
#
# The cutover is 2026-08-28, the date the strip-on-close convention was
# written into the pm-dispatch protocol's label-discipline section. ⛔ Do
# not move it EARLIER without re-measuring: every day it moves back pulls
# in cards closed under no convention at all. `resolveClosureFloor` in the
# sweeper refuses a malformed value (exit 2) rather than degrading to "no
# floor", because a silent degrade here restores the 87% flood four times
# a day and a flooded anchor reads exactly like a working patrol.
#
# ⚠️ The floor is UPSTREAM code, not a fourth hand divergence: a re-sync
# that replaces the sweeper with upstream's keeps it. What diverges is
# this WIRING — upstream sets no floor, because its own board measured 26%
# and it treats recent closed residue as a live duty.
# 2. `scripts/invoked-as.mjs` is in the `paths:` filter below — the sweeper
# imports it, and it was ported alongside.
# 3. `scripts/pm/check-half-states.mjs` carries `DEFAULT_SWEEP_REPO =
Expand DownExpand Up@@ -209,11 +232,14 @@ jobs:
# workflow — the two agree by construction and a copy of this file
# cannot end up sweeping the repo it was copied FROM.
PM_SWEEP_REPO: ${{ github.repository }}
# objectui#5791 — H22's closed-card reader is OFF here. See divergence
# (1) in this file's header for the measurement that decided it, and
# `resolveClosedWindowPages` in the sweeper for what 0 means. The
# rendered body reports the surface as UNREAD, never as clean.
PM_SWEEP_CLOSED_WINDOW_PAGES: '0'
# objectui#5985 — H22's closed-card reader is ON, with a DATED FLOOR:
# only cards closed on/after this date are judged. See divergence (1)
# in this file's header for the measurement and the reasoning, and
# `resolveClosureFloor` in the sweeper for the parsing and the loud
# refusal. The page window is deliberately absent: it is back to the
# script's own upstream default of 4, and the floor — not a zeroed
# window — is what keeps the ~815 historical carriers out.
PM_SWEEP_CLOSED_FLOOR: '2026-08-28'
PROVENANCE: >-
run [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
· commit `${{ github.sha }}` · trigger `${{ github.event_name }}`
Expand Down
110 changes: 84 additions & 26 deletions scripts/__tests__/check-half-states.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import {
DEFAULT_SWEEP_REPO,
h22ClosedCardPmResidue,
resolveClosedWindowPages,
resolveClosureFloor,
resolveSweepRepo,
summaryLine,
} from '../pm/check-half-states.mjs';
Expand DownExpand Up@@ -81,63 +82,120 @@ describe('check-half-states — sweeps THIS board (objectui#5791 adaptation)', (
});
});

describe('check-half-states — H22 closed-card reader is OFF here (objectui#5791)', () => {
describe('check-half-states — H22 runs here behind a DATED CLOSURE FLOOR (objectui#5985)', () => {
/**
* The measurement that decided this, re-measured 2026-08-24 for the port:
* 815 closed cards in objectui carry `pm:dispatched`, and ~347 of the 400
* ⚠️ REPLACED PIN, not a respelled one. Until 2026-08-28 this block pinned the
* opposite arrangement: the reader fully OFF via `PM_SWEEP_CLOSED_WINDOW_PAGES:
* '0'`, under a ruling that stripping `pm:*` on close was not this lane's
* convention. That ruling is superseded — fleet practice now strips `pm:*` in
* the landing/close stroke, and the convention is written into the pm-dispatch
* protocol's label-discipline section as of 2026-08-28.
*
* The measurement that forced the original hold still stands and is why the
* re-enable is FLOORED rather than plain (re-measured 2026-08-24 for the
* port): 815 closed cards here carry `pm:dispatched`, and ~347 of the 400
* issues inside upstream's window carry some `pm:*` residue label (~87%,
* against the 26% upstream measured on its own board). Stripping `pm:*` on
* close was never this lane's practice, so H22 here reports the CONVENTION
* rather than a defect — ~347 rows that would exhaust the body budget and
* trim every other predicate out of the anchor on day one.
* against the 26% upstream measured on its own board). An unfloored re-enable
* would report the CONVENTION rather than defects — ~347 rows that exhaust
* the body budget and trim every other predicate out of the anchor on day one.
*
* ⛔ The floor is what makes the re-enable cheap: no backfill of the 815
* historical carriers was run, and none is owed. The sweeper writes no label
* under any code path, so no bulk rewrite is even reachable from here.
*/
it('keeps upstream\'s default in the script, so the port stays a straight copy', () => {
it('keeps upstream\'s page default in the script, so the port stays a straight copy', () => {
// The divergence lives in the WORKFLOW, not in the script's default. This
// is what lets the predicate file be re-synced verbatim.
expect(CLOSED_ISSUE_WINDOW_PAGES).toBe(4);
expect(resolveClosedWindowPages({}).pages).toBe(4);
expect(resolveClosedWindowPages({}).source).toBe('default');
});

it('is switched off by the workflow, and visibly so', () => {
expect(workflow).toMatch(/PM_SWEEP_CLOSED_WINDOW_PAGES: '0'/);
expect(resolveClosedWindowPages({ PM_SWEEP_CLOSED_WINDOW_PAGES: '0' }).pages).toBe(0);
expect(resolveClosedWindowPages({ PM_SWEEP_CLOSED_WINDOW_PAGES: '0' }).valid).toBe(true);
it('is switched ON by the workflow — the page-window hold is GONE', () => {
// The hold's absence is asserted directly. Left in place beside a floor it
// would win silently (0 pages reads nothing whatever the floor says), and
// the anchor would keep reporting UNREAD while looking re-enabled.
expect(workflow).not.toMatch(/^\s*PM_SWEEP_CLOSED_WINDOW_PAGES:/m);
expect(resolveClosedWindowPages({}).pages).toBe(4);
});

it('sets a dated floor in the workflow, and visibly so', () => {
expect(workflow).toMatch(/PM_SWEEP_CLOSED_FLOOR: '2026-08-28'/);
const resolved = resolveClosureFloor({ PM_SWEEP_CLOSED_FLOOR: '2026-08-28' });
expect(resolved.valid).toBe(true);
expect(resolved.floor?.toISOString()).toBe('2026-08-28T00:00:00.000Z');
});

it('refuses a malformed page count instead of silently defaulting', () => {
// Silently falling back to 4 would re-open the reader this install shut,
// and the anchor would carry the residue as though someone chose that.
// The knob still exists and still refuses garbage — it is simply not what
// holds the historical residue out any more.
for (const raw of ['O', '-1', '1.5', 'four']) {
expect(resolveClosedWindowPages({ PM_SWEEP_CLOSED_WINDOW_PAGES: raw }).valid).toBe(false);
}
expect(resolveClosedWindowPages({ PM_SWEEP_CLOSED_WINDOW_PAGES: ' 2 ' }).pages).toBe(2);
});

it('leaves the H22 predicate itself untouched', () => {
// The adaptation is a window, not a rewritten rule: handed a closed card
// with residue the predicate must still say so. Re-enabling the reader is
// therefore a one-variable decision, not a code change.
it('refuses a malformed floor instead of silently running unfloored', () => {
// ⛔ The property the re-enable turns on. A floor that degraded to "no
// floor" would put ~347 convention rows in the anchor four times a day,
// and a flooded anchor reads exactly like a working patrol.
for (const raw of ['28-08-2026', '2026/08/28', 'yesterday', '2026-8-28', 'O']) {
expect(resolveClosureFloor({ PM_SWEEP_CLOSED_FLOOR: raw }).valid).toBe(false);
expect(resolveClosureFloor({ PM_SWEEP_CLOSED_FLOOR: raw }).floor).toBeNull();
}
// …including a shape-valid date that does not exist. `Date.parse` rolls
// `2026-02-31` to March rather than rejecting it, so the resolver
// round-trips the parse instead of trusting it.
expect(resolveClosureFloor({ PM_SWEEP_CLOSED_FLOOR: '2026-02-31' }).valid).toBe(false);
// Unset is valid and means "no floor" — upstream's own behaviour.
expect(resolveClosureFloor({}).valid).toBe(true);
expect(resolveClosureFloor({}).floor).toBeNull();
});

it('applies the floor to the H22 predicate: old closures out, new ones judged', () => {
// The whole re-enable, in two assertions. The old card is the ~815-card
// backlog in miniature — real residue, deliberately NOT a finding.
const closedCard = {
state: 'closed',
state_reason: 'completed',
labels: [{ name: 'pm:dispatched' }],
};
expect(h22ClosedCardPmResidue(closedCard)).toContain('`pm:dispatched`');
expect(h22ClosedCardPmResidue({ ...closedCard, state: 'open' })).toBeNull();
const floor = resolveClosureFloor({ PM_SWEEP_CLOSED_FLOOR: '2026-08-28' }).floor;
expect(h22ClosedCardPmResidue({ ...closedCard, closed_at: '2026-01-01T00:00:00Z' }, floor)).toBeNull();
expect(h22ClosedCardPmResidue({ ...closedCard, closed_at: '2026-08-29T00:00:00Z' }, floor)).toContain('`pm:dispatched`');
// The cutover date itself is judged: it is the first day the convention
// applies, so cards closed within it are the convention's own population.
expect(h22ClosedCardPmResidue({ ...closedCard, closed_at: '2026-08-28T12:00:00Z' }, floor)).toContain('`pm:dispatched`');
// Unfloored, the predicate is byte-for-byte upstream's — the port stays a
// straight copy and the floor is opt-in.
expect(h22ClosedCardPmResidue({ ...closedCard, closed_at: '2026-01-01T00:00:00Z' })).toContain('`pm:dispatched`');
expect(h22ClosedCardPmResidue({ ...closedCard, state: 'open' }, floor)).toBeNull();
});

it('names the floor in the summary, so a floored pass cannot read as a full one', () => {
// ⛔ #4690, in the shape this change could newly break: "H22 read 200" with
// a floor silently applied overstates what was judged. The line must carry
// the floor date, and must say the earlier closures are UNJUDGED rather
// than clean.
const counts = { repo: 'objectstack-ai/objectui', issues: 3, unscoped: 4, prs: 1, merged: 2, closed: 200 };
const floored = summaryLine({ ...counts, closedFloor: '2026-08-28' }, 0);
expect(floored).toContain('H22 read 200 recently-closed issue(s)');
expect(floored).toContain('only cards closed on/after 2026-08-28 are judged');
expect(floored).toContain('NOT a reading about them');
// An unfloored pass must not grow the clause.
expect(summaryLine(counts, 0)).not.toContain('are judged');
});

it('reports the closed surface as UNREAD, never as clean', () => {
// The property the whole adaptation turns on (#4690). A disabled reader
// and an empty result are the same number and opposite facts; if this ever
// renders "H22 read 0", the anchor starts asserting a clean closed surface
// that nothing looked at.
it('still reports a DISABLED reader as UNREAD, never as clean', () => {
// The disabled branch is no longer wired here, but it is still live code
// and still the property the port turned on (#4690): a disabled reader and
// an empty result are the same number and opposite facts. Kept pinned so
// re-adding the hold cannot quietly render "H22 read 0".
const counts = { repo: 'objectstack-ai/objectui', issues: 3, unscoped: 4, prs: 1, merged: 2, closed: 0 };
const disabled = summaryLine({ ...counts, closedWindowDisabled: true }, 0);
expect(disabled).toContain('is DISABLED in this install');
expect(disabled).toContain('UNREAD');
expect(disabled).not.toContain('H22 read 0');
// …and it names the way back, so the choice is reversible by a reader.
expect(disabled).toContain('PM_SWEEP_CLOSED_WINDOW_PAGES');

// The other direction: an enabled reader that found nothing IS a clean
Expand Down
Loading
Loading