Skip to content

Model org-admin credential acquisition and custody - #9778

Merged
briansrls merged 6 commits into
mainfrom
session/cool-boar-207
Aug 31, 2026
Merged

briansrls merged 6 commits into
mainfrom
session/cool-boar-207

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • model GitHub org-admin credential acquisition shapes and their org Actions capability surface from upstream docs
  • add a fail-closed SecretMaterial custody/standing admission that distinguishes stored bytes from a scope-proven, current credential
  • document the interim fine-grained PAT handoff, read-only validation receipt, and terminal GitHub App installation-token migration

No real credential is acquired, stored, or read by this change. CLI/REST transport remains outside the upstream interface model.

Verification

  • git diff --check
  • cargo test -p v1-compiler --test namespace_occurrence_serde --no-default-features — 7 passed
  • full .dag parse sweep via v1_src_dag_parse — 4,414 files parse-clean

@gunbai-bot

gunbai-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Analyst provenance ruling (relayed by proud-pike-265, 2026-08-30 side-chat consultation) — the authoritative critique of this PR's genealogy model. The two-arm CredentialProvenance shape is REJECTED as authoritative; the corrections below replace it. Ruling verbatim:


Overall judgment

The operator’s center is right: the human bootstrap must be represented, not hidden behind “credential exists.” The proposed two-arm recursive chain should not be built unchanged, however.

The principal correction is:

Acquisition genealogy, present-use validity, and future-renewal dependency are three different graphs.

A credential may have been acquired using another credential without continuing to depend on it. Conversely, a current credential may depend on an installation, organization membership, SSO authorization, provider policy, or revocation authority that was not itself a parent credential in the acquisition history.

I would therefore reject this as the authoritative shape:

CredentialProvenance =
    DerivedFrom { parent_credential, derivation }
  | HumanBootstrap { ... }

and replace it with a transaction graph whose edges are typed by what they mean.

The second major correction is that “well-founded means exactly one HumanBootstrap” is too strong. The closure may require:

  • more than one human participant;
  • a human plus a registered hardware authenticator;
  • a human plus an independent organization-owner approval;
  • a federated IdP assertion;
  • an external provider authority boundary;
  • a workload or device attestation root;
  • an alternate account-recovery path.

For this GitHub program, it is reasonable to require at least one explicit human ceremony in every initial privileged bootstrap path. It is not sound to make exactly one human the universal trust-root law.


Recommended core shape

Do not embed a recursively copied chain in every credential row. Give every artifact and transaction structural identity, then derive closures over the shared graph.

CredentialArtifact {
    credential_identity,
    credential_kind,
    issuer_identity,
    subject_identity,
    target_identity,
    granted_scope,
    intrinsic_validity_window,
    custody_handle,
    acquisition_transaction_identity
}

custody_handle identifies where the material can be used without carrying the bytes.

Then:

CredentialAcquisitionTransaction {
    transaction_identity,
    issuer_identity,
    requested_output,
    requirements,
    execution_receipt,
    output_credential_identity
}

The requirements should be a closed sum resembling:

AcquisitionRequirement =
    CredentialProof {
        credential_identity,
        proof_purpose
    }
  | HumanAuthorizationCeremony {
        ceremony_identity
    }
  | AuthorityResourceStanding {
        registration_or_installation_identity
    }
  | AuthorizationGrantStanding {
        grant_identity
    }
  | ApprovalReceipt {
        approver_identity,
        approved_request_identity
    }
  | AuthenticatorBindingStanding {
        actor_account_identity,
        authenticator_identity
    }
  | WorkloadOrDeviceAttestation {
        attestation_identity
    }
  | CustodyUseStanding {
        secret_handle
    }

This is naturally a multi-input transaction. That matters because an installation token is not simply “derived from a private key.” It is minted by GitHub after the caller proves the app’s identity with a JWT, names an installation, and requests permissions bounded by the app installation. GitHub installation tokens then expire after one hour. citeturn907305view2turn907305view3

