fastlane #28

Closed
larandar wants to merge 0 commits from fastlane into main
Owner
No description provided.
Caught while staging this ticket's own changes: `git add -A` picked up
the whole cargo build directory. Added before anything else lands.
jo.et0.pw is private, and Nix's sandboxed fixed-output fetch for a `git`
Cargo dependency has no credentials to reach it with (no /etc/nix/netrc,
no deploy key wired in) — `nix build` on this package failed on exactly
that. Vendoring as a path dependency sidesteps it structurally: the
source is just files inside `src` by the time the sandbox sees it, no
fetch to authenticate.

Not the real distribution model — that's still open (owner, 2026-08-09):
a deploy key, making jostoph-rs public, or folding it into a shared host
under Ting/ are all live options. This unblocks today's ticket
(Ting/Vedanta#1) without deciding between them. Bump by re-copying
vendor/jostoph-rs from a fresh clone at the new rev, deliberately, same
posture the git dependency had.
First time this code has actually been run through clippy — its own doc
comment said as much ("not yet cargo built"). Construct
PrincipalShapeProgram with its fields set at initialization instead of
Default::default() followed by two field assignments.
Two independent triggers, one binary — never one process trying to be
both. `vedanta serve` is the long-lived webhook responder (jostoph-rs's
`POST /v1/evaluate` and friends) a systemd *service* keeps alive.
`vedanta reconcile` is a single sweep a systemd *timer* invokes and lets
exit — no reconciliation rules exist yet (Ting/Vedanta#1), so it proves
the lldap wiring (src/lldap.rs: connect + bind against
VEDANTA_LLDAP_URL/BIND_DN/BIND_PASSWORD) and stops there. Conflating the
two would mean a webhook-handling process also carries a reconciliation
scheduler's failure modes — a stuck sweep wedging request handling.

src/telemetry.rs: tracing-subscriber always installs a local fmt layer;
an OTLP span exporter (tracing-opentelemetry) additionally activates when
OTEL_EXPORTER_OTLP_ENDPOINT is set — the standard OTel env var, not a
Vedanta-specific one, so the NixOS module needs no knowledge of the
fleet's telemetry topology beyond setting it. A failed exporter build
warns and falls back to local-only logging rather than refusing to
start — telemetry export failing is not a reason an identity service
should refuse to come up.

DOTENV_FILE (dotenv-rs), loaded before anything else touches the
environment: fleet-wide convention per owner ruling 2026-08-09 — sops-nix
decrypts a secret to a path, the unit sets DOTENV_FILE to it, the binary
loads it here. Optional: unset is a legitimate state (local `cargo run`
has no sops secret to point at), not a misconfiguration.

Verified against a real toolchain, not assumed: `cargo test`, `cargo
clippy --all-targets -- -D warnings`, and by hand — `serve` answers
/healthz and /v1/manifest and shuts down clean on SIGINT; `reconcile`
exits non-zero with the real cause for a missing env var, an unreadable
DOTENV_FILE, and a refused lldap connection, and does NOT hang when
OTEL_EXPORTER_OTLP_ENDPOINT points at a collector that isn't listening.
flake.nix: packages.default (rustPlatform.buildRustPackage against the
vendored dependency tree — no outputHashes needed, jostoph-rs is a path
dependency now) and nixosModules.default, built from the same mkVedanta
so the devShell, the package, and the module never drift against each
other. devShell carries forward from the bootstrap work on
tango/2-bootstrap (not yet merged to fastlane) — duplicated here rather
than depended on, since that branch isn't landed yet.

module.nix: two systemd units from one package, matching the binary's
own serve/reconcile split — vedanta.service (Restart=on-failure) and
vedanta-reconcile.service (Type=oneshot) behind a systemd.timer
(OnUnitActiveSec, default 15m, no measured requirement behind that number
yet). A static services.vedanta.user, not DynamicUser: DynamicUser's
per-activation username is unpredictable at eval time, and
services.sops.secrets.<>.owner needs a fixed name to target.

Secrets are explicitly NOT this module's decision: dotenvFile is a plain
nullOr path, and lldap.url/telemetry.otlpEndpoint are ordinary options
for the non-secret half — pointing dotenvFile at a real sops-nix secret
path is the deploying host's job (Ting/Vedanta#1's own scope note: this
ticket is the binary and the module it ships, not heimdallr's live
secrets wiring).

Verified: `nix build .#default` produces a working binary
(`vedanta --version` runs). `nix eval` against a minimal nixosSystem with
services.vedanta.enable = true confirms both units' ExecStart, the
timer's interval, and the environment (DOTENV_FILE, VEDANTA_LLDAP_URL,
OTEL_EXPORTER_OTLP_ENDPOINT) all wire through as declared — ONLY checked
by evaluating a real nixosSystem, not read off the module source by eye.
Everything up to this point had been verified against a nonexistent
lldap (connection refused) or a manual nix build + nix copy + ssh done
by hand. Neither is the same claim as "this works" — the real question
was always whether it binds against heimdallr's actual, live directory,
not a stand-in for it. This recipe is that check, repeatable: nix build
this working tree, nix copy the result onto heimdallr's own store over
ssh, run it there with the real admin bind credential — decrypted and
consumed entirely inside the remote shell, never crossing back to the
caller or landing in this recipe's own output.

