Files
reverse-engineering-anything/src/domain/analysisView/environmentStateWriteAttribution.ts
T
Edgar ArakelyanandClaude Opus 5.5 466ed8b433 fix(environment): name entities and weigh interference per write as serving and the recording show
Greptile raised these on this branch, the fidelity branch and the list-lines branch; five follow from the previous
round's changes.
- An entity field whose name looks like a pointer is matched by name; only a document's pointers cover the members under them.
- A failed read contradicts each exercised write that no unmodelled write came after, instead of skipping them all when the oldest pending write preceded one; the shared pending `since` time goes.
- An item read, update or delete names its entity as serving's namedEntity does: held collections its path matches, verbatim spellings first, the id decoded once, then as written; `book%2531` no longer reaches `book1`.
- A plan whose calls use a member both as the identity and as a fixed member, or fix it at different values, is refused, as serving could not take every recorded call.
- A size of zero bounds nothing only on a line whose recording listed items under it (pageBound), in serving and in the gate.
- An update whose observation drops a field the entity held is refused, as serving keeps every field it does not write.
- A later create whose clock takes another format, or whose unique value is not a UUID, is refused.
- A derived state data/get would write past the 32 MiB intake limit is not served (admitServedState); the environment serves replay.

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 11:53:26 -07:00

284 lines
10 KiB
TypeScript