The human step should likewise be an executed ceremony, not a parent credential:

HumanAuthorizationCeremonyReceipt {
    ceremony_identity,
    provider_identity,
    human_actor_identity,
    provider_account_identity,
    interaction_surface,
    authorized_action,
    target_resource,
    accepted_authenticator_classes,
    observed_role_or_authority,
    provider_result_identity,
    completed_at
}

Do not record:

what_the_human_proves = password | totp_value | ...

The model does not know or verify the password. It knows that the provider accepted an authentication ceremony using declared authenticator classes. NIST makes the same useful separation: authenticators are bound to accounts, authentication proves control of them, and binding, renewal, invalidation, and account recovery have distinct lifecycles. citeturn996558view6turn645818view0

org-role is also not something the human cryptographically proves. It is provider-side authorization state observed during or after authentication.


1. The two-arm provenance shape is insufficient

SSO is not either arm cleanly

An SSO-mediated GitHub session may require:

HumanUsesAuthenticator
+ IdPAuthenticatesHuman
+ IdPProducesAssertion
+ GitHubAcceptsAssertion
+ LinkedIdentityStanding
+ OrganizationMembershipOrRole

That is a composite authentication and federation ceremony, not a unary credential derivation.

For classic GitHub PATs, SAML authorization is also a separately revocable authorization relation. GitHub documents that the authorization can end because an owner revokes it, the user leaves the organization, the PAT is regenerated or its scopes are edited, or the PAT expires. Fine-grained PATs are authorized during creation instead. citeturn996558view2

So represent:

FederatedAuthenticationReceipt
LinkedIdentityStanding
CredentialOrganizationAuthorizationStanding

as distinct facts.

A hardware key is an authenticator, not the human root itself

The honest shape is:

HumanAuthorizationCeremony
    requires
HumanPresence
+ BoundAuthenticatorStanding(hardware_key)
+ ProviderAccountStanding

The human participates; the hardware key supplies cryptographic proof. The key has its own lifecycle—binding, loss, invalidation, replacement—and should not be collapsed into either parent_credential or prose under HumanBootstrap.

A second human is an authorization dependency

A fine-grained PAT may require organization-owner approval before it can access non-public organization resources. The requester and approver may therefore be different humans. GitHub explicitly models such tokens as pending until an organization administrator approves them. citeturn996558view0turn996558view1

That should produce:

PrivilegedCredentialRequest
+ RequesterCeremonyReceipt
+ ApproverCeremonyReceipt
→ AuthorizationGrantReceipt

The approver’s credential is not necessarily a parent of the resulting token. The approval is an authority-bearing fact consumed by issuance or activation.

Support exact participant requirements:

ApprovalRequirement {
    required_roles,
    required_distinct_actors,
    quorum,
    subject_request
}

For the current sole-founder organization, the accepted transaction may happen to use one actor in several roles. That should be an observed identity equality, not a universal structural assumption.

Device flow also disproves the binary shape

OAuth device authorization deliberately splits the process: software initiates a request, while a human uses a separate user agent to authenticate and authorize it. The eventual token is not purely programmatically derived, but neither is the whole flow a single terminal human action. citeturn996558view7

The useful decomposition is:

DeviceAuthorizationRequestReceipt
+ HumanAuthorizationCeremonyReceipt
+ AuthorizationServerGrant
→ TokenIssuanceReceipt

App registration and installation are not credentials

These are persistent authority resources:

GitHubAppRegistration
GitHubAppInstallation
GitHubAppPermissionGrant
InstallationRepositorySelection

They affect what credentials can be minted and what resulting credentials can do, but they are not secret-bearing credentials themselves.

Likewise, GitHub’s app private key is a proof key. GitHub stores the public portion, while the private material is downloaded and must be placed into custody. GitHub exposes a fingerprint that can be compared against the locally held key, which is a good model-compatible binding probe because no private bytes need enter the model. citeturn996558view5

A useful receipt is:

GitHubAppPrivateKeyBindingReceipt {
    app_registration_identity,
    provider_key_fingerprint,
    custody_key_fingerprint,
    custody_handle,
    compared_at,
    match_result
}

Account recovery is an alternate bootstrap path

The proposed “human with password plus 2FA” terminal omits the paths that can replace those authenticators:

  • backup authenticators;
  • recovery codes;
  • recovery contacts;
  • repeated identity proofing;
  • provider-assisted account recovery;
  • IdP recovery or IdP-administrator intervention.

NIST treats account recovery as distinct from ordinary authentication and explicitly describes several recovery methods. It also recommends multiple bound authenticators because recovery is often the weak point of an authentication system. citeturn645818view0turn645818view1

You do not need to model GitHub’s internal recovery implementation in detail. You do need an explicit boundary:

ExternalAccountRecoveryBoundary {
    provider_account_identity,
    documented_recovery_classes,
    authorities_able_to_rebind_authenticators,
    last_reviewed_at
}

Without that, “genealogy reaches the root” is an overclaim.

Revised well-foundedness law

Use:

CredentialGenealogyWellFounded =
    all_dependencies_resolve
  ∧ acquisition_graph_is_acyclic
  ∧ every_artifact_has_one_current_producer
  ∧ every_root_is_explicitly_classified
  ∧ every_required_approval_is_present
  ∧ every_recovery_boundary_is_named
  ∧ no_secret_bytes_are_carried

Possible root classes:

CredentialGenealogyRoot =
    HumanAuthorizationCeremony
  | ExternalIssuerTrustBoundary
  | ExternalAccountRecoveryBoundary
  | WorkloadOrDeviceAttestation
  | FactoryOrHardwareTrustAnchor

For this particular program, add:

PrivilegedGitHubBootstrap
→ at_least_one(HumanAuthorizationCeremony)

Do not add the generic law:

all credential genealogies
→ exactly_one(HumanBootstrap)

2. Acquisition history and runtime dependency must be distinct

Yes—this distinction is mandatory.

I would derive at least three separate closures.

A. Historical acquisition genealogy

AcquiredUsing {
    input_or_requirement,
    acquisition_transaction,
    output
}

This is immutable audit history. Invalidating an input later does not rewrite history and does not automatically invalidate the output.

Examples:

  • A PAT used to create a GitHub App registration is historical after registration.
  • A browser session used to generate an app private key is historical once the key is provisioned.
  • A human ceremony used to approve an installation is historical once the approval exists.

B. Present-use dependency

CurrentUseRequires {
    credential_identity,
    dependency_identity,
    exact_capability,
    invalidation_effect
}

This graph answers:

What must remain true for this credential to perform this operation now?

Typical dependencies include:

IntrinsicExpiryCurrent
IssuerAcceptsCredential
AppInstallationActive
OrganizationMembershipCurrent
CredentialOrganizationAuthorizationCurrent
ScopeContainsRequiredCapability
ResourceStillInGrantedSet
NetworkOrIpPolicySatisfied
CredentialMaterialAvailableInCustody

GitHub provides concrete examples of these non-genealogical dependencies:

  • PATs are tied to the user who generated them and become inactive if that user loses access to the resource. citeturn996558view0
  • A suspended GitHub App installation cannot access that installation account’s resources. citeturn996558view4
  • Uninstalling the app revokes tokens associated with it. citeturn996558view3
  • A classic PAT’s SSO authorization can be revoked independently of the token material. citeturn996558view2

C. Renewal or replacement dependency

RenewalRequires {
    credential_kind,
    dependency_identity,
    replacement_transaction_identity
}

This answers:

What must remain available to obtain the next credential after this one expires or is lost?

For a GitHub App installation token:

RenewalRequires:
    AppPrivateKeyCustodyAvailable
  + AppRegistrationCurrent
  + InstallationCurrent
  + TokenMintEndpointReachable

The current installation token has its own one-hour intrinsic expiry, while a valid app JWT is used to obtain its replacement. citeturn907305view3

For an expiring OAuth access token:

