Skip to content

product.data_category: give the six markers their reference functions, earned by their first sink - #11343

Merged
gunbai-bot[bot] merged 20 commits into
mainfrom
session/snappy-pike-154
Sep 15, 2026
Merged

gunbai-bot[bot] merged 20 commits into
mainfrom
session/snappy-pike-154

Conversation

@briansrls

@briansrls briansrls commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

What

product.data_category declares eight markers. Only two carried reference functions — personal_identity_ref and build_output_ref, earned from their mints. This adds the other six.

Why now, and why these are earned rather than speculative

The module's own rule: a marker gains its reference function with its first mint or SINK. These rows are that first sink.

The consumer is gunbc-private strategy.data_map, which binds one marker per description row and hands it to product.data_class admit_data_effect. That fold compares marker identity rather than the type argument, because a type argument has no value at run time — which is why every Classified and every Sink carries the declaration reference in the first place.

Without these six, the private map would re-spell module_path: "product.data_category" at six sites. That is the fork this module exists to prevent: the annotation above these functions already says "these are the only spellings of the references; a consumer that needs one imports it rather than re-spelling the module path" (DESIGN §3).

The annotation correction is not cosmetic

The annotation claimed only two references exist. It stood above two while the corpus needed eight, and it would have gone on asserting it. Prose asserting what the code contradicts rots silently, because no Accepted program can read it (DESIGN §4c).

I removed the count rather than updating it. A count in prose is a second census standing beside the functions themselves — the exact duplication that made the sentence wrong in the first place, and it would be wrong again at the ninth marker. What replaces it is the reason the six are earned, which does not go stale when the population changes.

§3c — consumer and executing route

Declarations added six fn *_ref() -> DeclarationRef
Consumer strategy.data_map handling_rows_for_category, binding c.marker
Executing route product.data_class admit_data_effect, comparing marker identity
Lands where gunbc-private#118, from eea5674 on session/quick-owl-739-blocker1-wip

This is the first half of a forced order. The private change imports these six functions, so it cannot land first — pushing it onto #118 before this would red that PR for something that is not a defect. Public lands, then the private side rebases onto #118.

This PR is therefore a declared frontier for one round, not a dangling one: the consumer exists and is written and pushed, it is named above, and the trigger is this PR merging. If this lands and the private side does not follow, these six become dangling and should be reverted.

Evidence

  • compile --source-root dag --source-root src/v2 --entry dag/gunbc/product/data_category.dag → rc=0, 0 blocking errors, 96 advisories (the standing gunbc.compile_clean_diagnostic_policy count), 10 files emitted. Run remotely against this exact sha.
  • The compiled tree carried the change: the file at 8f0f0565e98 has all eight ref functions, and that sha is the branch tip on origin.
  • Control that must fail: the release binary rejects --definitely-not-a-real-flag, so the compile reached a real compiler. Honest scope: that control was captured on the immediately preceding dispatch of the same build recipe; this dispatch's control line was lost to output truncation rather than not run.
  • Every marker now has exactly one reference function — eight types, eight functions, checked by name.

What this PR itself cannot prove, and where the evidence actually lives

No red is authorable here. Six one-line functions returning a decl_ref have no behaviour to make wrong, and the frontier rows are data. Asserting a wall in this PR would be a decoration citable as coverage (§4b: "ask whether the check's RED is authorable before writing the check").

The discriminating evidence is on the private side, where the binding this PR exists to enable is exercised. Measured by fierce-bee-436 on a composed tree — public main@0d96f5e27 + these six functions applied to a throwaway worktree + the private tree as an overlay, instrument /cargo-target/debug/gunbc, vintage control rc=0 before any arm:

arm mutation result
A clean all flags ok, _main rc=0 — positive control
B one marker → the private ref markers_are_public=RED, markers_are_expected=RED
C two markers swapped, both still public markers_are_public=ok, markers_are_expected=RED, rc=1
A2 restored after the mutations all flags ok, _main rc=0 — positive control

