Files
reverse-engineering-anything/src/domain/analysisView/environmentStateWriteExplain.test.ts
T
Edgar ArakelyanandClaude Opus 5.5 43d98ea941 fix(environment): pin a create's observation to the id it answered, and keep later identity, wide bodies and fixed values in check
Greptile raised these on the list-lines branch against this branch's code.
- A create that answers with its id alone (a scalar, the identity field or one member) is observed only through a read of that id. A read of another, unlisted book can no longer supply the created entity. Lists may supply it when they show that id.
- A later update call that is the first to send the path's id in its body adds the identity member to the plan, instead of making the tool unexplained.
- The copy search walks a request body with an index rather than shifting it. 500,000 zeros took 63 s before and 74 ms after.
- The sent values of fixed members a plan keeps are counted against the view's memory allowance, on the first call and when a later call adds more.

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>
2026-10-21 09:35:41 -07:00

568 lines
17 KiB
TypeScript

import { expect, it } from "vitest";
import type { JsonValue } from "../jsonValue.js";
import type { JsonObject } from "./environmentStateRules.js";
import {
compareValues,
documentPointerOf,
explainCreate,
explainUpdate,
insertCandidates,
insertIndex,
responseShapeOf,
type CreateEvidence,
type UpdateEvidence,
} from "./environmentStateWriteExplain.js";
import {
classifyWrite,
pathValuesOf,
prefixRelated,
type FieldRule,
type InsertRule,
type WriteEffect,
type WriteResponse,
} from "./environmentStateWriteRules.js";
const START = Date.UTC(2026, 2, 4, 5, 6, 0);
const MINUTE = 60_000;
const UUID = "123e4567-e89b-42d3-a456-426614174000";
const OTHER_UUID = "00000000-0000-4000-8000-000000000000";
const created = (
entity: JsonObject,
body: JsonObject,
context: Partial<CreateEvidence> & {
readonly path?: Record<string, string>;
} = {},
): CreateEvidence => {
const { path = {}, ...rest } = context;
return {
entity,
call: { path: "/items", pathValues: new Map(Object.entries(path)), body },
idField: "id",
startMs: START,
collection: [],
type: [],
...rest,
};
};
const updated = (
before: JsonObject,
after: JsonObject,
body: JsonObject,
context: Partial<UpdateEvidence> = {},
): UpdateEvidence => ({
before,
after,
call: { path: "/items/42", pathValues: new Map([["item", "42"]]), body },
method: "PATCH",
idField: "id",
id: "42",
startMs: START,
...context,
});
const ruleFor = (
rules: readonly FieldRule[],
field: string,
): FieldRule | undefined => rules.find((rule) => rule.field === field);
it("explains created fields by echo, copy, path and slug, leaving constants unlisted", () => {
const notes = ["x", "drafted by the finance team"];
const result = explainCreate(
created(
{
id: 7,
title: "Quarterly report",
heading: "Quarterly report",
summary: "drafted by the finance team",
projectId: 42,
slug: "quarterly-report",
code: "abc",
status: "open",
},
{ title: "Quarterly report", meta: { notes }, label: "abc" },
{ path: { project: "42" } },
),
);
expect(result.rules).toEqual([
{ field: "id", rule: "identity", generator: "sequence" },
{ field: "title", rule: "echo" },
{ field: "heading", rule: "copy", from: "/title" },
{ field: "summary", rule: "copy", from: "/meta/notes/1" },
{ field: "projectId", rule: "path", from: "project" },
{ field: "slug", rule: "slug", from: "title" },
]);
expect(result.tied).toBe(false);
});
it("copies only body strings of eight or more characters", () => {
const short = explainCreate(
created({ id: 1, label: "seven77" }, { name: "seven77" }),
);
expect(ruleFor(short.rules, "label")).toBeUndefined();
const long = explainCreate(
created({ id: 1, label: "eight888" }, { name: { first: "eight888" } }),
);
expect(ruleFor(long.rules, "label")).toEqual({
field: "label",
rule: "copy",
from: "/name/first",
});
});
it.each<[string, JsonValue, number | undefined, boolean]>([
[
"ten minutes after",
new Date(START + 10 * MINUTE).toISOString(),
START,
true,
],
[
"ten minutes before",
new Date(START - 10 * MINUTE).toISOString(),
START,
true,
],
[
"just outside",
new Date(START + 10 * MINUTE + 1).toISOString(),
START,
false,
],
["untimed", new Date(START).toISOString(), undefined, false],
])("explains a clock %s the request start", (_, value, startMs, clock) => {
const result = explainCreate(created({ id: 1, at: value }, {}, { startMs }));
expect(ruleFor(result.rules, "at")).toEqual(
clock
? {
field: "at",
rule: "clock",
format: { kind: "iso", separator: "T", fraction: 3, zone: "Z" },
}
: undefined,
);
});
it("keeps an epoch clock's unit", () => {
const result = explainCreate(created({ id: 1, at: START / 1000 + 5 }, {}));
expect(ruleFor(result.rules, "at")).toEqual({
field: "at",
rule: "clock",
format: { kind: "epoch", unit: "s" },
});
});
it.each<[JsonValue, FieldRule | undefined]>([
[4, { field: "number", rule: "sequence", scope: "collection" }],
["4", { field: "number", rule: "sequence", scope: "collection" }],
[10, { field: "number", rule: "sequence", scope: "type" }],
[5, undefined],
])("explains the number %j by the sequence it continues", (value, rule) => {
const collection = [{ number: 1 }, { number: "3" }];
const evidence = created(
{ id: 1, number: value },
{},
{
collection,
type: [...collection, { number: 9 }, { number: "x" }],
},
);
expect(ruleFor(explainCreate(evidence).rules, "number")).toEqual(rule);
});
it.each<[string, JsonObject[], boolean]>([
["no other entity shares", [{ ref: OTHER_UUID }, {}], true],
["another entity shares", [{ ref: OTHER_UUID }, { ref: UUID }], false],
["the type holds no other entity", [], false],
])("explains a UUID as unique when %s it", (_, type, unique) => {
const result = explainCreate(created({ id: 1, ref: UUID }, {}, { type }));
expect(ruleFor(result.rules, "ref")).toEqual(
unique ? { field: "ref", rule: "unique" } : undefined,
);
});
it.each<[JsonValue, "sequence" | "uuid" | "token"]>([
[17, "sequence"],
["17", "sequence"],
[UUID, "uuid"],
["tok_AbC9", "token"],
])("generates the identity %j as a %s", (id, generator) => {
const result = explainCreate(
created({ key: id, title: "x" }, {}, { idField: "key" }),
);
expect(result.rules).toEqual([{ field: "key", rule: "identity", generator }]);
});
it("rebuilds strings that embed a generated value as a delimited token", () => {
const result = explainCreate(
created(
{
id: "abc123",
number: 4,
url: "https://x.test/items/abc123",
ref: "#4",
near: "abc1234 is not it",
year: "2024",
},
{},
{ collection: [{ number: 3 }] },
),
);
expect(result.rules).toEqual([
{ field: "id", rule: "identity", generator: "token" },
{ field: "number", rule: "sequence", scope: "collection" },
{ field: "url", rule: "template", from: "id" },
{ field: "ref", rule: "template", from: "number" },
]);
});
it("accepts echoed members and fixes the others at their sent values", () => {
const result = explainCreate(
created(
{ id: 1, title: "A", priority: "high" },
{ title: "A", priority: "HIGH", notify: true },
),
);
expect(result.body).toEqual({
accepted: ["title"],
fixed: [
{ member: "priority", sent: "HIGH" },
{ member: "notify", sent: true },
],
required: ["title", "priority", "notify"],
identity: null,
});
});
it.each<[string, JsonObject, boolean]>([
[
"a constant holds the path value delimited",
{ team: "/orgs/acme/teams" },
true,
],
["a constant holds it only inside a word", { team: "acmecorp" }, false],
["only a path field holds it", { org: "acme" }, false],
[
"a template keeps it beside the generated value",
{ url: "/orgs/acme/items/1" },
true,
],
])("ties a create to its collection only when %s", (_, fields, tied) => {
const result = explainCreate(
created({ id: 1, ...fields }, {}, { path: { org: "acme", empty: "" } }),
);
expect(result.tied).toBe(tied);
});
it("explains an update's sent members as echoes, constants or the identity", () => {
const result = explainUpdate(
updated(
{ id: "42", title: "Old", status: "open" },
{ id: "42", title: "New", status: "closed" },
{ id: 42, title: "New", status: "CLOSED", comment: "done" },
),
);
expect(result).toEqual({
rules: [
{ field: "title", rule: "echo" },
{ field: "status", rule: "constant", value: "closed" },
],
body: {
accepted: ["title"],
fixed: [
{ member: "status", sent: "CLOSED" },
{ member: "comment", sent: "done" },
],
required: [],
identity: "id",
},
unexplained: [],
});
});
it("explains unsent changes as a clock, an increment or a slug of an echoed member", () => {
const result = explainUpdate(
updated(
{
id: "42",
title: "Old Title",
slug: "old-title",
version: 3,
revision: "9",
updatedAt: "2026-01-01T00:00:00Z",
color: "red",
},
{
id: "42",
title: "New Title",
slug: "new-title",
version: 4,
revision: "10",
updatedAt: new Date(START + 1000).toISOString(),
color: "blue",
added: true,
},
{ title: "New Title" },
),
);
expect(result.rules).toEqual([
{ field: "title", rule: "echo" },
{ field: "slug", rule: "slug", from: "title" },
{ field: "version", rule: "increment" },
{ field: "revision", rule: "increment" },
{
field: "updatedAt",
rule: "clock",
format: { kind: "iso", separator: "T", fraction: 3, zone: "Z" },
},
]);
expect(result.unexplained).toEqual(["color"]);
});
it("leaves a slug of a transformed member, an untimed clock and a jump unexplained", () => {
const result = explainUpdate(
updated(
{ id: "42", title: "Old", slug: "old", at: "2026-01-01T00:00:00Z", n: 3 },
{
id: "42",
title: "new title",
slug: "new-title",
at: new Date(START).toISOString(),
n: 5,
},
{ title: "New Title" },
{ startMs: undefined },
),
);
expect(result.rules).toEqual([
{ field: "title", rule: "constant", value: "new title" },
]);
expect(result.unexplained).toEqual(["slug", "at", "n"]);
});
it.each<[string, string[]]>([
["PUT", ["title", "status"]],
["PATCH", []],
["POST", []],
])(
"requires the members a %s sent apart from the identity",
(method, required) => {
const after = { id: "42", title: "New", status: "closed" };
const body = { id: "42", title: "New", status: "closed" };
const result = explainUpdate(updated(after, after, body, { method }));
expect(result.body.required).toEqual(required);
expect(result.body.identity).toBe("id");
},
);
type Shaped = [WriteResponse["shape"], string | null];
it.each<[string, JsonValue | undefined, boolean, Shaped]>([
["no body", undefined, true, ["empty", null]],
["an empty response with a body", { id: "42" }, true, ["empty", null]],
["no recorded body", undefined, false, ["recorded", null]],
["the entity at the root", { id: "42", title: "x" }, false, ["entity", ""]],
[
"the entity in one member",
{ data: { id: 42 } },
false,
["entity", "/data"],
],
[
"the entity in a one-element array",
[{ id: "42" }],
false,
["entity", "/0"],
],
["the identity at the root", "42", false, ["identity", ""]],
["a numeric identity at the root", 42, false, ["identity", ""]],
[
"the identity in one member",
{ created: "42", ok: true },
false,
["identity", "/created"],
],
[
"the identity in an escaped member",
{ "a/b": 42 },
false,
["identity", "/a~1b"],
],
[
"the identity in two members",
{ a: "42", b: "42" },
false,
["recorded", null],
],
["no identity", { ok: true }, false, ["recorded", null]],
])("shapes a response carrying %s", (_, body, empty, [shape, pointer]) => {
expect(responseShapeOf(3, body, empty, { idField: "id", id: "42" })).toEqual({
ordinal: 3,
shape,
pointer,
});
});
it.each<[JsonValue | undefined, JsonValue | undefined, number | undefined]>([
[2, 10, -1],
["10", 9, 1],
["7", 7, 0],
["2026-03-04T05:00:00Z", "2026-03-04T06:30:00+02:00", 1],
[Date.UTC(2026, 2, 4, 6) / 1000, "2026-03-04T05:00:00Z", 1],
["apple", "banana", -1],
["Zebra", "apple", -1],
["b", "b", 0],
[5, "apple", undefined],
[true, false, undefined],
[undefined, "x", undefined],
[{ a: 1 }, { a: 1 }, undefined],
])("orders %j against %j as %j", (left, right, sign) => {
const order = compareValues(left, right);
expect(order === undefined ? undefined : Math.sign(order)).toBe(sign);
});
it("offers each strictly ordered field in its direction, then last and first", () => {
const members = [
{ id: 1, at: "2026-03-02T00:00:00Z", name: "b", tag: "x" },
{ id: 2, at: "2026-03-01T12:00:00+02:00", name: "a", tag: "x" },
{ id: "3", at: "2026-02-28T00:00:00Z", name: "c" },
];
expect(insertCandidates(members, ["id", "at", "name", "tag"])).toEqual([
{ rule: "sorted", field: "id", direction: "ascending" },
{ rule: "sorted", field: "at", direction: "descending" },
{ rule: "last" },
{ rule: "first" },
]);
const fallback = [{ rule: "last" }, { rule: "first" }];
expect(insertCandidates([{ id: 1 }], ["id"])).toEqual(fallback);
expect(insertCandidates([], ["id"])).toEqual(fallback);
});
const ASCENDING = [{ n: 1 }, { n: 3 }, { n: 5 }];
const DESCENDING = [{ n: 5 }, { n: 3 }, { n: 1 }];
const up: InsertRule = { rule: "sorted", field: "n", direction: "ascending" };
const down: InsertRule = {
rule: "sorted",
field: "n",
direction: "descending",
};
it.each<[string, InsertRule, JsonObject, number]>([
["first", { rule: "first" }, { n: 9 }, 0],
["last", { rule: "last" }, { n: 0 }, 3],
["ascending, between members", up, { n: 4 }, 2],
["ascending, before every member", up, { n: 0 }, 0],
["ascending, after every member", up, { n: 6 }, 3],
["ascending, after an equal member", up, { n: 3 }, 2],
["descending, between members", down, { n: 4 }, 1],
["descending, after every member", down, { n: 0 }, 3],
["sorted, with an incomparable value", up, { n: true }, 3],
["sorted, without the field", up, {}, 3],
])("inserts %s", (_, rule, fields, index) => {
const members = rule === down ? DESCENDING : ASCENDING;
expect(insertIndex(rule, members, fields)).toBe(index);
});
it.each<[string, JsonValue, JsonObject, string | undefined]>([
["the root", { theme: "dark", lang: "en" }, { theme: "light" }, ""],
[
"the member sharing most",
{ theme: "dark", settings: { theme: "dark", lang: "en" } },
{ theme: "light", lang: "fr" },
"/settings",
],
[
"the root on a tie",
{ theme: "d", s: { lang: "en" } },
{ theme: "x", lang: "y" },
"",
],
["an escaped member", { "a/b": { theme: "dark" } }, { theme: "x" }, "/a~1b"],
[
"nothing when none is shared",
{ a: 1, b: { c: 2 } },
{ theme: "x" },
undefined,
],
["nothing in an array", [{ theme: "dark" }], { theme: "x" }, undefined],
])("points a document write at %s", (_, value, body, pointer) => {
expect(documentPointerOf(value, body)).toBe(pointer);
});
it.each<[string, string, WriteEffect, string | null]>([
["POST", "/users", "create", "/users"],
["POST", "/users/", "create", "/users"],
["POST", "/users/{userId}/posts", "create", "/users/{userId}/posts"],
["PUT", "/users/{userId}", "update", "/users"],
["PATCH", "/users/{id}", "update", "/users"],
["POST", "/users/{id}", "update", "/users"],
["DELETE", "/users/{id}", "delete", "/users"],
[
"DELETE",
"/users/{userId}/posts/{postId}",
"delete",
"/users/{userId}/posts",
],
["GET", "/users/{id}", "none", null],
["DELETE", "/users", "none", null],
["PUT", "/users", "none", null],
["PUT", "/users/me", "none", null],
["POST", "/users/{id}/archive", "none", null],
["PUT", "/settings", "document", "get_settings"],
["PATCH", "/settings/", "document", "get_settings"],
["POST", "/settings", "document", "get_settings"],
["DELETE", "/settings", "none", null],
])("classifies %s %s as %s", (method, path, effect, target) => {
expect(
classifyWrite(
{ method, path_template: path },
new Set(["/users", "/users/{userId}/posts"]),
new Map([["/settings", "get_settings"]]),
),
).toEqual({ effect, target });
});
it.each<[string, string, Record<string, string> | undefined]>([
[
"/orgs/{org}/repos/{repo}",
"/orgs/acme/repos/rea",
{ org: "acme", repo: "rea" },
],
["/orgs/{org}", "/orgs/a%20b%2Fc/", { org: "a b/c" }],
["/orgs/{org}", "/orgs/%E0%A4%A", { org: "%E0%A4%A" }],
["/orgs", "/orgs", {}],
["/orgs/{org}", "/teams/acme", undefined],
["/orgs/{org}", "/orgs/acme/repos", undefined],
])("reads %s from %s", (template, path, values) => {
expect(pathValuesOf(template, path)).toEqual(
values === undefined ? undefined : new Map(Object.entries(values)),
);
});
it.each<[string, string, boolean]>([
["/users", "/users/{id}", true],
["/users/{id}/posts", "/users/42", true],
["/users/42/posts", "/users/{id}/posts/7", true],
["/", "/anything/at/all", true],
["/users/42", "/users/43", false],
["/users", "/teams/{id}", false],
["/{tenant}/users", "/acme/teams", false],
])("relates %s and %s by prefix: %s", (left, right, related) => {
expect(prefixRelated(left, right)).toBe(related);
expect(prefixRelated(right, left)).toBe(related);
});
it(
"searches a wide request body for a copied value in linear time",
{ timeout: 5_000 },
() => {
// Shifting each value off the queue made one fruitless search over 500,000 zeros take about a minute.
const wide = Array.from({ length: 500_000 }, () => 0);
const result = explainCreate(
created({ id: 1, note: "not anywhere in the body" }, { items: wide }),
);
expect(ruleFor(result.rules, "note")).toBeUndefined();
},
);