RenewalRequires:
    RefreshTokenCurrent
  + OAuthGrantCurrent

For a PAT:

ReplacementRequires:
    HumanAuthorizationCeremony
  + AccountAndRoleStanding
  + OrganizationApproval, when applicable

Optional fourth graph: custody availability

Remote validity and local usability are also different.

CredentialCustodyStanding =
    AvailableToExactPrincipal
  | AvailableButWrongPrincipal
  | TemporarilyUnavailable
  | Missing
  | SuspectedCompromised
  | Destroyed

A remotely valid token whose secret handle cannot be accessed is unavailable to the actuator, but it has not necessarily been revoked at GitHub.

Typed invalidation effects

Every dependency edge should declare its effect:

DependencyInvalidationEffect =
    InvalidatesCurrentUse
  | ReducesCurrentScope
  | BlocksFutureMinting
  | BlocksHumanRecovery
  | MakesCustodyUnavailable
  | HistoricalOnly

Then event propagation is not:

parent invalid
→ all descendants invalid

It is:

dependency event
+ provider-specific invalidation rule
→ declared effect on affected credentials

Your app-token example

A PAT used only to register an app should normally have:

PAT
--AcquiredUsing-->
GitHubAppRegistration

not:

PAT
--CurrentUseRequires-->
InstallationToken

Revoking that PAT must therefore not transitively poison the app branch merely because the PAT appears earlier in history.

By contrast:

GitHubAppUninstalled
--InvalidatesCurrentUse-->
AssociatedInstallationTokens

is supported by GitHub’s documented behavior. citeturn996558view3

For app-private-key deletion, do not guess a universal effect. The documented safe conclusion is that the deleted key can no longer be used as the app proof key for future JWT-based minting. Unless provider evidence establishes that already minted installation tokens are also revoked, classify the effect as:

BlocksFutureMinting

and let the current token’s own probe and expiry determine current use. GitHub documents key deletion and installation-token minting separately, which is exactly why the model should not infer transitive revocation from acquisition order. citeturn996558view5turn907305view3

Standing should be capability-specific

Avoid:

CredentialCurrent

Use:

CredentialCapabilityStanding {
    credential_identity,
    provider,
    target_identity,
    exact_operation,
    observed_permissions,
    observed_at,
    valid_until,
    event_watermark
}

A token proven able to list runner groups is not thereby proven able to modify runner groups, alter organization settings, or install an app.

A useful total sum is:

CredentialCapabilityStanding =
    Current {
        exact_operation,
        target,
        probe_receipt,
        valid_until,
        event_watermark
    }
  | ProbeDue {
        prior_receipt
    }
  | IntrinsicallyExpired
  | ProviderRevoked
  | ProviderSuspended
  | AuthorizationGrantMissing
  | InsufficientScope
  | ResourceAccessLost
  | CustodyUnavailable
  | ProviderStateUnknown

3. Honest standing for the human bootstrap

A previous successful human ceremony is evidence of a historical event. It is not evidence that:

  • the password remains unchanged;
  • the hardware key is still possessed;
  • the TOTP device still works;
  • the account has not been suspended;
  • the person still has the required organization role;
  • the IdP account still works;
  • account recovery remains usable;
  • the human will be available at the next deadline.

Therefore do not produce:

HumanBootstrapCurrent

from a dated receipt.

Split the concern into three objects.

Historical ceremony evidence

HumanCeremonyOutcome =
    Succeeded {
        receipt
    }
  | AuthenticationRefused
  | AuthorizationRefused
  | ApprovalRefused
  | InteractionAbandoned
  | ProviderUnavailable

A success receipt never expires as history.

Planning readiness

HumanInterventionReadiness =
    RecentlyExercised {
        ceremony_class,
        last_success,
        planning_valid_until
    }
  | OperatorAttestedAvailable {
        attested_at,
        planning_valid_until
    }
  | ExerciseDue {
        due_by
    }
  | KnownUnavailable {
        cause
    }
  | Unknown