Arm C is the one that matters, and its shape is stronger than a bare red. markers_are_public stayed ok while markers_are_expected went RED. A swap leaves both markers in product.data_category, so a module-path check structurally cannot see it; only the independently-spelled expectation join catches support communications wearing the job-log marker. The two conjuncts are therefore two checks, not one written twice — which is what an earlier revision of that file was refused for.

A2 is not ceremony. Re-running the clean arm after the mutations is what separates "the reds were the mutations" from "the tree accumulated damage".

One number is missing and is not being inferred: arm B's _main rc. That pass was cut off by a 50-minute timeout (EXIT=124) partway through B, so C and A2 come from a second pass against a freshly restored overlay. B's two RED flags are real and from the first pass; its _main rc was never captured and is not reported.

Compile evidence for this PR

  • data_category.dag → rc=0, 0 blocking errors.
  • census_closure_frontier.dag (the module that consumes the new roster) → rc=1, 1 blocking error that is pre-existing and not from this change: error[dag/extdeps/ebay/inventory.dag:385:14] — a file this branch never touches. Established by baseline rather than assumed: the same entry point on origin/main with this change removed produces the same single error. Note this is --entry scope, which is not CI scope in either direction, so it is not a claim that main is red.
  • Control that must fail: the release binary rejects --definitely-not-a-real-flag (rc=2), so the compile reached a real compiler.
  • The approving review states "Builds and tests were not run", so the compile evidence above is mine, not the reviewer's.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2

Brian Searls and others added 11 commits September 12, 2026 18:32
…tside the producer

Three lanes hit absent_reads_identically_to_never_looked independently on
2026-09-12. This is the M2 compliance spine's receipt, written by the lane
that diagnosed it rather than transcribed from a report of it.

The axis it adds: every specimen already on the row is an instrument that
failed to reach its subject, repaired by a positive control or a denominator
-- things a producer can assert about its own run. This one has a correct
instrument, an honest carrier and a truly empty value, and the affirmative
verdict is supplied by a READER OUTSIDE THE SYSTEM. An empty customer
disclosure does not read as "nothing was assessed"; it reads as "there is
nothing to disclose". No control fires, because the instrument worked. The
repair is refusal to render, not instrumentation.

Two further receipts: the prevented form one layer down, where
ProviderPathStanding's Located | Absent | Unread constructor made the
collapse unwritable on the Hetzner census (zero Absent arms taken across
nine paths on two routes, because nobody had stated those paths do not
exist); and the two independent causes of the empty population, whose
remedies differ and which a single empty value cannot carry.

Filed with the miss that produced it: the lane manager twice instructed the
worker to ship the empty disclosures and the worker refused both times.

No rung, ceiling or trigger is added. The row carries none, and the reason
is already filed as obligation_fields_as_prose_make_their_own_grain_check_undecidable
-- a trigger is not a field on RecurringFailureMode, so adding prose shaped
like one would be the agreement-by-spelling this corpus refuses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
…hat nobody does

The review approved #11196 partly on the grounds that the new receipt "names
sibling rows via [[...]] identities". It did not -- it contained zero sibling
links. The approval credited the diff with a property it lacked.

That omission is the defect the receipt immediately above mine documents: the
absence family's own audit measured exactly one intra-family citation across
nine members, making the family unreachable from its own members at reading
time. I appended a receipt one paragraph below that finding and named no
sibling.

Now names the three nearest neighbours and states why each is NOT this class,
which is the pairwise non-substitutability test the family audit uses:
predicate_vacuously_true_on_an_empty_domain (domain genuinely empty, reader
inside the system), required_evidence_absent_reads_as_evidence_of_pass
(missing thing is evidence owed to us; here the record is complete), and
empty_observation_narrow (observation too narrow to have seen the subject).
All three repairs leave the empty artifact renderable, and none stops a
counterparty reading zero disclosures as zero to disclose.

All three cited rows were verified to exist under
dag/gunbc/recurring_failure_mode/ before citing them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
…t never calls

Two instances on 2026-09-12, found independently by two lanes, both of the
same rule and both of DESIGN 4c annotation attachment.