Verified by running it: `reconcile` (the default) actually bound against
heimdallr's live lldap and returned the real no-reconciliation-rules-yet
no-op; overriding ARGS (`--version`, `serve`) confirmed the override path
works too.

Defaults to `reconcile`, not `serve` — serve blocks in the foreground
until Ctrl-C, and a recipe meant for a quick "does it still work" check
should return, not become a process you have to remember you started.
Everything before this declared an Allow and stopped; nothing in this
binary ever actually wrote to lldap. This is the first effect that gets
executed, not just declared:

- principal-shape's ascent program now also derives an `identity.mint`
  effect (kind + `{"sub":...}` params) alongside its Allow conclusion,
  joined by (key, reason) per Derived::effects' own contract. `Derived`
  no longer discards effects with `..Default::default()`.
- src/lldap.rs: AdminClient, a session against lldap's GraphQL admin API
  — NOT the raw LDAP protocol `connect()` already used for reconcile.
  Confirmed live, by introspecting heimdallr's actual running lldap
  (Mutation type, CreateUserInput), not assumed from docs: lldap has no
  LDAP-protocol write path for user creation, and CreateUserInput has no
  password field at all — credential-setting is a separate, unbuilt flow.
  These accounts are meant to be passwordless (owner, 2026-08-09): they
  authenticate through modron's token contract, not an Authelia login
  window, so the missing password field is the correct end state here,
  not a gap to fill in later.
- `vedanta mint-agent <name> --display-name <display>` (sub = a+<name>)
  and `vedanta mint-service <name> --display-name <display>` (sub =
  sa+<name>) run the SAME principal-shape gate `serve` would — no side
  channel that skips it — and only execute the declared effect on Allow.
  `worker-` (pool slots) deliberately stays out: that's the pool-manager's
  checkout/reissue cycle, not a one-shot mint.
- reqwest pulled in via --no-default-features: this only ever talks
  http://127.0.0.1 (lldap's own loopback listener), and the default TLS
  backend (rustls + aws-lc-rs) would be dead weight in both the binary
  and the Nix build closure for a connection that is never TLS.

Scope, deliberately: user creation only — no group membership, no
custom attributes (librefang_node, pool_*), no password. Each of those
is its own undecided question already flagged in the schema docs
(default groups for a freshly minted identity, credential rotation) —
this effector executes what's actually settled and stops there, same
posture principal-shape itself took.

Verified against the real thing, not a mock: `nix build` + `nix copy` to
heimdallr + `vedanta mint-service minttest --display-name "Mint Test
(disposable)"` actually created uid=sa+minttest in the live directory
(confirmed via a direct GraphQL query), then deleted to leave the
directory clean. cargo test / clippy --all-targets -- -D warnings clean.
PR #2 vendored 21 files of the substrate because jo.et0.pw was private
and the sandboxed build had no credential to fetch it with. It said so
at the time: provisional, "the unblock, not the answer," bump by
re-copying.

Ting/Jostoph#3 settled the distribution model — lar.ad canonical,
midgard public over anonymous HTTPS — and midgard/jostoph-rs main is
029a102, the exact rev vendored here. Diffed before deleting anything:
byte-identical.

So the input moves to flake.lock and the copy leaves the tree. It stays
a Cargo path dependency, materialized by postPatch for the package and
by the devShell shellHook for a working tree, which keeps Cargo.lock
untouched, needs no outputHashes, and keeps the build credential-free.