planning_valid_until says how long you are willing to use the evidence for continuity planning. It does not authorize a privileged action and does not establish credential validity.

A low-risk scheduled exercise can strengthen this standing—for example, a real login to an appropriate read-only administration surface—without trying to inspect or reproduce the authenticator secrets.

Renewal obligation

HumanRenewalObligation {
    dependent_credential_or_key,
    required_ceremony,
    credential_expires_at,
    estimated_ceremony_lead_time,
    retry_and_escalation_buffer,
    latest_safe_start
}

with:

latest_safe_start =
    expires_at
  - ceremony_lead_time
  - retry_and_escalation_buffer

Then:

HumanRenewalStanding =
    NotDue
  | Due
  | InProgress
  | Completed
  | MissedContinuityAtRisk
  | CredentialUnavailable

This preserves the operator’s intended distinction:

HumanRenewalDue
≠ Outage

But also prevents the opposite mistake:

missed latest_safe_start
= mere scheduled obligation

Once the renewal path can no longer complete before the credential’s required use horizon, it is a continuity incident even if the current credential has a few minutes left.

Require only the horizon the operation actually needs

A one-shot read does not necessarily require a healthy twelve-month renewal path. It requires credential validity for:

operation_duration
+ retry_budget
+ rollback_or_followup_horizon

A recurring fleet controller may additionally require a continuity standing.

So consumption should be:

CredentialUsableForOperation {
    exact_capability,
    target,
    current_use_standing,
    material_availability,
    valid_through_required_horizon
}

and, where policy demands ongoing operation:

CredentialContinuityStanding {
    renewal_candidate,
    renewal_lead_time,
    projected_continuity_horizon
}

Do not require every historical acquisition ancestor to be “current.” That would make an expired browser session falsely invalidate a perfectly usable app key and installation token.

Recovery deserves a separate recurring standing

Because account recovery can rebind authenticators, the full control genealogy is incomplete without it. At minimum:

AccountRecoveryStanding =
    ReviewedCurrent {
        recovery_boundary,
        last_exercised_or_reviewed,
        valid_until
    }
  | ReviewDue
  | KnownBroken
  | ExternalProviderOpaque

ExternalProviderOpaque may be acceptable for current use, but should appear as an explicit continuity risk rather than disappear from the graph.


4. Fleet-converge is a good first consumer—with producer separation

There is nothing wrong with fleet-converge being the first policy consumer. It is probably better than building a generic /whoami-style auth probe, because the exact read needed by converge proves the exact target and permission that matter.

The correct vertical slice is:

ResolveCredentialCustody
        |
        v
ObserveGitHubRunnerGroups
        |
        +--> CapabilityProbeReceipt
        +--> ObservedRunnerGroupState
        |
        v
DiffDesiredAgainstObserved
        |
        v
FleetConvergeDisposition

The observer should have a total result:

GitHubRunnerGroupObservationOutcome =
    Executed {
        capability_probe_receipt,
        observed_runner_groups
    }
  | CredentialIdentityMissing
  | CredentialMaterialUnavailable
  | CredentialIntrinsicExpiry
  | AuthenticationRefused
  | OrganizationAuthorizationRefused
  | RequiredScopeMissing
  | AppInstallationSuspended
  | ProviderUnavailable
  | ResponseInvalid

Only Executed reaches the diff.

This is important:

Credential failure
≠ DesiredStateDivergence

If the observer could not read the remote state, the system does not know whether desired and observed diverge.

Converge must consume the standing, not mint it by assertion

The same network execution may produce both:

  • a credential capability receipt; and
  • the runner-group observation.

That is efficient and honest. But the producer identity should remain ObserveGitHubRunnerGroups or GitHubCredentialCapabilityProbe, not FleetConvergeDecision.

This preserves the producer/renderer/consumer distinction:

Observer produces evidence
Diff derives divergence
Converge consumes the disposition
Renderer displays it

A stale standing should normally trigger the probe

Avoid:

ProbeReceiptStale
→ ConvergeRefusedMissingCredential

when the credential material and probe path are available.