One tool blind: claim_batch resolves and EXECUTES .dag modules without the
annotation-attachment check, which runs only at gunbc compile. A lane held
155 green witnesses that were true and structurally blind to an unattached
annotation that then redded public CI.

An entire repository with no caller: between its two workflows, gunbc-private
invokes the binary exactly once, as `gunbc run`, never `gunbc compile`. So
4c has NO executing consumer in that repo. A compile over the private
composed root reports 19 blocking 4c errors, all in one file, matching
exactly the 19 indented annotation lines it carries on main.

The evidence that makes it a class rather than an oversight: that file
arrived through gunbc-private#89 -- six review rounds, four REQUEST_CHANGES
across three providers, an approval on the final head, both lanes green at
merge -- and nineteen blocking violations rode in anyway. Neither the
reviewers nor CI were wrong; no mechanism present could execute the check.

Distinguished from its four nearest neighbours by where each puts the
missing edge: schedule membership (witness_module_absent_from_the_executed_set),
preparation population (preparation_membership_derived_from_the_execution_selector),
denominator ownership between two executing actuators
(green_reported_over_a_population_the_instrument_does_not_own), and the
census/exclusion intersection behind a rung claim
(required_lens_red_control_never_executes_from_its_home). None of their
repairs is substitutable for this one: the repair here is a join from a
check, to the entry points that execute it, to the contexts holding its
subject.

All four cited rows verified present before citing them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
still-dove-458's silent-console receipts and its own twelve-hours-later
correction landed on main while this branch carried three receipts of its
own. Both sides append to the same `receipts` list, so git could not
choose -- and choosing would have been wrong either way.

Resolved by keeping ALL FIVE, main's first and this branch's appended,
because they are separate specimens of one class rather than competing
versions of one. This is the resolution this PR's own body specified in
advance, for exactly this collision: three lanes were known to be
appending to this row on the same day.

Verified after resolving rather than assumed: 23 receipt strings, quotes
balanced, no escapes, and both sides' content present by content check
rather than by line count.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
Both found by review at d5059d9, both mine, and both the same failure the
receipts are about: a sentence asserting more than the evidence carries.

ONE -- "where the distinction is a CONSTRUCTOR the author cannot collapse
it". It overstates what the type does. ProviderPathAbsent and
ProviderPathUnread force an EXPLICIT CHOICE; they do not prevent choosing
the wrong arm, and they do not prevent citing evidence that does not support
the arm chosen. The representation preserves the distinction; the author
still has to be honest. Narrowed to say exactly that, and to say what the
census actually did -- under pressure to look complete it chose Unread --
which is a reported fact rather than a property of the carrier.

TWO -- "neither could have caught it by being more careful". That exceeds
the evidence. A missing invocation explains why those CI executions were
blind; it does not establish that a reviewer could not have read the
annotations by eye or invoked the compiling entry point. Narrowed to what is
established: the recorded executions did not perform the check, no mechanism
in that repository executed it, and none of the reviewers who could have
looked did.

The second one is worse than the first, because it was doing rhetorical work
-- absolving the reviewers made the "the wall was absent" point land harder,
and that is exactly when a claim stops being measured. A receipt arguing that
walls must be observed to refuse does not get to assert an unobservable
counterfactual about who could have refused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
All prose, no mechanism change. Side-chat review at 11d681a named the first
two; the third is a typo my previous narrowing introduced.

1. "review and CI both green and both CORRECT: no mechanism present could have
   executed the check". CI's green IS correct and says nothing about the class,
   because no mechanism it ran executes the check. Review's green is NOT thereby
   vindicated -- a reader could have caught these by eye, or by invoking the
   compiling entry point. Merging the two turns a missing wall into nobody's
   omission, which is precisely the excuse a ledger row must not manufacture.
   The receipt now keeps them apart.

2. "...passed six review rounds because nothing COULD execute the check". The
   evidence establishes only that nothing DID. The wider phrasing excuses the
   reading along with the machinery, and the receipt now says so about its own
   first landing rather than silently swapping the word.

3. "whereas and where it is a RENDERED EMPTY LIST" -- a fragment left behind
   when I narrowed the constructor sentence in the previous commit.

