The Update branch of validate_standalone_proposal_account_identity_proof
(UPD-04, D-09/D-10) — the sibling of validateAddProposalAccountIdentityProofs
for standalone Update proposals. Pure and non-throwing. Used pre-apply by
the same two standalone-proposal admission seams (src/engine/admin-policy.ts
inbound, src/engine/group-engine.ts local propose path) so a bad Update —
an unattributable sender, an invalid 0x8009 proof, or a replacement leaf
bound to a different account identity — never reaches the queued-proposal
state. The commit-time tree diff in
validateCommitAccountIdentityProofs still catches a bad Update
after apply if either admission gate is bypassed; both entry points enforce
the same rule.
Deliberately returns CommitIntegrityViolation | undefined, NOT the
CommitLegalityOutcome tri-state: per D-10, pre-apply admission is
branch-independent — there is no candidate parent whose later arrival could
make an unresolvable-sender Update proposal judgeable, so there is no
deferral case here (unlike validateCommitAccountIdentityProofs's
undecidable outcome, which exists because a commit MAY later become
classifiable against a different candidate parent).
Accepts both bare Proposal and ProposalWithSender items (normalizes
each first) and ignores every non-Update proposal kind. Returns on the
first failing Update, in this order:
the sender must be attributable — a normalized item with an undefined
senderLeafIndex is rejected as unattributable-leaf (D-10 rejects
rather than defers, matching admin-policy.ts's self_remove
sender-resolution template);
the sender's CURRENT identity is resolved via
getCredentialFromLeafIndex(ratchetTree, senderLeafIndex) +
getCredentialPubkey; any throw (a blank or out-of-range leaf, a
non-basic credential) is also unattributable-leaf;
the replacement leaf's own 0x8009 proof is validated with
validateLeafAccountIdentityProof; an AccountIdentityProofError
carries its reason as proofReason, any other throw omits it;
the replacement leaf's credential identity is compared against the
resolved sender identity; a throw is invalid-credential, a mismatch is
member-identity-changed — the same literal the commit-time path uses
for the same spec rule (account-identity-proof-v2.md "a change of
account identity is not a self-update"), so the two admission points
cannot report the same violation differently.
leafIndex is omitted throughout (D-06): the proposal has not been
applied, so the replacement leaf has no tree position yet, matching the Add
sibling's documented convention. Every detail string names only the
positional proposal index and the reason — never a pubkey, credential
bytes, or err.message.
The Update branch of
validate_standalone_proposal_account_identity_proof(UPD-04, D-09/D-10) — the sibling of validateAddProposalAccountIdentityProofs for standalone Update proposals. Pure and non-throwing. Used pre-apply by the same two standalone-proposal admission seams (src/engine/admin-policy.tsinbound,src/engine/group-engine.tslocal propose path) so a bad Update — an unattributable sender, an invalid0x8009proof, or a replacement leaf bound to a different account identity — never reaches the queued-proposal state. The commit-time tree diff in validateCommitAccountIdentityProofs still catches a bad Update after apply if either admission gate is bypassed; both entry points enforce the same rule.Deliberately returns
CommitIntegrityViolation | undefined, NOT the CommitLegalityOutcome tri-state: per D-10, pre-apply admission is branch-independent — there is no candidate parent whose later arrival could make an unresolvable-sender Update proposal judgeable, so there is no deferral case here (unlike validateCommitAccountIdentityProofs'sundecidableoutcome, which exists because a commit MAY later become classifiable against a different candidate parent).Accepts both bare
ProposalandProposalWithSenderitems (normalizes each first) and ignores every non-Update proposal kind. Returns on the first failing Update, in this order:senderLeafIndexis rejected asunattributable-leaf(D-10 rejects rather than defers, matchingadmin-policy.ts's self_remove sender-resolution template);getCredentialFromLeafIndex(ratchetTree, senderLeafIndex)+ getCredentialPubkey; any throw (a blank or out-of-range leaf, a non-basic credential) is alsounattributable-leaf;0x8009proof is validated with validateLeafAccountIdentityProof; anAccountIdentityProofErrorcarries itsreasonasproofReason, any other throw omits it;invalid-credential, a mismatch ismember-identity-changed— the same literal the commit-time path uses for the same spec rule (account-identity-proof-v2.md "a change of account identity is not a self-update"), so the two admission points cannot report the same violation differently.leafIndexis omitted throughout (D-06): the proposal has not been applied, so the replacement leaf has no tree position yet, matching the Add sibling's documented convention. Everydetailstring names only the positional proposal index and the reason — never a pubkey, credential bytes, orerr.message.