Skip to content

Spark declared-unit digest: one sealed DigestStdin per bind at harness_bind_seat; delete the artifact store (Option A) - #11506

Closed
gunbai-bot[bot] wants to merge 47 commits into
mainfrom
session/bright-gull-790
Closed

gunbai-bot[bot] wants to merge 47 commits into
mainfrom
session/bright-gull-790

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Auto-opened by session-dashboard for session royal-ram-691.
Pushing to session/bright-gull-790 advances this PR.

Worker attestation

Before flipping this PR to ready for review, confirm each item:

  • Title describes the change (not the session id or branch).
  • PR body summarises what and why (replace the TODO below).
  • Tests run: name the command (e.g. npm test, cargo test) and the result.
  • If this closes a work item, the body contains a Closes #N directive.
  • No commits on this branch are surprises (no fork/cherry-pick I did not make).
  • No secrets / credentials / large binaries staged.

Summary

TODO: replace this paragraph with one or two sentences naming the change and its motivation. Reviewers read this first.

Test plan

  • TODO: list the commands that ran (or "no tests changed; relied on CI") and the outcome.

Brian Searls and others added 30 commits September 16, 2026 13:37
harness_serving_route can compare SHA-256 of those bytes with the observed unit digest instead of treating the declaration as unavailable.

Co-authored-by: Cursor <cursoragent@cursor.com>
…e the production mint.

The climb already supplies SHA-256 at spark_pair_head_unit_declared_digest; the leftover obligation row had no production reader. The wet witness now calls that fold over the realized head unit.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tStdin lane.

harness_serving_route now hashes, so leaving that inhabitance on hermetic discovery refused before a verdict. The claim still drives bind_candidate and harness_serving_route.

Co-authored-by: Cursor <cursoragent@cursor.com>
Git-plumbing mock coverage must not retire SHA-256 stdin witnesses.

Co-authored-by: Cursor <cursoragent@cursor.com>
Per-candidate DigestStdin was authored duplication of a roster-static value.

Co-authored-by: Cursor <cursoragent@cursor.com>
…rows.

The floor refused nine TargetChanged bindings; touching the roster also retires #11138.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ness drives production's roster-and-lookup route (review 66573)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…est claim paying a wet render; it is already held hermetically by the offer-route witness (review 66578)

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

The SHA-256 of the exact unit bytes stays DigestStdin at the render seal; apply reads artifact.text and serving admission reads artifact.digest from the same SparkPairRealization. Harness collection no longer mints spark_pair_declared_unit_digests; Group B uses the canary arm's own unrendered-unit obligation.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ment.

DigestStdin still hashes the exact unit bytes, but only when apply publishes the durable artifact keyed by render-input identity. Placement reads that file and never renders or hashes per turn.

Co-authored-by: Cursor <cursoragent@cursor.com>
… a render type.

The d409d20 CI parse refusal is already gone on this branch; this type mismatch would have been the next floor red on 27ae041.

Co-authored-by: Cursor <cursoragent@cursor.com>
Heads-only parse treated the unsigned unit constructors as an unterminated function body through EOF.

Co-authored-by: Cursor <cursoragent@cursor.com>
Callers name spark_pair_lookup_declared_head_digest. Worker/head _unit_file sealed nothing production reads; the digest witness seals unsigned bytes through spark_pair_seal_unit_render.

Co-authored-by: Cursor <cursoragent@cursor.com>
Lookup was treating a partial engine/lane fingerprint as current, so uncovered desire drift kept a stale digest looking valid. The withdrawn bind red now publishes before it overwrites, so its DigestStdin floor-route-gap row is the effect it actually reaches.

Co-authored-by: Cursor <cursoragent@cursor.com>
The digest and bind wet files publish and look up target/spark-pair-declared-head-*; retiring on sha256sum mocks alone would leave that store wire uncovered.

Co-authored-by: Cursor <cursoragent@cursor.com>
…nsumes it.

A product-local sha256: offset parser was a second rendering rule for one format. The declared-head file is one record encode/decode over that same wire.

