The same text can tell a different story when an image moves beneath another paragraph. After reading Northstar's ArticlePlan and media binding functions, I made an independent example for reviewing an ordered article as structured data. It compares synthetic observations without uploading files or saving a server document.

Keep order before flattening the body

The plan accepts version and blocks. A block is text, image or video; media carry a filename and SHA-256 digest, and video also needs a title. The rich plan starts and ends with text, contains media and combines adjacent text. This is a contract for this media-containing example, not a service-wide rule rejecting ordinary text-only writing.

The example bounds input to three through fifty blocks, twenty selected metadata entries and a text budget. Those are code input boundaries rather than a limit on future topics or article counts. Its independently authored shape resembles the original contract without claiming identical TypeScript string-length behavior or serialization. Knowing which part is illustrative makes adaptation safer.

Bind filename and bytes together

Compile_plan finds selected metadata matching both name and digest. Identical names with different bytes can be distinguished, while two matches with the same name and digest are refused as ambiguous. Duplicate handles are rejected too. An unresolved later image prevents returning a completed compilation instead of presenting partial binding as full preparation.

Handles are synthetic labels, not operating-system paths or upload permission. The module opens no file and compares only supplied metadata. Its record generator actually computes the hash of a small synthetic byte string, but it cannot authenticate that an arbitrary caller-supplied digest came from a particular real file. Binding data and establishing trusted provenance remain different responsibilities.

A plan digest prevents treating a changed article as the same one

Plan_digest hashes UTF-8 canonical sorted-key JSON. It covers paragraph text, media order, byte digests and video title; reordering dictionary keys alone does not change identity. This is explicitly the example's comparison rule, not a claim of byte-for-byte equality with the original program's JSON serialization.

Review compares a recorded expected_digest with a freshly computed plan digest. Changing the plan while retaining the old identity produces PLAN_CHANGED. This neither authenticates an author nor makes text secret, and it cannot stop a caller authorized to replace both plan and digest. It is an inspectable consistency check within a trusted handoff, not an authorization system.

Explore the implementation

Complete independent synthetic implementation

"""Independent synthetic ordered-plan review. No upload, browser or server proof."""
import hashlib
import json
import re
from copy import deepcopy


def fail(code):
    raise ValueError(code)


def shape(value, fields, code):
    if not isinstance(value, dict) or set(value) != set(fields):
        fail(code)


def name(value):
    if not isinstance(value, str) or not value.strip() or len(value) > 240 or any(c in value for c in "/\\\r\n\x00"):
        fail("FILENAME")


def digest(value):
    if not isinstance(value, str) or not re.fullmatch(r"[a-f0-9]{64}", value):
        fail("DIGEST")


def identity(value):
    if not isinstance(value, str) or not re.fullmatch(r"[A-Za-z0-9_-]{1,80}", value):
        fail("IDENTITY")


def validate(raw):
    shape(raw, {"version", "blocks"}, "PLAN_SHAPE")
    if type(raw["version"]) is not int or raw["version"] != 1:
        fail("VERSION")
    blocks = raw["blocks"]
    if not isinstance(blocks, list) or not 3 <= len(blocks) <= 50:
        fail("BLOCK_COUNT")
    text_size = 0
    for index, block in enumerate(blocks):
        if not isinstance(block, dict):
            fail("BLOCK_SHAPE")
        kind = block.get("kind")
        if kind == "text":
            shape(block, {"kind", "text"}, "TEXT_SHAPE")
            text = block["text"]
            if not isinstance(text, str) or not text.strip() or "\r" in text or len(text) > 20000:
                fail("TEXT")
            if index and blocks[index-1].get("kind") == "text":
                fail("ADJACENT_TEXT")
            text_size += len(text) + 2
        elif kind in {"image", "video"}:
            shape(block, {"kind", "fileName", "sha256"} | ({"title"} if kind == "video" else set()), "MEDIA_SHAPE")
            name(block["fileName"]); digest(block["sha256"])
            if kind == "video" and (not isinstance(block["title"], str) or not block["title"].strip() or len(block["title"]) > 100):
                fail("VIDEO_TITLE")
        else:
            fail("KIND")
    if blocks[0]["kind"] != "text" or blocks[-1]["kind"] != "text" or not any(b["kind"] != "text" for b in blocks):
        fail("RICH_LAYOUT")
    if text_size > 20000:
        fail("TEXT_LIMIT")
    return deepcopy(raw)


def plan_digest(plan):
    value = validate(plan)
    canonical = json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(canonical.encode("utf-8")).hexdigest()