Prefer:

ProbeReceiptStale
+ ProbeExecutable
→ ExecuteProbe

Refuse only when the refresh cannot be executed or the resulting probe refuses.

Read standing cannot authorize write

When the actuator later mutates organization settings:

RunnerGroupReadCapability
-X->
RunnerGroupWriteAuthorization

The mutation transaction must consume its own exact capability standing or let the attempted mutation itself produce the authoritative execution result.

You may ultimately choose separate credentials:

  • a continuously available read-only observer credential;
  • a more tightly controlled mutation credential.

The genealogy substrate should permit that without treating one as the parent of the other.

“Read-only probe” is not necessarily lifecycle-neutral

A GitHub API read does not mutate runner-group desired state, but it may still update provider-side token usage or audit metadata. GitHub automatically removes PATs that have not been used for a year, so a periodic validation request can, by inference, keep a PAT from reaching that inactivity condition. citeturn996558view0

Represent:

ProbeEffect =
    TargetResourceReadOnly
  + ProviderAuditEventPossible
  + CredentialLastUsedMayAdvance

This is another reason to use the actual needed converge observation rather than run gratuitous keepalive probes.


5. Prior art worth stealing

NIST digital-identity lifecycle: steal the vocabulary

The most directly useful source is NIST SP 800-63B:

AuthenticatorBinding
Authentication
Renewal
Invalidation
AccountRecovery

Those are separate operations, and the document treats authenticator lifecycle events and recovery paths independently. That maps cleanly to your need without requiring an identity framework. citeturn645818view0turn645818view3

Steal:

  • authenticators are bound to accounts;
  • successful authentication is an event;
  • compromised authenticators are invalidated;
  • renewal is distinct from authentication;
  • alternate authenticators and recovery paths are first-class;
  • lifecycle events carry time and source evidence.

Do not import NIST assurance levels unless the program has a concrete consumer for them.

OAuth device flow: steal split ceremonies

RFC 8628 is a clean example of a program-initiated transaction that requires a separate human authorization ceremony. It supports the transaction-graph model and disproves the idea that every output has one unary parent. citeturn996558view7

Steal:

ProgramInitiates
HumanAuthorizes
IssuerMints

as separate receipts.

OAuth token exchange: steal delegation semantics only when needed

RFC 8693 distinguishes impersonation from delegation and represents subject and actor tokens separately. That will be useful if the system later mints credentials “on behalf of” a human or another workload. citeturn996558view8

Steal:

SubjectIdentity
ActorIdentity
Delegation
Impersonation
Audience
RequestedScope

Do not implement a general token-exchange subsystem merely to model GitHub App tokens.

X.509: steal path validation, not the tree metaphor

RFC 5280 separates certification paths, trust, validity periods, policy constraints, and revocation processing. The useful lesson is that current acceptance is derived from a validation procedure over declared inputs—not from the historical story of how the certificate file arrived. citeturn505287view0

Steal:

ExplicitTrustAnchor
ValidityWindow
PurposeOrUsageConstraint
CurrentRevocationEvidence
PathValidationReceipt

Do not copy:

credential ancestry
= automatic transitive revocation

Your GitHub objects do not form an X.509 issuer chain.

SPIFFE/SPIRE: steal attestation-to-short-lived-credential rotation

SPIFFE/SPIRE separates workload attestation from short-lived identity issuance and automatic rotation. Its Workload API also streams current credential and trust-bundle sets; when credentials or bundles disappear from later authoritative updates, consumers are expected to stop using them. citeturn801082search8turn482072search3turn907305view4

Steal:

AttestationReceipt
→ ShortLivedCredentialIssuance
→ AutomaticRotation
→ CurrentAuthorizedSet
→ CeaseUseOnRemoval

Also steal the idea that some bootstrap roots are not secrets at all: SPIFFE’s Workload API can identify local callers through out-of-band process evidence rather than requiring a pre-shared client secret. citeturn907305view4

Do not deploy SPIFFE merely to mint a GitHub token. Its value here is conceptual.