Not a fastlane input: midgard/jostoph-rs is main-only by design.

Closes #3
lldap left the fleet at flake-ops#51 on 2026-08-10; its sops keys went at
phase 5 the day after. Every directory line here addressed it, so the
gigachad recipe was not stale but broken — it read a deleted secret path.

Vedanta now holds its OWN kanidm identity: service account `sa-vedanta`,
one read-write api-token, delivered through DOTENV_FILE. The alternative
was the operator path the off-repo spike uses — ssh as root, `kanidmd
recover-account idm_admin` — and it was refused (owner, 2026-08-11) for
reasons worth not re-arguing: recovering idm_admin at will IS admin, so it
is not the narrow grant it looks like; it forces this unit to run as root
and discard module.nix's NoNewPrivileges and ProtectSystem=strict; and a
token's rights can be read out of the directory, where root's cannot. The
rights themselves are granted at bootstrap, never in the flake (owner: "no
admin in the flake"), by lar.ad/flake-ops#98. A privileged helper standing
behind Vedanta was refused too: Vedanta IS the privileged component.

Every call was made against the live instance before it was written, the
standard the lldap effector set. What that bought, none of it in the docs:

- kanidm refuses `+` in a NAME (400 schemaviolation) but accepts it in
  MAIL. So a+/sa+ stays a JWT `sub` contract, the entity is a-freki, the
  plus-addressed mailbox survives where it is load-bearing, and the two
  are joined by UUID. This is why the spike writes `sa-<persona>` — a
  workaround nobody had recorded as one.
- A person cannot hold an api-token (MissingClass("service_account")), so
  the service-account choice flake-ops#72 ruled is forced, not preferred.
- A `-w` token in idm_service_account_admins creates accounts and writes
  group members. That premise is true, which is the whole reason this
  shape works.

The gate is untouched: mint() still routes through Steward::evaluate and
only then effects. Partial success is reported, not rolled back — if the
roster group join fails the account exists and the error says so, with the
uuid already logged. Nothing here grows a revoke path.

reqwest gains TLS (feature `rustls`, not the pre-0.13 `rustls-tls`
spelling), aimed at the public origin rather than kanidm's self-signed
loopback, so no client here is taught to accept an unverified peer.

Refs Ting/Vedanta#5, lar.ad/flake-ops#51, #72, #97, #98
Both files existed untracked through the whole kanidm port, which meant
`nix build` could not see them and neither could a reviewer. They are
rules and state, not project bookkeeping — the board stays the place work
is tracked (AGENTS.md says so itself).

Two rulings from the session that ported the effector (Ting/Vedanta#6):

- UNSUPERVISED WORK NEEDS A TICKET. An agent working without the
  freeholder present has no one to answer a scope question, so the ticket
  IS the scope. Supervised work does not: whether a session runs HITL is
  the freeholder's call, and a freeholder in the loop is a better scope
  authority than any issue text. This commit and its ticket are that
  clause being used — both written after the work.
- ONE PR PER SESSION, NOT PER TICKET. The session is the delivery unit;
  the old "scoped to one ticket" pulled toward splitting a single story
  across PRs. Branches still name the primary ticket; the rest are named
  in the PR body.

CONTEXT.md's largest hazard section — "the directory moved under us" —
becomes a landed port, carrying the five findings the live instance forced
and the two that are still flake-ops' to fix (lar.ad/flake-ops#99: the
`agents` group is undeployed, and overwriteMembers will wipe it once it
lands). The old "bind account is an acknowledged over-grant" open question
becomes the honest one: sa-vedanta's rights are sufficient, not minimal.

Refs Ting/Vedanta#5, #6, lar.ad/flake-ops#99
AGENTS.md has always said `.doctor.just` and `.fastlane.just` are
gitignored, self-distributing copies owned by Ting/Jostoph — but this
repo's .gitignore never listed them, so `just -f .doctor.just wire` left
them staged and a routine `git add -A` would have committed both. One is
overwritten from its canonical URL by `doctor::sync`; the other's mere
presence is the development-seam toggle. Neither is this repo's to carry.

Refs Ting/Vedanta#5
`/run/secrets/vedanta/kanidm_token` is not created by deploying — sops-nix
materializes DECLARED secrets and nothing else, and flake-ops declares no
`vedanta/*` yet (lar.ad/flake-ops#91). This recipe exists precisely to run
code in production BEFORE that lands, so it now falls back to the sops file
the token was minted into (lar.ad/flake-ops#98) and uses the host path when
something finally does declare one.

The credential goes over STDIN, never the command line: `ssh host
"TOKEN=abc vedanta"` puts it in heimdallr's process table for the life of
the call, readable by anyone on the box.

And a missing credential now fails at 78 (EX_CONFIG) instead of limping.
Observed for real: `VEDANTA_KANIDM_TOKEN="$(cat missing)"` does not stop a
shell — `cat` writes to stderr, the substitution yields an EMPTY string,
and kanidm answers `401 notauthenticated`, which reads as "your token is
wrong" when the truth is "you have no token".

Verified end to end against the live directory:

    INFO vedanta: reconcile: kanidm reachable, no reconciliation rules
    defined yet — no-op [email protected]

Refs Ting/Vedanta#5, lar.ad/flake-ops#91, #98
Bind the OpenBao peer and Ed25519 signature to one typed command, then validate freshness, deployed authority, principal state, generations, expiry, and predecessor ownership in stable order. Opaque validated commands are the only values the future journal and mutation adapters may accept.
Separate principal lifecycle from private credential effects, replace the pre-minted queen handoff with OpenBao-owned drone leases, and document exact-token invalidation plus journal metadata without turning Vedanta into an authority store.
CPU handoff checkpoint. This intentionally preserves an unverified and potentially non-compiling review repair in progress; result envelopes, RFC3339 wire types, queen-tenure evidence, and expanded fixtures are partially reconciled, but the fixture conversion and dependency lock verification are not complete.
9750b29 added time = { version = "0.3", features = ["formatting", "parsing"] } to Cargo.toml and left the lock stale; this is that resolution and nothing else.
The ordered validator denies a command whose assignment_authority is absent, but no fixture exercised that branch — the one axis in the table without its own negative. Add it; fmt also settles the last non-canonical lines carried by the handoff checkpoint.
Vedanta owns IDM mint_api_token, rotate_api_token, and explicit
invalidate_api_token (owner ruling, 2026-08-26); this is the adapter those
rulings named, delivered as #8's agent-unit with capture-double tests.

The wire is kanidm v1.11.1's, verified against upstream source —
server/core/src/https/v1.rs, proto/src/internal/token.rs, and
server/lib/src/idm/serviceaccount.rs — not against the live instance: the
live narrow-manager proof stays flake-ops#123 per #8's delivery class, and
the adapter says so in its own doc comment rather than inheriting the file's
live-verified header.

The rulings this encodes:

- Mint names explicit expiry (a plain i64 — the request cannot be built
  without one; gate I03) and target account by UUID, never by label, and
  returns value, token ID, expiry, and subject exactly once. The value
  crosses this boundary one hop: mint result to caller to OpenBao's
  immediate result. Nothing here stores or logs it.
- Rotation mints a distinct successor — a token returned with the
  predecessor's ID is refused — and issues no DELETE: grace is
  caller-selected, so the predecessor stays valid until explicitly
  invalidated, and the overlap is bounded by the caller's policy, not by
  the adapter deciding when a credential dies.
- Invalidation addresses exactly one authenticated token ID. Absence is
  external success with the distinction kept (observed_before), per the
  2026-08-26 ruling; a kanidm refusal stays a final Error.
- Unrelated-subject mint and kanidm denial are terminal. No retry, no
  second account, no broader credential — the capture doubles assert call
  counts, not just outcomes.

The kanidm module moves from the binary into the library beside
private_api: the private lifecycle service's mutation adapter consumes the
same bounded calls the CLI mint path does, and in a bin crate the
unconsumed-public-API lint would otherwise read as dead code — the wiring
that silences it honestly is the Session's, not a stub.

just check green: fmt stable, clippy -D warnings clean, 59 tests
(10 new capture-double cases: wire shape incl. integer expiry and
compact=false, bearer presentation, distinct successor, no-delete
rotation, in-place refusal, exact-path invalidation, absent-token
distinction, final 403, metadata-only list).
No mutation reaches Kanidm before a durable record of its intent exists;
one operation ID maps to at most one mutation; a restart re-derives
everything from one file. That is the whole of #21, and it is now
src/operations.rs.

The rulings this encodes:

- Write-ahead: begin() appends a pending record and sync_all()s it before
  the service may mutate. A crash between the two leaves a pending
  record — exactly the evidence #23's reconciliation needs to tell
  "never minted" from "minted, delivery unacknowledged".
- One operation, one mutation: a begin for an operation ID the journal
  already holds is refused, whatever its state. The validator's
  freshness check normally catches replays first; one that reaches
  begin means two writers or torn history, and the answer is no.
- Metadata only, by type: JournalRecord carries identifiers, ownership,
  generations, outcome, and acknowledgement state. There is no field a
  credential could land in, so the one-hop value rule is enforced by the
  type system, not by a convention tests have to police — though the
  tests grep the durable bytes for the fixture secret anyway.
- Status and ack are non-secret by the same construction:
  OperationStatus maps off the record, acknowledge() is idempotent
  (re-acknowledging a committed lease is recovery, per the ack-timeout
  contract), and acknowledging an unknown operation is refused.
- Torn tail tolerated, torn middle fatal: a crash mid-append can only
  tear the last line, which loads as never-begun (fresh, re-beginnable);
  corruption between durable records refuses to load — deny-biased,
  loudly. Loading also propagates read errors instead of defaulting
  them: on unix a directory at the journal path opens fine and then
  answers every read with EISDIR forever, and a loader that mapped that
  to empty strings would collect them without end. Found the honest way
  — the first version of this module did exactly that and hung its own
  test.

module.nix grows StateDirectory=vedanta and VEDANTA_JOURNAL (fixed path,
not an option — a per-host configurable journal location is a journal an
operator can point at the wrong history), and its "Vedanta holds no state
of its own" comment, true when written, is corrected with them.

private_api grows a #[cfg(test)] ValidatedCommand::for_tests constructor
so the journal's tests record already-validated commands without a
bypass existing in any non-test build.

Gate: just check green — fmt stable, clippy -D warnings clean, 67 tests
(8 new: write-ahead + restart, freshness flip, once-per-operation,
metadata-only completion/ack/status with byte-level secret absence,
unknown-ack refusal, stable failure class, torn tail vs torn middle,
unopenable-journal denial). alejandra clean on module.nix.
A mint whose acknowledgement never arrived is ambiguous between "OpenBao
committed the lease and lost the ack" and "the delivery never landed, and
a credential no lease owns is live in the directory" — and the two demand
opposite actions. src/reconcile.rs resolves the ambiguity against
OpenBao's committed lease state before touching anything:

- Matching lease — same operation, same token — recovers the
  acknowledgement in the journal and delivers NOTHING. Acknowledgement
  loss is never evidence of lease loss, and the one-shot value is long
  gone besides: there is nothing to redeliver and nowhere a second
  delivery would be legal.
- A missing lease, or one naming a different operation or token, makes
  the journalled mint an ORPHAN: invalidated by exact token ID — the
  journaled token, never the committed lease's — with the reason kept
  (lease_missing vs operation_mismatch vs token_mismatch), the
  compensation durably recorded, and the invalidation's own
  observed-before distinction preserved.
- Replacement on a FRESH operation ID is not a new mechanism: the
  compensated operation's ID stays replay in the journal forever, which
  is the rule enforced by a fact the journal already keeps.

Only minted-and-unacknowledged records are delivery-uncertain — a
pending record's mutation never completed and has no token to reconcile.
A refused invalidation is reported per-selection and journalled as no
compensation at all: the next sweep must see an uncompensated orphan,
not a success-shaped hole.

The invalidation effect rides a one-method trait the Kanidm client
implements; tests capture it. Journal gains an optional
orphan_compensation record (serde default, so pre-existing journals load
unmodified).

Gate: just check green — 73 tests (6 new: ack recovery delivers nothing,
missing-lease orphan invalidates by exact ID, mismatch orphans OUR token
not the committed one, compensation survives restart and forces fresh
operation IDs, sweep scope excludes acknowledged/pending/failed, refused
invalidation reported not swallowed).
A new workspace member, vedanta-openbao-plugin: the OpenBao side of the
identity-lease contract (OpenSpec 20/61, 0.1.4). OpenBao is the only
workload-facing lease authority; this crate is its issue path — the
thirteen-stage ordered authorization table, the durable pre-mutation
intent, the signed private mint dispatch to Vedanta, the commit, and the
one-shot wrapped delivery.

authorize() runs the contract's canonical order — caller authentication,
claimant, seat tenure (exactly one active runtime-seat tenure; zero and
many both deny), grant validity including exact grant binding, principal
state, assignment, isolation, resource, operation, audience, requested
TTL against the 30-minute pilot ceiling, active lease limit, projection
freshness — and returns the FIRST failure: the stage a denial names is
observable contract behavior, which is why no check is reordered or
folded into a neighbour, and why the error carries nothing about any
other principal.

build_command() emits the full private-contract LifecycleCommand (Mint,
credential_generation 1, no predecessor, 60-second command window) and
Ed25519Signer seals it into the envelope vedanta's Ed25519Verifier
accepts; the seed never leaves the signer.

IssueService::issue() walks the flow the contract words exactly:
a denial touches nothing; an unrecordable intent never dispatches; a
transport failure or a returned refusal yields NEITHER a committed lease
NOR credential material; a lease that cannot commit never wraps (the
orphan is Vedanta-side #23's to compensate, not ours to paper over with
a wrapper for a lease that does not exist); a refused wrap reports
WrapFailed against a committed lease — retryable, because durable state
is consistent and only delivery was lost. The credential value exists in
exactly one scope of the flow — the mint result on its way into the
wrapper — and no outcome, store, or committed lease has a field it could
land in. The queen authorizes the seat claim but only the drone
receives: the committed lease's subject is the claimant, never the
tenure holder.

Scaffolding and the authorization table were drafted by a delegated
agent session; the service flow and its capture doubles were finished
and corrected in review. Root Cargo.toml gains only the [workspace]
section; Cargo.lock's additions are the new member plus the jostoph
build-time transitives that workspace-wide resolution now pins.

Gate (workspace-wide — the root-only gate silently skips new members):
fmt stable, clippy -D warnings clean, 95 workspace tests (23 here:
14 stage negatives incl. first-fault ordering and envelope verification,
9 flow tests incl. denial-touches-nothing, intent-before-dispatch,
refusal/transport-without-lease, commit-failure-never-wraps,
queen-never-receives).
The non-issue state machine of the lease contract, in
openbao-plugin/src/lease.rs — everything after the issue path #12 opened.

- ReadLease is metadata-only BY CONSTRUCTION: no credential field exists
  to fill, and none could — past the wrap window there is no value to
  recover, which is a property of the system, not of the method's
  discipline.
- RotateLease re-runs the thirteen-stage table against the CURRENT
  projection before anything: the grant may have moved to a new version
  or generation, and a rotation authorized against yesterday's world is
  an unauthorized mint. The successor command carries
  credential_generation = stored + 1 and predecessor = the live token;
  the predecessor is NOT invalidated — caller-selected grace, the #8
  ruling — and lands on the still-valid-predecessor list revocation
  later sweeps.
- RevokeLease FAILS FORWARD: the FIRST durable act is saving
  revocation_pending (deny use immediately — the status IS the denial,
  and any read between save and completion refuses), then every token
  in the invalidation set — current plus still-valid predecessors — is
  invalidated by exact signed command. The first unverified deletion
  leaves the outcome RevocationPending with the outstanding suffix
  named; only all-verified closes to Revoked, idempotently. A revoke
  that cannot prove its lease Active denies rather than sweeps.

Retryability diverges from the issue path deliberately, in-code:
SuccessorCommitFailed/SuccessorUndeliverable are NOT retryable because
rotate has no journal replay-guard — a blind re-rotate is refused by
Vedanta's expected-generation check, so recovery by exact token ID
(#23) is the path, not another mint under the same command.

Invalidate commands carry only what stored metadata can prove — token,
lease, principal — and never invent grant or tenure content; the
generation simplification (all tokens at the stored generation) matches
what Vedanta's predecessor-ownership stage actually checks for
Invalidate. Drafted by a delegated agent session; reviewed, corrected,
and gated here.

Gate (workspace-wide): fmt stable, clippy -D warnings clean, 135
workspace tests (32 in the plugin: 9 lease-transition tests incl. exact
save-before-dispatch event ordering, partial-invalidation pending,
idempotent completion, and no-old-secret-recovery).
larandar closed this pull request 2026-09-02 19:28:59 +00:00

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Ting/Vedanta!28
No description provided.