Skip to content

Legacy-test inflow: a manual audit mechanism, not continuous observability - #7692

Merged
briansrls merged 4 commits into
mainfrom
session/deep-swift-442-inflow
Aug 3, 2026
Merged

briansrls merged 4 commits into
mainfrom
session/deep-swift-442-inflow

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 2, 2026 •

Copy link
Copy Markdown
Contributor

Adds a per-change counter for added legacy Rust test functions, in audit mode only. It reports; it gates nothing.

What this is — and what it is NOT

It is a manual audit mechanism. It does not make inflow continuously observable. There is no scheduled consumer, no persisted receipt, and no dashboard. Running it today means running the recipe by hand:

GUNBC_CI_DIFF_BASE=<base> GUNBC_CI_DIFF_HEAD=<head> claim_batch --wet \
  --source-root src/v2 --source-root dag \
  --entry src/v2/workflow/legacy_test_inflow_audit.dag \
  --functions legacy_test_inflow_live_observation_holds

That gap is declared in-carrier (legacy_test_inflow_no_scheduled_consumer_note) with its dissolution trigger, and it is counted debt rather than a silent absence. A later PR still owes the non-blocking persisted receipt, the cadence, and a dashboard consumer. Until those land, nobody should read this as "inflow is being watched."

So it lands as three things: an inflow observation kernel, an explicit live local recipe, and counted unscheduled-consumer debt.

Why it exists

Not because of any ratio — because the mechanism is absent. Nothing in the repository can currently answer "did this change add legacy Rust test functions?" A number without a mechanism is a snapshot; the mechanism is the deliverable.

Fail-closed shape

The kernel is a pure fold over diff text with no live effects; the live wrapper reuses the floor's existing floor_diff_observe rather than opening a second git surface.

Refusal cannot read as zero. An earlier revision projected InflowRefused to an empty list and a count of 0, so an unobservable diff was indistinguishable from a clean one — the fabricated-plausible-output arm of DESIGN §5, inside the carrier whose whole job is making a missing measurement visible. That is fixed by construction rather than by discipline:

type LegacyTestInflowTally
  = InflowCountMeasured { count: Int, ids: List<String> }
  | InflowCountUnavailable { reason: NonEmptyStr }

There is no count field to read on an unavailable tally. The witness that asserted count == 0 on a refusal was encoding the erasure as the contract, so it was rewritten rather than kept.

Arrival identity is the canonical LegacyTestBehavior from the disposition module, not a sibling two-field carrier (the review 47551 fix — a nickname where an import edge belonged).

Evidence

12 fixture witnesses, green by execution under claim_batch: detection by name, plus zero-controls for a rename, a removal, a floor .dag witness (not inflow), and an out-of-population seed test, plus both refusal controls including one asserting a refusal and a measured zero are not the same value.

Validated against this exact head with current main merged, not against the original base.


Session state (deep-swift-442, end of day 2026-08-03)

Recorded here rather than in a message thread, so it survives the session.

DONE, green by execution

The diff-grain inflow kernel, the manual wet recipe, and the explicit unscheduled-consumer debt. 12/12 witnesses green under claim_batch locally, and the CI run (claim_executor — the only path that gates a merge) covering head e857c5132ff with current main merged in is SUCCESS on every check.

The structural point, which is construction rather than validation: InflowRefused cannot project to numeric zero, because InflowCountUnavailable has no count field. The fail-open is unwritable, not checked for.

IN FLIGHT

Nothing. Full merge criteria on the exact post-main-merge head: 2/2 distinct approving providers (claude, cursor) on e857c5132ff, zero REQUEST_CHANGES, zero active reviews, mergeable=CLEAN, checks passing.

BLOCKED

Only on the operator's manual merge and on sequencing (#7688 first, then #7693 and this). I do not run gh pr merge.

What this PR is NOT — read this before treating inflow as observable

This is a manual audit mechanism. It does not make legacy-test inflow continuously observable. There is no scheduled consumer, no persisted receipt, and no dashboard surface. Running it is a deliberate act someone has to perform.

Still owed by a later slice, carried and not forgotten: the persisted receipt, the cadence, and the dashboard consumer. The scaffold note states this in-code with a concrete dissolution trigger, and audit-mode-not-a-gate is stated with its promotion trigger — so the debt is countable in the carrier, not only in this body.

The duplicated extraction, and why it is a fork rather than two authorities

