import type { CredentialUnusableObservation, HarnessEvent } from "@claudexor/schema"; /** * The daemon's bounded, self-expiring memory of typed `credential_unusable` * observations (A7): "this credential is DEAD, not quota-spent". * * Deliberately IN-MEMORY, never journaled: profile readiness is non-durable by * contract (the doctor's projection), the quota poller re-derives vendor * rejections within a poll cycle after a restart, and a restart usually * follows exactly the re-login that heals a dead credential — journaling would * buy rollback-compat risk to preserve evidence that expires anyway. The * `QuotaAbsence` channel is unsuitable on purpose: the registry hides an * absence while ANY live snapshot covers the subject, which is exactly how a * dead credential with a lingering cooldown snapshot would vanish. * * Clearing contract (all three, per the design roast): * 1. self-expiry — every row carries `expires_at`, clamped to 24h max; * 2. a successful model response for the same subject (`observeEvent`); * 3. a credential-generation change voids the verdicts about the changed * generation: a login/logout clears the WHOLE ledger * (`noteCredentialChange`, wired in claudexord's setup lifecycle), while a * control-API credential mutation (profile enable/disable/create/remove, * secret set/delete) clears PER SUBJECT (`clearSubject` / * `clearDefaultSubjects`, wired beside the daemon's status-cache busting). * Clearing is always fail-open — a lost observation costs at * most one attempt rediscovering a refusal, while a stale one poisons * rotation. */ export declare class CredentialUnusableLedger { private readonly now; private rows; constructor(now?: () => Date); /** Validate, clamp to the TTL bound, newest-wins per (subject, model). */ record(value: CredentialUnusableObservation): void; /** Every un-expired observation (the read side of the orchestrator deps). */ live(): readonly CredentialUnusableObservation[]; /** * Success telemetry (wired where usage events already flow): a usage event * with served tokens proves the vendor honored this subject's credential, * so its credential-wide observations are stale. A model-SCOPED entitlement * observation clears only when the event's observed model matches exactly — * vendor display labels are not slugs, so an unprovable match honestly * leaves the row to its short TTL or a generation change. */ observeEvent(harnessId: string, event: HarnessEvent): void; /** Credential generation changed wholesale (login/logout): every verdict * about the old generation is void. */ noteCredentialChange(): void; /** ONE subject's credential changed (a control-API profile or profile-secret * mutation): only ITS verdicts are void, across every model scope. * `profileId` null = the harness's default subject. */ clearSubject(harnessId: string, profileId: string | null): void; /** A bare managed secret name changed an engine-DEFAULT credential slot. * WHICH harness reads that slot is adapter knowledge the daemon does not * duplicate, so every default subject's verdicts are voided — fail-open by * the clearing contract (costs at most one rediscovered refusal). */ clearDefaultSubjects(): void; private prune; } //# sourceMappingURL=credential-unusable-ledger.d.ts.map