import type { StateView } from "./environmentStateRules.js";
/** The fields a read of a view shows of its entities, less volatile ones it does not compare; all of a document's. */
export const shownFields = (
view: StateView,
volatileOf: (type: string) => ReadonlySet<string>,
): ReadonlySet<string> | "all" => {
if (view.shape !== "item" && view.shape !== "list") return "all";
const volatile = volatileOf(view.type);
return new Set(view.fields.filter((field) => !volatile.has(field)));
};
/** Modelled writes per target since its last check, with the fields each wrote (null: all). */
export type TouchedTargets = Map<string, Map<string, readonly string[] | null>>;
/** Per target, when the latest modelled write since its last check ended. */
export type PendingTargets = Map<string, { until: number }>;
/** Whether a modelled write to the target was still running when a read began at `start`, so the read may show either state. */
export const runningAt = (
pending: PendingTargets,
key: string,
start: number,
): boolean => (pending.get(key)?.until ?? -Infinity) > start;
/** The tools whose writes a read exercises: those that changed its targets since they were last checked, less those that borrowed the read to learn their effect. */
export const exercisedBy = (
touched: TouchedTargets,
keys: readonly string[],
borrowers: ReadonlySet<string> | undefined,
): Set<string> => {
const exercised = new Set<string>();
for (const key of keys)
for (const name of touched.get(key)?.keys() ?? [])
if (!borrowers?.has(name)) exercised.add(name);
return exercised;
};
/** Record a modelled write on a target: the fields it wrote (undefined: all) and when it ended. */
export const touchTarget = (
touched: TouchedTargets,
pending: PendingTargets,
target: string,
write: {
readonly tool: string;
readonly end: number;
readonly fields: readonly string[] | undefined;
},
): void => {
pending.set(target, {
until: Math.max(pending.get(target)?.until ?? -Infinity, write.end),
});
const tools = touched.get(target) ?? new Map();
const before = tools.get(write.tool);
tools.set(
write.tool,
write.fields === undefined || before === null
? null
: [...new Set([...(before ?? []), ...write.fields])],
);
touched.set(target, tools);
};
/** The fields of a write's effect on an entity no later write has overwritten: all of them for a create or delete (null). */
type ChangedFields = readonly string[] | null;
/** What a later write overwrites: the whole entity, the fields it sets, or every field (a recorded outcome). A document's fields are pointers, each covering the members under it. */
interface Overwrite {
readonly whole: boolean;
readonly fields: ReadonlySet<string> | "all";
readonly pointers: boolean;
}
/** Whether a write's fields cover a field: the same one, or, for a document's pointers, one above it. */
const covers = (write: Overwrite, field: string): boolean => {
const { fields } = write;
if (fields === "all" || fields.has(field)) return true;
return (
write.pointers && [...fields].some((over) => field.startsWith(`${over}/`))
);
};
/** What an earlier effect keeps after a write: nothing once every field it holds is overwritten; an update leaves a create's or delete's whole effect. */
const remaining = (
claim: ChangedFields,
write: Overwrite,
): ChangedFields | undefined => {
if (write.whole) return undefined;
if (claim === null) return null;
if (write.fields === "all") return undefined;
const left = claim.filter((field) => !covers(write, field));
return left.length > 0 ? left : undefined;
};
/** Add a write's changed fields under a key: all of them once any write there changed the whole entity. */
const record = (
map: Map<string, ChangedFields>,
key: string,
whole: boolean,
changed: readonly string[],
): Map<string, ChangedFields> => {
const before = map.get(key);
return map.set(
key,
whole || before === null
? null
: [...new Set([...(before ?? []), ...changed])],
);
};
/**
* What each write changed since the targets it touched were last checked, less what later writes overwrote, so a
* write whose effect is gone drops out: from the entity's target, and from its collection's once no entity it changed
* there keeps any of it.
*/
export class WriteEffects {
/** Per entity target, the fields each tool changed there. */
readonly #changed = new Map<string, Map<string, ChangedFields>>();
/** Per collection target, the entities each tool's claim there rests on, with the fields it changed on each. */
readonly #members = new Map<
string,
Map<string, Map<string, ChangedFields>>
>();
/** Forget a checked target's writes, as the touched targets do: all, or all but those a read showed nothing of. */
checked(key: string, unseen?: ReadonlySet<string>): void {
for (const byTool of [this.#changed, this.#members])
if (unseen === undefined) byTool.delete(key);
else
for (const tool of byTool.get(key)?.keys() ?? [])
if (!unseen.has(tool)) byTool.get(key)!.delete(tool);
}
/** Whether a read showing `fields` of a target shows anything of a tool's effect there: a create's or delete's always, an update's through a field it changed; unknown claims count as shown. */
shows(
tool: string,
key: string,
fields: ReadonlySet<string> | "all",
): boolean {
const visible = (claim: ChangedFields | undefined): boolean =>
fields === "all" ||
claim === undefined ||
claim === null ||
claim.some((field) => fields.has(field));
const own = this.#changed.get(key);
if (own !== undefined) return visible(own.get(tool));
const members = this.#members.get(key)?.get(tool);
return members === undefined || [...members.values()].some(visible);
}
/** A write's effect replaces what earlier writes left of theirs, then joins them. */
supersede(
touched: TouchedTargets,
writer: string,
effect: {
readonly targets: readonly string[];
readonly fields?: readonly string[];
readonly changed?: {
readonly fields: readonly string[];
readonly accumulated: readonly string[];
};
/** Set when the fields are a document's pointers. */
readonly pointers?: boolean;
},
): void {
const [entity, collection] = effect.targets as [string, string?];
const changed = effect.changed?.fields ?? effect.fields ?? [];
const whole = effect.fields === undefined;
this.#overwrite(
touched,
{ entity, collection, writer },
{
whole,
fields: new Set(
changed.filter(
(field) => !effect.changed?.accumulated.includes(field),
),
),
pointers: effect.pointers === true,
},
);
this.#changed.set(
entity,
record(this.#changed.get(entity) ?? new Map(), writer, whole, changed),
);
if (collection === undefined) return;
const byTool = this.#members.get(collection) ?? new Map();
byTool.set(
writer,
record(byTool.get(writer) ?? new Map(), entity, whole, changed),
);
this.#members.set(collection, byTool);
}
/** A recorded outcome is the entity's new baseline: what earlier writes changed on it is gone, its membership is not. */
observed(touched: TouchedTargets, targets: readonly string[]): void {
const [entity, collection] = targets as [string, string?];
this.#overwrite(
touched,
{ entity, collection, writer: undefined },
{ whole: false, fields: "all", pointers: false },
);
}
#overwrite(
touched: TouchedTargets,
at: {
readonly entity: string;
readonly collection: string | undefined;
readonly writer: string | undefined;
},
write: Overwrite,
): void {
const own = this.#changed.get(at.entity);
for (const [tool, claim] of own ?? []) {
const left = tool === at.writer ? claim : remaining(claim, write);
if (left !== undefined) own!.set(tool, left);
else {
own!.delete(tool);
touched.get(at.entity)?.delete(tool);
}
}
if (at.collection === undefined) return;
const byTool = this.#members.get(at.collection);
for (const [tool, entities] of byTool ?? []) {
const claim = entities.get(at.entity);
if (tool === at.writer || claim === undefined) continue;
const left = remaining(claim, write);
if (left !== undefined) entities.set(at.entity, left);
else entities.delete(at.entity);
if (entities.size > 0) continue;
byTool!.delete(tool);
touched.get(at.collection)?.delete(tool);
}
}
}
/** Of the tools a read exercised, those it shows something of on some target, and per target those it shows nothing of. */
export const shownWrites = (
touched: TouchedTargets,
effects: WriteEffects,
read: {
readonly keys: readonly string[];
readonly exercised: ReadonlySet<string>;
readonly fields: ReadonlySet<string> | "all";
},
): {
readonly confirmed: string[];
readonly unseen: Map<string, Set<string>>;
} => {
const confirmed: string[] = [];
const unseen = new Map<string, Set<string>>();
for (const name of read.exercised) {
const on = read.keys.filter((key) => touched.get(key)?.has(name));
const seen = on.filter((key) => effects.shows(name, key, read.fields));
for (const key of on)
if (!seen.includes(key))
unseen.set(key, (unseen.get(key) ?? new Set()).add(name));
if (seen.length > 0) confirmed.push(name);
}
return { confirmed, unseen };
};
/** A checked target forgets its writes, but for those a passing read showed nothing of, which a later check still takes. */
export const forgetChecked = (
pending: {
readonly touched: TouchedTargets;
readonly since: PendingTargets;
readonly effects: WriteEffects;
},
key: string,
unseen: ReadonlySet<string> | undefined,
): void => {
const writes = pending.touched.get(key);
if (unseen === undefined || writes === undefined) {
pending.touched.delete(key);
pending.effects.checked(key);
pending.since.delete(key);
return;
}
for (const name of writes.keys()) if (!unseen.has(name)) writes.delete(name);
pending.effects.checked(key, unseen);
};