feat: serializer preserves unknown fields at every level (F5 SLICE-2, INV-15, #14)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -103,6 +103,74 @@ describe("cross-rung identity (F5 SLICE-2)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("unknown-field preservation (F5 SLICE-2, INV-15)", () => {
|
||||
it("a rewrite preserves unknown fields at every level, after known keys, sorted", () => {
|
||||
const foreign = {
|
||||
schemaVersion: 1,
|
||||
document: { path: "docs/x.md", zFuture: "keep-me" },
|
||||
anchors: {
|
||||
a_1: { fingerprint: { text: "alpha", before: "", after: "", lineHint: 0, confidence: 0.9 }, label: "intro" },
|
||||
},
|
||||
threads: [
|
||||
{
|
||||
id: "t_1",
|
||||
anchorId: "a_1",
|
||||
status: "open",
|
||||
messages: [
|
||||
{
|
||||
id: "m_1",
|
||||
author: { kind: "human", id: "ben", forgeLogin: "bstull" },
|
||||
body: "hi",
|
||||
createdAt: "2026-06-10T00:00:00.000Z",
|
||||
reactions: ["+1"],
|
||||
},
|
||||
],
|
||||
locked: false,
|
||||
},
|
||||
],
|
||||
attributions: [
|
||||
{
|
||||
id: "at_1",
|
||||
anchorId: "a_1",
|
||||
author: { kind: "human", id: "ben" },
|
||||
createdAt: "2026-06-10T00:00:00.000Z",
|
||||
updatedAt: "2026-06-10T00:00:00.000Z",
|
||||
reviewState: "approved",
|
||||
},
|
||||
],
|
||||
proposals: [
|
||||
{
|
||||
id: "p_1",
|
||||
anchorId: "a_1",
|
||||
replacement: "ALPHA",
|
||||
author: { kind: "human", id: "ben" },
|
||||
createdAt: "2026-06-10T00:00:00.000Z",
|
||||
priority: 2,
|
||||
},
|
||||
],
|
||||
futureSection: [{ id: "f_1" }],
|
||||
aaaEarly: true,
|
||||
};
|
||||
const out = serializeArtifact(foreign as unknown as Artifact);
|
||||
const parsed = JSON.parse(out);
|
||||
expect(parsed.futureSection).toEqual([{ id: "f_1" }]);
|
||||
expect(parsed.aaaEarly).toBe(true);
|
||||
expect(parsed.document.zFuture).toBe("keep-me");
|
||||
expect(parsed.anchors.a_1.label).toBe("intro");
|
||||
expect(parsed.anchors.a_1.fingerprint.confidence).toBe(0.9);
|
||||
expect(parsed.threads[0].locked).toBe(false);
|
||||
expect(parsed.threads[0].messages[0].reactions).toEqual(["+1"]);
|
||||
expect(parsed.threads[0].messages[0].author.forgeLogin).toBe("bstull");
|
||||
expect(parsed.attributions[0].reviewState).toBe("approved");
|
||||
expect(parsed.proposals[0].priority).toBe(2);
|
||||
// unknown ROOT keys serialize AFTER known keys, sorted: aaaEarly then futureSection, both after proposals
|
||||
expect(out.indexOf('"proposals"')).toBeLessThan(out.indexOf('"aaaEarly"'));
|
||||
expect(out.indexOf('"aaaEarly"')).toBeLessThan(out.indexOf('"futureSection"'));
|
||||
// byte-stable on re-serialize (INV-2 holds with unknowns present)
|
||||
expect(serializeArtifact(parsed as Artifact)).toBe(out);
|
||||
});
|
||||
});
|
||||
|
||||
describe("attributions[] (F3 SLICE-1)", () => {
|
||||
it("round-trips an attribution record through serialize → parse", () => {
|
||||
const a = emptyArtifact("docs/x.md");
|
||||
|
||||
Reference in New Issue
Block a user