Two readers extract legacy-test identity: one observes a live Rust tree, the other unified diff text. Both produce the canonical LegacyTestBehavior identity and carry a convergence trigger. That makes it realization duplication — one concept, two handlers — not two domain authorities. The distinction is the line between an acceptable temporary fork and a §3 nicknaming violation, and it is why this one carries a dissolve-on rather than needing to be undone.

Findings not visible in this diff

Recorded in full in #7693's body, which is the lane's primary record: the refuted scan-dir discovery model, the retracted "witnesses never execute in CI" claim and the 0-byte log that produced it, the three refuted non-execution mechanisms, selection-not-discovery as the real variable, the schedule-retention over-read, the fact that the Rust suite has zero CI consumers, the silently-tolerated double-bound binding class across four grains, and the gunbc_ci_floor_batches stale citation (repaired in #7688).

On the numbers above

12/12 is witnesses passed in the named suite under claim_batch locally, not corpus coverage. Any inflow count this mechanism produces is scoped to the diff window it was handed and is a lower bound on nothing outside it — that is the whole reason InflowCountUnavailable exists as a distinct variant.

— deep-swift-442

The v1-test-migration node declares in its own out_of_scope that a test
written only in Rust counts against the finish line rather than toward
it. Nothing observed that inflow, so the declared rule and the enforced
rule differed invisibly. This adds the observation at the grain the rule
is stated in.

Deliberately NOT justified by any measured arrival rate: a rate is one
window's sample, and a mechanism argued from a sample invites deletion
the first window the sample inverts. The rate is what this measures.

AUDIT MODE, no refusal (following the acceptance-door split): a blocking
rule here lands on every lane in the wave at once, and that throughput
should be spent against a measurement, not an argument. The one thing
audit mode does not relax is fail-closed observation — an unobservable
diff, or an added attribute whose declaration never arrives, yields
InflowRefused with a typed reason, never InflowMeasured with an empty
list. Not-observed and nothing-arrived stay different states.

No new hand-Rust: the kernel is a pure fold over diff text, and the live
half reuses the floor's existing diff observation rather than opening a
second git surface, so it measures arrivals over exactly the window the
affected set was computed over.

MEASURED, and it corrected a number: over the gunbc#7652 -> 9f978aa
window the counter reports 18 arrivals where an identity join over the
two discovered populations reports 21 added. The gap is exactly three
RENAMED tests — a rename emits -fn/+fn with its #[test] line unchanged,
so the population join counts one departure plus one arrival and this
counter counts neither. Renaming a legacy test does not grow the
population the migration must drain; 18 is the arrival count, 21 was
identity churn. Both shapes are now pinned by fixtures.

Executed: 11/11 fixture witnesses PASS, including the two detection
witnesses asserting arrivals BY NAME (a fold counting attributes without
resolving declarations passes a count assertion and fails these), the
rename and migration-direction controls, and both refusal controls.
Kernel perturbed to drop the context-line arm: the attribute-above-
existing-function witness reds while the others stay green, so that arm
is load-bearing rather than defensive.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot force-pushed the session/deep-swift-442-inflow branch from 4d3719b to 7dd89d0 Compare August 2, 2026 20:13
…551)

The counter minted LegacyTestInflowAddition with the same two fields as
gunbc.legacy_test_behavior_disposition's LegacyTestBehavior, plus a
private id function producing the same path::fn string — and the carrier
note ARGUED that the matching string made the two joinable. That is the
nickname failure exactly: a second name for one concept, joinable only
until someone edits either serializer, with prose where an import edge
belonged.

An arrival is now a LegacyTestBehavior, imported and constructed here,
serialized by that module's legacy_test_behavior_id. The reading of Rust
source text stays forked because neither reading can call the other —
the host builtin walks the tree and cannot be pointed at a diff — but
the thing the readings PRODUCE is one type from one authority. The note
records the correction rather than quietly dropping the claim.

Also drops an unused gunbc.ci_spec import in the audit module.

11/11 fixture witnesses still PASS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in the pushed commit, not disputed — the finding is right and the note made it worse rather than better.

LegacyTestInflowAddition and its private inflow_addition_id are gone. An arrival is now a LegacyTestBehavior imported from gunbc.legacy_test_behavior_disposition and serialized by that module's legacy_test_behavior_id. The extraction-fork note previously claimed the two could be joined because the strings matched, which is precisely the nickname failure — joinable only until someone edits either serializer, with prose standing where an import edge belonged. The note now records that correction instead of the claim.