Co-authored-by: Cursor <cursoragent@cursor.com>
Floor compile refused the cargo pin because SourceApt is now a record, not a unit.

Co-authored-by: Cursor <cursoragent@cursor.com>
Lookup treated a digest as current when only engine/lane/snapshot matched, which would keep a stale unit after model-name, port, parser, or Ray argv changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
Lookup already treats a missing file as unavailable; the bind RED now deletes the store path in the witness. Worker realization inlines the only render lambda.

Co-authored-by: Cursor <cursoragent@cursor.com>
Build refused generated surface drift on std_content_hash.rs after the wire inverse landed in the .dag authority.

Co-authored-by: Cursor <cursoragent@cursor.com>
Apply was collapsing every publish failure to one Bool false. The bind RED was neutralizing Filesystem.Delete with a constant-true conjunct.

Co-authored-by: Cursor <cursoragent@cursor.com>
…hermetically.

Lookup treated a digest as current after image, binary, mount, or log-path changes. The completeness claim lived in a wet-only file and was not on the wet schedule, so it could not go red.

Co-authored-by: Cursor <cursoragent@cursor.com>
…d render.

The input-wire identity was a second encoding of the renderer and drifted whenever a knob was added only to spark_pair_head_unit_unsigned. Placement still does not DigestStdin.

Co-authored-by: Cursor <cursoragent@cursor.com>
…st_unit_render fold.

Wire tags are thread_local like every other data String row; the hand mirror drifted the stage0 population. Digest standing is matched at the witness sites that were the only consumers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Main enrolled live_deploy.emit nullary renders as warm producers outside the gate prefixes; a PR compile-subject that does not already include that module refused PureProducerShareProducerModuleOutsideSubject. Decode those rosters in the policy closure and join their modules as seeds, the same motion as the wet schedule.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ed Read.

Lookup Lists target/, then filesystem_exact_read only when the group entry is present. Bind RED asserts listing membership after Delete. The named replaceable slot stays a stated §3b divergence from WriteOnce materialization; the stored digest stays the apply-time mint so placement never DigestStdin.

Co-authored-by: Cursor <cursoragent@cursor.com>
The harness_declared_unit_digest annotation claimed placement never renders, which contradicted lookup's pure unsigned fold (review 66806).

Co-authored-by: Cursor <cursoragent@cursor.com>
Brian Searls and others added 17 commits September 16, 2026 13:41
…etic bind call.

harness_bind_candidate still requires incarnation plus HarnessCandidates.incarnations; the hermetic product-path claim was missing both (review 66833). Collect now builds one roster for FabricGroup A/B so lookup is not re-folded per admitted candidate.

Co-authored-by: Cursor <cursoragent@cursor.com>
ci_layer_roots had two excl_local_repo_wet_digest_stdin_reason/dissolve rows after the rebase onto main's capture-verification standing, so heal_repair_declaration could not resolve the module.

Co-authored-by: Cursor <cursoragent@cursor.com>
Digest refusal fires before incarnation, so withholding the digest made the
unobserved-incarnation claim unreachable and the observed-incarnation claim
green even if the harness ignored its incarnation argument.

Co-authored-by: Cursor <cursoragent@cursor.com>
Main moved NAMESPACE_TRANSITION_ADMISSIONS off the seed const onto
dag/gunbc/namespace/transition_admission/ files. These six TargetChanged
rows are the same binding deltas the old const carried for this PR.

Co-authored-by: Cursor <cursoragent@cursor.com>
…rite.

harness_add_serving_candidate takes the once-per-collect roster so the wet
claim still drives that one fold; admission rows keep the #11440 labels.

Co-authored-by: Cursor <cursoragent@cursor.com>
The route needs one fact -- does the answering launch's observed unit digest
equal the digest of the unit bytes the CURRENT declaration renders. The
apply-written receipt answered a different question (what an earlier apply
published) that no consumer asked, and paid write/read/parse/currency-check
plus its own integrity obligation for it. DESIGN section 2: minimize the demand
graph before materializing its answers.

