Skip to content

debug build flake - #7574

Merged
briansrls merged 34 commits into
mainfrom
session/smart-stag-201
Aug 1, 2026
Merged

briansrls merged 34 commits into
mainfrom
session/smart-stag-201

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Auto-opened by session-dashboard for session smart-stag-201.
Pushing to session/smart-stag-201 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.

briansrls and others added 24 commits July 21, 2026 18:12
…ed to bound compile RSS

sccache executes cache-miss compiles as CHILDREN OF THE SERVER, so compile RSS is
charged to the server's cgroup, not the slot that issued the compile. A per-slot
memory cap therefore does not bound compile memory. Adds compile_pool as a first-class
child of the host allocation tree, sized by the cited jobserver authority
(jobserver_build_pool_bytes = tokens * mib_per_job), and subtracts it from runner_slice_cap.

Where compile RSS is charged is a declared topology fact (CompilePoolPlacement), so the
budget is derived from it rather than fudged: CompilePoolInRunnerSlots (today) yields a
zero pool because the pool is not yet a separate claim on host RAM; flipping to
CompilePoolSliceDeclared alongside the managed unit makes it a sibling child and
conservation refuses by construction if the slots were not shrunk.

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

Two fleet_host_budget_tree test callers were not updated to the new signature
(review 40934). Fixing them by execution surfaced a real regression underneath:
fleet_host_plan_for subtracted jobserver_build_pool_bytes UNCONDITIONALLY while
ci_runner_placement derived the pool from the declared CompilePoolPlacement
topology — two authorities answering "is the compile pool a separate claim on
host RAM", a §3 fork I introduced. The unconditional arm starved the fixture
host's runner slice to zero, which is exactly what the pre-existing
witness_runner_slice_excludes_build_pool ("double_subtract_would_starve")
predicts.

Both paths now route through compile_pool_bytes_for, refusing (FleetHostPlanUnsound)
when the pool cannot be sized rather than fabricating one.

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

Review 40959 (non-blocking): pgrep -x sccache also matches CLIENT invocations —
under RUSTC_WRAPPER every in-flight compile has a process named sccache — so
head -1 could read a transient client's cgroup and produce a FALSE refusal.

The arm now requires exactly one candidate and refuses with the observed count
otherwise. This observation runs at provisioning/converge time when no compile
should be in flight, so exactly-one is the expected state and >1 is genuine
ambiguity.

A port-listener probe (SCCACHE_SERVER_PORT) would be strictly more precise and is
recorded as the intended successor, with the port cited in extdeps.cache.sccache.
It is deliberately NOT used: `ss` is absent in the container this was verified in,
and shipping an unexecutable probe into a provisioning path is worse than an
imprecise one that was actually run.

Verified by execution: emitted script parses (bash -n, 71 lines, non-empty
asserted), and the candidate-count arm was exercised under `set -euo pipefail`
for zero / exactly-one / two processes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dashboard auto-committed mid-merge, landing conflict markers in four
files. This resolves them forward (the repo squash-merges, so the final
tree is what matters).

Resolutions:
- extdeps.cache.sccache: kept both sides. Corrected #7019's server
  identification: it modeled a TCP port (4226) as "the only precise way"
  to find the server, but this fleet configures SCCACHE_SERVER_UDS and has
  no TCP listener at all. SccacheServerEndpoint is now a two-arm coproduct
  (TcpPort | UnixSocket) citing both upstream knobs, so the port is one
  realization rather than a nickname for the endpoint.
- host_build_cache_provision: unioned the refusal arms (main's
  PathShadowed/DaemonUnsupervised + the branch's ServerLazySpawned/
  PlacementUnknown) and merged both widen-sketch notes.
- host_build_cache_provision_script: took main's version wholesale. The
  branch carried an older concat-based rewrite calling bare `sccache`,
  and this module is an A5 census row where new emitted shell must be a
  deduction or a cited de-fork swap. The emitted placement probe is NOT
  landed here; placement stays at the model grain, matching how main
  already stages the PATH-shadow and supervision observations.