The PR body carried the ORIGINAL constructor overclaim ("the author cannot
collapse it") that the ledger had already been narrowed away from, so the two
disagreed. The body is now the narrow claim: a constructor forces an explicit,
attributable choice; it does not make the wrong arm unwritable --
ProviderPathAbsent was there to be picked, and the census chose Unread.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
…, earned by their first sink

PersonalIdentity and BuildOutput earned their ref functions from their mints.
The other six had none, so the first consumer that needs them -- gunbc-private
strategy.data_map, which binds one marker per description row and hands it to
product.data_class admit_data_effect -- would have had to re-spell the module
path at six sites, forking the only spelling this module exists to keep single
(DESIGN 3). The module's own rule is that a marker gains its reference function
with its first mint or SINK; these rows are that first sink.

The annotation above them claimed only two references exist. It stood above
two while the corpus needed eight, and prose asserting what the code
contradicts rots silently because no Accepted program can read it (DESIGN 4c).
The count is gone rather than updated -- a count in prose is a second census
beside the functions themselves -- and the reason the six are earned is stated
in its place.

Consumer and route (DESIGN 3c): gunbc-private strategy.data_map
handling_rows_for_category binds c.marker from these functions; the executing
route is product.data_class admit_data_effect, which compares marker identity
rather than the type argument. That private change is pushed at eea5674 and
lands on gunbc-private#118 after this.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
@gunbai-bot gunbai-bot Bot changed the title m2-compliance-spine: pin the contract standard, census provider routes, and build the sealed permit (M2 ranks 2-12, excluding 6) product.data_category: give the six markers their reference functions, earned by their first sink Sep 14, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 14, 2026 05:23
Brian Searls and others added 7 commits September 14, 2026 05:41
…by the dissolution census

Review 65961 refused the previous revision and was right: the six functions
have no call site in this tree, and the consumer was named only in a // block.
DESIGN 4c settles that an annotation is never evidence a machine claim holds,
because no Accepted program can read one -- so "the consumer is the private
map" was a claim with nothing behind it, which is the same defect this module's
annotation had when it said only two references exist.

DESIGN 3c gives three honest states: consumed by execution here, a declared
frontier with its trigger stated BESIDE it, or dangling. These are the second,
and this makes that machine-readable: data_category_frontier_rows carries one
FrontierRow per function, each naming its own symbol, its reason, and a
dissolution that names the consumer (strategy.data_map handling_rows_for_category),
the executing route (product.data_class admit_data_effect, comparing marker
identity), and the trigger (that binding landing from eea5674 on
gunbc-private#118). Each row states what does NOT retire it: a public witness
calling the function, which would prove it evaluates and not that anything
consumes the identity it names.

The rows are enrolled in gunbc.census_closure_frontier
census_closure_frontier_row_groups, so the dissolution census folds them like
every sibling group -- that fold is the executing consumer, which is what the
previous revision lacked.

Kept separate from data_class_frontier_rows deliberately. That roster carries
the frontier for the MARKERS; this one carries it for the REFERENCE FUNCTIONS.
They dissolve together in practice and are still two declaration sets in two
modules, so merging them would put one module's declarations in another
module's roster (DESIGN 3).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
Review 65976 refused the previous revision and was right: the six
frontier_row_decl rows were one authored row copied six times, with only the
symbol substituted inside otherwise identical reason and dissolution strings.
That is DESIGN 2 authored duplication -- the per-name text was readability, not
six distinct facts -- and six copies is also the growth surface, since a
seventh marker would have meant a seventh paste.

The repo already carries this exact shape: extdeps.deepseek.deepseek_v4_1_flash
deepseek_v4_1_flash_frontier_rows takes decl_names plus one shared reason and
one shared dissolution and maps frontier_row_decl over them. This is that call
with the six reference-function names, so the fold is reused rather than a
second one invented (DESIGN 3).

The six names are now a list, which is also the honest shape of the fact: they
share ONE reason (no public caller, one private consumer) and ONE trigger. The
dissolution says what it is sufficient for at the right grain -- deleting a NAME
from the list, with the roster emptying when all six are imported -- rather than
implying the whole roster retires on the first import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
…allers consume it

Review 65996 made two findings and the second is the one that matters.

FIRST: data_category_ref_frontier_rows was a second copy of the deepseek
module's fold -- same signature, same map(decl_names, n => frontier_row_decl(..)),
differing only in how the module path reaches decl_ref. So the concept "one
shared reason and one shared dissolution mapped over a list of decl names" had
two authorities, which is DESIGN 2's re-invention test failing: net concepts
must not grow. Its home is std.roster_frontier, which already owns
frontier_row_decl. frontier_rows_for_decls now lives there, parameterised by
module path, and BOTH callers consume it: product.data_category directly, and
extdeps.deepseek.deepseek_v4_1_flash by delegation, keeping its own name because
its callers cite it and the module path is its fact to supply. The second
instance is the moment to lift, which is why this lands now rather than on the
third roster.

SECOND, AND WORSE: my previous commit message said "the fold is reused rather
than a second one invented (DESIGN 3)". It was COPIED, not reused -- there was
no import of the deepseek fold anywhere in the diff. The stated compliance and
the diff disagreed, and the DESIGN 2 claim was the thing that commit rested on.
A commit message asserting a law it does not satisfy is worse than one that says
nothing, because it is the artifact a later reader trusts when deciding whether
the question was already asked.

Also single-spelled the deepseek module path while delegating: the literal was
written inline in its fact builder and the delegation needed it too, and two
spellings of one module's own name is the DESIGN 3 fork in miniature -- rename
the module and one of them silently keeps naming the old one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
…e them

Review 66072 found the defect this PR was supposed to prevent, created by this
PR. Three of the six functions -- source_and_build_input_ref,
metering_telemetry_ref, ci_secret_ref -- already had PUBLIC call sites, spelled
the long way as decl_ref(module_path: "product.data_category", ...) in
product.data_class's own frontier rows. So the diff minted a second spelling
beside an existing one rather than cutting over, which is DESIGN 3 nicknaming,
and it made this module's own annotation false at three sites: "these are the
only spellings of the references" was contradicted by the tree the moment the
functions landed. DESIGN 3's replacement rule is to cut over at the root, not to
leave X and Y both answering for one fact.

Cut over: product.data_class imports the three and calls them at those rows.

A CENSUS FOUND A FOURTH SITE THE REVIEW DID NOT NAME. Grepping the long-way
spelling corpus-wide, dag/test/probe/bare_string_from_boundary_probe.dag was
re-spelling the path for PersonalIdentity while personal_identity_ref() has
existed all along. That one is pre-existing rather than created here, and it is
the same fork, so it is cut over too. There are now ZERO long-way spellings of
this module path outside the module itself.

The frontier roster drops to the three that are genuinely uncalled in public,
and its reason says which three left and why -- a frontier claiming "no public
call site" over names that have one is worse than no frontier, because it is
the kind of row a later reader trusts instead of re-checking.

Two counts removed while here, both of which had just gone stale AGAIN in the
same way this module's original annotation did: the header said SIX references
with no call site (now three) and the dissolution said the roster empties when
"all six" are imported. Both now name the list instead of counting it. That is
the third time a transcribed count in this one file has been wrong; the list is
the census.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
The generated-artifact FAIL was stage0-mirrors, not the registry: adding
frontier_rows_for_decls to std.roster_frontier moved the .dag authority and
nothing installs the regenerated mirror on a branch, so the committed
std_roster_frontier.rs stayed behind its source.

TWO POPULATIONS, TWO ACTUATORS, AND THEIR SUMMARY LINES READ ALIKE. The
heal-generated-artifacts lane covers the gunbc.generated_artifact REGISTRY and
was passing the whole time -- registry-projections rostered=40 adjudicated=40
matches=40 drifted=0. It shares no population with the ~156-file stage0 Rust
mirror, which only claim_executor --required-regen produces. Reading heal's
green as cover for the mirror is what kept this red across three pushes.

Regenerated UNSCOPED (no --regen-affected-scope): a scoped first half renders a
different population than --required-regen-fixed-point and reports
fixed_point_equal=false as though the tree were non-idempotent.
planned=155 executed=155 adjudicated=155, declared_divergent=1 [main.rs].

THE CANDIDATE WAS DIFFED, NOT COUNTED. A per-artifact count is evidence about
the artifacts counted and silent about the rest, so every one of the 206
candidate files was compared against its committed counterpart rather than
trusting the one filename the summary named. Exactly one differs, and its diff
is exactly this PR's change: the new frontier_rows_for_decls, plus List joining
NonEmptyStr in the std_types import. No unrelated content rode along.

RUN LOCALLY BECAUSE REMOTE STRUCTURALLY CANNOT. claim_executor --required-regen
refuses on BuildBuddy with HostBudgetUnreadable -- no cgroup memory.high or
memory.max binds the runner, and GUNBC_MEMORY_BUDGET_BYTES may only LOWER a
verified ceiling, never establish one. That refusal is correct: the arm it
replaced admitted against the machine-wide reading and was SIGKILLed at rc=137.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
…d import

Review 66128: on main, deepseek_v4_1_flash_fact had exactly one call site --
inside deepseek_v4_1_flash_frontier_rows. This PR rewrote that body to delegate
to std.roster_frontier frontier_rows_for_decls and left the fact function with
zero call sites, which is DESIGN 3c's dangling state and its verbatim tell: a
declaration with no call site in the closure. Censused corpus-wide before
deleting -- the vllm_recipe_deepseek_v4_1_flash_fact hits are a different
symbol, so nothing else reads it. frontier_row_decl went unused in that module
at the same moment and is dropped from the import; DeclarationRef and
WholeDeclaration are still read at the declaration row and stay.

A lift removes call sites as well as adding them, and I checked only the
direction I was adding.

The module-path constant's annotation is corrected with it. It said "both the
fact builder below and the frontier delegation need it" -- true when written,
false the moment the builder went. That is the third stale count-or-consumer
sentence this PR has produced, all in annotations I wrote while explaining why
prose beside code rots (DESIGN 4c). The constant keeps one consumer, which is
still better than a bare literal inside the delegation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UNzi2Ht3mXzngnKsdZnfH2
@briansrls
briansrls added this pull request to the merge queue Sep 14, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 14, 2026
The frontier's dissolution required "that binding lands on gunbc-private#118 from
eea5674". It cannot. #118 merged at 3406db44c WITHOUT the binding, and eea5674 is
preserved as a WIP side-branch commit marked DO NOT MERGE. The row would have sat
here indefinitely reading as tracked while its trigger could never fire.

DESIGN section 4b(3) already rules this: a trigger must name the CAPABILITY, not
an artifact that would contribute to one. The usual failure is a trigger that is
merely INSUFFICIENT -- satisfied while the capability stays dead. This is the same
rule from the other side, where the named artifact is not insufficient but
IMPOSSIBLE, and the failure is the mirror image: never satisfied while the
capability may well be alive.

The trigger is now the capability -- gunbc-private strategy.data_map's handling
rows IMPORT these names from this module as it stands on public main, by whatever
change carries that import -- with a read obligation that whoever lands it names
their change at that time. No PR is named, deliberately: naming a not-yet-existing
one would repeat the original mistake at one remove.

SUFFICIENT FOR and the NOT-satisfied-by-a-public-witness clause are kept verbatim.
Both were right and neither is what the refusal was about.

One line changed. The six functions are untouched.

data_category.dag compiles through emit and
data_class_marker_identity_witness_test classified_over_two_markers_is_two_identities_in_the_projection
returns true.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D3CjFsyzbu46mYw6gJ5VfN
…ion exclusion, so this PR's edited probe fixture is no longer seeded into strict preparation

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qc3VJ9KnBA7aXp2ZQjCwTq
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 15, 2026
Merged via the queue into main with commit 828ecce Sep 15, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/snappy-pike-154 branch September 15, 2026 16: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