Files
reverse-engineering-anything/src/domain/analysisView/environmentStateWriteDocument.ts
T
morluto 3c5c887a2c refactor(json): consolidate representation size accounting
Share bounded UTF-8 and UTF-16 JSON measurements across state serving, write retention and source-map admission. Remove duplicate counters and distinguish retained state estimates from encoded bytes while preserving limits and exact refusal diagnostics.
2026-10-23 20:54:19 +08:00

160 lines
5.2 KiB
TypeScript

import { jsonTextCodeUnits } from "../jsonSerialization.js";
import type { JsonValue } from "../jsonValue.js";
import {
at as valueAt,
isObject,
pathSegmentMatches,
pointerTo,
same,
segmentsOf,
type JsonObject,
} from "./environmentStateRules.js";
import {
documentBodyProblem,
writtenDocument,
} from "./environmentStateWriteApply.js";
import { documentTarget } from "./environmentStateWriteChecks.js";
import {
built,
callOf,
fail,
refuse,
requestObject,
UNKNOWN,
type EffectContext,
type EffectResult,
type WriteDraft,
type WriteStep,
} from "./environmentStateWriteEffects.js";
import { documentPointerOf } from "./environmentStateWriteExplain.js";
/** Whether a write's path names the held document's: each segment verbatim, or either spelling once percent-decoded, as serving matches a supplied value. */
const namesDocument = (path: string, held: string): boolean => {
const written = segmentsOf(path);
const recorded = segmentsOf(held);
return (
written.length === recorded.length &&
recorded.every((segment, index) =>
pathSegmentMatches(segment, written[index]!),
)
);
};
/** Where a write goes: a built plan writes where serving does, at its own object; an exemplar at the object holding most of its members. */
const writePointer = (
draft: WriteDraft,
value: JsonValue,
body: JsonObject,
): string | undefined =>
built(draft)
? draft.plan.observation?.pointer
: documentPointerOf(value, body);
/**
* The fields a document write changed, as pointers: a merge the members it sent at its object, a replacement every
* member it wrote or removed there, so later writes can overwrite its effect (undefined: the whole document).
*/
const writtenPointers = (
draft: WriteDraft,
body: JsonObject,
values: { readonly before: JsonValue; readonly after: JsonValue },
): readonly string[] | undefined => {
const at = draft.plan.observation?.pointer ?? "";
if (draft.plan.merge === "merge")
return Object.keys(body).map((member) => `${at}${pointerTo(member)}`);
const members = new Set(
[values.before, values.after].flatMap((value) => {
const object = valueAt(value, at);
return isObject(object) ? Object.keys(object) : [];
}),
);
if (members.size === 0) return at === "" ? undefined : [at];
return [...members].map((member) => `${at}${pointerTo(member)}`);
};
/** Build a document plan from its exemplar: its object, merge or replacement by method, and the members it sent. */
const buildDocument = (
draft: WriteDraft,
step: WriteStep,
evidence: { readonly pointer: string; readonly body: JsonObject },
): void => {
const { ordinal } = step.record;
Object.assign(draft.plan, {
exemplar_ordinal: ordinal,
observation: { ordinal, pointer: evidence.pointer },
merge: step.tool.method === "PUT" ? "replace" : "merge",
body: {
accepted: Object.keys(evidence.body),
fixed: [],
required: [],
identity: null,
kinds: [],
},
});
};
/** Apply a recorded document write: the body merged into, or replacing, the object holding most of its members. */
export const applyDocument = (
context: EffectContext,
draft: WriteDraft,
step: WriteStep,
): EffectResult => {
const tool = draft.plan.target!;
const initial = context.initialDocument(tool);
// Serving refuses a write at another path, so one here changes no document the state holds.
if (initial !== undefined && !namesDocument(step.record.path, initial.path))
return UNKNOWN;
const value = context.state.document(tool);
const body = requestObject(context, step.record);
const pointer =
value === undefined || body === undefined
? undefined
: writePointer(draft, value, body);
if (step.observeOnly || pointer === undefined) {
fail(draft, step, body === undefined ? "body-unusable" : "no-observation");
return UNKNOWN;
}
if (!built(draft)) buildDocument(draft, step, { pointer, body: body! });
const call = callOf(step, body!);
// Serving refuses a body its check refuses, so such a call cannot confirm the plan.
if (
documentBodyProblem(draft.plan, call, {
initial: initial?.value,
current: value!,
}) !== undefined
) {
refuse(draft, step, "unexplained-change");
return UNKNOWN;
}
const written = writtenDocument(draft.plan, value!, call);
if (!written.ok) {
refuse(draft, step, "no-observation");
return UNKNOWN;
}
const { ordinal } = step.record;
draft.plan.response ??= context.io.withBody(ordinal, (response) => ({
ordinal,
shape: context.io.emptyResponse(ordinal)
? "empty"
: response !== undefined && same(response, written.value)
? "entity"
: "recorded",
pointer: null,
}));
context.io.retain(64 + jsonTextCodeUnits(written.value) * 2);
context.state.setDocument(tool, written.value);
const fields = writtenPointers(draft, body!, {
before: value!,
after: written.value,
});
const replaced = draft.plan.merge === "merge" ? undefined : pointer;
return {
kind: "applied",
targets: [documentTarget(tool)],
...(fields === undefined ? {} : { fields, pointers: true }),
...(fields === undefined || replaced === undefined
? {}
: { overwrites: [replaced] }),
};
};