Repository navigation
feat(aaas): tenant ownership core — epoch-fenced lease store and holder session (A1.1) - #678
Merged
Merged
Conversation
…er session (A1.1) A1 must prove a single writer per tenant before any durable copy or router exists, so the lease protocol and its fencing come first, outside the kernel and not yet wired into a runtime path. Refs #674
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #674
A1 of the AaaS charter must prove a single writer per tenant before any durable copy or router exists. This is its first slice: who may write a tenant, and when they must stop. It lives outside the kernel and is not wired into any runtime path yet.
state-ledger.tsand the kernel manifest are untouched, and no dependency is added.What it adds (
ts/src/tenant-state/)t-plus the first 128 bits of HMAC-SHA256(K_org, issuer ‖ NUL ‖ subject). Organization and tenant validators build every path of the layer from validated ids only (threat S-3). A lone surrogate, a NUL, an empty or oversized claim, and a key under 32 bytes are refused, so two different subjects can never share a tenant.TenantLease). It stops acknowledging atsentAt + ttl − marginon a monotonic clock measured from before the request went out, fails closed when the store is down, resumes only when the epoch never changed, and hands the lease back on a graceful release. A holder never has two renewals or releases outstanding at the store.A limit, pinned by a test instead of hidden. The local fence cannot see a frozen clock, such as a process paused between its check and its acknowledgement (test D6). The store refuses that holder on its next renewal, and the epoch-scoped durable copies of A1.2 are what keep its writes from becoming authoritative.
Evidence on
04f938156dc7014df505af0e89fef9661debd383(local Node v26.9.0)cd ts && npx tsx scripts/tenant-state-tests.ts: exit 0, 28 checks (run-all §89). It includes six real child processes racing one lease file, once fresh and once after a real expiry; exactly one wins each time.cd ts && npx tsc --noEmit,smoke.ts,g5-guard.ts,kernel-manifest-gate.ts: exit 0, with a zero-diff kernel manifest.scripts/run-all-tests.shon this commit:ALL SUITES GREEN, exit 0. CI runs it again on Node 22 and 24.check-docs-i18n.mjs,check-doc-readability.mjs,run-all-tests-wiring-tests.mjs: OK. The code map has a row in both languages.Not in this PR. Durable copies, restore and forget are A1.2. The router and handoff are A1.3. Multi-process fault injection and the #275 closure are A1.4. Minimal E2E: N/A, since nothing is wired into a runtime path.
Review ask. Nothing needs a decision. The shape of
LeaseStoreis the one thing worth a look: it is what the MySQL binding will implement.