What remains forked is only the reading of Rust source text: the seed host bridge walks the working tree and cannot be pointed at a diff, and .dag cannot yet enumerate a revision's files, so neither reading can call the other. That fork keeps its declared dissolve-on, shared with the discovery scaffold it mirrors. The thing the readings produce is no longer forked.

Also dropped the unused gunbc.ci_spec import flagged in review 47547. On the Bool nit there: std.types and std.logic are both imported but Bool is taken from std.logic only, matching the surrounding workflow modules, so I left it.

11/11 fixture witnesses re-executed green after the change.

— sent from deep-swift-442

Two operator blockers on #7692.

BLOCKER 2 — the projection erased the refusal. inflow_observation_count
and _addition_ids mapped InflowRefused to an empty list, and count of
empty is zero, so an unobservable diff PROJECTED AS ZERO ARRIVALS unless
every caller remembered to consult inflow_observation_is_measured first.
The typed outcome existed to remove that footgun and the projection put
it back, one call-order mistake from the silent widening this carrier's
own note forbids.

A count and an id list now exist ONLY on InflowCountMeasured; a refusal
projects to InflowCountUnavailable carrying its reason, with no count to
read. Fail-closed is a property of the shape, not of caller discipline.
The witness that asserted count == 0 on a refusal encoded the erasure
and has been rewritten; a new control asserts a refusal and a measured
zero are not the same value.

BLOCKER 1 — no scheduled consumer. Nothing schedules, enrols, persists,
or renders the live observation, so after merge it runs only by hand.
Narrowing the claim rather than papering the gap: a declared scaffold
note names the local recipe and the dissolution trigger (a non-blocking
persisted receipt on a cadence). This is the same finding this lane made
against CoveredByWitness rows citing witnesses no lane executes, applied
to its own audit.

12/12 fixture witnesses PASS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Both blockers fixed and pushed. Verified each against the current code rather than acknowledged.

Blocker 2 — refusal projected as count zero

You were right that this was the load-bearing one, and right that call-order discipline was doing the work. inflow_observation_count returned 0 and inflow_observation_addition_ids returned [] on the InflowRefused arm. A reader who did not first match the observation got a plausible zero back from a refusal — the fabricated-plausible-output arm of DESIGN §5, inside the very carrier whose purpose is to make a missing measurement visible.

Fixed by removing the projections that could lie, not by documenting the order to call them in:

type LegacyTestInflowTally
  = InflowCountMeasured { count: Int, ids: List<String> }
  | InflowCountUnavailable { reason: NonEmptyStr }

A count and an id list now exist only on the measured arm — there is no count field to read on an unavailable tally, so the erasure is unrepresentable rather than merely discouraged (§5 construction over validation, §4b's top rung rather than a check).

The witness that asserted inflow_observation_count(refused) == 0 was itself encoding the erasure as the contract, so it was rewritten rather than kept. Its replacement inflow_refusal_has_no_count_to_read asserts that a refusal and a measured zero are not the same value — which is precisely the distinction the old witness denied.

Blocker 1 — no durable live consumer

Applied the wall to my own audit, as you said. The honest finding is that the audit has no scheduled consumer today, so I narrowed the claim instead of papering the gap: legacy_test_inflow_no_scheduled_consumer_note is a declared scaffold naming the exact local recipe

GUNBC_CI_DIFF_BASE=<base> GUNBC_CI_DIFF_HEAD=<head> claim_batch --wet \
  --source-root src/v2 --source-root dag \
  --entry src/v2/workflow/legacy_test_inflow_audit.dag \
  --functions legacy_test_inflow_live_observation_holds

and the dissolution trigger: a non-blocking persisted receipt on a cadence. The counter is honest about being run-on-demand rather than described as continuously measuring.

The same gap in general is what #7700 walls at the disposition grain — a CoveredByWitness row citing a witness no scheduled lane executes now refuses with a typed reason, and unknown does not admit.

12/12 fixture witnesses green by execution.

— sent from deep-swift-442

@gunbai-bot gunbai-bot Bot changed the title Observe legacy-test inflow at diff grain (audit mode, no gate) Legacy-test inflow: a manual audit mechanism, not continuous observability Aug 3, 2026
@briansrls
briansrls merged commit cc56032 into main Aug 3, 2026
5 checks passed
@briansrls
briansrls deleted the session/deep-swift-442-inflow branch August 3, 2026 02:23
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