mirror of
https://github.com/morluto/rea.git
synced 2026-11-04 13:56:06 +00:00
fix(environment): make the write gate and serving agree on lines, rules, inserts and documents
Five places where the gate approved a write serving would answer differently: - list and document reads are matched to checked lines as serving matches calls (path and query values decoded, the query in any order), so a reordered query no longer hides a contradiction; - an increment or slug applies to every call, so a plan is unexplained-change when one call changes such a field and another leaves it as it was, in either order; - an item read confirming a create no longer stops a later list from choosing another insert candidate; only a list check fixes the rule; - the gate runs serving's document body check (accepted members, JSON types from the held and initial document), so a recorded write that serving would refuse leaves the plan unserved; - a served create decodes its path values from the collection the call names, as the gate decoded the recorded path, whichever spelling the call used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
df2bded16e
commit
2086da6cc7
11 files changed
+343
-52
No files matched your search
@@ -17,9 +17,13 @@ import {
|
||||
renamedBook,
|
||||
type Book,
|
||||
} from "../../../tests/fixtures/environmentStateWrites.js";
|
||||
import type { TimedCaptureRow } from "../../../tests/fixtures/analysisView.js";
|
||||
import type { ReplayArguments } from "./environmentReplay.js";
|
||||
import { servedCatalog } from "./environmentState.js";
|
||||
import { environmentToolDefinitions } from "./environmentTools.js";
|
||||
import {
|
||||
environmentToolArguments,
|
||||
environmentToolDefinitions,
|
||||
} from "./environmentTools.js";
|
||||
|
||||
/** The book the first served create of "New Book" makes: the next id, one second past the served clock's start. */
|
||||
const NEW_BOOK = book(3, "New Book", bookClock(13));
|
||||
@@ -355,3 +359,52 @@ describe("paged list lines", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("path values", () => {
|
||||
const orgBook = (id: number, org: string, name: string): Book => ({
|
||||
id,
|
||||
org,
|
||||
name,
|
||||
});
|
||||
const ALPHA = orgBook(1, "my org1", "Alpha");
|
||||
const BETA = orgBook(2, "acme2", "Beta");
|
||||
const GAMMA = orgBook(3, "my org1", "Gamma");
|
||||
const DELTA = orgBook(4, "acme2", "Delta");
|
||||
/** Books under two organisations, one whose name the paths percent-encode, and a create under each. */
|
||||
const ROWS: readonly TimedCaptureRow[] = [
|
||||
["GET", "/api/orgs/my%20org1/books", [ALPHA]],
|
||||
["GET", "/api/orgs/acme2/books", [BETA]],
|
||||
["GET", "/api/orgs/my%20org1/books/1", ALPHA],
|
||||
["GET", "/api/orgs/acme2/books/2", BETA],
|
||||
["POST", "/api/orgs/my%20org1/books", GAMMA, 201, { name: "Gamma" }],
|
||||
["GET", "/api/orgs/my%20org1/books", [ALPHA, GAMMA]],
|
||||
["POST", "/api/orgs/acme2/books", DELTA, 201, { name: "Delta" }],
|
||||
["GET", "/api/orgs/acme2/books", [BETA, DELTA]],
|
||||
];
|
||||
|
||||
it("stores a parent path value decoded, as the gate learned it, whichever spelling the call uses", () => {
|
||||
for (const spelling of ["my%20org1", "my org1"]) {
|
||||
const books = servedFrom(ROWS);
|
||||
const tool = books.source.manifest.tools.find(
|
||||
(candidate) => candidate.method === "POST",
|
||||
)!;
|
||||
expect(books.state.writes.get(tool.name)).toMatchObject({
|
||||
served: true,
|
||||
rules: expect.arrayContaining([
|
||||
expect.objectContaining({ field: "org", rule: "path" }),
|
||||
]),
|
||||
});
|
||||
const [org] = environmentToolArguments(tool).path.values();
|
||||
books.answer(tool.name, { [org!]: spelling, body: { name: "Epsilon" } });
|
||||
const created = books.store
|
||||
.snapshot()
|
||||
.rea_state.entities.find(
|
||||
(entity) => entity.fields["name"] === "Epsilon",
|
||||
);
|
||||
expect(created).toMatchObject({
|
||||
collection: "/api/orgs/my%20org1/books",
|
||||
fields: { org: "my org1" },
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user