Skip to content

The falsifier alert notified once per incident; a renamed witness left two stale roster rows - #7884

Merged
briansrls merged 5 commits into
mainfrom
session/smart-raven-471
Aug 6, 2026
Merged

briansrls merged 5 commits into
mainfrom
session/smart-raven-471

Conversation

@briansrls

@briansrls briansrls commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

Two independent defects behind "the falsifier is red and it isn't notifying me", both found from the falsifier's own receipts.

1. The alert reached its recipient once per incident, not every 20 hours

An @mention notifies when it is created, and only an issue body's first write is a creation — body edits send nothing (which is exactly why this workflow rewrites the body every window). The mention lived only in the body, so the artifacts that carry current state notified nobody.

Receipt: issue #7737 opened 2026-08-03 and accrued four github-actions comments over the next two days — one heartbeat, three failing-set-changed. None carried a mention. The alerting mechanism was working the whole time and its state was correct; delivery is what never happened.

  • The handle is now one ALERT_MENTION constant read by every notifying artifact: body, heartbeat, failing-set-changed, green-close. One constant rather than four literals because gunbc.falsifier_lane falsifier_lane_owner_roster_note records this mention as the only owner fact in the tree — a second copy would be a second authority for one fact. That note is updated to name the constant.
  • Latent second defect on the same path: the 20h throttle read comments[length-1] from a single per_page=100 request. The endpoint returns oldest-first and accepts no sort/direction, so past 100 comments that index is the 100th and only gets older — the throttle would have inverted into "heartbeat every run". Paginated.

The property ships UNENFORCED, and the gap is named rather than implied. A hand-authored JS harness was written beside the workflow and then removed (operator, 2026-08-06): every foreign-language artifact in this tree is emitted from .dag — .github/live-deploy-srv1-apply.sh is shell and sits in the generated_artifact registry — so hand-authoring a second realization adds maintained foreign-language surface rather than a scaffold. Checked before removing rather than assumed: the .dag route is genuinely blocked at the same seam this workflow's own dissolve-on names — there is no workflow_run trigger model (extdeps.github.workflow_runs models runs as an API resource) and gunbc.falsifier_workflow declares issues: none, so the notifying artifacts are not substrate objects and no lens has a Node tree to read.

What stands is an unenrolled authoring-time receipt, cited in the workflow header as exactly that and not as a live control:

$ node .github/scripts/falsifier-alert-selfcheck.cjs .github/workflows/falsifier-alert.yml origin/main
PASS  1 open-issue body mentions owner
FAIL  2 failing-set-changed comment mentions owner
FAIL  3 heartbeat comment mentions owner
FAIL  4 green-close comment mentions owner
FAIL  5 throttle holds when newest comment is fresh (>100 comments)
4 RED

$ node .github/scripts/falsifier-alert-selfcheck.cjs      # this branch
ALL GREEN

Its honest limit is stated in the job: nothing watches falsifier-alert run conclusions today, so this is a real control that is not itself alerted on. That residue closes with the script's dissolve-on.

2. A renamed witness left two stale long-lane rows

#7822 renamed witness_live_constraint_present_iff_line_unaccepted → witness_fixture_constraint_present_iff_line_unaccepted while decomposing the live witness onto planted fixtures. Two byte-identical falsifier_substrate_long_lane_rows kept the old name, so batch 6 tried to run a function that does not exist:

witness_live_constraint_present_iff_line_unaccepted ... runtime error: no such function (run 31047744902)

Both rows are deleted rather than repointed, because the row's own dissolve_on first arm is met by execution — the renamed witness measures cpu=48ms wall=50ms against the 5000ms fast-lane budget:

PASS witness_fixture_constraint_present_iff_line_unaccepted
[witness] cpu=47ms wall=47ms subject=e4dc124ae5ac569b

The deferral reason those rows carried (live_view() joining declared nodes, edges, receipts and finish-line specs at ~3074ms) describes work the function no longer does. Nothing is de-enrolled: the file is under dag/test/claim, so deleting the rows returns it to per-PR discovery, and #7822 already gave the live half its own long-lane row on roadmap_program_view_live_corpus_receipt_test.dag.

Verified on the merged tree

