feat: replace revision counters with domain state contracts
Use content digests, key fingerprints, binding and trust identities, immutable mutation receipts, and observation tokens instead of state-update ordinals across API, storage, Runtime, and Web contracts. Preserve historical replay and secret material through frozen migrations; preflight uncertain removals before cutover, resume provisioning receipts, validate encrypted migration candidates, and align fresh/upgraded schemas. Include reviewed regression fixes, generated artifacts, and validation evidence.
This commit is contained in:
@@ -6,7 +6,7 @@ The ordinary Rust test exercises loopback HTTP signed Worker ingress: explicit r
|
||||
|
||||
The explicit process test starts a loopback Axum Server and launches Deno against it. `roundtrip.ts` imports the production `src/lib/workspace/drive/api.ts` adapter, not a copy or mock. Its typed `fetchFn` resolves relative paths only to the bound loopback origin and adds fixture bearer authorization. Tokens travel over stdin, not command-line arguments or logs; Rust failure diagnostics defensively redact both fixture bearer tokens. Deno has network permission only for the exact loopback port, uses no npm dependencies, and runs with `--cached-only`. Each listener is abort-on-drop, child processes are kill-on-drop, and the child has a 60-second upper timeout, without sleeps or readiness polling.
|
||||
|
||||
Coverage: Worker file list/read, Japanese folder/Markdown names, create/read/edit/download, empty files, actual PNG upload/authenticated image/download and binary update, publication receipt lookup, paged list, two authenticated accounts racing a common revision (one commit/one typed conflict, no hidden retry), stable latest URL through rename and move, deleted URL and same-name recreation, and unauthorized latest URLs. The exact Workers-page `drive-grants/api.ts` adapter also lists persisted grants, creates both access levels, revokes them and re-reads durable state, and rejects member administration. Its global browser fetch is temporarily origin/auth-bound in this isolated child; network responses are never mocked. This tests real authenticated HTTP with test bearer credentials, not a Passkey/cookie browser login or a full Runtime process. UI dirty-draft retention, delayed response handling, visual review and browser cancellation belong to the **separate browser fixture**, not this API test.
|
||||
Coverage: Worker file list/read, Japanese folder/Markdown names, create/read/edit/download, empty files, actual PNG upload/authenticated image/download and binary update, publication receipt lookup, paged list, two authenticated accounts racing a common observed committed request (one commit/one typed conflict, no hidden retry), stable latest URL through rename and move, deleted URL and same-name recreation, and unauthorized latest URLs. The exact Workers-page `drive-grants/api.ts` adapter also lists persisted grants, creates both access levels, revokes them and re-reads durable state, and rejects member administration. Its global browser fetch is temporarily origin/auth-bound in this isolated child; network responses are never mocked. This tests real authenticated HTTP with test bearer credentials, not a Passkey/cookie browser login or a full Runtime process. UI dirty-draft retention, delayed response handling, visual review and browser cancellation belong to the **separate browser fixture**, not this API test.
|
||||
|
||||
## Registration
|
||||
|
||||
|
||||
@@ -93,9 +93,9 @@ async function download(
|
||||
entry: DriveEntry,
|
||||
): Promise<Uint8Array> {
|
||||
const response = await fetchFn(
|
||||
driveDownloadUrl(ws, entry.entry, entry.revision),
|
||||
driveDownloadUrl(ws, entry.entry, entry.last_mutation_id),
|
||||
);
|
||||
assert(response.status === 200, "download must succeed at exact revision");
|
||||
assert(response.status === 200, "download must succeed at exact last_mutation_id");
|
||||
equal(
|
||||
response.headers.get("x-content-type-options"),
|
||||
"nosniff",
|
||||
@@ -203,7 +203,7 @@ equal(
|
||||
const updated = await saved(owner, ws, "web-edit", {
|
||||
operation: "update_text",
|
||||
id: markdown.entry,
|
||||
expected_revision: markdown.revision,
|
||||
expected_mutation_id: markdown.last_mutation_id,
|
||||
text: "# 更新\n",
|
||||
content_type: "text/markdown",
|
||||
});
|
||||
@@ -274,7 +274,7 @@ const binaryUpdated = await owner.upload(
|
||||
{
|
||||
operation: "update",
|
||||
id: empty.entry,
|
||||
expected_revision: empty.revision,
|
||||
expected_mutation_id: empty.last_mutation_id,
|
||||
content_type: "image/png",
|
||||
},
|
||||
);
|
||||
@@ -313,12 +313,12 @@ equal(
|
||||
"paged traversal must contain each file once",
|
||||
);
|
||||
|
||||
// Two authenticated accounts read the same revision, then race real HTTP writes.
|
||||
// Two authenticated accounts read the same last_mutation_id, then race real HTTP writes.
|
||||
const secondRead = await second.readText(ws, updated.entry);
|
||||
equal(
|
||||
secondRead.entry.revision,
|
||||
updated.revision,
|
||||
"second actor must observe same revision",
|
||||
secondRead.entry.last_mutation_id,
|
||||
updated.last_mutation_id,
|
||||
"second actor must observe same last_mutation_id",
|
||||
);
|
||||
const drafts = ["# actor A draft\n", "# actor B draft\n"];
|
||||
const race = await Promise.allSettled(
|
||||
@@ -326,7 +326,7 @@ const race = await Promise.allSettled(
|
||||
saved(client, ws, `web-race-${index}`, {
|
||||
operation: "update_text",
|
||||
id: updated.entry,
|
||||
expected_revision: updated.revision,
|
||||
expected_mutation_id: updated.last_mutation_id,
|
||||
text: drafts[index],
|
||||
content_type: "text/markdown",
|
||||
})
|
||||
@@ -335,7 +335,7 @@ const race = await Promise.allSettled(
|
||||
equal(
|
||||
race.filter((result) => result.status === "fulfilled").length,
|
||||
1,
|
||||
"same-revision two-actor CAS must have exactly one winner",
|
||||
"same-last_mutation_id two-actor CAS must have exactly one winner",
|
||||
);
|
||||
const loser = race.find((result) => result.status === "rejected");
|
||||
assert(
|
||||
@@ -358,14 +358,14 @@ const stableUrl = markdown.latest_url;
|
||||
const renamed = await saved(owner, ws, "web-rename", {
|
||||
operation: "relocate",
|
||||
id: latest.entry.entry,
|
||||
expected_revision: latest.entry.revision,
|
||||
expected_mutation_id: latest.entry.last_mutation_id,
|
||||
parent: folder.entry,
|
||||
name: "改名.md",
|
||||
});
|
||||
const moved = await saved(owner, ws, "web-move", {
|
||||
operation: "relocate",
|
||||
id: renamed.entry,
|
||||
expected_revision: renamed.revision,
|
||||
expected_mutation_id: renamed.last_mutation_id,
|
||||
parent: root.entry,
|
||||
name: renamed.name,
|
||||
});
|
||||
@@ -397,7 +397,7 @@ await rejected(
|
||||
const deleted = await owner.mutate(ws, "web-delete", {
|
||||
operation: "delete",
|
||||
id: moved.entry,
|
||||
expected_revision: moved.revision,
|
||||
expected_mutation_id: moved.last_mutation_id,
|
||||
});
|
||||
equal(deleted.entry, null, "delete must remove live metadata");
|
||||
await rejected(() => owner.readText(ws, moved.entry), "not_found");
|
||||
|
||||
Reference in New Issue
Block a user