Minimal live model

For the first build, I would keep the implementation to these authorities:

CredentialArtifact
CredentialAcquisitionTransaction
HumanAuthorizationCeremonyReceipt
AuthorityResourceStanding
AuthorizationGrantStanding
CredentialCapabilityProbeReceipt
CredentialCapabilityStanding
CredentialRenewalCandidate
CredentialContinuityStanding
CredentialGenealogyStanding

with these edge types:

AcquiredUsing
CurrentUseRequires
RenewalRequires
AuthorizedBy
ScopeBoundBy
CustodiedAt
InvalidatedBy

and this total genealogy standing:

CredentialGenealogyStanding =
    Complete {
        acquisition_root_set,
        transaction_set_digest
    }
  | MissingProducer {
        artifact
    }
  | MissingDependency {
        transaction,
        dependency
    }
  | AmbiguousProducer {
        artifact,
        producers
    }
  | CycleDetected {
        cycle
    }
  | UnclassifiedRoot {
        root
    }
  | RecoveryBoundaryUnmodeled {
        provider_account
    }

Do not make CredentialGenealogyStanding::Complete imply current usability.

Current usability is separately:

CredentialOperationStanding =
    Usable {
        capability,
        target,
        valid_through,
        capability_probe_receipt
    }
  | ProbeRequired
  | MaterialUnavailable
  | Expired
  | Revoked
  | Suspended
  | AuthorizationMissing
  | InsufficientCapability
  | ProviderUnknown

Permanent witnesses

The build should carry at least these falsifiers.

PAT used to create app registration
+ PAT later revoked
+ no CurrentUseRequires edge
→ app branch not transitively invalidated
GitHub App uninstalled
→ associated installation credential refused
app private key unavailable
+ unexpired installation token currently proves exact read capability
→ CurrentUse may remain
∧ RenewalBlocked

The last witness should be provider-profile-specific; do not admit it until the GitHub behavior is evidenced.

expired browser session that originally generated app key
→ historical acquisition remains valid
∧ app key not invalidated
classic PAT bytes present
+ SSO authorization revoked
→ organization capability refused
fine-grained PAT request pending owner approval
→ public-only or pending standing
≠ organization-admin standing
two distinct human approvals required
→ well-founded genealogy with two human participants admitted
recent successful human login
+ organization role subsequently removed
→ bootstrap readiness refused for org-admin ceremony
human ceremony receipt exists
+ account recovery boundary unmodeled
→ genealogy cannot claim complete control-root closure
read capability current
+ requested mutation
→ mutation authorization refused
credential probe stale
+ custody available
+ probe executable
→ probe runs rather than reporting missing credential
credential validity ends before operation retry horizon
+ no renewal candidate completes in time
→ operation refused
secret bytes appear in any modeled value or receipt
→ custody-model violation
acquisition dependency cycle
→ genealogy refused

Consolidated ruling

Adopt the human-bootstrap center with this replacement construction:

A privileged credential is produced by an identified acquisition transaction over an explicit set of credential proofs, human ceremonies, authority resources, approvals, authenticator bindings, and external trust boundaries. The immutable acquisition genealogy is finite, acyclic, and root-complete, but it does not determine present validity. Current use, scope, custody availability, and renewal continuity are separately derived from their real provider dependencies. Human ceremony receipts prove only that a ceremony succeeded at a past time; they support planning readiness but never stand in for a current credential probe. Fleet-converge may be the first policy consumer, provided the exact read observer remains the evidence producer and credential failure cannot masquerade as desired-state divergence.

The most consequential refusals are:

unary parent-credential genealogy
generic parent-revokes-all-descendants propagation
exactly-one-human universal root law
historical human receipt represented as current authentication
read capability generalized to write authority
unmodeled recovery paths hidden behind “human with 2FA”
converge minting its own credential standing

With those corrections, the model will capture the operator’s intended recursion without turning acquisition history into a false PKI chain or paging the human merely because an obsolete historical session expired.

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