DELETED: RenderedUnitArtifact, SparkPairUnitSealed, spark_pair_seal_unit_render,
spark_pair_publish_declared_head_artifact, SparkPairDeclaredHeadPublish, the
target/spark-pair-declared-head-* paths, the record serialize/parse, the
Filesystem List/Read/Write/Delete around them, apply's artifact-publish stage,
and the store-specific enrollment. parse_content_hash_wire and its v1 seed work
go with them: this PR introduced them for that record and nothing else consumes
them.

REPLACED BY a sealed digest-evidence record with exactly one mint:
DeclaredUnitDigestEvidence is a sole_constructor RECORD (not the coproduct --
that does not seal variant construction), carrying unit_name and digest and no
text, so there is no second field for the digest to disagree with.
spark_pair_declared_unit_digest is the only way to obtain one, over an ordinary
render, and every failure of the digest leg is a typed Unavailable.

COMPUTED ONCE PER BIND. harness_bind_seat mints the roster before the
placement-round fold and carries it through harness_placement_round ->
harness_collect_candidates -> harness_add_candidate -> harness_serving_route as
a supplied value. It was previously read inside harness_collect_candidates,
which is invoked inside the fold. No round or candidate renders or hashes.
Group B keeps its own typed obligation and never inherits the pair unit.

EVIDENCE. Because the evidence is sealed, a fixture cannot author a standing --
it must supply a render to the real mint, which is a DigestStdin. That is the
inhabitance half of DESIGN section 3's pairing obligation, and it is why the
witnesses that need a declared digest move to the local-repo wet lane, enrolled
per function. Rows that reach a verdict without a digest stay hermetic: render
refusal and empty render in the realization witness, and the seven availability
rows that never consult the declared unit.

One control is deleted rather than kept: a DECLARED digest in another hash
family is no longer authorable anywhere, since the only mint is DigestStdin, so
per DESIGN section 4b that check would be a decoration. The incomparable arm is
still walled from the OBSERVED side, which is a host reading and remains free to
be any family.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review 67007. The mint wrote a unit name that no consumer read --
spark_service_from_observation takes the digest alone -- which is DESIGN 3c red
however well shaped, and is the same argument the module already makes two lines
above for having no text field.

Not repaired by adding a reader. Which unit was compared is already fixed by the
group the route is deciding for, so carrying the name in the evidence would be a
second authority for a fact the caller holds.

The record is now a single-field sole-constructor carrier, so the comment states
the known hazard rather than leaving it to be rediscovered:
gunbc.recurring_failure_mode
sole_constructor_wrapper_satisfies_a_typecheck_declared_for_its_payload records
that such a carrier is ACCEPTED where its payload type is declared and then
fails at evaluation. Consumers read evidence.digest explicitly. That class's wall
is a compiler trigger; it is not a reason to keep a dead field as padding.

The witness rows that asserted the name drop those conjuncts; each still
discriminates on the digest, which is what they exist to establish.

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

b892997 added ~51 lines of seed Rust to required_floor_runner.rs to get past
a PureProducerShareProducerModuleOutsideSubject floor refusal. #11455 ("Floor
pure-producer share: scope roster admission to the prepared subject; stale only
when absent from the corpus") landed the same class of fix on main and is
already an ancestor of this head via the merge, so the branch was carrying a
hand-rolled solution beside the modelled one -- a second authority for one fact
(DESIGN 3), and seed growth with no receipt.

Restoring main's version of that file reverts exactly that commit: it was the
only branch change to it. Reverting rather than documenting also puts the
question to the floor instead of to a paragraph -- if the refusal returns the
hunk was load-bearing and comes back with its receipt and a
gunbc.seed_growth_admission row; if the floor is green it was redundant.

Review 67015.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Floor run 35145168818 refused with 23 WetTerminalMissing, one per row of
spark_serving_offer_route_witness: "unreachable: scheduled module
test.claim.spark.spark_serving_offer_route_witness has no scope in this subject:
EntryModuleOutsidePreparedSubject -- the manifest named this module and the
prepared subject does not contain it".

