Skip to content

App Attest step 4: the six device routes on the approval broker as body-authenticated POSTs; wire header rows deleted, vectors regenerated, Swift mirror (stacked on #11989) - #12000

Merged
gunbai-bot[bot] merged 166 commits into
mainfrom
session/nimble-eagle-216-step4
Sep 25, 2026

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

Step 4 of the iOS approval-app plan: the six device routes on gunbc.auth.approval_broker_serve, under decision B (msg_5b415336: every device operation is a POST whose body carries its authentication — gunbc serve hands a route no header but the tailnet login, and the seed's purpose standing refuses growing it for the approval product). Stacked on #11989 → #11981 → #11975 → #11970.

Wire (gunbc.auth.approval_device_wire) — one shape, no headers

  • The three X-Approval-* header rows are deleted. ReadAuthentication { enrollment_id, requested_at, assertion_b64 } is the POST body of the three reads; PushUpdateRequest { auth, push } is the push-update body. Strict decoders with located refusals, same idiom as the rest of the wire. The assertion's client data (device_read_client_data, device_push_update_client_data) is unchanged — moving the carrier off the headers changed no signed byte.
  • Fixtures: gunbc.auth.approval_device_redemption_fixtures renders read_authentication and push_update_request envelopes and a method_every_device_operation = POST surface row; dag/test/fixture/approval_device_redemption/vectors.json regenerated from the renderer (generated_artifact_gate main_wet_one), never hand-edited.
  • Swift mirror: Wire.swift drops ReadHeader, sends readRequest(auth) / pushUpdateRequest(auth, push) bodies over POST for pending/fetch/readback/updatePush; ProtocolVectorTests checks the two new envelopes against the fixture bytes and the method row. (Still the first Swift this project has never executed — operator item.)

Routes (gunbc.auth.approval_device_routes, mounted by approval_broker_serve)

Six folds, each returning {status, JSON body}; the broker owns routing, markers (six new ApprovalBrokerMarker arms) and the process; the redemption/wire/verifier modules own every decision:

  • POST /approve/device/enrol — decode → writer gate → verifier config → enrolment_admission over verify_attestation (client data = enrolment_transcript) → commit_enrolment → push registration stored (owner-only, last-write-wins file beside the slot) → EnrolmentGrant.
  • POST /approve/device/redeem — decode → writer gate → redeem_device_over_store with verify_signature under the enrolment's decision key and verify_assertion over the signing input as verdicts.
  • POST /approve/device/pending / …/requests/<segment> / …/enrollments/<segment> — admit_device_read (active enrolment, requested_at inside the ±60 s skew of the observed instant, assertion over the route's framed client data) then the pending listing / a FetchedRequest (stored request text, a MAC-keyed RedemptionChallenge with a 5-minute window, both verb capabilities via issue_capability) / the readback.
  • POST /approve/device/push — writer gate + read admission, then the registration.
  • The operator's verb issue_device_enrolment_code (a CliWireResponse): 4 entropy octets → 8 hex chars, 10-minute window, written through issue_enrolment_code; never a route.
  • gunbc.roadmap_serve roadmap_mounts_during_cutover classifies all six as false — the total match the module built for exactly this reason.

Supporting authorities: gunbc.durable_cas_file_store cas_slot_keys (the store's own inverse of its layout — the one place a name becomes a key), gunbc.auth.approval_decision_store pending_escalations (keys from the listing, each standing through observe_escalation; an unreadable slot is carried, not dropped), and gunbc.auth.approval_app_attest_config — AppAttestVerifierAwaitingOperator today: bundle id ai.gunb.approve and the production environment are known; the App ID prefix and the distributed bundle version are the operator's, and until that row changes every route that needs the verifier refuses 503 naming what is missing (no guessed prefix).

Established by execution (claim_batch, exact head ba3dda3)

test.claim.approval_device_routes_witness_test (8): malformed bodies 400 on all six routes naming where; bad/non-canonical segment 400; readback for another enrolment 403 before any verification; the non-writer process 503 with the writer reason on a mutating route (which process is the non-holder is read from the gate); reads 503 "not configured" while the config row is awaiting the operator (the claim reads the row's arm, so it flips when the row does); the skew window brackets exactly [−60 s, +60 s) (on the wet route — Clock.TimestampAdd); the redemption status map; the roadmap mounts none of the six.
test.claim.approval_broker_serve_witness_test: the table selects the ten routes, the six device routes only as POST (GET → 405), and carries exactly ten.
test.claim.approval_device_wire_witness_test (28): the new bodies round-trip and refuse strictly at auth / assertion_b64 / push.

Mutation control: readback identity check inverted → a_readback_for_another_enrolment_refuses_403 FAIL, a_bad_segment_refuses_400 PASS; restored.

What this does not establish (honest)

The admitted paths — a real enrolment committing, a real redemption deciding, a real read answering — need (a) the operator's App ID prefix + bundle version in approval_app_attest_config, (b) a live store, and (c) the ECDSA execution route (decision A). They are the declared frontier ecdsa_verification_realization_frontier and are not faked with designed fixtures.

Nothing fired at srv1.

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 30 commits September 21, 2026 15:24
…thn authenticator-data decoders in .dag, claimed over a real Apple-issued attestation

The first of the pure byte decoders the App Attest verifier needs (extdeps.apple.app_attest
attestation_verification_from_implementation has no supplier on main). Three extdeps modules,
each cited: extdeps.standards.rfc_8949 (strict CBOR: definite-length only, floats and reserved
additional info refuse, integers beyond 2^53 refuse before the multiply, nesting bounded, unique
text-key member read), extdeps.standards.rfc_9052 (COSE_Key EC2 P-256 ES256 -> SEC 1 point),
extdeps.standards.webauthn_authenticator_data (the §6.1 layout, whole and 37-octet prefix).

The fixture is a real attestation object and assertion Apple issued to a development build
(veehaitch/devicecheck-appattest ios-14.4.yaml at cb26211f), transcribed as octets with its
published facts; over it the decoders establish Apple's steps 4, 5, 6, 7 and 8 from real bytes.
One upstream fact the sample surfaced: Apple's assertion authenticatorData is 37 octets with the
AT flag set and nothing following, so assertions are read as the prefix, never the full layout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ers in .dag and the pinned Apple App Attestation Root CA, claimed over the sample's real certificate chain

extdeps.standards.x690_der reads the DER profile and refuses BER's freedoms by name:
indefinite lengths, non-minimal long-form lengths, high tag numbers, unused BIT STRING bits,
non-minimal or negative INTEGERs. extdeps.standards.rfc_5280 reads Certificate/TBSCertificate/
AlgorithmIdentifier/Validity/SubjectPublicKeyInfo/Extension, refuses an outer signature
algorithm that disagrees with the signed one, looks extensions up uniquely, and renders
ECDSA-Sig-Value as fixed-width r||s for the curve verifiers. extdeps.standards.rfc_7468 reads
one PEM block. extdeps.apple.app_attest gains the root CA pinned byte for byte from apple.com.

Over the sample chain the readers establish, from real bytes: Apple's steps 2 and 3 (the leaf's
nonce extension equals SHA-256(authData || clientDataHash)); the leaf's SPKI point IS the
credential key the authData carries; leaf -> CA 1 -> pinned root join by DER Name equality;
CA 1 and the root are secp384r1 / ecdsa-with-SHA384, so the chain step needs P-384.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ther than re-matching CborValue (review 69585)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…P-256 and P-384 as parameter rows, SHA-384, and the frontier retargeted to the decided shape

extdeps.crypto.nist_prime_curve carries the a = -3 Jacobian group law, Shamir double-scalar
ladder, partial public-key validation and ECDSA verification over a SUPPLIED digest, written
once (the formulas #11645 landed for P-256, moved not rewritten). extdeps.crypto.nist_p256 is
now its parameter row plus the SHA-256-bound verifier the device signature uses; the new
extdeps.crypto.nist_p384 is the second row, consumed by Apple's chain step, whose two links are
a P-384 key signing with SHA-256 and a P-384 key signing with SHA-384. extdeps.crypto.sha2 gains
SHA-384 (the SHA-512 computation with its own initial state, truncated) over std.bitwise Word64,
its constants derived from the definition rather than transcribed.

P-256 semantics preserved by execution: the RFC 6979 sample signature verifies and the
different-message control is false through the family fold (88 s / 86 s, 56M / 55M eval steps,
peak 15.5 GiB), and n.G = infinity holds. P-384 established on real bytes: Apple's CA 1 and root
keys are on the curve, a neighbouring point is not; the two chain-link verifications are enrolled
and NOT executed here (at 17 limbs they exceed this container's memory), the same disposition as
#11645's eight P-256 rows: a dedicated native gunbc test row is their executing evidence.

gunbc.auth.approval_device_redemption ecdsa_verification_realization_frontier no longer names
the host-Rust primitive the operator refused; it names the .dag readers landed by #11970/#11975/
this change, the verifier folds still owed, and the execution route decision (natively emitted
handler once MachineWidth<N> reification lands; interpreter cost is the v1-performance row).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ture's ByteSize authority; the two guard-shadowed zero defaults (CBOR argument octets, authenticator-data octets) now refuse as located truncations

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…t or a second block; OID subidentifiers refuse a leading 0x80 (X.690 §8.19.2), and the witness now asserts that refusal instead of announcing it

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…dag, Apple's real assertion signature verified by execution, and the signature-seam join

extdeps.apple.app_attest verify_attestation runs Apple's ten steps over the readers: CBOR shape
and fmt, the nonce extension against SHA-256(authData || SHA-256(clientData)), the credential
certificate's public key against the key id, RP ID, counter 0, AAGUID for the environment,
credentialId, chain names and validity at the observed instant against the pinned root, the
validation-category and bundle-version extensions, and last -- because they cost minutes -- the
two chain-link ECDSA verifications. verify_assertion runs steps 1-4, 7, 8 and carries the counter
out. Both supply the seams; nothing else may mint VerifiedAttestation / AuthenticAssertion.

Established on Apple's real objects: the attestation passes every step up to the validation
category the 2021 sample predates (AttestationValidationCategoryAbsent is the first refusal), each
earlier step reds by name when its expectation is wrong, and observing it in 2026 finds the
credential certificate expired at 2021-01-25T12:13:35Z. THE ASSERTION SIGNATURE VERIFIES under the
credential key -- after a defect found only by executing it: Apple's nonce is the signed MESSAGE
(ECDSA-with-SHA256 over the 32 nonce octets), not the digest; the first cut refused and openssl
confirmed the reading.

extdeps.crypto.signature verify_signature is the join the frontier called (b): base64url carriers
-> measured sizes -> the seam -> nist_p256; RFC 6979's sample verifies through it and is
SignatureInvalid over another message. rfc_5280 gains UTCTime/GeneralizedTime -> Timestamp and
validity at an instant. The frontier row now names the execution route as the only remainder.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-> 11, 384 -> 16), not ceiling + 1; annotations corrected. Re-measured: one P-256 verify 73-75 s / 48.5M eval steps, from 88 s / 56M at the extra limb

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…read (X.690 §8.6.2.3); every positional TBS, outer, SPKI, AlgorithmIdentifier, Extension and ECDSA-Sig-Value read asserts its ASN.1 type through der_element_expect, consuming the tag constants that were imported and unused

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ture fields (the placeholder-filled certificate has no constructor); left_pad consumes std.bignat bignat_pad_front instead of re-minting a zero fill

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…mily fold reads the octet rows), the witness's limb count corrected to 16, and the SHA-256/SHA-512 two-pipeline divergence stated on the carrier with its collapsing capability (MachineWidth<N> reification)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… the authenticator data are decoded once (decode_attestation) and carried to the refusal fold and the success mint; the assertion document is decoded once for its counter and its refusal

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…of re-declaring its fields; extnValue and Time reads assert class and form through the typed reads; an explicitly encoded critical FALSE refuses (X.690 §11.5); the never-called der_expect_universal deleted and der_element_expect_universal consumed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…in counter, key or receipt reaches the seam), a non-unsigned validation category is Undecodable rather than category -1, chain_link_verifies is claimed at its producer (three refusing arms executed over the real leaf and CA; the two verifying links enrolled with the P-384 cost stated), and nist_p256's header says its consumers are the declared frontier; the validity fold reads the nested tbs

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…y one a POST whose body carries its authentication; the wire's header rows deleted; vectors regenerated; Swift mirror

Decision msg_5b415336 (B): gunbc serve hands a route no header but the tailnet login, and the
seed's purpose standing refuses growing it for the approval product, so the enrolment id, the
claimed time and the App Attest assertion ride in the body (ReadAuthentication; PushUpdateRequest
{ auth, push }). The assertion's client data is unchanged.

gunbc.auth.approval_device_routes: enrol (writer gate, verify_attestation over the enrolment
transcript, enrolment_admission, commit, push registration), redeem (writer gate, verify_signature
under the decision key and verify_assertion over the signing input into redeem_device_over_store),
pending / one request / enrolment readback (admit_device_read: active enrolment, +-60 s skew,
assertion over the route's framed client data; the request answer mints a MAC-keyed challenge
and both verb capabilities), push update, and the operator's code-issuing verb as a CliWire
answer. gunbc.auth.approval_broker_serve mounts the six with their own markers; gunbc.roadmap_serve
classifies all six as never mounted by the roadmap. gunbc.durable_cas_file_store cas_slot_keys
(the store's own inverse of its layout) and approval_decision_store pending_escalations list what
the phone lists. gunbc.auth.approval_app_attest_config is AwaitingOperator until the App ID prefix
and bundle version land; every verifier-needing route refuses 503 naming that until then.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e), the pinned root's SHA-256 is a data row computed by a claim over the decoded PEM, and a Certificate, TBS tail or AlgorithmIdentifier with children the profile does not name refuses instead of reading past them

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 5 commits September 24, 2026 03:21
…/ SignatureUndecodable, not Malformed at a fabricated size 0

decoded_or_empty mapped a non-base64 key or signature to [], so verify_signature reported
VerifyingKeyMalformed/SignatureMalformed { declared: 0 } -- a size never observed (review 70731,
DESIGN section 5). Deleted it; verify_signature now refuses with a typed arm naming the carrier.
Consumers of SignatureVerification all match with wildcards. Claims: non-base64 key and signature
each reach their arm, and "==" (decodes to zero octets) stays VerifyingKeyMalformed at declared 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	docs/design-rung-drops.md
Ledger-Repair-Judged: docs/design-rung-drops.md
Ledger-Rows-Repaired: docs/design-rung-drops.md microvm_shakedown_slot_row_above_fleet_row
Ledger-Rows-Repaired: docs/design-rung-drops.md network_requirement_unrepresented_after_uses_cut
Ledger-Rows-Repaired: docs/design-rung-drops.md v41_row_store_host_realized_by_sample
Ledger-Rows-Repaired: docs/design-rung-drops.md admit_callers_discarded_on_the_native_route
Heal-Candidate-Run: 35951131764
Base automatically changed from session/nimble-eagle-216-step3b to main September 24, 2026 12:21
gunbc-ci-auto-heal and others added 3 commits September 24, 2026 16:03
The merge conflict on the generated projection was resolved from its
authority (docs_projection_gate regen), not by picking a side.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ct-bound claims to the wet lane

The floor on 7b217bc refused three identities in
test.claim.approval_device_routes_witness_test:

- the_redemption_refuses_503_before_any_crypto_while_the_native_handler_is_unbound
  ran 76957 eval steps against the 72300 new-witness budget. Nearly all of
  that was fx_signing_input building the redemption vectors, which mint real
  capability tags through interpreted hashing. This claim is about the gate
  and never looks at that input. It now supplies a well-formed signed
  redemption body and runs 21357 steps. The real vector's decode stays
  exercised by test.claim.approval_device_wire_witness_test, so no execution
  of the real path is lost.
- the_read_skew_window_brackets_sixty_seconds (Clock.TimestampAdd) and
  a_bound_realization_passes_the_read_past_the_gate (the enrolment store's
  Filesystem.Read) can't reach their subjects on the hermetic route. The skew
  claim's own comment already said it was meant for the wet route, but it was
  never enrolled. Both move to test.claim.approval_device_routes_wet_witness_test.
  Each gets the full triple enrolment: a floor_route_gap expectation, a
  WetScheduledClaim, and a ci_layer_roots LocalRepoWetLane row with its own
  reason and dissolution condition.

Local receipts: claim_batch passes all 13 hermetic claims. claim_batch --wet
passes both moved claims.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 24, 2026
…12000's head (which already carries main); elevation's command rows kept; mode roster unioned; fleet-converge.yml main's side pending regen

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 24, 2026
… step 4 caught up to its reviewed head; approval_device_routes keeps the dissolution import both sides use

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 24, 2026
…fter the main + #12000 merges

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 2 commits September 24, 2026 18:40
…minus, skew claim back to hermetic

device_instant_minus handed 0 - 60 to Clock.TimestampAdd's `offset: Nat`,
which is a carrier violation. It only worked because GNU date accepts
"+-60 seconds". The skew window never needed a shifted instant. It needs the
signed distance between two canonical instants. So
gunbc.auth.approval_capability now carries utc_instant_seconds and
utc_instant_seconds_after beside utc_instant_before. Both are pure folds over
the fields utc_instant_is_canonical already validates, counted from a
Gregorian origin shifted one 400-year cycle so every term stays non-negative.
requested_at_within_skew compares integers, and now also refuses a
non-canonical observed instant. device_instant_minus had no other callers and
is deleted. device_instant_plus keeps its positive, effectful uses (challenge
and enrolment-code expiry off a live Clock.Now).

the_read_skew_window_brackets_sixty_seconds is back on the hermetic route,
with its wet schedule row and route-gap expectation removed. It also gains a
leap-day crossing, a year crossing, and a non-canonical observed instant.

The bound-realization control stays wet. device_pending_response_at takes no
store, so the store Read can't be supplied at that interface. Its exclusion
row now names only that Read, and its dissolution condition names either
route that would bring it back to hermetic.

Local: claim_batch 14/14 hermetic (skew claim 5982 eval steps);
claim_batch --wet passes the control.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 24, 2026
…2942, route_gap_unenrolled=3)

The two enrolment-code claims and the ntfy readback root move to
*_wet_witness_test.dag files with the triple enrolment #12000 uses:
FloorRouteGapExpectation rows (chunk_25), WetScheduledClaim rows, and
LocalRepoWetLane rows in gunbc.ci_layer_roots with named reasons and
dissolution conditions. Per the section 3 witness rule the mint's encoding is
split out as enrolment_code_of_entropy and witnessed hermetically over supplied
octets (16 -> exact hex, 15/17 -> refused); the real Urandom mint stays as the
one wet inhabitance claim. The root claim now asserts only what holds on every
host (refused before minting, store never created): every reading's verdict
is a refusal, ending at ActiveProcessJoinsUnbound.

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

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

APPROVE-MERGE at exact head 70687a30413d3797c53b3e870762f2fd2750f68c.

The current main-based tree preserves the reviewed App Attest step-4 design and resolves the two source conflicts correctly.

  • approval_broker_serve consumes the relocated HttpMethod/GET/POST authority and still carries exactly six device handlers, each mounted only as POST and dispatched to its corresponding route fold.
  • floor_route_gap keeps main's chunk-13 population and appends exactly the bound-realization wet control. That identity is also in local_repo_wet_schedule; its first unmocked effect is the enrolment-store Filesystem.Read, so the wet standing is honest rather than a designed substitute.
  • docs/design-rung-drops.md is regenerated, and the exact-head generated-artifact gate passes.

The security-critical route seams remain coherent:

  • the three unreadable X-Approval-* header authorities are deleted; reads carry strict ReadAuthentication JSON and push carries { auth, push };
  • the Swift client sends the same six POST shapes and signs the same canonical route/client-data projections the server reconstructs;
  • writer admission precedes decoding on enrolment, redemption and push-update writes;
  • native crypto admission precedes store reads or verifier calls and remains fail-closed until one receipt covers P-256 signature verification, App Attest attestation and assertion verification, and the P-256 base-point-order fact;
  • read admission requires an active enrolment, canonical timestamps in the [-60s,+60s) window, an assertion over the exact route bytes, and an atomic per-enrolment counter advance before the operation;
  • path identities are canonicalized and the store rejects non-slot-addressable keys before any filesystem read.

The later repairs are accepted:

  1. device_instant_minus is deleted. Skew is now pure signed-second arithmetic over fully canonical UTC instants, with leap-day, year-boundary, exact-boundary and non-canonical controls.
  2. The redemption-gate claim supplies a decodable signed-redemption body at the route interface instead of paying to mint capability tags it never inspects. The real body decoder remains executed by the wire witness, so this is a legitimate witness split rather than lost evidence.
  3. The one bound-realization control remains wet for the structural reason stated: device_pending_response_at owns the store read and accepts no store observation. Its route-gap and wet-schedule enrollments agree.
  4. CasGenerationSpaceExhausted is carried through gunbc.compute.attempt_lifecycle as its own typed store refusal rather than becoming a non-exhaustive or generic failure.
  5. The prior linear-generation lifetime cliff is absent; the counter wet population covers replay, per-enrolment standing, races, interleaving and operation beyond the former 4096 bound.

Run 36060763867 passes compiler, clippy, emit-build, floor and witnesses at this exact SHA. GitHub reports CLEAN and mergeable.

No source condition remains. Current main has advanced by two emitter commits since this head; the merge queue must adjudicate that composed revision normally. A queue red is a repair/requeue event, never grounds to bypass the queue.

gunbai-bot Bot pushed a commit that referenced this pull request Sep 24, 2026
…by the d6f3ef1 merge (floor 36065148040, route_gap_unenrolled=2)

The chunk_13 conflict was resolved to main's line on a misread diff; main never
carried test.claim.approval_device_routes_wet_witness_test's TimestampAdd and
Read expectations. Restored verbatim from #12000's head 50c93dc. Audit: every
line #12000 adds is present in this tree except approval_device_routes' original
issuance verb, which this PR replaces by design.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit 41c12eb Sep 25, 2026
5 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/nimble-eagle-216-step4 branch September 25, 2026 03:46
gunbai-bot Bot pushed a commit that referenced this pull request Sep 25, 2026
Conflicts resolved as a three-way merge against #12000's pre-landing head
50c93dc as base, so #12000's landed fixes and this PR's changes both apply.
floor_route_gap chunk_13 takes the landed line: #12000 moved the read-skew
claim to the hermetic file, so its wet expectation is gone by design.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 25, 2026
Resolves the project.yml conflict with #12000 by deriving its MARKETING_VERSION and
CURRENT_PROJECT_VERSION in gunbc.approve_ios_project (MARKETING_VERSION and
PRODUCT_BUNDLE_IDENTIFIER read from gunbc.auth.approval_app_attest_config); both
generated files regenerated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.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