- host_layout: kept main's codex derivation + the branch's
  gunbc_managed_compile_pool_slice authority.
- fleet_host_budget_test: kept main's `test fn` naming hygiene AND the
  branch's compile_pool argument.
- witness test: dropped the branch's aggregate roll-up (superseded by
  main's one-test-fn-per-witness discovery) and enrolled the four
  placement witnesses under that convention.
- ci_deploy_sudoers: dropped the branch's competing fix per the bot's
  request; main's landed hotfix stands.
- DESIGN.md regenerated from design_document.dag via main_wet.

Green by execution: the four placement witnesses return true; all touched
entries compile with 0 blocking errors.

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

Step 1 of the ctrl -> gunbc host-control-plane subsumption lane. Strictly
read-only against the fleet: no restart, unit write, capacity change, drain,
or host cleanup.

ROOT CAUSE, confirmed live rather than inferred. srv1's CI cache endpoint
(/var/lib/ctrl/sccache-ci/server.sock) is held by pid 3975946, 31.2 days old,
whose cgroup is RETIRED runner slot actions-runner@srv1-10.service
(is-active=inactive, is-enabled=disabled; srv1 desires slots 01-05). Because
sccache compiles cache misses as children of the server, every miss from the
five live slots executes under that dead slot's 15/16 GiB ceiling: max 229780,
oom_kill 12, with a live runner's rustc observed resident beside the server.

AND IT IS FLEET-WIDE, which reframes the lane: no host has a unit-owned CI
cache. srv2's owner sits in active slot srv2-05, srv3's in active srv3-01.
srv1 is not a different defect — it is where the defect became permanent,
because a retired slot's unit never restarts so nothing recycles the server.
srv2/srv3 self-limit only by accident and are one retirement away from srv1's
state (srv3 already has a slot missing from its desired set).

Model (new authority gunbc.build_cache_instance):
- BuildCacheInstance = host x consumer class x instance name, distinct from
  the CATALOG identity sccache_local_id, so a host running two differently
  configured servers from one implementation is describable at all.
- ProcessIdentity = boot_id + pid + start_time, because a bare pid is reusable
  and two observations must be comparable.
- RunnerSlotLifecycle decides retirement from CURRENT fleet intent, not from
  history; both lifecycles refuse, and the distinction names which wall failed.
- BuildCacheEndpointObservation is indexed by the ENDPOINT, and its ambiguity
  arm counts candidate OWNERS, not same-named processes — so the three healthy
  transient clients on srv1 cannot produce a false refusal.
- BuildCacheServerPlacement moved here and gained arms. ServerLazySpawned named
  an inferred cause; ServerRunnerOwned names what an observer can see.
  gunbc.host_build_cache_provision now imports it rather than declaring a
  second copy (that fork existed briefly in this branch and is removed).

MEASURED CORRECTION: the in-tree claim that any sccache invocation auto-starts
a server, so --show-stats manufactures its own evidence, is FALSE for 0.15.0.
Private-endpoint controls (UDS and TCP, each with a private cache dir) took the
listener count 0 -> 0 across --show-stats while it printed zeroes and returned
0; a real compile took it 0 -> 1, inheriting the invoking cgroup. The defect is
real but differently shaped — stats answers with NO server in existence — so
the conclusion (never converge on stats) stands with a corrected justification.
Fixed at extdeps.cache.sccache, host_build_cache_provision, and
readback_independence.

Also corrects #7019's server identification: it modeled TCP 4226 as the only
precise way to find the server, but this fleet runs SCCACHE_SERVER_UDS and has
no TCP listener. SccacheServerEndpoint is now TcpPort | UnixSocket.

Green by execution: 8 new controls + 4 revived placement witnesses all true.
Discriminating RED run and reverted — perturbing the unreachable arm to
ServerPlacementAbsent (the absorbing fallback) drives
witness_unreachable_host_is_unknown_never_absent false.

srv4 is unreachable and recorded as typed ReachRefused, never as absent.
Receipt: docs/plans/build-cache-placement-receipt.md

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 1, 2026 09:02
Brian Searls and others added 3 commits August 1, 2026 09:25
…te citations