The module that file declares is test.claim.spark.spark_serving_offer_route_witness_TEST.
The wet schedule and the route-gap expectations named it without the suffix, so
the manifest asked the floor for a module that does not exist, and no terminal
could be produced. The sibling files in the same change were unaffected because
their declared modules genuinely carry no _test suffix
(spark_pair_head_unit_digest_witness, serving_availability_bind_wet_witness),
which is what made the mismatch look like a lane problem rather than a spelling.

Six controls executed and passed in that same run, so the lane itself and the
mint are sound: same bytes -> same digest; one byte different -> different
digest; the Group A production producer agreeing with the mint over its own
render; the production roster reaching the incarnation frontier; the withdrawn
roster refusing at the declared unit instead; and the ready route reaching that
frontier through harness_bind_candidate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Side-chat REFUSE on b9cf560: THE SEAL WAS BYPASSED THROUGH THE SANCTIONED
MINT. spark_pair_declared_unit_digest(render: SparkPairUnitRender) was exported
and returned the SEALED standing, and SparkPairUnitRendered is an ordinary
constructible variant -- so any module could hand it caller-authored bytes and
receive DeclaredUnitDigested over a digest it chose. The record was sealed and
the seal did nothing. gunbc.recurring_failure_mode
admitted_call_edge_with_unrestricted_value_egress: the rule is not who may call
the mint but WHAT MAY LEAVE, and an exported fn returning the confined value
without requiring one as input is an alternate mint.

I had written that egress rule into this module's own header and rationalised
past it, claiming the caller "cannot choose the digest". Choosing the bytes is
choosing the digest.

TWO PROPOSITIONS, NOW SEPARATE:
  these bytes hash to this digest -> RenderedUnitDigestStanding, UNSEALED,
    via spark_pair_rendered_unit_digest(render). Nothing to protect: the caller
    supplied the bytes.
  the current Group A declaration renders to this digest -> sealed
    DeclaredUnitDigestEvidence, via spark_pair_declared_head_digest(group) ONLY,
    which obtains the render from the production declaration.

EGRESS CLOSURE BY ENUMERATION, in the module header: every exported declaration
whose return type contains the evidence takes either a modeled FabricGroup, no
argument, or the carrier itself. None accepts SparkPairUnitRender, String or
ContentHash. The caller selects a declared group; it cannot supply bytes.

WITNESSES. The byte-level rows drive the unsealed fold. The route witness can no
longer author a standing at all, so it takes the declared side from the
production mint and builds each launch fixture's unit_digest from that digest to
agree, or from a foreign hex to disagree -- the discrimination moves to the
OBSERVED side, which is the fact the route decides about.

PROBE, WITH ITS STANDING STATED RATHER THAN CLAIMED. The new seal probe compiles
foreign source that forges the record and that tries to route bytes to a sealed
standing. It declares ReadsLiveTree because its sources import real modules, and
floor_route_gap records that such files are DECLINED BEFORE EXECUTION -- so it is
enrolled and NOT YET EXECUTED, and says so in its own header with the capability
trigger. The larger half needs no probe: the split is enforced by ordinary
compilation for every in-corpus module on every floor run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TWO DEFECTS IN bf116ce, both mine.

1. THE BUILD LANE, AND IT WAS THE ROOT OF ALL THREE RED JOBS. The seal-split
edit replaced a region of pair_serving_realization.dag that CONTAINED the
`type SparkPairUnitRender` declaration, and the replacement did not carry it
back. Every use site remained, so:
  pair_serving_apply.dag:29: error: name 'SparkPairUnitRendered' not found
  pair_serving_apply.dag:29: error: name 'SparkPairUnitRenderRefused' not found
That refused the docs-projections carrier, which is why heal-generated-artifacts
failed at its ledger-declaration step and the floor failed behind it. The type is
restored beside the byte-level fold it feeds.

