mirror of
https://github.com/morluto/rea.git
synced 2026-11-06 06:46:10 +00:00
fix(environment): check reads on the lines serving answers, and refuse plans later calls contradict
Greptile raised these on the list-lines branch against this branch's code. - The gate chooses a read's line as serving does. A read with no query on a whole list falls back to a checked line that only pages it, and a line whose query repeats a name, which no call can name, is never checked. - A read made while a modelled write to its targets was still running, starting before that write ended, checks nothing either way. - A later call that stores a member otherwise than the plan (echoed by one call and stored as something else by another, or ruled differently) refuses the plan as unexplained, rather than keeping the first rule. - A create keeps the spelling of a collection the capture listed empty: checked list lines of the type join the known spellings, so an encoded argument is not encoded twice. - containsDelimited walks children one at a time, since spreading a very wide array into push overflowed the stack. - The guide counts the confirmed write tools among the served catalog and the verifier's expected count. Attribution bookkeeping moves to environmentStateWriteAttribution.ts and the create's collection choice to environmentStateCollections.ts, keeping files under the line limit. The verdicts over the 50 captures are unchanged plan by plan, and the smoke applies all 31 served write tools. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
73c0e9b50a
commit
9f513d07e5
14 files changed
+515
-258
No files matched your search
@@ -527,3 +527,89 @@ describe("updates whose effect later writes erase", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("reads as serving answers them", () => {
|
||||
it("checks a read with no query on the line serving answers it from, a whole list's paging line", () => {
|
||||
const rows: TimedCaptureRow[] = [
|
||||
["GET", "/api/books?limit=50", [FIRST_BOOK, SECOND_BOOK]],
|
||||
["GET", "/api/books/1", FIRST_BOOK],
|
||||
["GET", "/api/books/2", SECOND_BOOK],
|
||||
["POST", "/api/books", THIRD_BOOK, 201, { name: "Third Book" }],
|
||||
["GET", "/api/books", [FIRST_BOOK, SECOND_BOOK, THIRD_BOOK]],
|
||||
];
|
||||
expect(gated(rows, "post_books")).toMatchObject({
|
||||
served: true,
|
||||
checked_record_ordinals: [4],
|
||||
});
|
||||
});
|
||||
|
||||
it("checks nothing by a line whose query repeats a name, which no call can name", () => {
|
||||
const rows: TimedCaptureRow[] = [
|
||||
["GET", "/api/books?tag=a&tag=b", [FIRST_BOOK]],
|
||||
["GET", "/api/books/1", FIRST_BOOK],
|
||||
["GET", "/api/books/2", SECOND_BOOK],
|
||||
["PATCH", "/api/books/1", RENAMED, 200, { name: "Renamed Book" }],
|
||||
["GET", "/api/books?tag=a&tag=b", [RENAMED]],
|
||||
];
|
||||
expect(gated(rows, "patch_books_by_id")).toMatchObject({
|
||||
checked_record_ordinals: [],
|
||||
});
|
||||
});
|
||||
|
||||
it("checks nothing by a read made while a write to its targets was still running", () => {
|
||||
const rows: TimedCaptureRow[] = [
|
||||
["GET", "/api/books", [FIRST_BOOK, SECOND_BOOK]],
|
||||
["GET", "/api/books/1", FIRST_BOOK],
|
||||
["GET", "/api/books/2", SECOND_BOOK],
|
||||
// The create runs from second 3 to 4.5; the list at second 4 still shows the books before it.
|
||||
["POST", "/api/books", THIRD_BOOK, 201, { name: "Third Book" }, 1500],
|
||||
["GET", "/api/books", [FIRST_BOOK, SECOND_BOOK]],
|
||||
["GET", "/api/books", [FIRST_BOOK, SECOND_BOOK, THIRD_BOOK]],
|
||||
];
|
||||
expect(gated(rows, "post_books")).toMatchObject({
|
||||
served: true,
|
||||
checked_record_ordinals: [5],
|
||||
contradicted_by: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("refuses an update a later call stores otherwise than the plan echoed", () => {
|
||||
const formatted = (at: number, format: string): Book => ({
|
||||
...renamedBook(FIRST_BOOK, "First Book", at),
|
||||
format,
|
||||
});
|
||||
const rows: TimedCaptureRow[] = [
|
||||
[
|
||||
"GET",
|
||||
"/api/books",
|
||||
[
|
||||
{ ...FIRST_BOOK, format: "EBOOK" },
|
||||
{ ...SECOND_BOOK, format: "EBOOK" },
|
||||
],
|
||||
],
|
||||
["GET", "/api/books/1", { ...FIRST_BOOK, format: "EBOOK" }],
|
||||
["GET", "/api/books/2", { ...SECOND_BOOK, format: "EBOOK" }],
|
||||
[
|
||||
"PATCH",
|
||||
"/api/books/1",
|
||||
formatted(3, "PAPER"),
|
||||
200,
|
||||
{ format: "PAPER" },
|
||||
],
|
||||
["GET", "/api/books/1", formatted(3, "PAPER")],
|
||||
[
|
||||
"PATCH",
|
||||
"/api/books/1",
|
||||
formatted(5, "HARDCOVER"),
|
||||
200,
|
||||
{ format: "hardcover" },
|
||||
],
|
||||
["GET", "/api/books/1", formatted(5, "HARDCOVER")],
|
||||
];
|
||||
// One call echoed the format, the other stored another value: no one plan serves both.
|
||||
expect(gated(rows, "patch_books_by_id")).toMatchObject({
|
||||
served: false,
|
||||
reason: "unexplained-change",
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user