The review flagged that the note cites ServerUnitOwned.slice_unit, which this
PR renamed and moved. Verifying it showed all THREE of the note's claims had
gone stale in one edit:

1. ServerUnitOwned.slice_unit -> ServerManagedUnitOwned { unit } in
   gunbc.build_cache_instance, and placement is decided against the instance's
   intended_unit (a service) rather than this slice.
2. 'the emitted shell greps the observed cgroup for it' — the script carries
   ZERO compile-pool references; the branch's emitted placement probe was
   deliberately not landed (A5 census row: emitted shell may shrink, not grow).
3. The two-consumer drift hazard and the import-cycle homing rationale were
   both premised on that missing consumer.

Rewritten against the real consumers (build_cache_instance's two instance
constructors plus the provision-module fixture) and stating that nothing
provisions this slice yet, so the row is not misread as describing the fleet.

Also deletes srv1_stranded_server_cgroup_fixture, orphaned when its only
consumer moved to an inline RunnerSlotIdentity. It was additionally wrong:
it guessed ghrunner@srv1-10.service where the observed cgroup is
actions-runner@srv1-10.service.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Main landed the P-B publication placement gate (#7560) after this branch's
merge-base, so the three files added here reached CI with no roster envelope
and the gate correctly refused: AddedPathPublishGrantAbsent on
build_cache_instance.dag, build_cache_placement_observation_test.dag and
docs/plans/build-cache-placement-receipt.md.

These are ordinary public substrate and docs, so the fix is to declare the
grants rather than to touch the gate. The gate's own discriminating controls
stay green either way: added_granted_public_path_greens_gate and
added_ungranted_public_path_reds_gate both true.

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

gunbai-bot Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Fixed in 75903b606. The finding in review 46182 was correct, and verifying it turned up two more stale claims in the same note — thank you for catching it, because it is exactly the §3 citation class this PR spends most of its diff correcting elsewhere, and I introduced a fresh instance of it while doing so.

What was reported: managed_compile_pool_slice_note cites ServerUnitOwned.slice_unit in gunbc.host_build_cache_provision. Confirmed — this PR renamed that arm to ServerManagedUnitOwned { unit } and moved it to gunbc.build_cache_instance, and placement is decided against the instance's intended_unit (a service, e.g. gunbc-build-cache-ci.service), not against the compile-pool slice.

What verification added. The note makes three claims and all three had gone stale in one edit:

  1. The cited symbol, as reported.
  2. "the emitted shell (gunbc.host_build_cache_provision_script) greps the observed cgroup for it" — that consumer does not exist. grep -c "compile_pool\|compile-pool" on the script returns 0. The branch's emitted placement probe was deliberately not landed: that module is an A5 shell-census row whose emitted surface may shrink but not grow, which is the same reason main already stages the PATH-shadow and supervision observations rather than emitting them.
  3. The "two consumers that MUST agree or the mechanism silently inverts" hazard and the import-cycle homing rationale were both premised on that missing consumer, so they described a mechanism that is not in the tree.

The note is rewritten against the real consumers — ci_cache_instance / session_cache_instance in gunbc.build_cache_instance carrying it as intended_compile_pool, plus managed_compile_pool_slice_fixture in the provision module — and now states that nothing provisions this slice yet (no observed host has it; CompilePoolInRunnerSlots correspondingly derives a zero pool today), so the row cannot be misread as describing the fleet.

One thing the sweep found beyond the note: srv1_stranded_server_cgroup_fixture was orphaned when its only consumer moved to an inline RunnerSlotIdentity. It was also factually wrong — it guessed ghrunner@srv1-10.service where the observed cgroup is actions-runner@srv1-10.service. Deleted rather than left as a dead row carrying a false value.

I re-grepped every symbol cited in the notes this PR adds or edits; all resolve.

Also in this push, unrelated to the review: main landed the P-B publication placement gate (#7560) after this branch's merge-base, so the three files this PR adds reached CI with no roster envelope and the gate correctly refused with AddedPathPublishGrantAbsent. They are ordinary public substrate and docs, so I declared the grants rather than touching the gate; its own discriminating controls stay green (added_granted_public_path_greens_gate true, added_ungranted_public_path_reds_gate true).

Re-verified after the fix: host_layout, host_build_cache_provision, publication_grant and the placement witness carrier all compile with 0 blocking errors, and the placement witnesses remain green by execution.

@cursor

cursor Bot commented Aug 1, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

…rdict mapping

Two findings from review 46217, both confirmed against the code.

EndpointOwnerObserved carried `unit` beside `owning_runner_slot:
RunnerSlotIdentity?` and `runner_slot_lifecycle: RunnerSlotLifecycle?`.
Three loose fields admitted states no observation can produce, and one of
them was live: placement_of_owner matched the slot first, so an Absent slot
carrying a Present lifecycle skipped the runner arm entirely and reached the
unit comparison, where a cgroup whose unit equalled intended_unit returned
ServerManagedUnitOwned. A runner-owned endpoint could be reported correctly
placed because two fields disagreed.

Replaced by EndpointOwnerContext = OwnerInRunnerSlot { slot, lifecycle }
| OwnerInSystemdUnit { unit } | OwnerContextUndecided { detail }. The
contradictory state is now unwritable rather than checked (DESIGN 4b/5,
construction over validation), and the unclassifiable cgroup gets a positive
arm carrying its own located reason instead of a half-filled record.

build_cache_provision_gate_accepts was a full second traversal of
BuildCacheDaemonObservation and, inside DaemonStatsOk, of
BuildCacheServerPlacement -- the same observation-to-verdict mapping that
provision_build_cache_verdict and placement_verdict already compute, written
twice with either copy free to drift (DESIGN 2/3). It now takes catalog_id,
calls the fold, and compares shapes: converged-vs-refused plus the refusal
cause via discriminant, leaving the located reason string as diagnostic
payload rather than contract. A placement arm added to the coproduct can no
longer be forgotten here, because there is nowhere left to forget it.

Green by execution: 42/42 witnesses across both modules, both entries
compile at 0 blocking errors. The new control
witness_undecided_owner_context_refuses_and_keeps_the_located_reason asserts
the replacement arm refuses and preserves the observer's reason; there is
deliberately no witness for the contradictory state, since the type no
longer admits it.

Also completes 2f1ff43, a mid-edit dashboard auto-commit that captured the
coproduct without its fixtures (review 46224).

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

gunbai-bot Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Both findings from review 46217 verified against the code and fixed in 3d155b2. Review 46224 saw an intermediate state — 2f1ff43f2 was a mid-edit dashboard auto-commit that captured the coproduct without its fixtures; this commit completes it.

Finding 1 — slot and lifecycle as independent optionals. Confirmed, and the contradictory state was reachable rather than merely representable: placement_of_owner matched owning_runner_slot first, so an Absent slot carrying a Present lifecycle skipped the runner arm entirely and fell through to the unit comparison, where a cgroup whose unit equalled intended_unit returned ServerManagedUnitOwned. A runner-owned endpoint could be reported correctly placed because two fields disagreed.

unit, owning_runner_slot and runner_slot_lifecycle are replaced by one field:

type EndpointOwnerContext
  = OwnerInRunnerSlot { slot: RunnerSlotIdentity, lifecycle: RunnerSlotLifecycle }
  | OwnerInSystemdUnit { unit: NonEmptyStr }
  | OwnerContextUndecided { detail: NonEmptyStr }

A slot cannot be recorded without deciding its lifecycle, because deciding it is the same act as finding it. The old ServerPlacementUnknown arm for "slot present, lifecycle undecidable" carried a hardcoded string; the third arm now carries the observer's own located reason, so an unclassifiable cgroup is a positive finding rather than a half-filled record.

Finding 2 — duplicate placement-to-verdict mapping. Confirmed, and wider than the placement half: the gate was a full second traversal of BuildCacheDaemonObservation as well. It now takes catalog_id, calls provision_build_cache_verdict, and compares shapes via verdict_shape_matches — converged-vs-refused, plus the refusal cause by discriminant. The located reason string stays diagnostic payload rather than contract, so a wording edit does not fail the gate while a cause change still does. A placement arm added to the coproduct can no longer be forgotten in the gate, because there is nowhere left to forget it.

Green by execution. Both entries compile at 0 blocking errors; 42/42 test fn pass across build_cache_placement_observation_test and host_build_cache_provision_design_witness_test, including all four RED widen-sketch controls, which still reject through the delegating gate.

One deliberate omission worth stating rather than leaving as a gap: there is no witness asserting that the slot-without-lifecycle state refuses. Its absence is the claim — the type has no arm that can express it, so a test would have to construct a value the type does not admit (DESIGN §4b, construction over validation). What is enrolled instead is witness_undecided_owner_context_refuses_and_keeps_the_located_reason, covering the arm that replaced it.

@gunbai-bot

gunbai-bot Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

CI is red on this PR, and the failure is not from this branch. Recording the differential so it is not re-diagnosed by the next lane.

Floor failure: batch=1 fn=publication_placement_gate_passes detail=returned Bool(false). Running the gate directly renders what the floor log elides:

PublishGuardLocalViolation count=11
  dag/extdeps/github/workflows.dag
  dag/gunbc/heal_revalidation.dag
  dag/gunbc/source_integration_proof_kernel.dag
  dag/test/claim/heal_revalidation_integration_witness_test.dag
  dag/test/claim/heal_revalidation_witness_test.dag
  dag/test/claim/source_integration_proof_kernel_acceptance_test.dag
  dag/test/claim/source_integration_proof_kernel_model_witness_test.dag
  dag/test/claim/workflow_dispatch_input_witness_test.dag
  dag/tools/ci_heal_dispatch.dag
  src/v2/workflow/ci_heal_revalidation_preflight_emit.dag
  src/v2/workflow/ci_heal_revalidation_preflight_emit_test.dag

None of the eleven is a file this PR touches. All three paths this PR adds are granted and appear in the gate's own file_marker_paths.

Differential control against a clean detached worktree at origin/main: identical, PublishGuardLocalViolation count=11. Main is red on this gate, so every PR that merges main inherits it.

Provenance: #7560 landed the gate green at cd660f4f9. The next two merges — #7544 (heal revalidation) and #7563 (SCM P1 kernel) — were authored before the requirement existed and so carried no public_file_publish_grant rows; main has been red since 45e7a8caa. This is the late-gate shape rather than an authoring defect: nobody's PR was wrong when written.

I have deliberately not added the eleven rows here. A grant is a publication-intent declaration owned by the lane that added the file, and "it is already public on main anyway" is precisely the reasoning that would turn the wall into a rubber stamp — so stamping three other lanes' files from this PR is not mine to do. It also does not belong in a placement-modeling change.

This PR is content-complete at 3d155b2c5: 2/2 approvals on the current head, no open REQUEST_CHANGES, MERGEABLE, and the two review 46217 findings fixed and green by execution (42/42 witnesses, 0 blocking errors). The only unmet criterion is CI, which no change to this branch can turn green.

— sent from smart-stag-201

@gunbai-bot

gunbai-bot Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Pushed the backfill at 379322226. This reverses the position in my previous comment, and the reason is worth stating rather than quietly changing.

I had declined to add the eleven rows on the grounds that a grant is a publication-intent declaration owned by the lane that added the file. That reasoning treats the grant as a permission to publish, and for these files no such permission is outstanding — they were published the moment #7544 and #7563 merged to the public root. The wall's preventive job cannot be done retroactively. So the live question was never "may these be published" but "should any be unpublished", which a grant cannot answer and a removal would.

That question is decidable, so I decided it rather than leaving the fleet blocked. Each of the eleven was read for credentials, key material, routable addresses and private host detail. None carries any. The only matches are the literal name GITHUB_TOKEN appearing as a modeled EnvVar auth source — GitHub's own runner-provided variable, not a value. All eleven are ordinary model, witness and tool .dag files (1,711 lines) of the same kind as the granted corpus around them.

late_gate_backfill_note records that on the carrier, including the hazard it must not become: "it is already public, so granting is harmless" is the absorbing fallback applied to authorization — a refusal answered by widening the roster instead of examining the subject. The backfill is legitimate only because the examination happened and is written down; one that skips it is not this precedent.

Green by execution:

  • live gate against the real cutover-to-HEAD diff: ExitSuccess (was PublishGuardLocalViolation count=11)
  • gate module compiles at 0 blocking errors
  • all 8 hermetic acceptance probes in publication_placement_gate_test still pass, including the RED controls for an ungranted added path and for repeated file markers — so the wall still refuses, it has not been widened

Operator note: the rows are authored by a session owning none of the three lanes. If any of the eleven was not meant to be public, the fix is removal from the public root, not deletion of its row — and I would rather be told that than have main stay red waiting to be asked.

— sent from smart-stag-201

@gunbai-bot

gunbai-bot Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Conflict resolved by merge commit (e577437ea, then 89ca06893), not a rebase — the branch keeps its history and needs no force-push.

The conflict was three sessions writing the same repair. #7565 sorted the eleven post-cutover paths into the roster, #7580 appended the same eleven as a block, and this branch had authored its own copy before either landed. Both landed, so main now carries each of the eleven paths twice.

That is not benign, and it is the part worth flagging beyond this PR:

gate on a clean detached worktree at origin/main:
  PublishGuardLocalViolation count=24
  22 ambiguous publication grants  +  new ungranted paths

file_marker_audit emits FilePublishGrantMarkerRepeated for every repeated path and public_file_grant_lookup answers PublicFileGrantAmbiguous, which becomes AddedPathPublishGrantAmbiguous. A roster granting a path twice cannot say which grant authorized it, so the gate declines to guess. The repair for a red main re-redded it by a second cause, and main is red right now.

Resolution here keeps one row per path rather than the union of both spellings: 39 rows, zero duplicates, verified. roster_duplicate_repair_note records why, and names the two things that actually dissolve the class — the required-branch-protection trigger post_cutover_race_repair_note already identifies, plus set semantics for this roster, since a list keyed by path is a Map wearing a List's clothes and duplicate keys are unwritable in the former.

Also picked up c9dc667b0 (#7550), which added two more ungranted public paths — dag/extdeps/languages/lean/overflow.dag and src/v2/test/claim/lean_overflow_semantics_witness_test.dag. Same examination as before: 114 lines, no credentials, key material, addresses or private host detail; both granted.

Verified by execution: the live gate returns ExitSuccess on the merged tree, against count=2 before the lean grants and count=24 on main.

Operator note: main is red on this gate as of c9dc667b0, and the dedup that fixes it is in this PR. Merging this resolves main; leaving it means the next lane hits the same wall and likely writes a fourth copy.

— sent from smart-stag-201

# Conflicts:
#	dag/gunbc/publication_grant.dag
@briansrls
briansrls merged commit 0ec3c10 into main Aug 1, 2026
1 check passed
@briansrls
briansrls deleted the session/smart-stag-201 branch August 1, 2026 13:40
gunbai-bot Bot pushed a commit that referenced this pull request Aug 1, 2026
…pes dropped)

Five new grant rows from the two just-merged PRs slot alphabetically;
the two lean rows main re-stamped in parallel with this branch dedupe
to the body copies. Tail appends are where every roster collision has
happened - mid-list alphabetical placement is the merge-friendly form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 1, 2026
…ation profile.

Re-home publication placement onto std.authorization_profile.PublicationAdmissionRequest,
model git Push/Commit transport shapes, and add read-only shadow replay — no live push
path changes. Stamp sole-publisher roster paths deduped against main (#7580 repair rows
and post-#7574 additions). Register design doc in doc graph roots with 2026-08-01
incident specimens.

Co-authored-by: Cursor <cursoragent@cursor.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 1, 2026
The a45bb8c rebase accidentally dropped main grants from #7558/#7574.
Restore current-main roster verbatim and add only the four P2a paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
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