WHY MY PARSE PROBE MISSED IT, stated so the probe is not trusted for more than it
does: HostBudgetUnreadable panics BEFORE resolution, so a clean probe establishes
that a module PARSED and says nothing about whether its names resolve. I read it
as "parses and resolves" and it is not that. A missing type is invisible to it.
Every symbol imported from the modules this change touches is now checked to be
declared, which is the check that would have caught it.

2. THE SEAL PROBE MISUSED THE CENSUS. It asserted census_total_count == 0 on a
source that imports production modules. gunbc.compile_diagnostic_census states
that the row set is the WHOLE COMPILE'S, closure included, so that assertion is
permanently false -- a check whose RED is unauthorable, which DESIGN 4b names a
decoration rather than a weak wall. The probe now uses the two forms that module
names as exact, following test.claim.fabric_m0_origin_readback_seal_test: a count
keyed to class AND subject (SoleConstructorViolation at
DeclaredUnitDigestEvidence), and a one-axis differential whose two sources share
module header, imports, signature and return type and differ only in the
producing expression -- forge versus the sanctioned
spark_pair_declared_head_digest. That also gives the red arm a real green
control, which the earlier version did not have.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
I wrote that these rows were DECLINED BEFORE EXECUTION and ran nowhere, reasoning
from floor_route_gap's note that ReadsLiveTree files are declined. That was
wrong. Required-floor run 35162345507 on e549dfd reports, for all three:
  standing=planned-and-passed disposition=planned_as_changed_witness outcome=passed
A PR that CHANGES a witness file gets it planned and executed as a changed
witness, which is a different route from the hermetic discovery corpus.

Understating a wall is a rung-honesty defect in the same direction-blind way
overstating one is (DESIGN 4b(1)): a wall that reads as unproven does not get
climbed, and the reader is misled about what actually holds.

THE LIMIT IS STATED WITH ITS OWN EVIDENCE rather than guessed a second time. This
is a wall measured ON THE CHANGE THAT INTRODUCES IT, not a standing gate: in that
same run the sibling probe test.claim.fabric_m0_origin_readback_seal_test -- also
ReadsLiveTree, but unchanged by this PR -- does not appear at all, so once this
file stops changing nothing re-runs these arms. Same standing filesystem_io
records for its own sole_constructor measurement. The next-rung trigger names the
capability: the floor planning ReadsLiveTree claims on every run.

Comment-only; no declaration changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DESIGN 3b admits a divergence with a stated reason and calls an UNSTATED one the
fork that gets consolidated later at interest. The reason for this one lived in a
PR comment, where a future reader of this witness file would never see it.

Review 67089 is RIGHT on the rule: a witness discriminates at one interface and
its inputs belong there as SUPPLIED VALUES; deriving them re-executes production
the claim is not about, once per claim. The subject of these rows is
spark_serving_route_standing's arm selection, not the mint.

WHY THERE IS NO THIRD OPTION, now recorded beside the code it governs. A supplied
value must be AUTHORABLE and this one is not: DeclaredUnitDigestEvidence is
sole_constructor with one corpus constructor, and that seal is the repair for
admitted_call_edge_with_unrestricted_value_egress whose receipt is on this very
carrier -- an earlier revision exported a mint taking SparkPairUnitRender and let
any module aim the declared digest. Re-opening an authorable standing for witness
convenience re-opens that hole, because sole_constructor cannot tell a fixture
from production. The Unavailable arm IS constructible and is supplied where it
fits, but it refuses before the incarnation, so it cannot serve rows whose
subject lies past a gate the brief requires stay in that order.

The cost is named and countable (one DigestStdin per row, the wet enrollment) and
the dissolution is the same trigger the exclusion row already names: sha256sum
DigestStdin mock_response coverage. On that day these rows stop reaching a host
effect and the divergence retires without unsealing anything.

