v2.0.0: claims model - signed MMUR2 votes in a truth DB, merged view in a rebuildable cache DB; POST /api/claims, claims and merge routes, unsigned writes answer 410
Build and Push Docker Image / build (push) Successful in 5m1s

This commit is contained in:
Worph
2026-10-25 17:36:00 +00:00
parent b0adefb97b
commit 84af298792
78 changed files with 7203 additions and 5617 deletions
+8 -10
View File
@@ -180,10 +180,9 @@ async function fetchAccounts(): Promise<Account[]> {
//
// Never throws and never reports an error upward: a name is decoration on top
// of the uid, and the account list must render identically whether the store is up
// (identity itself is file-backed, the UDL is not). The name is also *unsigned*
// — meta-core stores the plaintext beside the signed record and verifies
// nothing — so the uid stays on screen as the real identity, and the length cap
// bounds what a hostile writer can do to the layout.
// (identity itself is file-backed, the UDL is not). The name is the user's
// signed MMUR2 claim (meta-core verified it on write); the uid stays on screen
// as the real identity, and the length cap bounds the layout.
async function fetchDisplayName(uid: string): Promise<string | null> {
const url =
`/api/udl/record?uid=${encodeURIComponent(uid)}` +
@@ -192,12 +191,11 @@ async function fetchDisplayName(uid: string): Promise<string | null> {
try {
const res = await fetch(url);
if (!res.ok) return null; // 503 when storage is down, 500, …
const data = (await res.json()) as { exists?: boolean; value?: unknown };
// Key off `value`, not `exists`: clearing a name writes a tombstone, which
// leaves the cell existing with no plaintext. Private-tier cells look the
// same, which is exactly right — there is nothing to show for either.
if (typeof data.value !== 'string') return null;
const name = data.value.trim();
const data = (await res.json()) as { exists?: boolean; claim?: { value?: unknown } | null };
// A retraction (null) or ciphertext ({b64}) has nothing to show.
const value = data.claim?.value;
if (typeof value !== 'string') return null;
const name = value.trim();
return name ? name.slice(0, 64) : null;
} catch {
return null;