def compile_plan(raw, selected):
    plan = validate(raw)
    if not isinstance(selected, list) or not 1 <= len(selected) <= 20:
        fail("SELECTED_COUNT")
    handles = set()
    for file in selected:
        shape(file, {"handle", "name", "sha256"}, "SELECTED_SHAPE")
        identity(file["handle"]); name(file["name"]); digest(file["sha256"])
        if file["handle"] in handles:
            fail("DUPLICATE_HANDLE")
        handles.add(file["handle"])
    bindings = []
    for index, block in enumerate(plan["blocks"]):
        if block["kind"] == "text":
            continue
        matches = [f for f in selected if f["name"] == block["fileName"] and f["sha256"] == block["sha256"]]
        if len(matches) != 1:
            fail("FILE_NOT_UNIQUE")
        bindings.append({"index": index, "handle": matches[0]["handle"]})
    return {"plan": plan, "digest": plan_digest(plan), "bindings": bindings}


def review(compiled, observed, *, expected_digest):
    # Recompute identity. Bindings are inert diagnostic output, not service receipts.
    shape(compiled, {"plan", "digest", "bindings"}, "COMPILED_SHAPE")
    actual_digest = plan_digest(compiled["plan"])
    digest(expected_digest)
    if compiled["digest"] != actual_digest or expected_digest != actual_digest:
        fail("PLAN_CHANGED")
    if not isinstance(observed, list) or len(observed) > 50:
        fail("OBSERVATION")
    ids = set()
    for block in observed:
        if not isinstance(block, dict):
            fail("OBSERVED_SHAPE")
        if block.get("kind") == "text":
            shape(block, {"kind", "text"}, "OBSERVED_SHAPE")
            if not isinstance(block["text"], str):
                fail("OBSERVED_TEXT")
        elif block.get("kind") in {"image", "video"}:
            shape(block, {"kind", "fileName", "sha256", "id", "ready"}, "OBSERVED_SHAPE")
            name(block["fileName"]); digest(block["sha256"]); identity(block["id"])
            if type(block["ready"]) is not bool:
                fail("OBSERVED_READY")
            if block["id"] in ids:
                fail("DUPLICATE_COMPONENT")
            ids.add(block["id"])
        else:
            fail("OBSERVED_KIND")
    differences = []
    expected = compiled["plan"]["blocks"]
    if len(expected) != len(observed):
        differences.append({"code": "COUNT", "expected": len(expected), "actual": len(observed)})
    for index, (wanted, found) in enumerate(zip(expected, observed)):
        codes = []
        if wanted["kind"] != found["kind"]:
            codes.append("KIND")
        elif wanted["kind"] == "text":
            if wanted["text"] != found["text"]:
                codes.append("TEXT")
        else:
            if wanted["fileName"] != found["fileName"]:
                codes.append("FILENAME")
            if wanted["sha256"] != found["sha256"]:
                codes.append("MEDIA_BYTES")
            if not found["ready"]:
                codes.append("NOT_READY")
        differences.extend({"index": index, "code": code} for code in codes)
    return {"matches": not differences, "differences": differences,
            "evidence": "caller-declared synthetic layout only", "publication_verified": False}

Report differences without turning them into publication success

Observed entries are ordered text or media data. Review compares count, kind, exact paragraph text, media name and digest, and readiness; it returns indices and difference codes rather than copying full paragraphs into diagnostic summaries. Repeated component identities are refused. Video title affects plan identity, but the observation has no title field and therefore does not verify the actual title.

Even an exact match returns publication_verified=False. Observed hashes and readiness are caller declarations. Confirming that a server received a file or an editor saved the order requires a trusted observer and an actual service read. The example's matches field must not become another spelling of business completion.

What thirty tests and five records show

Tests reject path-like names, invalid digests, blank or adjacent text and ambiguous selected metadata. They distinguish same-name different bytes, misplaced media, changed paragraphs and observations that are not ready. Digest changes and preservation of caller-owned input objects are checked too. All input is synthetic.

Thirty source tests ran locally, and the packaging procedure repeats the same thirty after extracting the ZIP. Five saved scenarios come from actual local function calls. The selector reads those records. Neither the original browser nor a remote uploader or publisher was exercised. Passing a structured comparison and observing actual media storage are separate evidence, and the example keeps that separation visible.

A read-only viewer of synthetic local records

Define comparison evidence before attaching another editor

Code, tests, examples and documentation permit modification and reuse. There is no persistent journal, interruption recovery or automatic retry. Compile bindings are diagnostic material; review does not authenticate actual handle use. Integration first needs a trustworthy relationship between an observed component and the selected file it represents.

Another company's editor may have different media kinds and paragraph rules. Adapt the meaning that must survive rather than imposing the example's numbers and shapes everywhere. I share it as a small starting point for checking which image belongs in which position, extending verification beyond a body-text match while stating the service evidence still required.

Download code, tests and records
Python standard library, synthetic data, modification and reuse permitted