Comment-only: 35 added lines, all comments, no declaration touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review 67105 asked for the floor_route_gap enrollment of
an_observed_incarnation_without_a_declared_unit_digest_refuses to be deleted, on
the grounds that the row passes t_unit_unavailable() and so never reaches
DigestStdin. THE ENROLLMENT IS CORRECT AND THE ROW IS NOT STALE. It builds an
observed incarnation from t_incarnation(), which routes through
t_declared_digest() to spark_pair_declared_head_digest -- the mint -- because the
launch fixture's unit_digest has to be real bytes for the agreeing and
disagreeing arms to discriminate at all. Deleting it would make a live route gap
UNENROLLED, which this module's contract reds just as hard as a stale row.

Measured, not argued: the floor was GREEN on 351e42f and e549dfd with
this row enrolled, and this module's own contract says "Enrolled, and the route
did NOT gap: reds the build as a stale row". A green build with the row enrolled
is the receipt that the route gapped.

WHAT THE REVIEW DID FIND IS MINE, AND IT IS THIS COMMENT. The paragraph said such
rows are omitted "because the arm is decided before the mint is reached", which
is false as a rule: the fold's refusal ORDER says nothing about what a row
evaluated to build its ARGUMENTS. That sentence is what made a careful reviewer
reach the wrong conclusion, so it is replaced by the actual discriminator --
does the row's argument closure reach the mint -- with the two t_unit_unavailable
rows spelled out as the contrasting pair, since they differ only in whether an
incarnation fixture is built.

Comment-only; no enrollment changed.

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

CONFLICT: main's #11476 added floor_route_gap_expectation_chunk_13 for the V4.1
apply-seam DigestFile/DigestStdin claims while this branch added a chunk_13 for
the declared-unit digest mint. Both rosters are live and neither subsumes the
other, so both are kept: main's keeps chunk_13 verbatim, this branch's becomes
chunk_14, and chunk_14 joins floor_route_gap_expectation_chunks.

Resolved by MERGE, not rebase: squash-merge policy, no force-push (the branch
brief says so explicitly, and the dashboard's "rebase" wording does not override
the repo's own policy -- the end state is identical either way).

Verified after resolution: both chunks brace-balanced, no duplicate chunk number,
chunk_14 both defined and registered, this branch's 25 route-gap identities and
58 wet-schedule rows intact, and main's 10 v41 wet rows intact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls marked this pull request as ready for review September 17, 2026 04:27
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-17T04:42:29.096478Z 8d4d4f9 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8d4d4f9317

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

spark_service_unidentified(realization: realization, cause: ServiceIncarnationNotFromDeclaredUnit { provenance: LaunchedFromDifferentUnit { observed: o, declared: d } })
LaunchUnitDigestsIncomparable =>
spark_service_unidentified(realization: realization, cause: ServiceIncarnationNotFromDeclaredUnit { provenance: LaunchUnitDigestsIncomparable })
LaunchedFromDeclaredUnit { declared: _ } => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Bind the digest to the running invocation before asserting

When the unit file is rewritten while the old service remains active, this branch can incorrectly assert that the answering process was launched from the current declaration. In the product path, serving_incarnation_observe reads the active InvocationID but hashes the current file at FragmentPath (serving_incarnation_observe.dag:518-543); pair_serving_apply overwrites that file before restarting the service (pair_serving_apply.dag:116-123), and a manual edit can leave this mismatch indefinitely. Consequently, digest agreement here proves only that the on-disk file is current—not that the observed incarnation was launched from those bytes—so the route can bind to a stale running service. The observation must bind the digest to the invocation that actually started the answering process before reaching LaunchedFromDeclaredUnit.

Useful? React with 👍 / 👎.

@gunbai-bot

gunbai-bot Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Duplicate: this branch's content landed as #11440 (da6cd0c); the dashboard auto-reopened a PR for the leftover branch. Review 67177's finding (group equality via fabric_group_wire strings instead of gunbc.spark.pair_serving_observed fabric_group_same, at spark_pair_head_unit_render_for_group) is valid against landed main and will be taken as a small follow-up. — sent from merry-eagle-325

@gunbai-bot gunbai-bot Bot closed this Sep 17, 2026
@gunbai-bot
gunbai-bot Bot deleted the session/bright-gull-790 branch September 17, 2026 04:50
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.

0 participants