Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f9083ad
Rebuild the per-entry emission instrument as a .dag entry point
Aug 25, 2026
500d298
Bind the execution subject, and require cargo's terminal message
Aug 25, 2026
a42b245
The emit population states whether it is the whole population
Aug 25, 2026
8e95f46
The ratchet consumer: an emit-clean frontier over a discovered roster…
Aug 25, 2026
fe4a98c
Hash the discovery policy into the roster digest; avoid two corpus-wi…
Aug 25, 2026
3b62c9e
Give the verdict-entry accessor its consumer: every verdict names its…
Aug 25, 2026
fc06819
Fix the one blocking diagnostic: a renamed fixture binding missed ins…
Aug 25, 2026
c56f7f1
Adopt the superseded contract: three-valued outcome, the enrolment wa…
Aug 25, 2026
84271e0
Hole 2's mechanism was wrong: a parse failure under a recognized head…
Aug 25, 2026
5d1c8a8
The dual denominator: a file the index cannot classify blocks instead…
Aug 25, 2026
0c2d1b9
Four stale sentences, not one: the corrected mechanism had not reache…
Aug 25, 2026
fa36687
Merge branch 'session/gentle-bee-495' into session/gentle-bee-495-den…
Aug 25, 2026
f7c2f2b
A zero-file tree is not a clean entry: do not rest the load-bearing a…
Aug 25, 2026
3cfff69
Restore the standing section my own block replacement deleted
Aug 25, 2026
200bfbd
Delete the FIPS 180-4 fork in sha256sum: consume the citation extdeps…
Aug 25, 2026
de373ca
Merge branch 'session/gentle-bee-495' into session/gentle-bee-495-den…
Aug 25, 2026
d17caa5
The claim asserting the refusal string went stale when I corrected th…
Aug 25, 2026
e19639b
The printing-discipline probe pins one path, not the compiler: correc…
Aug 25, 2026
dd0a053
Subject identity for the emission ratchet: a key of root, kind and re…
Aug 25, 2026
ccd7e1c
A measurement over a subject whose boundary did not hold is not a mea…
Aug 25, 2026
76bbb1d
A sixth copy of string-list membership, differing only in parameter n…
Aug 25, 2026
80c479e
roster_identity had two declarers: a per-entry compile sees one, the …
Aug 25, 2026
bdbd401
Merge main
Aug 25, 2026
98c284f
Merge the roster_identity de-collision and main
Aug 25, 2026
324dfcb
Merge the de-collision and main
Aug 25, 2026
af16009
The witness declares imports, so its disposition type must be importe…
Aug 25, 2026
8f5d066
A keys() accessor has to answer something for the refused arm, and th…
Aug 25, 2026
ae4c4d5
The enrolment claim still asserted the pre-rename wording, so it went…
Aug 25, 2026
5824ab9
Merge the enrolment-assertion fix from the base branch
Aug 25, 2026
a4c8036
Merge the enrolment-assertion fix up the stack
Aug 25, 2026
76d5f09
Merge main
Aug 26, 2026
60ce9ed
Merge main via the base branch
Aug 26, 2026
39bf5fd
Merge main up the stack
Aug 26, 2026
e41f599
Merge main: take the squash-merged #9213 as the base and re-apply the…
Aug 26, 2026
24d29b6
Merge branch 'session/gentle-bee-495-denominator' into session/gentle…
briansrls Aug 26, 2026
47a213f
Merge main after #9231 squash-merged: three-way against the last shar…
Aug 26, 2026
f495de5
Take the citation repair over the stale wording, and record main's th…
Aug 26, 2026
cd89087
Answer the dual-denominator question in the carrier, and decline the …
Aug 26, 2026
4d32a14
WITHDRAWN: the three "blocking diagnostics on main" in the previous c…
Aug 26, 2026
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
53 changes: 47 additions & 6 deletions dag/gunbc/emit_subject_clean_frontier.dag
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import std.roster_frontier {
frontier_row_well_formed,
frontier_subject_key
}
import gunbc.emit_subject_identity {
SubjectMembership,
MembershipInvariantStanding,
MembershipInvariantHolds,
MembershipInvariantViolated,
MembershipInvariantNotEvaluated,
candidates_within_closure
}
import gunbc.emit_diagnostic_observation {
GunbcDiagnostic,
EmittedFileCount,
Expand Down Expand Up @@ -101,10 +109,10 @@ import tools.emission_entry_instrument {
// later because a carrier that does not name its own gaps is the rung inflation DESIGN §4b(1) calls
// worse than sitting low: a class whose carrier already claims the rung never ranks for climbing.
//
// HOLE 2 IS CLOSED BY THIS CHANGE AND ITS BLOCK IS KEPT RATHER THAN DELETED, because the closing is
// the evidence -- a hole that vanishes on the commit that fixes it leaves a reader unable to tell a
// gap that was closed from one that was never found. The numbering does not renumber for the same
// reason: hole 3 is hole 3 wherever it is cited.
// HOLE 2 IS CLOSED (gunbc#9231, the dual denominator) AND ITS BLOCK IS KEPT RATHER THAN DELETED,
// because the closing is the evidence -- a hole that vanishes on the commit that fixes it leaves a
// reader unable to tell a gap that was closed from one that was never found. The numbering does not
// renumber for the same reason: hole 3 is hole 3 wherever it is cited.
//
// HOLE 1 -- A BLOCKED SUBJECT GAINING ANOTHER BLOCKER IS HELD, NOT REFUSED.
//
Expand Down Expand Up @@ -143,7 +151,7 @@ import tools.emission_entry_instrument {
// `blocked_subject_gaining_a_blocker_is_held_not_refused` in the witness. It is GREEN while the
// hole is open and goes RED the moment the wall lands, which is what forces its own deletion.
//
// HOLE 2 -- CLOSED BY THIS CHANGE, AND RECORDED BECAUSE THE CLOSING IS THE POINT.
// HOLE 2 -- CLOSED BY gunbc#9231, AND RECORDED BECAUSE THE CLOSING IS THE POINT.
//
// WHAT IT WAS: the universe was discovered from the PARSED DECLARATION INDEX alone, so a `.dag`
// file the index could not CLASSIFY was not a subject at all. The fold was never asked about it,
Expand Down Expand Up @@ -222,7 +230,7 @@ import tools.emission_entry_instrument {
// by this carrier's own rule, stops the line. THAT IS THE CORRECT BEHAVIOUR AND NOT THE HOLE --
// measuring only the quiet subjects and reporting the population as complete is the failure this
// carrier exists to refuse. The hole is that THIS IS NOW THE LAST HARD PREREQUISITE ON ENROLMENT:
// hole 2's dual denominator landed in this same change, so the reader's reach is what remains --
// hole 2's dual denominator has landed, so the reader's reach is what remains --
// until the instrument can recover a talkative subject's scope, a realistic universe folds to a
// wall of not-evaluated rows rather than to a standing. Nothing about that is unsafe, and it is
// precisely why the enrolment wall must not be read as satisfied merely because the denominator
Expand Down Expand Up @@ -536,6 +544,7 @@ type EmitNotEvaluatedCause
| PopulationUnreadable { stage: EmissionStage, cause: String }
| ExtentUnestablished
| EmittedNothing
| ResolutionPopulationExceedsClosure { outside: List<String> }

fn emit_not_evaluated_cause_text(cause: EmitNotEvaluatedCause) -> String {
match cause {
Expand All @@ -562,6 +571,11 @@ fn emit_not_evaluated_cause_text(cause: EmitNotEvaluatedCause) -> String {
)
EmittedNothing =>
"emit reported a tree of ZERO files and printed no blocking diagnostic — an entry that produced no output and no complaint has not been shown to emit, and reading it as clean would be the strongest possible verdict drawn from the weakest possible observation"
ResolutionPopulationExceedsClosure { outside: os } =>
concat(
"the subject resolved names from OUTSIDE its own closure, so what was measured is not the subject the roster names: ",
join(os, ", ")
)
}
}

Expand Down Expand Up @@ -1100,3 +1114,30 @@ fn emit_ratchet_report_text(r: EmitSubjectCleanRatchet) -> String {
// empty roster that greened would be the absorbing fallback; one that refuses is a debt roster with
// nothing yet admitted to it.
data emit_subject_clean_admissions: List<EmitDebtAdmission> = []


// ---------------------------------------------------------------------------------------------
// A MEASUREMENT OVER A SUBJECT WHOSE BOUNDARY DID NOT HOLD IS NOT A MEASUREMENT OF THAT SUBJECT.
//
// If a subject resolved names from outside its own closure, then the population the instrument read
// belongs to a larger thing than the roster names, and its verdict -- clean OR blocked -- is about
// something else. The outcome is therefore replaced with NotEvaluated, which refuses, rather than
// being kept and annotated, which would let a boundary failure pass as a clean subject.
//
// THE UNOBSERVED ARM DELIBERATELY DOES NOT MASK. The candidate population is unobservable today
// (`gunbc.emit_subject_identity` `resolution_candidate_membership_unobservable`), so this relation
// reports NOT-EVALUATED for every real subject right now. Turning that into a NotEvaluated OUTCOME
// would refuse the entire roster on the strength of a measurement nobody took -- the absorbing
// fallback wearing the fail-closed name. An unobserved invariant leaves the measured outcome
// exactly as it was, and the gap is carried by the declared row rather than by a blanket refusal.
fn emit_outcome_under_membership(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route membership validation through the ratchet fold

When callers use the normal measurement path, a violated subject boundary never reaches this helper: in the reviewed tree, emit_subject_reading still derives its outcome directly with emit_subject_outcome, fold_emit_subject_clean_ratchet accepts no membership observations, and a repo-wide caller search finds emit_outcome_under_membership only in witness tests. Consequently, even observed out-of-closure candidates remain clean or blocked in the actual ratchet; integrate this transformation into reading construction or require membership in the fold API.

Useful? React with 👍 / 👎.

membership: SubjectMembership,
outcome: EmitSubjectOutcome
) -> EmitSubjectOutcome {
match candidates_within_closure(membership: membership) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the closure-to-checked half of the invariant

When resolution_candidates ⊆ closure holds but closure ⊆ checked is violated, this match returns the original outcome unchanged because it consults only candidates_within_closure. For example, candidates/closure ['a'] with an empty checked population preserves EmitSubjectClean, even though closure_within_checked classifies the membership as violated and the module defines this as a subject measured over less than it declared. Evaluate both relations and turn either observed violation into a not-evaluated outcome.

Useful? React with 👍 / 👎.

MembershipInvariantHolds => outcome
MembershipInvariantNotEvaluated { relation: _, cause: _ } => outcome
MembershipInvariantViolated { relation: _, outside: os } =>
EmitSubjectNotEvaluated { cause: ResolutionPopulationExceedsClosure { outside: os } }
}
}
Loading
Loading