Main moved three commits during review and two of them touched this same roster file (#7763, #7857 — the floor-plan witness file itself grew 33 → 36 test fns). The textual merge was clean, which is the case worth re-executing rather than trusting, so every figure below is re-run against the merged tree with a rebuilt binary (main added a build.rs):

  • ci_floor_plan_witness_test — 36/36, the plan⇄roster consistency authority
  • gauntlet_lane_enrollment_witness_test — 6/6, incl. both RED controls

What this does not fix

So the falsifier's remaining red is not read as this change's failure:

  • Batch 6 also reports direct_rust_door_production_group_closing_expectation_holds false. It is declared known-red by Direct Rust door: one canonical stage-located acceptance group #7814 and red by design. It counts as a plain failure because discovery_entries_are_expect_red requires every explicit entry in a batch to be a known-red path, and the witness joins the long-lane roster to earn its budget — the machinery deficit gunbc.explicit_witness_admission already documents on its sibling row, with a named dissolve-on. Untouched; that row says the only edit that may green it is making the real inferred tree survive emission.
  • The 170-minute step timeout that killed run 31031283447 mid-floor. The following run completed inside budget, so the floor is running marginal against that cap rather than over it — the run-stability / five-minute-CI-gate lanes' subject. The cap is not raised here.
  • Registration validates a roster row's shape, never its referents. gunbc.roster_registry already registers falsifier_substrate_long_lane_rows as a DeclaredFrontier and v2.lens.roster_registry already holds it to carrying a non-empty reason and dissolve-on — which both stale rows satisfied perfectly. Nothing joins a row's (entry, function) to a declaration that exists, and the nearest assertion compares roster lengths, a count equality rather than the identity join DESIGN §5 asks for. That is why the stale name sat unnoticed. Deliberately not built here: roster_registry_enforcement_intent_convergence_note says the enforcement-intent thread absorbs this registry when StandingIntent/LensContract land, and "Do not build that machinery here."

🤖 Generated with Claude Code

Brian Searls and others added 2 commits August 6, 2026 00:39
… left two stale roster rows

Two independent defects, both found from the falsifier's own receipts.

ALERT REACHED ITS RECIPIENT ONCE PER INCIDENT, NOT EVERY 20 HOURS.

An @mention notifies when it is CREATED, and only an issue body's first
write is a creation; body edits send nothing. The mention lived only in
the body, so the artifacts that carry current state — the sustained-red
heartbeat and the failing-set-changed comments — notified nobody. That is
the whole mechanism the workflow header describes as its purpose.

Receipt: issue #7737 opened 2026-08-03 and accrued four github-actions
comments over the next two days (one heartbeat, three failing-set-changed).
None carried a mention. The alerting MECHANISM was working the entire time
and its state was correct; what never happened was delivery.

The handle is now one ALERT_MENTION constant read by every notifying
artifact — body, heartbeat, failing-set-changed, and the green close.
One constant rather than four literals because gunbc.falsifier_lane
falsifier_lane_owner_roster_note records this mention as the only owner
fact in the tree, and a second copy of it would be a second authority for
that one fact. That note is updated to name the constant.

A latent second defect on the same path: the 20h throttle read
comments[length-1] from a single per_page=100 request. The endpoint
returns oldest-first and accepts no sort/direction, so past 100 comments
that index is the 100th, not the newest, and its age only grows — the
throttle would have inverted into "heartbeat every run", turning a silent
alert into a spamming one. Paginated.

Enrolled as an executing control rather than left to review:
.github/scripts/falsifier-alert-selfcheck.cjs runs the SHIPPED yaml's
script body against stubbed APIs, as a separate job so it can only ever
add a red and never suppress an alert. Measured against 70b422f, four of
its five scenarios are discriminating REDs (heartbeat, failing-set-changed,
green-close, throttle-pagination) and the open-issue-body scenario is the
positive control. Its honest limit is stated in the job: nothing watches
falsifier-alert run conclusions today, so this is a real control that is
not itself alerted on; that residue closes with the script's dissolve-on.

A RENAMED WITNESS LEFT TWO STALE LONG-LANE ROWS.

#7822 renamed witness_live_constraint_present_iff_line_unaccepted to
witness_fixture_constraint_present_iff_line_unaccepted as part of
decomposing the live witness onto planted fixtures. Two byte-identical
gunbc.ci_layer_roots falsifier_substrate_long_lane_rows rows kept the old
name, so the falsifier's batch 6 tried to run a function that does not
exist and reported "no such function" (run 31047744902).

Both rows are DELETED rather than repointed, because the row's own
dissolve_on first arm is met by execution: the renamed witness measures
cpu=48ms wall=50ms against the 5000ms fast-lane budget, two orders under
it. The deferral reason those rows carried — live_view() joining declared
nodes, edges, receipts and finish-line specs at ~3074ms — describes work
the function no longer does. Nothing is de-enrolled: the file sits under
dag/test/claim, so deleting the rows returns it to per-PR discovery, and
#7822 already gave the live half its own long-lane row on
roadmap_program_view_live_corpus_receipt_test.dag.

WHAT THIS DOES NOT FIX, so the falsifier's remaining red is not read as
this change's failure. Batch 6 also reports
direct_rust_door_production_group_closing_expectation_holds returning
false. That witness is DECLARED known-red by #7814 and is red by design.
It counts as a plain failure because discovery_entries_are_expect_red
requires EVERY explicit entry in a batch to be a known-red path, and the
witness joins the long-lane roster to earn its budget — the machinery
deficit gunbc.explicit_witness_admission already documents on its sibling
row, with a named dissolve_on (separate the execution-requirement/budget
authority from the batch roster). Untouched here; that row says the only
edit that may green it is making the real inferred tree survive emission.

Also untouched: the 170-minute step timeout that killed run 31031283447
mid-floor. The following run completed inside the budget, so the floor is
running marginal against that cap rather than over it — the run-stability
and five-minute-CI-gate lanes' subject, and the cap is not raised here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title falsifier is red - also, it's not actually notifying me? i think we need to @ me every so often? i thought it did that every 20 hours? i'm not getting the notifs on my phone The falsifier alert notified once per incident; a renamed witness left two stale roster rows Aug 6, 2026
Two hygiene fixes on the control added in the previous commit, both of the
same class it exists to catch.

A harness that throws partway printed "ALL GREEN" over however many
scenarios had reported — zero failures among two executed scenarios is not
the same fact as zero among five, and only one of those is a pass. It now
refuses (exit 2) unless every declared scenario reported, and the top-level
promise has a catch arm so a throw before reporting refuses rather than
exiting 0 on an unhandled rejection.

Each scenario chdirs into a fresh mkdtemp so the workflow script can read
its receipt relative to cwd; on a self-hosted runner firing every four
hours those accumulated. Registered and removed on both exit paths.

Re-verified both directions after the change: ALL GREEN on this branch,
4 RED against origin/main, and no temp dirs left behind by either run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 6, 2026 00:57
Brian Searls and others added 2 commits August 6, 2026 01:04
Both #7763 and #7857 touched dag/gunbc/ci_layer_roots.dag, the same file this
branch deletes two long-lane roster rows from. The textual merge is clean, which
is exactly the case worth re-executing rather than trusting: a roster defect can
live only in the composition of two individually correct changes.
… as a named gap

Operator correction: .github/scripts/falsifier-alert-selfcheck.cjs was raw
hand-authored JavaScript. Every foreign-language artifact in this tree is
EMITTED from .dag — .github/live-deploy-srv1-apply.sh is shell and sits in the
generated_artifact registry — so hand-authoring a second realization here added
maintained foreign-language surface rather than a scaffold. A declared
dissolution trigger is what makes a scaffold legitimate when the substrate route
is unavailable; it does not license skipping a route that was never attempted,
and this one was not. The subject was JS, so the check was written in JS. That is
the unmarked-workaround shape DESIGN names, and noticing it is the line-stop.

Checked before removing rather than assumed: the .dag route is genuinely blocked,
at the same seam this workflow's own dissolve-on already names. There is no
workflow_run TRIGGER model — extdeps.github.workflow_runs models runs as an API
resource, not as a trigger — and gunbc.falsifier_workflow declares issues: none.
So the alert's notifying artifacts are not substrate objects, no lens has a Node
tree to read, and a .dag witness cannot exist until falsifier_workflow absorbs
this file. Modeling it as text analysis over the yaml would be the grep-not-lens
antipattern, which is not the substrate route either.

So the mention property ships UNENFORCED, and that is recorded in the workflow
header with its next-rung trigger rather than left implied — the honest state is
a gap that is named and counted, not one papered over by a check that executes
in the wrong language. The authoring-time execution receipt stands as evidence
the shape is correct (4 discriminating REDs against 70b422f: heartbeat,
failing-set-changed, green-close, throttle pagination; open-issue-body green as
the positive control), and it is cited in the header as an unenrolled receipt
rather than presented as a live control.

Re-verified after the removal that the fix itself is untouched: same 4 RED
against origin/main, all green here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls merged commit 4c49eb4 into main Aug 6, 2026
5 checks passed
@briansrls
briansrls deleted the session/smart-raven-471 branch August 6, 2026 03:14
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.

1 participant